From 9f1aa866bda7678261f2f441d4cfd5bb524c2411 Mon Sep 17 00:00:00 2001 From: Jo Asplin Date: Thu, 20 Oct 2011 13:17:26 +0200 Subject: Moved tests into integrationtests/ and widgets/ Task-number: QTBUG-19013 Change-Id: Ibb776f5967c0645ce6d22ef7afdc40657c575461 Reviewed-by: Holger Ihrig --- tests/auto/widgets/kernel/kernel.pro | 17 + tests/auto/widgets/kernel/qaction/.gitignore | 1 + tests/auto/widgets/kernel/qaction/qaction.pro | 5 + tests/auto/widgets/kernel/qaction/tst_qaction.cpp | 373 + tests/auto/widgets/kernel/qactiongroup/.gitignore | 1 + .../widgets/kernel/qactiongroup/qactiongroup.pro | 5 + .../kernel/qactiongroup/tst_qactiongroup.cpp | 247 + tests/auto/widgets/kernel/qapplication/.gitignore | 3 + .../desktopsettingsaware/desktopsettingsaware.pro | 14 + .../qapplication/desktopsettingsaware/main.cpp | 54 + tests/auto/widgets/kernel/qapplication/heart.svg | 55 + .../widgets/kernel/qapplication/modal/base.cpp | 62 + .../auto/widgets/kernel/qapplication/modal/base.h | 64 + .../widgets/kernel/qapplication/modal/main.cpp | 54 + .../widgets/kernel/qapplication/modal/modal.pro | 9 + .../widgets/kernel/qapplication/qapplication.pro | 7 + .../auto/widgets/kernel/qapplication/test/test.pro | 27 + tests/auto/widgets/kernel/qapplication/tmp/README | 3 + .../kernel/qapplication/tst_qapplication.cpp | 2107 +++++ .../kernel/qapplication/wincmdline/main.cpp | 53 + .../kernel/qapplication/wincmdline/wincmdline.pro | 8 + tests/auto/widgets/kernel/qboxlayout/.gitignore | 1 + .../auto/widgets/kernel/qboxlayout/qboxlayout.pro | 5 + .../widgets/kernel/qboxlayout/tst_qboxlayout.cpp | 280 + .../auto/widgets/kernel/qdesktopwidget/.gitignore | 1 + .../kernel/qdesktopwidget/qdesktopwidget.pro | 3 + .../kernel/qdesktopwidget/tst_qdesktopwidget.cpp | 187 + tests/auto/widgets/kernel/qformlayout/.gitignore | 1 + .../widgets/kernel/qformlayout/qformlayout.pro | 3 + .../widgets/kernel/qformlayout/tst_qformlayout.cpp | 913 ++ tests/auto/widgets/kernel/qgridlayout/.gitignore | 1 + .../widgets/kernel/qgridlayout/qgridlayout.pro | 10 + .../auto/widgets/kernel/qgridlayout/sortdialog.ui | 135 + .../widgets/kernel/qgridlayout/tst_qgridlayout.cpp | 1646 ++++ .../widgets/kernel/qinputcontext/qinputcontext.pro | 7 + .../kernel/qinputcontext/tst_qinputcontext.cpp | 398 + tests/auto/widgets/kernel/qlayout/.gitignore | 1 + .../widgets/kernel/qlayout/baseline/smartmaxsize | 1792 ++++ tests/auto/widgets/kernel/qlayout/qlayout.pro | 16 + tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp | 345 + tests/auto/widgets/kernel/qsound/.gitignore | 1 + tests/auto/widgets/kernel/qsound/4.wav | Bin 0 -> 5538 bytes tests/auto/widgets/kernel/qsound/qsound.pro | 10 + tests/auto/widgets/kernel/qsound/tst_qsound.cpp | 88 + .../auto/widgets/kernel/qstackedlayout/.gitignore | 1 + .../kernel/qstackedlayout/qstackedlayout.pro | 6 + .../kernel/qstackedlayout/tst_qstackedlayout.cpp | 372 + tests/auto/widgets/kernel/qtooltip/.gitignore | 1 + tests/auto/widgets/kernel/qtooltip/qtooltip.pro | 5 + .../auto/widgets/kernel/qtooltip/tst_qtooltip.cpp | 186 + tests/auto/widgets/kernel/qwidget/.gitignore | 1 + .../widgets/kernel/qwidget/geometry-fullscreen.dat | Bin 0 -> 46 bytes .../widgets/kernel/qwidget/geometry-maximized.dat | Bin 0 -> 46 bytes tests/auto/widgets/kernel/qwidget/geometry.dat | Bin 0 -> 46 bytes tests/auto/widgets/kernel/qwidget/qwidget.pro | 23 + tests/auto/widgets/kernel/qwidget/qwidget.qrc | 7 + .../testdata/paintEvent/res_Motif_data0.qsnap | Bin 0 -> 722 bytes .../testdata/paintEvent/res_Motif_data1.qsnap | Bin 0 -> 1509 bytes .../testdata/paintEvent/res_Motif_data2.qsnap | Bin 0 -> 7965 bytes .../testdata/paintEvent/res_Motif_data3.qsnap | Bin 0 -> 8265 bytes .../testdata/paintEvent/res_Windows_data0.qsnap | Bin 0 -> 710 bytes .../testdata/paintEvent/res_Windows_data1.qsnap | Bin 0 -> 1497 bytes .../testdata/paintEvent/res_Windows_data2.qsnap | Bin 0 -> 7953 bytes .../testdata/paintEvent/res_Windows_data3.qsnap | Bin 0 -> 8253 bytes tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 9472 ++++++++++++++++++++ .../kernel/qwidget/tst_qwidget_mac_helpers.h | 52 + .../kernel/qwidget/tst_qwidget_mac_helpers.mm | 83 + .../auto/widgets/kernel/qwidget_window/.gitignore | 1 + .../kernel/qwidget_window/qwidget_window.pro | 8 + .../kernel/qwidget_window/tst_qwidget_window.cpp | 326 + tests/auto/widgets/kernel/qwidgetaction/.gitignore | 1 + .../widgets/kernel/qwidgetaction/qwidgetaction.pro | 5 + .../kernel/qwidgetaction/tst_qwidgetaction.cpp | 405 + 73 files changed, 19968 insertions(+) create mode 100644 tests/auto/widgets/kernel/kernel.pro create mode 100644 tests/auto/widgets/kernel/qaction/.gitignore create mode 100644 tests/auto/widgets/kernel/qaction/qaction.pro create mode 100644 tests/auto/widgets/kernel/qaction/tst_qaction.cpp create mode 100644 tests/auto/widgets/kernel/qactiongroup/.gitignore create mode 100644 tests/auto/widgets/kernel/qactiongroup/qactiongroup.pro create mode 100644 tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/.gitignore create mode 100644 tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro create mode 100644 tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/heart.svg create mode 100644 tests/auto/widgets/kernel/qapplication/modal/base.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/modal/base.h create mode 100644 tests/auto/widgets/kernel/qapplication/modal/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/modal/modal.pro create mode 100644 tests/auto/widgets/kernel/qapplication/qapplication.pro create mode 100644 tests/auto/widgets/kernel/qapplication/test/test.pro create mode 100644 tests/auto/widgets/kernel/qapplication/tmp/README create mode 100644 tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp create mode 100644 tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro create mode 100644 tests/auto/widgets/kernel/qboxlayout/.gitignore create mode 100644 tests/auto/widgets/kernel/qboxlayout/qboxlayout.pro create mode 100644 tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp create mode 100644 tests/auto/widgets/kernel/qdesktopwidget/.gitignore create mode 100644 tests/auto/widgets/kernel/qdesktopwidget/qdesktopwidget.pro create mode 100644 tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp create mode 100644 tests/auto/widgets/kernel/qformlayout/.gitignore create mode 100644 tests/auto/widgets/kernel/qformlayout/qformlayout.pro create mode 100644 tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp create mode 100644 tests/auto/widgets/kernel/qgridlayout/.gitignore create mode 100644 tests/auto/widgets/kernel/qgridlayout/qgridlayout.pro create mode 100644 tests/auto/widgets/kernel/qgridlayout/sortdialog.ui create mode 100644 tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp create mode 100644 tests/auto/widgets/kernel/qinputcontext/qinputcontext.pro create mode 100644 tests/auto/widgets/kernel/qinputcontext/tst_qinputcontext.cpp create mode 100644 tests/auto/widgets/kernel/qlayout/.gitignore create mode 100644 tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize create mode 100644 tests/auto/widgets/kernel/qlayout/qlayout.pro create mode 100644 tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp create mode 100644 tests/auto/widgets/kernel/qsound/.gitignore create mode 100644 tests/auto/widgets/kernel/qsound/4.wav create mode 100644 tests/auto/widgets/kernel/qsound/qsound.pro create mode 100644 tests/auto/widgets/kernel/qsound/tst_qsound.cpp create mode 100644 tests/auto/widgets/kernel/qstackedlayout/.gitignore create mode 100644 tests/auto/widgets/kernel/qstackedlayout/qstackedlayout.pro create mode 100644 tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp create mode 100644 tests/auto/widgets/kernel/qtooltip/.gitignore create mode 100644 tests/auto/widgets/kernel/qtooltip/qtooltip.pro create mode 100644 tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp create mode 100644 tests/auto/widgets/kernel/qwidget/.gitignore create mode 100644 tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat create mode 100644 tests/auto/widgets/kernel/qwidget/geometry-maximized.dat create mode 100644 tests/auto/widgets/kernel/qwidget/geometry.dat create mode 100644 tests/auto/widgets/kernel/qwidget/qwidget.pro create mode 100644 tests/auto/widgets/kernel/qwidget/qwidget.qrc create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap create mode 100644 tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp create mode 100644 tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h create mode 100644 tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm create mode 100644 tests/auto/widgets/kernel/qwidget_window/.gitignore create mode 100644 tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro create mode 100644 tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp create mode 100644 tests/auto/widgets/kernel/qwidgetaction/.gitignore create mode 100644 tests/auto/widgets/kernel/qwidgetaction/qwidgetaction.pro create mode 100644 tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp (limited to 'tests/auto/widgets/kernel') diff --git a/tests/auto/widgets/kernel/kernel.pro b/tests/auto/widgets/kernel/kernel.pro new file mode 100644 index 0000000000..2e55f8eba2 --- /dev/null +++ b/tests/auto/widgets/kernel/kernel.pro @@ -0,0 +1,17 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qaction \ + qactiongroup \ + qapplication \ + qboxlayout \ + qdesktopwidget \ + qformlayout \ + qgridlayout \ + qinputcontext \ + qlayout \ + qsound \ + qstackedlayout \ + qtooltip \ + qwidget \ + qwidget_window \ + qwidgetaction \ diff --git a/tests/auto/widgets/kernel/qaction/.gitignore b/tests/auto/widgets/kernel/qaction/.gitignore new file mode 100644 index 0000000000..bf81f5bf2c --- /dev/null +++ b/tests/auto/widgets/kernel/qaction/.gitignore @@ -0,0 +1 @@ +tst_qaction diff --git a/tests/auto/widgets/kernel/qaction/qaction.pro b/tests/auto/widgets/kernel/qaction/qaction.pro new file mode 100644 index 0000000000..9c3648d52f --- /dev/null +++ b/tests/auto/widgets/kernel/qaction/qaction.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qaction.cpp + + diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp new file mode 100644 index 0000000000..637ec144d2 --- /dev/null +++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QAction : public QObject +{ + Q_OBJECT + +public: + tst_QAction(); + virtual ~tst_QAction(); + + + void updateState(QActionEvent *e); + +public slots: + void initTestCase(); + void cleanupTestCase(); +private slots: + void getSetCheck(); + void setText_data(); + void setText(); + void setIconText_data() { setText_data(); } + void setIconText(); + void actionEvent(); + void setStandardKeys(); + void alternateShortcuts(); + void enabledVisibleInteraction(); + void task200823_tooltip(); + void task229128TriggeredSignalWithoutActiongroup(); + void task229128TriggeredSignalWhenInActiongroup(); + +private: + int m_lastEventType; + QAction *m_lastAction; + QWidget *m_tstWidget; +}; + +// Testing get/set functions +void tst_QAction::getSetCheck() +{ + QAction obj1(0); + // QActionGroup * QAction::actionGroup() + // void QAction::setActionGroup(QActionGroup *) + QActionGroup *var1 = new QActionGroup(0); + obj1.setActionGroup(var1); + QCOMPARE(var1, obj1.actionGroup()); + obj1.setActionGroup((QActionGroup *)0); + QCOMPARE((QActionGroup *)0, obj1.actionGroup()); + delete var1; + + // QMenu * QAction::menu() + // void QAction::setMenu(QMenu *) + QMenu *var2 = new QMenu(0); + obj1.setMenu(var2); + QCOMPARE(var2, obj1.menu()); + obj1.setMenu((QMenu *)0); + QCOMPARE((QMenu *)0, obj1.menu()); + delete var2; + + QCOMPARE(obj1.priority(), QAction::NormalPriority); + obj1.setPriority(QAction::LowPriority); + QCOMPARE(obj1.priority(), QAction::LowPriority); +} + +class MyWidget : public QWidget +{ + Q_OBJECT +public: + MyWidget(tst_QAction *tst, QWidget *parent = 0) : QWidget(parent) { this->tst = tst; } + +protected: + virtual void actionEvent(QActionEvent *e) { tst->updateState(e); } + +private: + tst_QAction *tst; +}; + +tst_QAction::tst_QAction() +{ +} + +tst_QAction::~tst_QAction() +{ + +} + +void tst_QAction::initTestCase() +{ + m_lastEventType = 0; + m_lastAction = 0; + + MyWidget *mw = new MyWidget(this); + m_tstWidget = mw; + mw->show(); + qApp->setActiveWindow(mw); +} + +void tst_QAction::cleanupTestCase() +{ + QWidget *testWidget = m_tstWidget; + if (testWidget) { + testWidget->hide(); + delete testWidget; + } +} + +void tst_QAction::setText_data() +{ + QTest::addColumn("text"); + QTest::addColumn("iconText"); + QTest::addColumn("textFromIconText"); + + //next we fill it with data + QTest::newRow("Normal") << "Action" << "Action" << "Action"; + QTest::newRow("Ampersand") << "Search && Destroy" << "Search & Destroy" << "Search && Destroy"; + QTest::newRow("Mnemonic and ellipsis") << "O&pen File ..." << "Open File" << "Open File"; +} + +void tst_QAction::setText() +{ + QFETCH(QString, text); + + QAction action(0); + action.setText(text); + + QCOMPARE(action.text(), text); + + QFETCH(QString, iconText); + QCOMPARE(action.iconText(), iconText); +} + +void tst_QAction::setIconText() +{ + QFETCH(QString, iconText); + + QAction action(0); + action.setIconText(iconText); + QCOMPARE(action.iconText(), iconText); + + QFETCH(QString, textFromIconText); + QCOMPARE(action.text(), textFromIconText); +} + + +void tst_QAction::updateState(QActionEvent *e) +{ + if (!e) { + m_lastEventType = 0; + m_lastAction = 0; + } else { + m_lastEventType = (int)e->type(); + m_lastAction = e->action(); + } +} + +void tst_QAction::actionEvent() +{ + QAction a(0); + a.setText("action text"); + + // add action + m_tstWidget->addAction(&a); + qApp->processEvents(); + + QCOMPARE(m_lastEventType, (int)QEvent::ActionAdded); + QCOMPARE(m_lastAction, &a); + + // change action + a.setText("new action text"); + qApp->processEvents(); + + QCOMPARE(m_lastEventType, (int)QEvent::ActionChanged); + QCOMPARE(m_lastAction, &a); + + // remove action + m_tstWidget->removeAction(&a); + qApp->processEvents(); + + QCOMPARE(m_lastEventType, (int)QEvent::ActionRemoved); + QCOMPARE(m_lastAction, &a); +} + +//basic testing of standard keys +void tst_QAction::setStandardKeys() +{ + QAction act(0); + act.setShortcut(QKeySequence("CTRL+L")); + QList list; + act.setShortcuts(list); + act.setShortcuts(QKeySequence::Copy); + QVERIFY(act.shortcut() == act.shortcuts().first()); + + QList expected; +#if defined(Q_WS_MAC) + expected << QKeySequence("CTRL+C"); +#elif defined(Q_WS_WIN) || defined(Q_WS_QWS) || defined(Q_WS_QPA) + expected << QKeySequence("CTRL+C") << QKeySequence("CTRL+INSERT"); +#else + expected << QKeySequence("CTRL+C") << QKeySequence("F16") << QKeySequence("CTRL+INSERT"); +#endif + QVERIFY(act.shortcuts() == expected); +} + + +void tst_QAction::alternateShortcuts() +{ + //test the alternate shortcuts (by adding more than 1 shortcut) + + QWidget *wid = m_tstWidget; + + { + QAction act(wid); + wid->addAction(&act); + QList shlist = QList() << QKeySequence("CTRL+P") << QKeySequence("CTRL+A"); + act.setShortcuts(shlist); + + QSignalSpy spy(&act, SIGNAL(triggered())); + + act.setAutoRepeat(true); + QTest::keyClick(wid, Qt::Key_A, Qt::ControlModifier); + QCOMPARE(spy.count(), 1); //act should have been triggered + + act.setAutoRepeat(false); + QTest::keyClick(wid, Qt::Key_A, Qt::ControlModifier); + QCOMPARE(spy.count(), 2); //act should have been triggered a 2nd time + + //end of the scope of the action, it will be destroyed and removed from wid + //This action should also unregister its shortcuts + } + + + //this tests a crash (if the action did not unregister its alternate shortcuts) + QTest::keyClick(wid, Qt::Key_A, Qt::ControlModifier); +} + +void tst_QAction::enabledVisibleInteraction() +{ + QAction act(0); + // check defaults + QVERIFY(act.isEnabled()); + QVERIFY(act.isVisible()); + + // !visible => !enabled + act.setVisible(false); + QVERIFY(!act.isEnabled()); + act.setVisible(true); + QVERIFY(act.isEnabled()); + act.setEnabled(false); + QVERIFY(act.isVisible()); + + // check if shortcut is disabled if not visible + m_tstWidget->addAction(&act); + act.setShortcut(QKeySequence("Ctrl+T")); + QSignalSpy spy(&act, SIGNAL(triggered())); + act.setEnabled(true); + act.setVisible(false); + QTest::keyClick(m_tstWidget, Qt::Key_T, Qt::ControlModifier); + QCOMPARE(spy.count(), 0); //act is not visible, so don't trigger + act.setVisible(false); + act.setEnabled(true); + QTest::keyClick(m_tstWidget, Qt::Key_T, Qt::ControlModifier); + QCOMPARE(spy.count(), 0); //act is not visible, so don't trigger + act.setVisible(true); + act.setEnabled(true); + QTest::keyClick(m_tstWidget, Qt::Key_T, Qt::ControlModifier); + QCOMPARE(spy.count(), 1); //act is visible and enabled, so trigger +} + +void tst_QAction::task200823_tooltip() +{ + QAction *action = new QAction("foo", 0); + QString shortcut("ctrl+o"); + action->setShortcut(shortcut); + + // we want a non-standard tooltip that shows the shortcut + action->setToolTip(QString("%1 (%2)").arg(action->text()).arg(action->shortcut().toString())); + + QString ref = QString("foo (%1)").arg(QKeySequence(shortcut).toString()); + QCOMPARE(action->toolTip(), ref); +} + +void tst_QAction::task229128TriggeredSignalWithoutActiongroup() +{ + // test without a group + QAction *actionWithoutGroup = new QAction("Test", qApp); + QSignalSpy spyWithoutGroup(actionWithoutGroup, SIGNAL(triggered(bool))); + QCOMPARE(spyWithoutGroup.count(), 0); + actionWithoutGroup->trigger(); + // signal should be emitted + QCOMPARE(spyWithoutGroup.count(), 1); + + // it is now a checkable checked action + actionWithoutGroup->setCheckable(true); + actionWithoutGroup->setChecked(true); + spyWithoutGroup.clear(); + QCOMPARE(spyWithoutGroup.count(), 0); + actionWithoutGroup->trigger(); + // signal should be emitted + QCOMPARE(spyWithoutGroup.count(), 1); +} + +void tst_QAction::task229128TriggeredSignalWhenInActiongroup() +{ + QActionGroup ag(0); + QAction *action = new QAction("Test", &ag); + QAction *checkedAction = new QAction("Test 2", &ag); + ag.addAction(action); + action->setCheckable(true); + ag.addAction(checkedAction); + checkedAction->setCheckable(true); + checkedAction->setChecked(true); + + QSignalSpy actionSpy(checkedAction, SIGNAL(triggered(bool))); + QSignalSpy actionGroupSpy(&ag, SIGNAL(triggered(QAction *))); + QCOMPARE(actionGroupSpy.count(), 0); + QCOMPARE(actionSpy.count(), 0); + checkedAction->trigger(); + // check that both the group and the action have emitted the signal + QCOMPARE(actionGroupSpy.count(), 1); + QCOMPARE(actionSpy.count(), 1); +} + +QTEST_MAIN(tst_QAction) +#include "tst_qaction.moc" diff --git a/tests/auto/widgets/kernel/qactiongroup/.gitignore b/tests/auto/widgets/kernel/qactiongroup/.gitignore new file mode 100644 index 0000000000..daba003e96 --- /dev/null +++ b/tests/auto/widgets/kernel/qactiongroup/.gitignore @@ -0,0 +1 @@ +tst_qactiongroup diff --git a/tests/auto/widgets/kernel/qactiongroup/qactiongroup.pro b/tests/auto/widgets/kernel/qactiongroup/qactiongroup.pro new file mode 100644 index 0000000000..9b8636968b --- /dev/null +++ b/tests/auto/widgets/kernel/qactiongroup/qactiongroup.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qactiongroup.cpp + + diff --git a/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp new file mode 100644 index 0000000000..406298807a --- /dev/null +++ b/tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include + +class tst_QActionGroup : public QObject +{ + Q_OBJECT + +private slots: + void enabledPropagation(); + void visiblePropagation(); + void exclusive(); + void separators(); + void testActionInTwoQActionGroup(); + void unCheckCurrentAction(); +}; + +void tst_QActionGroup::enabledPropagation() +{ + QActionGroup testActionGroup( 0 ); + + QAction* childAction = new QAction( &testActionGroup ); + QAction* anotherChildAction = new QAction( &testActionGroup ); + QAction* freeAction = new QAction(0); + + QVERIFY( testActionGroup.isEnabled() ); + QVERIFY( childAction->isEnabled() ); + + testActionGroup.setEnabled( false ); + QVERIFY( !testActionGroup.isEnabled() ); + QVERIFY( !childAction->isEnabled() ); + QVERIFY( !anotherChildAction->isEnabled() ); + + childAction->setEnabled(true); + QVERIFY( !childAction->isEnabled()); + + anotherChildAction->setEnabled( false ); + + testActionGroup.setEnabled( true ); + QVERIFY( testActionGroup.isEnabled() ); + QVERIFY( childAction->isEnabled() ); + QVERIFY( !anotherChildAction->isEnabled() ); + + testActionGroup.setEnabled( false ); + QAction *lastChildAction = new QAction(&testActionGroup); + + QVERIFY(!lastChildAction->isEnabled()); + testActionGroup.setEnabled( true ); + QVERIFY(lastChildAction->isEnabled()); + + freeAction->setEnabled(false); + testActionGroup.addAction(freeAction); + QVERIFY(!freeAction->isEnabled()); + delete freeAction; +} + +void tst_QActionGroup::visiblePropagation() +{ + QActionGroup testActionGroup( 0 ); + + QAction* childAction = new QAction( &testActionGroup ); + QAction* anotherChildAction = new QAction( &testActionGroup ); + QAction* freeAction = new QAction(0); + + QVERIFY( testActionGroup.isVisible() ); + QVERIFY( childAction->isVisible() ); + + testActionGroup.setVisible( false ); + QVERIFY( !testActionGroup.isVisible() ); + QVERIFY( !childAction->isVisible() ); + QVERIFY( !anotherChildAction->isVisible() ); + + anotherChildAction->setVisible(false); + + testActionGroup.setVisible( true ); + QVERIFY( testActionGroup.isVisible() ); + QVERIFY( childAction->isVisible() ); + + QVERIFY( !anotherChildAction->isVisible() ); + + testActionGroup.setVisible( false ); + QAction *lastChildAction = new QAction(&testActionGroup); + + QVERIFY(!lastChildAction->isVisible()); + testActionGroup.setVisible( true ); + QVERIFY(lastChildAction->isVisible()); + + freeAction->setVisible(false); + testActionGroup.addAction(freeAction); + QVERIFY(!freeAction->isVisible()); + delete freeAction; +} + +void tst_QActionGroup::exclusive() +{ + QActionGroup group(0); + group.setExclusive(false); + QVERIFY( !group.isExclusive() ); + + QAction* actOne = new QAction( &group ); + actOne->setCheckable( true ); + QAction* actTwo = new QAction( &group ); + actTwo->setCheckable( true ); + QAction* actThree = new QAction( &group ); + actThree->setCheckable( true ); + + group.setExclusive( true ); + QVERIFY( !actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actOne->setChecked( true ); + QVERIFY( actOne->isChecked() ); + QVERIFY( !actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); + + actTwo->setChecked( true ); + QVERIFY( !actOne->isChecked() ); + QVERIFY( actTwo->isChecked() ); + QVERIFY( !actThree->isChecked() ); +} + +void tst_QActionGroup::separators() +{ + QMainWindow mw; + QMenu menu(&mw); + QActionGroup actGroup(&mw); + + mw.show(); + +#ifdef QT_SOFTKEYS_ENABLED + // Softkeys add extra "Select" and "Back" actions to menu by default. + // Two first actions will be Select and Back when softkeys are enabled + int numSoftkeyActions = 2; +#else + int numSoftkeyActions = 0; +#endif + + QAction *action = new QAction(&actGroup); + action->setText("test one"); + + QAction *separator = new QAction(&actGroup); + separator->setSeparator(true); + actGroup.addAction(separator); + + QListIterator it(actGroup.actions()); + while (it.hasNext()) + menu.addAction(it.next()); + + QCOMPARE((int)menu.actions().size(), 2 + numSoftkeyActions); + + it = QListIterator(actGroup.actions()); + while (it.hasNext()) + menu.removeAction(it.next()); + + QCOMPARE((int)menu.actions().size(), 0 + numSoftkeyActions); + + action = new QAction(&actGroup); + action->setText("test two"); + + it = QListIterator(actGroup.actions()); + while (it.hasNext()) + menu.addAction(it.next()); + + QCOMPARE((int)menu.actions().size(), 3 + numSoftkeyActions); +} + +void tst_QActionGroup::testActionInTwoQActionGroup() +{ + QAction action1("Action 1", this); + + QActionGroup group1(this); + QActionGroup group2(this); + + group1.addAction(&action1); + group2.addAction(&action1); + + QCOMPARE(action1.actionGroup(), &group2); + QCOMPARE(group2.actions().first(), &action1); + QCOMPARE(group1.actions().isEmpty(), true); +} + +void tst_QActionGroup::unCheckCurrentAction() +{ + QActionGroup group(0); + QAction action1(&group) ,action2(&group); + action1.setCheckable(true); + action2.setCheckable(true); + QVERIFY(!action1.isChecked()); + QVERIFY(!action2.isChecked()); + action1.setChecked(true); + QVERIFY(action1.isChecked()); + QVERIFY(!action2.isChecked()); + QAction *current = group.checkedAction(); + QCOMPARE(current, &action1); + current->setChecked(false); + QVERIFY(!action1.isChecked()); + QVERIFY(!action2.isChecked()); + QVERIFY(group.checkedAction() == 0); +} + + +QTEST_MAIN(tst_QActionGroup) +#include "tst_qactiongroup.moc" diff --git a/tests/auto/widgets/kernel/qapplication/.gitignore b/tests/auto/widgets/kernel/qapplication/.gitignore new file mode 100644 index 0000000000..ca666e480a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/.gitignore @@ -0,0 +1,3 @@ +tst_qapplication +desktopsettingsaware/desktopsettingsaware +wincmdline/wincmdline diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro new file mode 100644 index 0000000000..216a9710c7 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/desktopsettingsaware.pro @@ -0,0 +1,14 @@ +###################################################################### +# Automatically generated by qmake (2.00a) Mon Jul 11 11:30:34 2005 +###################################################################### + +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . +wince*:TARGET = ../desktopsettingsaware + +# Input +QT += widgets +SOURCES += main.cpp +CONFIG += qt warn_on create_prl link_prl +CONFIG -= app_bundle diff --git a/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp new file mode 100644 index 0000000000..9e2172829a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/desktopsettingsaware/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +int main(int argc, char **argv) { + QApplication::setDesktopSettingsAware(false); + QApplication app(argc, argv); + QComboBox box; + box.insertItem(0, "foo"); + box.setEditable(true); + box.show(); + return 0; +} diff --git a/tests/auto/widgets/kernel/qapplication/heart.svg b/tests/auto/widgets/kernel/qapplication/heart.svg new file mode 100644 index 0000000000..8c982cd93c --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/heart.svg @@ -0,0 +1,55 @@ + + + + + +Heart Left-Highlight +This is a normal valentines day heart. + + +holiday +valentines + +valentine +hash(0x8a091c0) +hash(0x8a0916c) +signs_and_symbols +hash(0x8a091f0) +day + + + + +Jon Phillips + + + + +Jon Phillips + + + + +Jon Phillips + + + +image/svg+xml + + +en + + + + + + + + + + + + + + + diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.cpp b/tests/auto/widgets/kernel/qapplication/modal/base.cpp new file mode 100644 index 0000000000..2f7b4ad529 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/base.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "base.h" + +base::base(QWidget *parent) : + QWidget(parent) +{ + m_timer = new QTimer(this); + m_modalStarted = false; + m_timer->setSingleShot(false); + connect(m_timer, SIGNAL(timeout()), this, SLOT(periodicTimer())); + m_timer->start(5000); +} + +void base::periodicTimer() +{ + if(m_modalStarted) + exit(0); + m_modalDialog = new QDialog(this); + m_modalDialog->setModal(true); + m_modalDialog->show(); + m_modalStarted = true; +} diff --git a/tests/auto/widgets/kernel/qapplication/modal/base.h b/tests/auto/widgets/kernel/qapplication/modal/base.h new file mode 100644 index 0000000000..e1f36e11bd --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/base.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BASE_H +#define BASE_H + +#include +#include +#include + +class base : public QWidget +{ +Q_OBJECT + QTimer *m_timer; + bool m_modalStarted; + QDialog *m_modalDialog; +public: + explicit base(QWidget *parent = 0); + +signals: + +public slots: + void periodicTimer(); +}; + +#endif // BASE_H diff --git a/tests/auto/widgets/kernel/qapplication/modal/main.cpp b/tests/auto/widgets/kernel/qapplication/modal/main.cpp new file mode 100644 index 0000000000..53c6008eb5 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include "base.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_NativeWindows); //QTBUG-15774 + base *b = new base(); + Q_UNUSED(b); + return app.exec(); +} diff --git a/tests/auto/widgets/kernel/qapplication/modal/modal.pro b/tests/auto/widgets/kernel/qapplication/modal/modal.pro new file mode 100644 index 0000000000..9ed69769bb --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/modal/modal.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +QT += widgets +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +SOURCES += main.cpp \ + base.cpp +DESTDIR = ./ +HEADERS += base.h diff --git a/tests/auto/widgets/kernel/qapplication/qapplication.pro b/tests/auto/widgets/kernel/qapplication/qapplication.pro new file mode 100644 index 0000000000..becc6c6f4b --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/qapplication.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs +SUBDIRS = test \ + desktopsettingsaware \ + modal \ + wincmdline + + diff --git a/tests/auto/widgets/kernel/qapplication/test/test.pro b/tests/auto/widgets/kernel/qapplication/test/test.pro new file mode 100644 index 0000000000..65aae7b0b9 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/test/test.pro @@ -0,0 +1,27 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += core-private gui-private + +SOURCES += ../tst_qapplication.cpp +TARGET = ../tst_qapplication + +wince* { + additional.files = ../desktopsettingsaware/desktopsettingsaware.exe + additional.path = desktopsettingsaware + someTest.files = test.pro + someTest.path = test + DEPLOYMENT += additional deploy someTest +} + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qapplication +} else { + TARGET = ../../release/tst_qapplication + } +} + +mac*:CONFIG+=insignificant_test + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/widgets/kernel/qapplication/tmp/README b/tests/auto/widgets/kernel/qapplication/tmp/README new file mode 100644 index 0000000000..e758961ddf --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/tmp/README @@ -0,0 +1,3 @@ +this dummy directory is needed for the QApplication::libraryPaths() autotest +that calls QDir(applicationDirPath + "/tmp/..").canonicalPath(). canonicalPath() +stat()'s the given directory, so if the tmp directory doesn't exist it fails... diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp new file mode 100644 index 0000000000..c37dfc609e --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -0,0 +1,2107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +//#define QT_TST_QAPP_DEBUG +#include + +#include + +#include "qabstracteventdispatcher.h" +#include +#include + +#include "private/qapplication_p.h" +#include "private/qstylesheetstyle_p.h" +#ifdef Q_OS_WINCE +#include +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QApplication : public QObject +{ +Q_OBJECT + +public: + tst_QApplication(); + virtual ~tst_QApplication(); + +public slots: + void init(); + void cleanup(); +private slots: + void sendEventsOnProcessEvents(); // this must be the first test + void getSetCheck(); + void staticSetup(); + + void alert(); + + void multiple_data(); + void multiple(); + + void nonGui(); + + void setFont_data(); + void setFont(); + + void args_data(); + void args(); + + void lastWindowClosed(); + void quitOnLastWindowClosed(); + void closeAllWindows(); + void testDeleteLater(); + void testDeleteLaterProcessEvents(); + + void libraryPaths(); + void libraryPaths_qt_plugin_path(); + void libraryPaths_qt_plugin_path_2(); + + void sendPostedEvents(); + + void thread(); + void desktopSettingsAware(); + + void setActiveWindow(); + + void focusChanged(); + void focusOut(); + + void execAfterExit(); + + void wheelScrollLines(); + + void task109149(); + + void style(); + + void allWidgets(); + void topLevelWidgets(); + + void setAttribute(); + + void windowsCommandLine_data(); + void windowsCommandLine(); + + void touchEventPropagation(); + + void qtbug_12673(); + + void globalStaticObjectDestruction(); // run this last +}; + +class EventSpy : public QObject +{ + Q_OBJECT + +public: + QList recordedEvents; + bool eventFilter(QObject *, QEvent *event) + { + recordedEvents.append(event->type()); + return false; + } +}; + +void tst_QApplication::sendEventsOnProcessEvents() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + EventSpy spy; + app.installEventFilter(&spy); + + QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1))); + QCoreApplication::processEvents(); + QVERIFY(spy.recordedEvents.contains(QEvent::User + 1)); +} + +class MyInputContext : public QInputContext +{ +public: + MyInputContext() : QInputContext() {} + QString identifierName() { return QString("NoName"); } + QString language() { return QString("NoLanguage"); } + void reset() {} + bool isComposing() const { return false; } +}; + +// Testing get/set functions +void tst_QApplication::getSetCheck() +{ + int argc = 0; + QApplication obj1(argc, 0, QApplication::GuiServer); + MyInputContext *var1 = new MyInputContext; + + // QApplication takes ownership, so check for reparenting: + obj1.setInputContext(var1); + QCOMPARE(var1->parent(), static_cast(&obj1)); + + // Test for self-assignment: + obj1.setInputContext(obj1.inputContext()); + QVERIFY(obj1.inputContext()); + QCOMPARE(static_cast(var1), obj1.inputContext()); + + // Resetting the input context to 0 is not allowed: + QTest::ignoreMessage(QtWarningMsg, "QApplication::setInputContext: called with 0 input context"); + obj1.setInputContext(0); + + QCOMPARE(static_cast(var1), obj1.inputContext()); +} + +class CloseEventTestWindow : public QWidget +{ +public: + CloseEventTestWindow(QWidget *parent = 0) + : QWidget(parent) + { + } + + void closeEvent(QCloseEvent *event) + { + QWidget dialog; + dialog.show(); + dialog.close(); + + hide(); + event->ignore(); + } +}; + +static char *argv0; + +tst_QApplication::tst_QApplication() +{ +#ifdef Q_OS_WINCE + // Clean up environment previously to launching test + qputenv("QT_PLUGIN_PATH", QByteArray()); +#endif +} + +tst_QApplication::~tst_QApplication() +{ + +} + +void tst_QApplication::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. +} + +void tst_QApplication::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. +} + +void tst_QApplication::staticSetup() +{ + QVERIFY(!qApp); + + QStyle *style = QStyleFactory::create(QLatin1String("Windows")); + QVERIFY(style); + QApplication::setStyle(style); + + QPalette pal; + QApplication::setPalette(pal); + + /*QFont font; + QApplication::setFont(font);*/ + + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); +} + + +// QApp subclass that exits the event loop after 150ms +class TestApplication : public QApplication +{ +public: + TestApplication( int &argc, char **argv ) + : QApplication( argc, argv, QApplication::GuiServer ) + { + startTimer( 150 ); + } + + void timerEvent( QTimerEvent * ) + { + quit(); + } +}; + +void tst_QApplication::alert() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + app.alert(0, 0); + + QWidget widget; + QWidget widget2; + app.alert(&widget, 100); + widget.show(); + widget2.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); + qt_x11_wait_for_window_manager(&widget2); +#endif + QTest::qWait(100); + app.alert(&widget, -1); + app.alert(&widget, 250); + widget2.activateWindow(); + QApplication::setActiveWindow(&widget2); + app.alert(&widget, 0); + widget.activateWindow(); + QApplication::setActiveWindow(&widget); + app.alert(&widget, 200); + app.syncX(); +} + +void tst_QApplication::multiple_data() +{ + QTest::addColumn("features"); + + // return a list of things to try + QTest::newRow( "data0" ) << QStringList( "" ); + QTest::newRow( "data1" ) << QStringList( "QFont" ); + QTest::newRow( "data2" ) << QStringList( "QPixmap" ); + QTest::newRow( "data3" ) << QStringList( "QWidget" ); +} + +void tst_QApplication::multiple() +{ + QFETCH(QStringList,features); + + int i = 0; + int argc = 0; + while ( i++ < 5 ) { + TestApplication app( argc, 0 ); + + if ( features.contains( "QFont" ) ) { + // create font and force loading + QFont font( "Arial", 12 ); + QFontInfo finfo( font ); + finfo.exactMatch(); + } + if ( features.contains( "QPixmap" ) ) { + QPixmap pix( 100, 100 ); + pix.fill( Qt::black ); + } + if ( features.contains( "QWidget" ) ) { + QWidget widget; + } + + QVERIFY(!app.exec()); + } +} + +void tst_QApplication::nonGui() +{ +#ifdef Q_OS_HPUX + // ### This is only to allow us to generate a test report for now. + QSKIP("This test shuts down the window manager on HP-UX.", SkipAll); +#endif + + int argc = 0; + QApplication app(argc, 0, false); + QCOMPARE(qApp, &app); +} + +void tst_QApplication::setFont_data() +{ + QTest::addColumn("family"); + QTest::addColumn("pointsize"); + QTest::addColumn("beforeAppConstructor"); + + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); // Needed for QFontDatabase + + int cnt = 0; + QFontDatabase fdb; + QStringList families = fdb.families(); + for (QStringList::const_iterator itr = families.begin(); + itr != families.end(); + ++itr) { + if (cnt < 3) { + QString family = *itr; + QStringList styles = fdb.styles(family); + if (styles.size() > 0) { + QString style = styles.first(); + QList sizes = fdb.pointSizes(family, style); + if (!sizes.size()) + sizes = fdb.standardSizes(); + if (sizes.size() > 0) { + QTest::newRow(QString("data%1a").arg(cnt).toLatin1().constData()) + << family + << sizes.first() + << false; + QTest::newRow(QString("data%1b").arg(cnt).toLatin1().constData()) + << family + << sizes.first() + << true; + } + } + } + ++cnt; + } + + QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" + << 0 << false; + QTest::newRow("nonexistingfont") << "nosuchfont_probably_quiteunlikely" + << 0 << true; + + QTest::newRow("largescaleable") << "smoothtimes" << 100 << false; + QTest::newRow("largescaleable") << "smoothtimes" << 100 << true; + + QTest::newRow("largeunscaleale") << "helvetica" << 100 << false; + QTest::newRow("largeunscaleale") << "helvetica" << 100 << true; +} + +void tst_QApplication::setFont() +{ + QFETCH( QString, family ); + QFETCH( int, pointsize ); + QFETCH( bool, beforeAppConstructor ); + + QFont font( family, pointsize ); + if (beforeAppConstructor) { + QApplication::setFont( font ); + QCOMPARE(QApplication::font(), font); + } + + int argc = 0; + QApplication app( argc, 0, QApplication::GuiServer ); + if (!beforeAppConstructor) + QApplication::setFont( font ); + + QCOMPARE( app.font(), font ); +} + +void tst_QApplication::args_data() +{ + QTest::addColumn("argc_in"); + QTest::addColumn("args_in"); + QTest::addColumn("argc_out"); + QTest::addColumn("args_out"); + + QTest::newRow( "App name" ) << 1 << "/usr/bin/appname" << 1 << "/usr/bin/appname"; + QTest::newRow( "No arguments" ) << 0 << QString() << 0 << QString(); + QTest::newRow( "App name, style" ) << 3 << "/usr/bin/appname -style motif" << 1 << "/usr/bin/appname"; + QTest::newRow( "App name, style, arbitrary, reverse" ) << 5 << "/usr/bin/appname -style motif -arbitrary -reverse" + << 2 << "/usr/bin/appname -arbitrary"; +} + +void tst_QApplication::task109149() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QApplication::setFont(QFont("helvetica", 100)); + + QWidget w; + w.setWindowTitle("hello"); + w.show(); + + app.processEvents(); +} + +static char ** QString2cstrings( const QString &args ) +{ + static QList cache; + + int i; + char **argarray = 0; + QStringList list = args.split(' ');; + argarray = new char*[list.count()+1]; + + for (i = 0; i < (int)list.count(); ++i ) { + QByteArray l1 = list[i].toLatin1(); + argarray[i] = l1.data(); + cache.append(l1); + } + argarray[i] = 0; + + return argarray; +} + +static QString cstrings2QString( char **args ) +{ + QString string; + if ( !args ) + return string; + + int i = 0; + while ( args[i] ) { + string += args[i]; + if ( args[i+1] ) + string += " "; + ++i; + } + return string; +} + +void tst_QApplication::args() +{ + QFETCH( int, argc_in ); + QFETCH( QString, args_in ); + QFETCH( int, argc_out ); + QFETCH( QString, args_out ); + + char **argv = QString2cstrings( args_in ); + + QApplication app( argc_in, argv, QApplication::GuiServer ); + QString argv_out = cstrings2QString(argv); + + QCOMPARE( argc_in, argc_out ); + QCOMPARE( argv_out, args_out ); + + delete [] argv; +} + +class CloseWidget : public QWidget +{ + Q_OBJECT +public: + CloseWidget() + { + startTimer(500); + } + +protected: + void timerEvent(QTimerEvent *) + { + close(); + } + +}; + +void tst_QApplication::lastWindowClosed() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QSignalSpy spy(&app, SIGNAL(lastWindowClosed())); + + QPointer dialog = new QDialog; + QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); + QTimer::singleShot(1000, dialog, SLOT(accept())); + dialog->exec(); + QVERIFY(dialog); + QCOMPARE(spy.count(), 0); + + QPointerwidget = new CloseWidget; + QVERIFY(widget->testAttribute(Qt::WA_QuitOnClose)); + QObject::connect(&app, SIGNAL(lastWindowClosed()), widget, SLOT(deleteLater())); + app.exec(); + QVERIFY(!widget); + QCOMPARE(spy.count(), 1); + spy.clear(); + +#if 0 + // everything is closed, so doing this should not emit lastWindowClosed() again + QMetaObject::invokeMethod(dialog, "close", Qt::QueuedConnection); + QTimer::singleShot(1000, &app, SLOT(quit())); + app.exec(); + QCOMPARE(spy.count(), 0); +#endif + + delete dialog; + + // show 3 windows, close them, should only get lastWindowClosed once + QWidget w1; + QWidget w2; + QWidget w3; + w1.show(); + w2.show(); + w3.show(); + + QTimer::singleShot(1000, &app, SLOT(closeAllWindows())); + app.exec(); + QCOMPARE(spy.count(), 1); +} + +class QuitOnLastWindowClosedDialog : public QDialog +{ + Q_OBJECT +public: + QPushButton *okButton; + + QuitOnLastWindowClosedDialog() + { + QHBoxLayout *hbox = new QHBoxLayout(this); + okButton = new QPushButton("&ok", this); + + hbox->addWidget(okButton); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(okButton, SIGNAL(clicked()), this, SLOT(ok_clicked())); + } + +public slots: + void ok_clicked() + { + QDialog other; + + QTimer timer; + connect(&timer, SIGNAL(timeout()), &other, SLOT(accept())); + QSignalSpy spy(&timer, SIGNAL(timeout())); + QSignalSpy appSpy(qApp, SIGNAL(lastWindowClosed())); + + timer.start(1000); + other.exec(); + + // verify that the eventloop ran and let the timer fire + QCOMPARE(spy.count(), 1); + QCOMPARE(appSpy.count(), 1); + } +}; + +class QuitOnLastWindowClosedWindow : public QWidget +{ + Q_OBJECT + +public: + QuitOnLastWindowClosedWindow() + { } + +public slots: + void execDialogThenShow() + { + QDialog dialog; + QTimer timer1; + connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); + QSignalSpy spy1(&timer1, SIGNAL(timeout())); + timer1.setSingleShot(true); + timer1.start(1000); + dialog.exec(); + QCOMPARE(spy1.count(), 1); + + show(); + } +}; + +void tst_QApplication::quitOnLastWindowClosed() +{ + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QuitOnLastWindowClosedDialog d; + d.show(); + QTimer::singleShot(1000, d.okButton, SLOT(animateClick())); + + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + app.exec(); + + // lastWindowClosed() signal should only be sent after the last dialog is closed + QCOMPARE(appSpy.count(), 2); + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + + QDialog dialog; + QTimer timer1; + connect(&timer1, SIGNAL(timeout()), &dialog, SLOT(accept())); + QSignalSpy spy1(&timer1, SIGNAL(timeout())); + timer1.setSingleShot(true); + timer1.start(1000); + dialog.exec(); + QCOMPARE(spy1.count(), 1); + QCOMPARE(appSpy.count(), 0); + + QTimer timer2; + connect(&timer2, SIGNAL(timeout()), &app, SLOT(quit())); + QSignalSpy spy2(&timer2, SIGNAL(timeout())); + timer2.setSingleShot(true); + timer2.start(1000); + int returnValue = app.exec(); + QCOMPARE(returnValue, 0); + QCOMPARE(spy2.count(), 1); + QCOMPARE(appSpy.count(), 0); + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QTimer timer; + timer.setInterval(100); + + QSignalSpy spy(&app, SIGNAL(aboutToQuit())); + QSignalSpy spy2(&timer, SIGNAL(timeout())); + + QPointer mainWindow = new QMainWindow; + QPointer dialog = new QDialog(mainWindow); + + QVERIFY(app.quitOnLastWindowClosed()); + QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); + QVERIFY(dialog->testAttribute(Qt::WA_QuitOnClose)); + + mainWindow->show(); + dialog->show(); + + timer.start(); + QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application + QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + + app.exec(); + + QCOMPARE(spy.count(), 1); + QVERIFY(spy2.count() < 15); // Should be around 10 if closing caused the quit + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QTimer timer; + timer.setInterval(100); + + QSignalSpy spy(&app, SIGNAL(aboutToQuit())); + QSignalSpy spy2(&timer, SIGNAL(timeout())); + + QPointer mainWindow = new CloseEventTestWindow; + + QVERIFY(app.quitOnLastWindowClosed()); + QVERIFY(mainWindow->testAttribute(Qt::WA_QuitOnClose)); + + mainWindow->show(); + + timer.start(); + QTimer::singleShot(1000, mainWindow, SLOT(close())); // This should quit the application + QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + + app.exec(); + + QCOMPARE(spy.count(), 1); + QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit + } + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + QSignalSpy appSpy(&app, SIGNAL(lastWindowClosed())); + + // exec a dialog for 1 second, then show the window + QuitOnLastWindowClosedWindow window; + QTimer::singleShot(0, &window, SLOT(execDialogThenShow())); + + QTimer timer; + QSignalSpy timerSpy(&timer, SIGNAL(timeout())); + connect(&timer, SIGNAL(timeout()), &window, SLOT(close())); + timer.setSingleShot(true); + timer.start(2000); + int returnValue = app.exec(); + QCOMPARE(returnValue, 0); + // failure here means the timer above didn't fire, and the + // quit was caused the the dialog being closed (not the window) + QCOMPARE(timerSpy.count(), 1); + QCOMPARE(appSpy.count(), 2); + } +} + +class PromptOnCloseWidget : public QWidget +{ +public: + void closeEvent(QCloseEvent *event) + { + QMessageBox *messageBox = new QMessageBox(this); + messageBox->setWindowTitle("Unsaved data"); + messageBox->setText("Would you like to save or discard your current data?"); + messageBox->setStandardButtons(QMessageBox::Save|QMessageBox::Discard|QMessageBox::Cancel); + messageBox->setDefaultButton(QMessageBox::Save); + + messageBox->show(); + QTest::qWaitForWindowShown(messageBox); + + // verify that all windows are visible + foreach (QWidget *w, qApp->topLevelWidgets()) + QVERIFY(w->isVisible()); + // flush event queue + qApp->processEvents(); + // close all windows + qApp->closeAllWindows(); + + if (messageBox->standardButton(messageBox->clickedButton()) == QMessageBox::Cancel) + event->ignore(); + else + event->accept(); + + delete messageBox; + } +}; + +void tst_QApplication::closeAllWindows() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // create some windows + new QWidget; + new QWidget; + new QWidget; + + // show all windows + foreach (QWidget *w, app.topLevelWidgets()) { + w->show(); + QTest::qWaitForWindowShown(w); + } + // verify that they are visible + foreach (QWidget *w, app.topLevelWidgets()) + QVERIFY(w->isVisible()); + // empty event queue + app.processEvents(); + // close all windows + app.closeAllWindows(); + // all windows should no longer be visible + foreach (QWidget *w, app.topLevelWidgets()) + QVERIFY(!w->isVisible()); + + // add a window that prompts the user when closed + PromptOnCloseWidget *promptOnCloseWidget = new PromptOnCloseWidget; + // show all windows + foreach (QWidget *w, app.topLevelWidgets()) { + w->show(); + QTest::qWaitForWindowShown(w); + } + // close the last window to open the prompt (eventloop recurses) + promptOnCloseWidget->close(); + // all windows should not be visible, except the one that opened the prompt + foreach (QWidget *w, app.topLevelWidgets()) { + if (w == promptOnCloseWidget) + QVERIFY(w->isVisible()); + else + QVERIFY(!w->isVisible()); + } + + qDeleteAll(app.topLevelWidgets()); +} + +bool isPathListIncluded(const QStringList &l, const QStringList &r) +{ + int size = r.count(); + if (size > l.count()) + return false; +#if defined (Q_OS_WIN) + Qt::CaseSensitivity cs = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity cs = Qt::CaseSensitive; +#endif + int i = 0, j = 0; + for ( ; i < l.count() && j < r.count(); ++i) { + if (QDir::toNativeSeparators(l[i]).compare(QDir::toNativeSeparators(r[j]), cs) == 0) { + ++j; + i = -1; + } + } + return j == r.count(); +} + +#define QT_TST_QAPP_DEBUG +void tst_QApplication::libraryPaths() +{ + { +#ifndef Q_OS_WINCE + QString testDir = QDir::current().canonicalPath() + "/test"; +#else + // On Windows CE we need QApplication object to have valid + // current Path. Therefore we need to identify it ourselves + // here for the test. + QFileInfo filePath; + wchar_t module_name[MAX_PATH]; + GetModuleFileName(0, module_name, MAX_PATH); + filePath = QString::fromWCharArray(module_name); + QString testDir = filePath.path() + "/test"; +#endif + QApplication::setLibraryPaths(QStringList() << testDir); + QCOMPARE(QApplication::libraryPaths(), (QStringList() << testDir)); + + // creating QApplication adds the applicationDirPath to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = QDir(app.applicationDirPath()).canonicalPath(); + + QStringList actual = QApplication::libraryPaths(); + actual.sort(); + QStringList expected = QSet::fromList((QStringList() << testDir << appDirPath)).toList(); + expected.sort(); + + QVERIFY2(isPathListIncluded(actual, expected), + qPrintable("actual:\n - " + actual.join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + } + { + // creating QApplication adds the applicationDirPath and plugin install path to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + + QStringList actual = QApplication::libraryPaths(); + actual.sort(); + + QStringList expected = QSet::fromList((QStringList() << installPathPlugins << appDirPath)).toList(); + expected.sort(); + + QVERIFY2(isPathListIncluded(actual, expected), + qPrintable("actual:\n - " + actual.join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + + // setting the library paths overrides everything + QString testDir = QDir::currentPath() + "/test"; + QApplication::setLibraryPaths(QStringList() << testDir); + QVERIFY2(isPathListIncluded(QApplication::libraryPaths(), (QStringList() << testDir)), + qPrintable("actual:\n - " + QApplication::libraryPaths().join("\n - ") + + "\nexpected:\n - " + testDir)); + } + { +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "Initial library path:" << QApplication::libraryPaths(); +#endif + + int count = QApplication::libraryPaths().count(); +#if 0 + // this test doesn't work if KDE 4 is installed + QCOMPARE(count, 1); // before creating QApplication, only the PluginsPath is in the libraryPaths() +#endif + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + QApplication::addLibraryPath(installPathPlugins); +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "installPathPlugins" << installPathPlugins; + qDebug() << "After adding plugins path:" << QApplication::libraryPaths(); +#endif + QCOMPARE(QApplication::libraryPaths().count(), count); + + QApplication::addLibraryPath(QDir::currentPath() + "/test"); + QCOMPARE(QApplication::libraryPaths().count(), count + 1); + + // creating QApplication adds the applicationDirPath to the libraryPath + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + qDebug() << QApplication::libraryPaths(); + // On Windows CE these are identical and might also be the case for other + // systems too + if (appDirPath != installPathPlugins) + QCOMPARE(QApplication::libraryPaths().count(), count + 2); + } + { + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "Initial library path:" << app.libraryPaths(); +#endif + int count = app.libraryPaths().count(); + QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); + app.addLibraryPath(installPathPlugins); +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "installPathPlugins" << installPathPlugins; + qDebug() << "After adding plugins path:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count); + + QString appDirPath = app.applicationDirPath(); + + app.addLibraryPath(appDirPath); +#ifdef Q_OS_WINCE + app.addLibraryPath(appDirPath + "/../.."); +#else + app.addLibraryPath(appDirPath + "/.."); +#endif +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "appDirPath" << appDirPath; + qDebug() << "After adding appDirPath && appDirPath + /..:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count + 1); +#ifdef Q_OS_MAC + app.addLibraryPath(appDirPath + "/../MacOS"); +#else + app.addLibraryPath(appDirPath + "/tmp/.."); +#endif +#ifdef QT_TST_QAPP_DEBUG + qDebug() << "After adding appDirPath + /tmp/..:" << app.libraryPaths(); +#endif + QCOMPARE(app.libraryPaths().count(), count + 1); + } +} + +void tst_QApplication::libraryPaths_qt_plugin_path() +{ + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + QString appDirPath = app.applicationDirPath(); + + // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable + QString installPathPluginsDeCanon = appDirPath + QString::fromLatin1("/tmp/.."); + QByteArray ascii = installPathPluginsDeCanon.toAscii(); + qputenv("QT_PLUGIN_PATH", ascii); + + QVERIFY(!app.libraryPaths().contains(appDirPath + QString::fromLatin1("/tmp/.."))); +} + +void tst_QApplication::libraryPaths_qt_plugin_path_2() +{ +#ifdef Q_OS_UNIX + QByteArray validPath = QDir("/tmp").canonicalPath().toLatin1(); + QByteArray nonExistentPath = "/nonexistent"; + QByteArray pluginPath = validPath + ":" + nonExistentPath; +#elif defined(Q_OS_WIN) +# ifdef Q_OS_WINCE + QByteArray validPath = "/Temp"; + QByteArray nonExistentPath = "/nonexistent"; + QByteArray pluginPath = validPath + ";" + nonExistentPath; +# else + QByteArray validPath = "C:\\windows"; + QByteArray nonExistentPath = "Z:\\nonexistent"; + QByteArray pluginPath = validPath + ";" + nonExistentPath; +# endif +#endif + + { + // Our hook into libraryPaths() initialization: Set the QT_PLUGIN_PATH environment variable + qputenv("QT_PLUGIN_PATH", pluginPath); + + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // library path list should contain the default plus the one valid path + QStringList expected = + QStringList() + << QLibraryInfo::location(QLibraryInfo::PluginsPath) + << QDir(app.applicationDirPath()).canonicalPath() + << QDir(QDir::fromNativeSeparators(QString::fromLatin1(validPath))).canonicalPath(); +# ifdef Q_OS_WINCE + expected = QSet::fromList(expected).toList(); +# endif + QVERIFY2(isPathListIncluded(app.libraryPaths(), expected), + qPrintable("actual:\n - " + app.libraryPaths().join("\n - ") + + "\nexpected:\n - " + expected.join("\n - "))); + } + + { + int argc = 1; + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // library paths are initialized by the QApplication, setting + // the environment variable here doesn't work + qputenv("QT_PLUGIN_PATH", pluginPath); + + // library path list should contain the default + QStringList expected = + QStringList() + << QLibraryInfo::location(QLibraryInfo::PluginsPath) + << app.applicationDirPath(); +# ifdef Q_OS_WINCE + expected = QSet::fromList(expected).toList(); +# endif + QVERIFY(isPathListIncluded(app.libraryPaths(), expected)); + + qputenv("QT_PLUGIN_PATH", QByteArray()); + } +} + +class SendPostedEventsTester : public QObject +{ + Q_OBJECT +public: + QList eventSpy; + bool event(QEvent *e); +private slots: + void doTest(); +}; + +bool SendPostedEventsTester::event(QEvent *e) +{ + eventSpy.append(e->type()); + return QObject::event(e); +} + +void SendPostedEventsTester::doTest() +{ + QPointer p = this; + QApplication::postEvent(this, new QEvent(QEvent::User)); + // DeferredDelete should not be delivered until returning from this function + QApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); + + QEventLoop eventLoop; + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p != 0); + + QCOMPARE(eventSpy.count(), 2); + QCOMPARE(eventSpy.at(0), int(QEvent::MetaCall)); + QCOMPARE(eventSpy.at(1), int(QEvent::User)); + eventSpy.clear(); +} + +void tst_QApplication::sendPostedEvents() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + SendPostedEventsTester *tester = new SendPostedEventsTester; + QMetaObject::invokeMethod(tester, "doTest", Qt::QueuedConnection); + QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); + QPointer p = tester; + (void) app.exec(); + QVERIFY(p == 0); +} + +void tst_QApplication::thread() +{ + QThread *currentThread = QThread::currentThread(); + // no app, but still have a valid thread + QVERIFY(currentThread != 0); + + // the thread should be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // this should probably be in the tst_QObject::thread() test, but + // we put it here since we want to make sure that objects created + // *before* the QApplication has a thread + QObject object; + QObject child(&object); + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // current thread still valid + QVERIFY(QThread::currentThread() != 0); + // thread should be the same as before + QCOMPARE(QThread::currentThread(), currentThread); + + // app's thread should be the current thread + QCOMPARE(app.thread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + QTestEventLoop::instance().enterLoop(1); + } + + // app dead, current thread still valid + QVERIFY(QThread::currentThread() != 0); + QCOMPARE(QThread::currentThread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + // do the test again, making sure that the thread is the same as + // before + { + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + // current thread still valid + QVERIFY(QThread::currentThread() != 0); + // thread should be the same as before + QCOMPARE(QThread::currentThread(), currentThread); + + // app's thread should be the current thread + QCOMPARE(app.thread(), currentThread); + + // the thread should be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); + + QTestEventLoop::instance().enterLoop(1); + } + + // app dead, current thread still valid + QVERIFY(QThread::currentThread() != 0); + QCOMPARE(QThread::currentThread(), currentThread); + + // the thread should still be running and not finished + QVERIFY(currentThread->isRunning()); + QVERIFY(!currentThread->isFinished()); + + // should still have a thread + QVERIFY(object.thread() == currentThread); + QVERIFY(child.thread() == currentThread); +} + +class DeleteLaterWidget : public QWidget +{ + Q_OBJECT +public: + DeleteLaterWidget(QApplication *_app, QWidget *parent = 0) + : QWidget(parent) { app = _app; child_deleted = false; } + + bool child_deleted; + QApplication *app; + +public slots: + void runTest(); + void checkDeleteLater(); + void childDeleted() { child_deleted = true; } +}; + + +void DeleteLaterWidget::runTest() +{ + QObject *stillAlive = qFindChild(this, "deleteLater"); + + QWidget *w = new QWidget(this); + connect(w, SIGNAL(destroyed()), this, SLOT(childDeleted())); + + w->deleteLater(); + QVERIFY(!child_deleted); + + QDialog dlg; + QTimer::singleShot(500, &dlg, SLOT(reject())); + dlg.exec(); + + QVERIFY(!child_deleted); + app->processEvents(); + QVERIFY(!child_deleted); + + QTimer::singleShot(500, this, SLOT(checkDeleteLater())); + + app->processEvents(); + + QVERIFY(!stillAlive); // verify at the end to make test terminate +} + +void DeleteLaterWidget::checkDeleteLater() +{ + QVERIFY(child_deleted); + + close(); +} + +void tst_QApplication::testDeleteLater() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); + + DeleteLaterWidget *wgt = new DeleteLaterWidget(&app); + QTimer::singleShot(500, wgt, SLOT(runTest())); + + QObject *object = new QObject(wgt); + object->setObjectName("deleteLater"); + object->deleteLater(); + + QObject *stillAlive = qFindChild(wgt, "deleteLater"); + QVERIFY(stillAlive); + + app.exec(); + + delete wgt; + +} + +class EventLoopNester : public QObject +{ + Q_OBJECT +public slots: + void deleteLaterAndEnterLoop() + { + QEventLoop eventLoop; + QPointer p(this); + deleteLater(); + /* + DeferredDelete events are compressed, meaning this second + deleteLater() will *not* delete the object in the nested + event loop + */ + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + QTimer::singleShot(1000, &eventLoop, SLOT(quit())); + eventLoop.exec(); + QVERIFY(p); + } + void deleteLaterAndExitLoop() + { + // Check that 'p' is not deleted before exec returns, since the call + // to QEventLoop::quit() should stop 'eventLoop' from processing + // any more events (that is, delete later) until we return to the + // _current_ event loop: + QEventLoop eventLoop; + QPointer p(this); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); // not dead yet + } + + void processEventsOnly() + { + QApplication::processEvents(); + } + void processEventsWithDeferredDeletion() + { + QApplication::processEvents(QEventLoop::DeferredDeletion); + } + void sendPostedEventsWithDeferredDelete() + { + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } + void deleteLaterAndProcessEvents1() + { + QEventLoop eventLoop; + + QPointer p = this; + deleteLater(); + + // trying to delete this object in a deeper eventloop just won't work + QMetaObject::invokeMethod(this, + "processEventsOnly", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "processEventsWithDeferredDeletion", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "sendPostedEventsWithDeferredDelete", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + + // trying to delete it from this eventloop still doesn't work + QApplication::processEvents(); + QVERIFY(p); + + // however, it *will* work with this magic incantation + QApplication::processEvents(QEventLoop::DeferredDeletion); + QVERIFY(!p); + } + + void deleteLaterAndProcessEvents2() + { + QEventLoop eventLoop; + + QPointer p = this; + deleteLater(); + + // trying to delete this object in a deeper eventloop just won't work + QMetaObject::invokeMethod(this, + "processEventsOnly", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "processEventsWithDeferredDeletion", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + QMetaObject::invokeMethod(this, + "sendPostedEventsWithDeferredDelete", + Qt::QueuedConnection); + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + eventLoop.exec(); + QVERIFY(p); + + // trying to delete it from this eventloop still doesn't work + QApplication::processEvents(); + QVERIFY(p); + + // however, it *will* work with this magic incantation + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QVERIFY(!p); + } +}; + +void tst_QApplication::testDeleteLaterProcessEvents() +{ + int argc = 0; + + // Calling processEvents() with no event dispatcher does nothing. + QObject *object = new QObject; + QPointer p(object); + object->deleteLater(); + QApplication::processEvents(); + QVERIFY(p); + delete object; + + { + QApplication app(argc, 0, QApplication::GuiServer); + // If you call processEvents() with an event dispatcher present, but + // outside any event loops, deferred deletes are not processed unless + // QEventLoop::DeferredDeletion is passed. + object = new QObject; + p = object; + object->deleteLater(); + app.processEvents(); + QVERIFY(p); + app.processEvents(QEventLoop::ProcessEventsFlag(0x10)); // 0x10 == QEventLoop::DeferredDeletion + QVERIFY(!p); + + // sendPostedEvents(0, DeferredDelete); also works + object = new QObject; + p = object; + object->deleteLater(); + app.processEvents(); + QVERIFY(p); + QApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QVERIFY(!p); + + // If you call deleteLater() on an object when there is no parent + // event loop, and then enter an event loop, the object will get + // deleted. + object = new QObject; + p = object; + object->deleteLater(); + QEventLoop loop; + QTimer::singleShot(1000, &loop, SLOT(quit())); + loop.exec(); + QVERIFY(!p); + } + { + // When an object is in an event loop, then calls deleteLater() and enters + // an event loop recursively, it should not die until the parent event + // loop continues. + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester; + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndEnterLoop())); + + loop.exec(); + QVERIFY(!p); + } + + { + // When the event loop that calls deleteLater() is exited + // immediately, the object should die when returning to the + // parent event loop + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester; + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndExitLoop())); + + loop.exec(); + QVERIFY(!p); + } + + { + // when the event loop that calls deleteLater() also calls + // processEvents() immediately afterwards, the object should + // not die until the parent loop continues + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester(); + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents1())); + + loop.exec(); + QVERIFY(!p); + } + + { + // when the event loop that calls deleteLater() also calls + // processEvents() immediately afterwards, the object should + // not die until the parent loop continues + QApplication app(argc, 0, QApplication::GuiServer); + QEventLoop loop; + EventLoopNester *nester = new EventLoopNester(); + p = nester; + QTimer::singleShot(3000, &loop, SLOT(quit())); + QTimer::singleShot(0, nester, SLOT(deleteLaterAndProcessEvents2())); + + loop.exec(); + QVERIFY(!p); + } +} + +/* + Test for crash with QApplication::setDesktopSettingsAware(false). +*/ +void tst_QApplication::desktopSettingsAware() +{ +#ifndef QT_NO_PROCESS + QProcess testProcess; +#ifdef Q_OS_WINCE + int argc = 0; + QApplication tmpApp(argc, 0, QApplication::GuiServer); + testProcess.start("desktopsettingsaware/desktopsettingsaware"); +#else +#if defined(Q_OS_WIN) && defined(QT_DEBUG) + testProcess.start("desktopsettingsaware/debug/desktopsettingsaware"); +#elif defined(Q_OS_WIN) + testProcess.start("desktopsettingsaware/release/desktopsettingsaware"); +#else + testProcess.start("desktopsettingsaware/desktopsettingsaware"); +#endif +#endif + QVERIFY(testProcess.waitForFinished(10000)); + QCOMPARE(int(testProcess.state()), int(QProcess::NotRunning)); + QVERIFY(int(testProcess.error()) != int(QProcess::Crashed)); +#endif +} + +void tst_QApplication::setActiveWindow() +{ + int argc = 0; + QApplication MyApp(argc, 0, QApplication::GuiServer); + + QWidget* w = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(w); + + QLineEdit* pb1 = new QLineEdit("Testbutton1", w); + QLineEdit* pb2 = new QLineEdit("Test Line Edit", w); + + layout->addWidget(pb1); + layout->addWidget(pb2); + + pb2->setFocus(); + pb2->setParent(0); + delete pb2; + + w->show(); + QApplication::setActiveWindow(w); // needs this on twm (focus follows mouse) + QVERIFY(pb1->hasFocus()); + delete w; +} + + +/* This might fail on some X11 window managers? */ +void tst_QApplication::focusChanged() +{ + int argc = 0; + QApplication app(argc, 0, QApplication::GuiServer); + + QSignalSpy spy(&app, SIGNAL(focusChanged(QWidget *, QWidget *))); + QWidget *now = 0; + QWidget *old = 0; + + QWidget parent1; + QHBoxLayout hbox1(&parent1); + QLabel lb1(&parent1); + QLineEdit le1(&parent1); + QPushButton pb1(&parent1); + hbox1.addWidget(&lb1); + hbox1.addWidget(&le1); + hbox1.addWidget(&pb1); + + QCOMPARE(spy.count(), 0); + + parent1.show(); + QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).count(), 2); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == 0); + spy.clear(); + QCOMPARE(spy.count(), 0); + + pb1.setFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le1); + spy.clear(); + + lb1.setFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &lb1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb1); + spy.clear(); + + lb1.clearFocus(); + QCOMPARE(spy.count(), 1); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == 0); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &lb1); + spy.clear(); + + QWidget parent2; + QHBoxLayout hbox2(&parent2); + QLabel lb2(&parent2); + QLineEdit le2(&parent2); + QPushButton pb2(&parent2); + hbox2.addWidget(&lb2); + hbox2.addWidget(&le2); + hbox2.addWidget(&pb2); + + parent2.show(); + QApplication::setActiveWindow(&parent2); // needs this on twm (focus follows mouse) + QVERIFY(spy.count() > 0); // one for deactivation, one for activation on Windows + old = qVariantValue(spy.at(spy.count()-1).at(0)); + now = qVariantValue(spy.at(spy.count()-1).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == 0); + spy.clear(); + + QTestKeyEvent tab(QTest::Press, Qt::Key_Tab, 0, 0); + QTestKeyEvent backtab(QTest::Press, Qt::Key_Backtab, 0, 0); + QTestMouseEvent click(QTest::MouseClick, Qt::LeftButton, 0, QPoint(5, 5), 0); + + bool tabAllControls = true; +#ifdef Q_WS_MAC + // Mac has two modes, one where you tab to everything, one where you can + // only tab to input controls, here's what we get. Determine which ones we + // should get. + QSettings appleSettings(QLatin1String("apple.com")); + QVariant appleValue = appleSettings.value(QLatin1String("AppleKeyboardUIMode"), 0); + tabAllControls = (appleValue.toInt() & 0x2); +#endif + + tab.simulate(now); + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + } + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + tab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + backtab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + } + + + if (!tabAllControls) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + old = &pb2; + } else { + backtab.simulate(now); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + click.simulate(old); + if (!(pb2.focusPolicy() & Qt::ClickFocus)) { + QVERIFY(spy.count() == 0); + QVERIFY(now == QApplication::focusWidget()); + } else { + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &pb2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); + + click.simulate(old); + QVERIFY(spy.count() > 0); + old = qVariantValue(spy.at(0).at(0)); + now = qVariantValue(spy.at(0).at(1)); + QVERIFY(now == &le2); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &pb2); + spy.clear(); + } + + parent1.activateWindow(); + QApplication::setActiveWindow(&parent1); // needs this on twm (focus follows mouse) + QVERIFY(spy.count() == 1 || spy.count() == 2); // one for deactivation, one for activation on Windows + + //on windows, the change of focus is made in 2 steps + //(the focusChanged SIGNAL is emitted twice) + if (spy.count()==1) + old = qVariantValue(spy.at(spy.count()-1).at(0)); + else + old = qVariantValue(spy.at(spy.count()-2).at(0)); + now = qVariantValue(spy.at(spy.count()-1).at(1)); + QVERIFY(now == &le1); + QVERIFY(now == QApplication::focusWidget()); + QVERIFY(old == &le2); + spy.clear(); +} + +class LineEdit : public QLineEdit +{ +public: + LineEdit(QWidget *parent = 0) : QLineEdit(parent) { } + +protected: + void focusOutEvent(QFocusEvent *e) { + QLineEdit::focusOutEvent(e); + if (objectName() == "le1") + setStyleSheet(""); + } + + void focusInEvent(QFocusEvent *e) { + QLineEdit::focusInEvent(e); + if (objectName() == "le2") + setStyleSheet(""); + } +}; + +void tst_QApplication::focusOut() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + + // Tests the case where the style pointer changes when on focus in/out + // (the above is the case when the stylesheet changes) + QWidget w; + QLineEdit *le1 = new LineEdit(&w); + le1->setObjectName("le1"); + le1->setStyleSheet("background: #fee"); + le1->setFocus(); + + QLineEdit *le2 = new LineEdit(&w); + le2->setObjectName("le2"); + le2->setStyleSheet("background: #fee"); + le2->move(100, 100); + w.show(); + + QTest::qWait(2000); + le2->setFocus(); + QTest::qWait(2000); +} + +void tst_QApplication::execAfterExit() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection); + // this should be ignored, as exec() will reset the exitCode + QApplication::exit(1); + int exitCode = app.exec(); + QCOMPARE(exitCode, 0); + + // the quitNow flag should have been reset, so we can spin an + // eventloop after QApplication::exec() returns + QEventLoop eventLoop; + QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection); + exitCode = eventLoop.exec(); + QCOMPARE(exitCode, 0); +} + +void tst_QApplication::wheelScrollLines() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + // If wheelScrollLines returns 0, the mose wheel will be disabled. + QVERIFY(app.wheelScrollLines() > 0); +} + +void tst_QApplication::style() +{ + int argc = 1; + + { + QApplication app(argc, &argv0, QApplication::GuiServer); + QPointer style = app.style(); + app.setStyle(new QWindowsStyle); + QVERIFY(style.isNull()); + } + + QApplication app(argc, &argv0, QApplication::GuiServer); + + // qApp style can never be 0 + QVERIFY(QApplication::style() != 0); +} + +void tst_QApplication::allWidgets() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QWidget *w = new QWidget; + QVERIFY(app.allWidgets().contains(w)); // uncreate widget test + QVERIFY(app.allWidgets().contains(w)); // created widget test + delete w; + w = 0; + QVERIFY(!app.allWidgets().contains(w)); // removal test +} + +void tst_QApplication::topLevelWidgets() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QWidget *w = new QWidget; + w->show(); +#ifndef QT_NO_CLIPBOARD + QClipboard *clipboard = QApplication::clipboard(); + QString originalText = clipboard->text(); + clipboard->setText(QString("newText")); +#endif + app.processEvents(); + QVERIFY(QApplication::topLevelWidgets().contains(w)); + QCOMPARE(QApplication::topLevelWidgets().count(), 1); + delete w; + w = 0; + app.processEvents(); + QCOMPARE(QApplication::topLevelWidgets().count(), 0); +} + + + +void tst_QApplication::setAttribute() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + QWidget *w = new QWidget; + QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); + delete w; + + QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation); + QVERIFY(QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + w = new QWidget; + QVERIFY(w->testAttribute(Qt::WA_WState_Created)); + QWidget *w2 = new QWidget(w); + w2->setParent(0); + QVERIFY(w2->testAttribute(Qt::WA_WState_Created)); + delete w; + delete w2; + + QApplication::setAttribute(Qt::AA_ImmediateWidgetCreation, false); + QVERIFY(!QApplication::testAttribute(Qt::AA_ImmediateWidgetCreation)); + w = new QWidget; + QVERIFY(!w->testAttribute(Qt::WA_WState_Created)); + delete w; +} + +void tst_QApplication::windowsCommandLine_data() +{ +#if defined(Q_OS_WIN) + QTest::addColumn("args"); + QTest::addColumn("expected"); + + QTest::newRow("hello world") + << QString("Hello \"World\"") + << QString("Hello \"World\""); + QTest::newRow("sql") + << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME") + << QString("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PNR' AND TABLE_TYPE = 'VIEW' ORDER BY TABLE_NAME"); +#endif +} + +void tst_QApplication::windowsCommandLine() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QFETCH(QString, args); + QFETCH(QString, expected); + + QProcess testProcess; +#if defined(QT_DEBUG) + testProcess.start("wincmdline/debug/wincmdline", QStringList(args)); +#else + testProcess.start("wincmdline/release/wincmdline", QStringList(args)); +#endif + QVERIFY(testProcess.waitForFinished(10000)); + QByteArray error = testProcess.readAllStandardError(); + QString procError(error); + QCOMPARE(procError, expected); +#endif +} + +class TouchEventPropagationTestWidget : public QWidget +{ + Q_OBJECT + +public: + bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent; + + TouchEventPropagationTestWidget(QWidget *parent = 0) + : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false) + { } + + void reset() + { + seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false; + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + // qDebug() << objectName() << "seenMouseEvent = true"; + seenMouseEvent = true; + event->setAccepted(acceptMouseEvent); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + // qDebug() << objectName() << "seenTouchEvent = true"; + seenTouchEvent = true; + event->setAccepted(acceptTouchEvent); + break; + default: + return QWidget::event(event); + } + return true; + } +}; + +void tst_QApplication::touchEventPropagation() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + + QList pressedTouchPoints; + QTouchEvent::TouchPoint press(0); + press.setState(Qt::TouchPointPressed); + pressedTouchPoints << press; + + QList releasedTouchPoints; + QTouchEvent::TouchPoint release(0); + release.setState(Qt::TouchPointReleased); + releasedTouchPoints << release; + + { + // touch event behavior on a window + TouchEventPropagationTestWidget window; + window.setObjectName("1. window"); + + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + window.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } + + { + // touch event behavior on a window with a child widget + TouchEventPropagationTestWidget window; + window.setObjectName("2. window"); + TouchEventPropagationTestWidget widget(&window); + widget.setObjectName("2. widget"); + + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptTouchEvents, false); + window.setAttribute(Qt::WA_AcceptTouchEvents); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first + window.acceptTouchEvent = true; + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, pressedTouchPoints); + qt_translateRawTouchEvent(&window, QTouchEvent::TouchScreen, releasedTouchPoints); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } +} + +void tst_QApplication::qtbug_12673() +{ + QProcess testProcess; + QStringList arguments; +#ifdef Q_OS_MAC + testProcess.start("modal/modal.app", arguments); +#else + testProcess.start("modal/modal", arguments); +#endif + QVERIFY(testProcess.waitForFinished(20000)); + QCOMPARE(testProcess.exitStatus(), QProcess::NormalExit); +} + +/* + This test is meant to ensure that certain objects (public & commonly used) + can safely be used in a Q_GLOBAL_STATIC such that their destructors are + executed *after* the destruction of QApplication. + */ +Q_GLOBAL_STATIC(QLocale, tst_qapp_locale); +Q_GLOBAL_STATIC(QProcess, tst_qapp_process); +Q_GLOBAL_STATIC(QFileSystemWatcher, tst_qapp_fileSystemWatcher); +Q_GLOBAL_STATIC(QSharedMemory, tst_qapp_sharedMemory); +Q_GLOBAL_STATIC(QElapsedTimer, tst_qapp_elapsedTimer); +Q_GLOBAL_STATIC(QMutex, tst_qapp_mutex); +Q_GLOBAL_STATIC(QWidget, tst_qapp_widget); +Q_GLOBAL_STATIC(QPixmap, tst_qapp_pixmap); +Q_GLOBAL_STATIC(QFont, tst_qapp_font); +Q_GLOBAL_STATIC(QRegion, tst_qapp_region); +Q_GLOBAL_STATIC(QFontDatabase, tst_qapp_fontDatabase); +Q_GLOBAL_STATIC(QCursor, tst_qapp_cursor); + +void tst_QApplication::globalStaticObjectDestruction() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QVERIFY(tst_qapp_locale()); + QVERIFY(tst_qapp_process()); + QVERIFY(tst_qapp_fileSystemWatcher()); + QVERIFY(tst_qapp_sharedMemory()); + QVERIFY(tst_qapp_elapsedTimer()); + QVERIFY(tst_qapp_mutex()); + QVERIFY(tst_qapp_widget()); + QVERIFY(tst_qapp_pixmap()); + QVERIFY(tst_qapp_font()); + QVERIFY(tst_qapp_region()); + QVERIFY(tst_qapp_fontDatabase()); + QVERIFY(tst_qapp_cursor()); +} + +//QTEST_APPLESS_MAIN(tst_QApplication) +int main(int argc, char *argv[]) +{ + tst_QApplication tc; + argv0 = argv[0]; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qapplication.moc" diff --git a/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp b/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp new file mode 100644 index 0000000000..d0f802231a --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/wincmdline/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + if (argc > 1) + fprintf(stderr, "%s", argv[1]); + else + fprintf(stderr, "Failed"); + fflush(stderr); + return 0; +} + diff --git a/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro b/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro new file mode 100644 index 0000000000..3ba8f48167 --- /dev/null +++ b/tests/auto/widgets/kernel/qapplication/wincmdline/wincmdline.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +QT += widgets +SOURCES += main.cpp + + diff --git a/tests/auto/widgets/kernel/qboxlayout/.gitignore b/tests/auto/widgets/kernel/qboxlayout/.gitignore new file mode 100644 index 0000000000..034edba563 --- /dev/null +++ b/tests/auto/widgets/kernel/qboxlayout/.gitignore @@ -0,0 +1 @@ +tst_qboxlayout diff --git a/tests/auto/widgets/kernel/qboxlayout/qboxlayout.pro b/tests/auto/widgets/kernel/qboxlayout/qboxlayout.pro new file mode 100644 index 0000000000..c37f12f74f --- /dev/null +++ b/tests/auto/widgets/kernel/qboxlayout/qboxlayout.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qboxlayout.cpp + + diff --git a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp new file mode 100644 index 0000000000..4e5b357de5 --- /dev/null +++ b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QBoxLayout : public QObject +{ + Q_OBJECT + +public: + tst_QBoxLayout(); + virtual ~tst_QBoxLayout(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void insertSpacerItem(); + void sizeHint(); + void sizeConstraints(); + void setGeometry(); + void setStyleShouldChangeSpacing(); + + void taskQTBUG_7103_minMaxWidthNotRespected(); +}; + +class CustomLayoutStyle : public QWindowsStyle +{ + Q_OBJECT +public: + CustomLayoutStyle() : QWindowsStyle() + { + hspacing = 5; + vspacing = 10; + } + + virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, + const QWidget * widget = 0 ) const; + + int hspacing; + int vspacing; +}; + +int CustomLayoutStyle::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, + const QWidget * widget /*= 0*/ ) const +{ + switch (metric) { + case PM_LayoutLeftMargin: + return 0; + break; + case PM_LayoutTopMargin: + return 3; + break; + case PM_LayoutRightMargin: + return 6; + break; + case PM_LayoutBottomMargin: + return 9; + break; + case PM_LayoutHorizontalSpacing: + return hspacing; + case PM_LayoutVerticalSpacing: + return vspacing; + break; + default: + break; + } + return QWindowsStyle::pixelMetric(metric, option, widget); +} + + +tst_QBoxLayout::tst_QBoxLayout() +{ +} + +tst_QBoxLayout::~tst_QBoxLayout() +{ +} + +void tst_QBoxLayout::initTestCase() +{ +} + +void tst_QBoxLayout::cleanupTestCase() +{ +} + +void tst_QBoxLayout::init() +{ +} + +void tst_QBoxLayout::cleanup() +{ +} + +void tst_QBoxLayout::insertSpacerItem() +{ + QWidget *window = new QWidget; + + QSpacerItem *spacer1 = new QSpacerItem(20, 10, QSizePolicy::Expanding, QSizePolicy::Expanding); + QSpacerItem *spacer2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Expanding); + + QBoxLayout *layout = new QHBoxLayout; + layout->addWidget(new QLineEdit("Foooooooooooooooooooooooooo")); + layout->addSpacerItem(spacer1); + layout->addWidget(new QLineEdit("Baaaaaaaaaaaaaaaaaaaaaaaaar")); + layout->insertSpacerItem(0, spacer2); + window->setLayout(layout); + + QVERIFY(layout->itemAt(0) == spacer2); + QVERIFY(layout->itemAt(2) == spacer1); + + window->show(); +} + +void tst_QBoxLayout::sizeHint() +{ + QWidget *window = new QWidget; + QHBoxLayout *lay1 = new QHBoxLayout; + QHBoxLayout *lay2 = new QHBoxLayout; + QLabel *label = new QLabel("widget twooooooooooooooooooooooooooooooooooooooooooooooooooooooo"); + lay2->addWidget(label); + lay1->addLayout(lay2); + window->setLayout(lay1); + window->show(); + label->setText("foooooooo baaaaaaar"); + QSize sh = lay1->sizeHint(); + QApplication::processEvents(); + // Note that this is not strictly required behaviour - actually + // the preferred behaviour would be that sizeHint returns + // the same value regardless of what's lying in the event queue. + // (i.e. we would check for equality here instead) + QVERIFY(lay1->sizeHint() != sh); +} + +void tst_QBoxLayout::sizeConstraints() +{ + QWidget *window = new QWidget; + QHBoxLayout *lay = new QHBoxLayout; + lay->addWidget(new QLabel("foooooooooooooooooooooooooooooooooooo")); + lay->addWidget(new QLabel("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar")); + lay->setSizeConstraint(QLayout::SetFixedSize); + window->setLayout(lay); + window->show(); + QApplication::processEvents(); + QSize sh = window->sizeHint(); + lay->takeAt(1); + QVERIFY(sh.width() >= window->sizeHint().width() && + sh.height() >= window->sizeHint().height()); + +} + +void tst_QBoxLayout::setGeometry() +{ + QWidget toplevel; + QWidget w(&toplevel); + QVBoxLayout *lay = new QVBoxLayout; + lay->setMargin(0); + lay->setSpacing(0); + QHBoxLayout *lay2 = new QHBoxLayout; + QDial *dial = new QDial; + lay2->addWidget(dial); + lay2->setAlignment(Qt::AlignTop); + lay2->setAlignment(Qt::AlignRight); + lay->addLayout(lay2); + w.setLayout(lay); + toplevel.show(); + + QRect newGeom(0, 0, 70, 70); + lay2->setGeometry(newGeom); + QVERIFY2(newGeom.contains(dial->geometry()), "dial->geometry() should be smaller and within newGeom"); +} + +void tst_QBoxLayout::setStyleShouldChangeSpacing() +{ + + QWidget *window = new QWidget; + QHBoxLayout *hbox = new QHBoxLayout(window); + QPushButton *pb1 = new QPushButton(tr("The spacing between this")); + QPushButton *pb2 = new QPushButton(tr("and this button should depend on the style of the parent widget"));; + pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect); + pb2->setAttribute(Qt::WA_LayoutUsesWidgetRect); + hbox->addWidget(pb1); + hbox->addWidget(pb2); + CustomLayoutStyle *style1 = new CustomLayoutStyle; + style1->hspacing = 6; + window->setStyle(style1); + window->show(); + + QTest::qWait(100); + int spacing = pb2->geometry().left() - pb1->geometry().right() - 1; + QCOMPARE(spacing, 6); + + CustomLayoutStyle *style2 = new CustomLayoutStyle(); + style2->hspacing = 10; + window->setStyle(style2); + QTest::qWait(100); + spacing = pb2->geometry().left() - pb1->geometry().right() - 1; + QCOMPARE(spacing, 10); + + delete window; + delete style1; + delete style2; +} + +void tst_QBoxLayout::taskQTBUG_7103_minMaxWidthNotRespected() +{ + QLabel *label = new QLabel("Qt uses standard C++, but makes extensive use of the C pre-processor to enrich the language. Qt can also be used in several other programming languages via language bindings. It runs on all major platforms, and has extensive internationalization support. Non-GUI features include SQL database access, XML parsing, thread management, network support and a unified cross-platform API for file handling."); + label->setWordWrap(true); + label->setFixedWidth(200); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(label); + layout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + QWidget widget; + widget.setLayout(layout); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + int height = label->height(); + + QRect g = widget.geometry(); + g.setWidth(600); + widget.setGeometry(g); + + QTest::qWait(50); + + QCOMPARE(label->height(), height); +} + +QTEST_MAIN(tst_QBoxLayout) +#include "tst_qboxlayout.moc" diff --git a/tests/auto/widgets/kernel/qdesktopwidget/.gitignore b/tests/auto/widgets/kernel/qdesktopwidget/.gitignore new file mode 100644 index 0000000000..d6f7cc7ca9 --- /dev/null +++ b/tests/auto/widgets/kernel/qdesktopwidget/.gitignore @@ -0,0 +1 @@ +tst_qdesktopwidget diff --git a/tests/auto/widgets/kernel/qdesktopwidget/qdesktopwidget.pro b/tests/auto/widgets/kernel/qdesktopwidget/qdesktopwidget.pro new file mode 100644 index 0000000000..730b273c4f --- /dev/null +++ b/tests/auto/widgets/kernel/qdesktopwidget/qdesktopwidget.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qdesktopwidget.cpp diff --git a/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp b/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp new file mode 100644 index 0000000000..e7e3abeb25 --- /dev/null +++ b/tests/auto/widgets/kernel/qdesktopwidget/tst_qdesktopwidget.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include + +//TESTED_CLASS= + +class tst_QDesktopWidget : public QObject +{ + Q_OBJECT + +public: + tst_QDesktopWidget(); + virtual ~tst_QDesktopWidget(); + +public slots: + void init(); + void cleanup(); + +private slots: + void numScreens(); + void primaryScreen(); + void screenNumberForQWidget(); + void screenNumberForQPoint(); + void availableGeometry(); + void screenGeometry(); +}; + +tst_QDesktopWidget::tst_QDesktopWidget() +{ +} + +tst_QDesktopWidget::~tst_QDesktopWidget() +{ +} + +void tst_QDesktopWidget::init() +{ +} + +void tst_QDesktopWidget::cleanup() +{ +} + +void tst_QDesktopWidget::numScreens() +{ + QDesktopWidget desktop; + QVERIFY(desktop.numScreens() > 0); +} + +void tst_QDesktopWidget::primaryScreen() +{ + QDesktopWidget desktop; + QVERIFY(desktop.primaryScreen() >= 0); + QVERIFY(desktop.primaryScreen() < desktop.numScreens()); +} + +void tst_QDesktopWidget::availableGeometry() +{ + QDesktopWidget desktop; + QTest::ignoreMessage(QtWarningMsg, "QDesktopWidget::availableGeometry(): Attempt " + "to get the available geometry of a null widget"); + desktop.availableGeometry((QWidget *)0); + + QRect total; + QRect available; + + for (int i = 0; i < desktop.screenCount(); ++i) { + total = desktop.screenGeometry(i); + available = desktop.availableGeometry(i); + QVERIFY(total.contains(available)); + } + + total = desktop.screenGeometry(); + available = desktop.availableGeometry(); + QVERIFY(total.contains(available)); + QCOMPARE(desktop.availableGeometry(desktop.primaryScreen()), available); + QCOMPARE(desktop.screenGeometry(desktop.primaryScreen()), total); +} + +void tst_QDesktopWidget::screenNumberForQWidget() +{ + QDesktopWidget desktop; + + QCOMPARE(desktop.screenNumber(0), 0); + + QWidget widget; + widget.show(); + QTest::qWaitForWindowShown(&widget); + QVERIFY(widget.isVisible()); + + int widgetScreen = desktop.screenNumber(&widget); + QVERIFY(widgetScreen > -1); + QVERIFY(widgetScreen < desktop.numScreens()); +} + +void tst_QDesktopWidget::screenNumberForQPoint() +{ + // make sure QDesktopWidget::screenNumber(QPoint) returns the correct screen + QDesktopWidget *desktopWidget = QApplication::desktop(); + QRect allScreens; + for (int i = 0; i < desktopWidget->numScreens(); ++i) { + QRect screenGeometry = desktopWidget->screenGeometry(i); + QCOMPARE(desktopWidget->screenNumber(screenGeometry.center()), i); + allScreens |= screenGeometry; + } + + // make sure QDesktopWidget::screenNumber(QPoint) returns a valid screen for points that aren't on any screen + int screen; + screen = desktopWidget->screenNumber(allScreens.topLeft() - QPoint(1, 1)); + +#ifdef Q_WS_QWS + QEXPECT_FAIL("", "Task 151710", Abort); +#endif + QVERIFY(screen >= 0 && screen < desktopWidget->numScreens()); + screen = desktopWidget->screenNumber(allScreens.topRight() + QPoint(1, 1)); + QVERIFY(screen >= 0 && screen < desktopWidget->numScreens()); + screen = desktopWidget->screenNumber(allScreens.bottomLeft() - QPoint(1, 1)); + QVERIFY(screen >= 0 && screen < desktopWidget->numScreens()); + screen = desktopWidget->screenNumber(allScreens.bottomRight() + QPoint(1, 1)); + QVERIFY(screen >= 0 && screen < desktopWidget->numScreens()); +} + +void tst_QDesktopWidget::screenGeometry() +{ + QDesktopWidget *desktopWidget = QApplication::desktop(); + QTest::ignoreMessage(QtWarningMsg, "QDesktopWidget::screenGeometry(): Attempt " + "to get the screen geometry of a null widget"); + QRect r = desktopWidget->screenGeometry((QWidget *)0); + QVERIFY(r.isNull()); + QWidget widget; + widget.show(); + QTest::qWaitForWindowShown(&widget); + r = desktopWidget->screenGeometry(&widget); + + QRect total; + QRect available; + for (int i = 0; i < desktopWidget->screenCount(); ++i) { + total = desktopWidget->screenGeometry(i); + available = desktopWidget->availableGeometry(i); + } +} + +QTEST_MAIN(tst_QDesktopWidget) +#include "tst_qdesktopwidget.moc" + diff --git a/tests/auto/widgets/kernel/qformlayout/.gitignore b/tests/auto/widgets/kernel/qformlayout/.gitignore new file mode 100644 index 0000000000..24e93d561f --- /dev/null +++ b/tests/auto/widgets/kernel/qformlayout/.gitignore @@ -0,0 +1 @@ +tst_qformlayout diff --git a/tests/auto/widgets/kernel/qformlayout/qformlayout.pro b/tests/auto/widgets/kernel/qformlayout/qformlayout.pro new file mode 100644 index 0000000000..24c452af9f --- /dev/null +++ b/tests/auto/widgets/kernel/qformlayout/qformlayout.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qformlayout.cpp diff --git a/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp new file mode 100644 index 0000000000..4425205eb9 --- /dev/null +++ b/tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp @@ -0,0 +1,913 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFormLayout : public QObject +{ + Q_OBJECT + +public: + tst_QFormLayout(); + ~tst_QFormLayout(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void rowCount(); + void buddies(); + void getItemPosition(); + void wrapping(); + void spacing(); + void contentsRect(); + + void setFormStyle(); + void setFieldGrowthPolicy(); + void setRowWrapPolicy(); + void setLabelAlignment(); + void setFormAlignment(); + +/* + void setHorizontalSpacing(int spacing); + int horizontalSpacing() const; + void setVerticalSpacing(int spacing); + int verticalSpacing() const; +*/ + + void addRow(); + void insertRow_QWidget_QWidget(); + void insertRow_QWidget_QLayout(); + void insertRow_QString_QWidget(); + void insertRow_QString_QLayout(); + void insertRow_QWidget(); + void insertRow_QLayout(); + void setWidget(); + void setLayout(); + +/* + QLayoutItem *itemAt(int row, ItemRole role) const; + void getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const; + void getLayoutPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const; + void getItemPosition(QLayoutItem *item, int *rowPtr, ItemRole *rolePtr) const; + QWidget *labelForField(QWidget *widget) const; + QWidget *labelForField(QLayoutItem *item) const; + + void addItem(QLayoutItem *item); +*/ + + void itemAt(); + void takeAt(); + void layoutAlone(); +/* + void setGeometry(const QRect &rect); + QSize minimumSize() const; + QSize sizeHint() const; + + bool hasHeightForWidth() const; + int heightForWidth(int width) const; + Qt::Orientations expandingDirections() const; +*/ + +}; + +tst_QFormLayout::tst_QFormLayout() +{ +} + +tst_QFormLayout::~tst_QFormLayout() +{ +} + +void tst_QFormLayout::initTestCase() +{ +} + +void tst_QFormLayout::cleanupTestCase() +{ +} + +void tst_QFormLayout::init() +{ +} + +void tst_QFormLayout::cleanup() +{ +} + +void tst_QFormLayout::rowCount() +{ + QWidget *w = new QWidget; + QFormLayout *fl = new QFormLayout(w); + + fl->addRow(tr("Label 1"), new QLineEdit); + fl->addRow(tr("Label 2"), new QLineEdit); + fl->addRow(tr("Label 3"), new QLineEdit); + QCOMPARE(fl->rowCount(), 3); + + fl->addRow(new QWidget); + fl->addRow(new QHBoxLayout); + QCOMPARE(fl->rowCount(), 5); + + fl->insertRow(1, tr("Label 0.5"), new QLineEdit); + QCOMPARE(fl->rowCount(), 6); + + //TODO: remove items + + delete w; +} + +void tst_QFormLayout::buddies() +{ + QWidget *w = new QWidget; + QFormLayout *fl = new QFormLayout(w); + + //normal buddy case + QLineEdit *le = new QLineEdit; + fl->addRow(tr("Label 1"), le); + QLabel *label = qobject_cast(fl->labelForField(le)); + QVERIFY(label); + QWidget *lew = le; + QCOMPARE(label->buddy(), lew); + + //null label + QLineEdit *le2 = new QLineEdit; + fl->addRow(0, le2); + QWidget *label2 = fl->labelForField(le2); + QVERIFY(label2 == 0); + + //no label + QLineEdit *le3 = new QLineEdit; + fl->addRow(le3); + QWidget *label3 = fl->labelForField(le3); + QVERIFY(label3 == 0); + + //TODO: empty label? + + delete w; +} + +void tst_QFormLayout::getItemPosition() +{ + QWidget *w = new QWidget; + QFormLayout *fl = new QFormLayout(w); + + QList labels; + QList fields; + for (int i = 0; i < 5; ++i) { + labels.append(new QLabel(QString("Label %1").arg(i+1))); + fields.append(new QLineEdit); + fl->addRow(labels[i], fields[i]); + } + + //a field + { + int row; + QFormLayout::ItemRole role; + fl->getWidgetPosition(fields[3], &row, &role); + QCOMPARE(row, 3); + QCOMPARE(role, QFormLayout::FieldRole); + } + + //a label + { + int row; + QFormLayout::ItemRole role; + fl->getWidgetPosition(labels[2], &row, &role); + QCOMPARE(row, 2); + QCOMPARE(role, QFormLayout::LabelRole); + } + + //a layout that's been inserted + { + QVBoxLayout *vbl = new QVBoxLayout; + fl->insertRow(2, "Label 1.5", vbl); + int row; + QFormLayout::ItemRole role; + fl->getLayoutPosition(vbl, &row, &role); + QCOMPARE(row, 2); + QCOMPARE(role, QFormLayout::FieldRole); + } + + delete w; +} + +void tst_QFormLayout::wrapping() +{ + QWidget *w = new QWidget; + QFormLayout *fl = new QFormLayout(w); + fl->setRowWrapPolicy(QFormLayout::WrapLongRows); + + QLineEdit *le = new QLineEdit; + QLabel *lbl = new QLabel("A long label"); + le->setMinimumWidth(200); + fl->addRow(lbl, le); + + w->setFixedWidth(240); + w->show(); + + QCOMPARE(le->geometry().y() > lbl->geometry().y(), true); + + //TODO: additional tests covering different wrapping cases + + delete w; +} + +class CustomLayoutStyle : public QWindowsStyle +{ + Q_OBJECT +public: + CustomLayoutStyle() + { + hspacing = 5; + vspacing = 10; + } + + virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, + const QWidget * widget = 0 ) const; + + int hspacing; + int vspacing; +}; + +int CustomLayoutStyle::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, + const QWidget * widget /*= 0*/ ) const +{ + switch (metric) { + case PM_LayoutHorizontalSpacing: + return hspacing; + case PM_LayoutVerticalSpacing: + return vspacing; + break; + default: + break; + } + return QWindowsStyle::pixelMetric(metric, option, widget); +} + +void tst_QFormLayout::spacing() +{ + //TODO: confirm spacing behavior + QWidget *w = new QWidget; + CustomLayoutStyle *style = new CustomLayoutStyle; + style->hspacing = 5; + style->vspacing = 10; + w->setStyle(style); + QFormLayout *fl = new QFormLayout(w); + QCOMPARE(style->hspacing, fl->horizontalSpacing()); + QCOMPARE(style->vspacing, fl->verticalSpacing()); + + //QCOMPARE(fl->spacing(), -1); + fl->setVerticalSpacing(5); + QCOMPARE(5, fl->horizontalSpacing()); + QCOMPARE(5, fl->verticalSpacing()); + //QCOMPARE(fl->spacing(), 5); + fl->setVerticalSpacing(-1); + QCOMPARE(style->hspacing, fl->horizontalSpacing()); + QCOMPARE(style->vspacing, fl->verticalSpacing()); + + style->hspacing = 5; + style->vspacing = 5; + //QCOMPARE(fl->spacing(), 5); + + fl->setHorizontalSpacing(20); + //QCOMPARE(fl->spacing(), -1); + style->vspacing = 20; + QCOMPARE(fl->horizontalSpacing(), 20); + QCOMPARE(fl->verticalSpacing(), 20); + //QCOMPARE(fl->spacing(), 20); + fl->setHorizontalSpacing(-1); + //QCOMPARE(fl->spacing(), -1); + style->hspacing = 20; + //QCOMPARE(fl->spacing(), 20); + + delete w; + delete style; +} + +void tst_QFormLayout::contentsRect() +{ + QWidget w; + QFormLayout form; + w.setLayout(&form); + form.addRow("Label", new QPushButton(&w)); + w.show(); +/*#if defined(Q_WS_X11) + qt_x11_wait_for_window_manager(&w); // wait for the show +#endif*/ + int l, t, r, b; + form.getContentsMargins(&l, &t, &r, &b); + QRect geom = form.geometry(); + + QCOMPARE(geom.adjusted(+l, +t, -r, -b), form.contentsRect()); +} + + +class DummyMacStyle : public QCommonStyle +{ +public: + virtual int styleHint ( StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const + { + switch(hint) { + case SH_FormLayoutFormAlignment: + return Qt::AlignHCenter | Qt::AlignTop; + case SH_FormLayoutLabelAlignment: + return Qt::AlignRight; + case SH_FormLayoutWrapPolicy: + return QFormLayout::DontWrapRows; + case SH_FormLayoutFieldGrowthPolicy: + return QFormLayout::FieldsStayAtSizeHint; + default: + return QCommonStyle::styleHint(hint, option, widget, returnData); + } + } +}; + +class DummyQtopiaStyle : public QCommonStyle +{ +public: + virtual int styleHint ( StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const + { + switch(hint) { + case SH_FormLayoutFormAlignment: + return Qt::AlignLeft | Qt::AlignTop; + case SH_FormLayoutLabelAlignment: + return Qt::AlignRight; + case SH_FormLayoutWrapPolicy: + return QFormLayout::WrapLongRows; + case SH_FormLayoutFieldGrowthPolicy: + return QFormLayout::AllNonFixedFieldsGrow; + default: + return QCommonStyle::styleHint(hint, option, widget, returnData); + } + } +}; + +void tst_QFormLayout::setFormStyle() +{ + QWidget widget; + QFormLayout layout; + widget.setLayout(&layout); + +#ifndef QT_NO_STYLE_PLASTIQUE + widget.setStyle(new QPlastiqueStyle()); + + QVERIFY(layout.labelAlignment() == Qt::AlignRight); + QVERIFY(layout.formAlignment() == (Qt::AlignLeft | Qt::AlignTop)); + QVERIFY(layout.fieldGrowthPolicy() == QFormLayout::ExpandingFieldsGrow); + QVERIFY(layout.rowWrapPolicy() == QFormLayout::DontWrapRows); +#endif + + widget.setStyle(new QWindowsStyle()); + + QVERIFY(layout.labelAlignment() == Qt::AlignLeft); + QVERIFY(layout.formAlignment() == (Qt::AlignLeft | Qt::AlignTop)); + QVERIFY(layout.fieldGrowthPolicy() == QFormLayout::AllNonFixedFieldsGrow); + QVERIFY(layout.rowWrapPolicy() == QFormLayout::DontWrapRows); + + /* can't directly create mac style or qtopia style, since + this test is cross platform.. so create dummy styles that + return all the right stylehints. + */ + widget.setStyle(new DummyMacStyle()); + + QVERIFY(layout.labelAlignment() == Qt::AlignRight); + QVERIFY(layout.formAlignment() == (Qt::AlignHCenter | Qt::AlignTop)); + QVERIFY(layout.fieldGrowthPolicy() == QFormLayout::FieldsStayAtSizeHint); + QVERIFY(layout.rowWrapPolicy() == QFormLayout::DontWrapRows); + + widget.setStyle(new DummyQtopiaStyle()); + + QVERIFY(layout.labelAlignment() == Qt::AlignRight); + QVERIFY(layout.formAlignment() == (Qt::AlignLeft | Qt::AlignTop)); + QVERIFY(layout.fieldGrowthPolicy() == QFormLayout::AllNonFixedFieldsGrow); + QVERIFY(layout.rowWrapPolicy() == QFormLayout::WrapLongRows); +} + +void tst_QFormLayout::setFieldGrowthPolicy() +{ + QWidget window; + QLineEdit fld1, fld2, fld3; + fld1.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + fld2.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + fld3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + QFormLayout layout; + layout.addRow("One:", &fld1); + layout.addRow("Two:", &fld2); + layout.addRow("Three:", &fld3); + window.setLayout(&layout); + window.resize(1000, 200); + + for (int i = 0; i < 3; ++i) { + layout.setFieldGrowthPolicy(i == 0 ? QFormLayout::FieldsStayAtSizeHint : + i == 1 ? QFormLayout::ExpandingFieldsGrow : + QFormLayout::AllNonFixedFieldsGrow); + layout.activate(); + + if (i == 0) { + QVERIFY(fld1.width() == fld2.width()); + QVERIFY(fld2.width() == fld3.width()); + } else if (i == 1) { + QVERIFY(fld1.width() == fld2.width()); + QVERIFY(fld2.width() < fld3.width()); + } else { + QVERIFY(fld1.width() < fld2.width()); + QVERIFY(fld2.width() == fld3.width()); + } + } +} + +void tst_QFormLayout::setRowWrapPolicy() +{ +} + +void tst_QFormLayout::setLabelAlignment() +{ +} + +void tst_QFormLayout::setFormAlignment() +{ +} + +void tst_QFormLayout::addRow() +{ + QFormLayout layout; + QWidget w1, w2, w3; + QHBoxLayout l1, l2, l3; + QLabel lbl1, lbl2; + + QCOMPARE(layout.rowCount(), 0); + + layout.addRow(&lbl1, &w1); + layout.addRow(&lbl2, &l1); + layout.addRow("Foo:", &w2); + layout.addRow("Bar:", &l2); + layout.addRow(&w3); + layout.addRow(&l3); + + QCOMPARE(layout.rowCount(), 6); + + QVERIFY(layout.itemAt(0, QFormLayout::LabelRole)->widget() == &lbl1); + QVERIFY(layout.itemAt(1, QFormLayout::LabelRole)->widget() == &lbl2); + QVERIFY(layout.itemAt(2, QFormLayout::LabelRole)->widget()->property("text") == "Foo:"); + QVERIFY(layout.itemAt(3, QFormLayout::LabelRole)->widget()->property("text") == "Bar:"); + QVERIFY(layout.itemAt(4, QFormLayout::LabelRole) == 0); + QVERIFY(layout.itemAt(5, QFormLayout::LabelRole) == 0); + + QVERIFY(layout.itemAt(0, QFormLayout::FieldRole)->widget() == &w1); + QVERIFY(layout.itemAt(1, QFormLayout::FieldRole)->layout() == &l1); + QVERIFY(layout.itemAt(2, QFormLayout::FieldRole)->widget() == &w2); + QVERIFY(layout.itemAt(3, QFormLayout::FieldRole)->layout() == &l2); +// ### should have a third role, FullRowRole? +// QVERIFY(layout.itemAt(4, QFormLayout::FieldRole) == 0); +// QVERIFY(layout.itemAt(5, QFormLayout::FieldRole) == 0); +} + +void tst_QFormLayout::insertRow_QWidget_QWidget() +{ + QFormLayout layout; + QLabel lbl1, lbl2, lbl3, lbl4; + QLineEdit fld1, fld2, fld3, fld4; + + layout.insertRow(0, &lbl1, &fld1); + QCOMPARE(layout.rowCount(), 1); + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&lbl1, &row, &role); + QCOMPARE(row, 0); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&fld1, &row, &role); + QCOMPARE(row, 0); + QCOMPARE(int(role), int(QFormLayout::FieldRole)); + } + + // check that negative values append + layout.insertRow(-2, &lbl2, &fld2); + QCOMPARE(layout.rowCount(), 2); + + QVERIFY(layout.itemAt(0, QFormLayout::LabelRole)->widget() == &lbl1); + QVERIFY(layout.itemAt(1, QFormLayout::LabelRole)->widget() == &lbl2); + + // check that too large values append + layout.insertRow(100, &lbl3, &fld3); + QCOMPARE(layout.rowCount(), 3); + QCOMPARE(layout.count(), 6); + + layout.insertRow(3, (QWidget *)0, (QWidget *)0); + QCOMPARE(layout.rowCount(), 4); + QCOMPARE(layout.count(), 6); + + layout.insertRow(4, (QWidget *)0, &fld4); + QCOMPARE(layout.rowCount(), 5); + QCOMPARE(layout.count(), 7); + + layout.insertRow(5, &lbl4, (QWidget *)0); + QCOMPARE(layout.rowCount(), 6); + QCOMPARE(layout.count(), 8); + + QVERIFY(layout.itemAt(0, QFormLayout::LabelRole)->widget() == &lbl1); + QVERIFY(layout.itemAt(1, QFormLayout::LabelRole)->widget() == &lbl2); + QVERIFY(layout.itemAt(2, QFormLayout::LabelRole)->widget() == &lbl3); + QVERIFY(layout.itemAt(3, QFormLayout::LabelRole) == 0); + QVERIFY(layout.itemAt(4, QFormLayout::LabelRole) == 0); + QVERIFY(layout.itemAt(5, QFormLayout::LabelRole)->widget() == &lbl4); + + QVERIFY(layout.itemAt(0, QFormLayout::FieldRole)->widget() == &fld1); + QVERIFY(layout.itemAt(1, QFormLayout::FieldRole)->widget() == &fld2); + QVERIFY(layout.itemAt(2, QFormLayout::FieldRole)->widget() == &fld3); + QVERIFY(layout.itemAt(3, QFormLayout::FieldRole) == 0); + QVERIFY(layout.itemAt(4, QFormLayout::FieldRole)->widget() == &fld4); + QVERIFY(layout.itemAt(5, QFormLayout::FieldRole) == 0); +} + +void tst_QFormLayout::insertRow_QWidget_QLayout() +{ + QFormLayout layout; + QLabel lbl1, lbl2, lbl3, lbl4; + QHBoxLayout fld1, fld2, fld3, fld4; + + layout.insertRow(0, &lbl1, &fld1); + QCOMPARE(layout.rowCount(), 1); + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&lbl1, &row, &role); + QCOMPARE(row, 0); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(&fld1, &row, &role); + QCOMPARE(row, 0); + QCOMPARE(int(role), int(QFormLayout::FieldRole)); + } + + // check that negative values append + layout.insertRow(-2, &lbl2, &fld2); + QCOMPARE(layout.rowCount(), 2); + + QVERIFY(layout.itemAt(0, QFormLayout::LabelRole)->widget() == &lbl1); + QVERIFY(layout.itemAt(1, QFormLayout::LabelRole)->widget() == &lbl2); + + // check that too large values append + layout.insertRow(100, &lbl3, &fld3); + QCOMPARE(layout.rowCount(), 3); + + QVERIFY(layout.itemAt(0, QFormLayout::LabelRole)->widget() == &lbl1); + QVERIFY(layout.itemAt(1, QFormLayout::LabelRole)->widget() == &lbl2); + QVERIFY(layout.itemAt(2, QFormLayout::LabelRole)->widget() == &lbl3); + + QVERIFY(layout.itemAt(0, QFormLayout::FieldRole)->layout() == &fld1); + QVERIFY(layout.itemAt(1, QFormLayout::FieldRole)->layout() == &fld2); + QVERIFY(layout.itemAt(2, QFormLayout::FieldRole)->layout() == &fld3); +} + +void tst_QFormLayout::insertRow_QString_QWidget() +{ + QFormLayout layout; + QLineEdit fld1, fld2, fld3; + + layout.insertRow(-5, "&Name:", &fld1); + QLabel *label1 = qobject_cast(layout.itemAt(0, QFormLayout::LabelRole)->widget()); + QVERIFY(label1 != 0); + QVERIFY(label1->buddy() == &fld1); + + layout.insertRow(0, "&Email:", &fld2); + QLabel *label2 = qobject_cast(layout.itemAt(0, QFormLayout::LabelRole)->widget()); + QVERIFY(label2 != 0); + QVERIFY(label2->buddy() == &fld2); + + layout.insertRow(5, "&Age:", &fld3); + QLabel *label3 = qobject_cast(layout.itemAt(2, QFormLayout::LabelRole)->widget()); + QVERIFY(label3 != 0); + QVERIFY(label3->buddy() == &fld3); +} + +void tst_QFormLayout::insertRow_QString_QLayout() +{ + QFormLayout layout; + QHBoxLayout fld1, fld2, fld3; + + layout.insertRow(-5, "&Name:", &fld1); + QLabel *label1 = qobject_cast(layout.itemAt(0, QFormLayout::LabelRole)->widget()); + QVERIFY(label1 != 0); + QVERIFY(label1->buddy() == 0); + + QCOMPARE(layout.rowCount(), 1); + + layout.insertRow(0, "&Email:", &fld2); + QLabel *label2 = qobject_cast(layout.itemAt(0, QFormLayout::LabelRole)->widget()); + QVERIFY(label2 != 0); + QVERIFY(label2->buddy() == 0); + + QCOMPARE(layout.rowCount(), 2); + + layout.insertRow(5, "&Age:", &fld3); + QLabel *label3 = qobject_cast(layout.itemAt(2, QFormLayout::LabelRole)->widget()); + QVERIFY(label3 != 0); + QVERIFY(label3->buddy() == 0); + + QCOMPARE(layout.rowCount(), 3); +} + +void tst_QFormLayout::insertRow_QWidget() +{ + // ### come back to this later +} + +void tst_QFormLayout::insertRow_QLayout() +{ + // ### come back to this later +} + +void tst_QFormLayout::setWidget() +{ + QFormLayout layout; + + QWidget w1; + QWidget w2; + QWidget w3; + QWidget w4; + + QCOMPARE(layout.count(), 0); + QCOMPARE(layout.rowCount(), 0); + + layout.setWidget(5, QFormLayout::LabelRole, &w1); + QCOMPARE(layout.count(), 1); + QCOMPARE(layout.rowCount(), 6); + + layout.setWidget(3, QFormLayout::FieldRole, &w2); + layout.setWidget(3, QFormLayout::LabelRole, &w3); + QCOMPARE(layout.count(), 3); + QCOMPARE(layout.rowCount(), 6); + + // should be ignored and generate warnings + layout.setWidget(3, QFormLayout::FieldRole, &w4); + layout.setWidget(-1, QFormLayout::FieldRole, &w4); + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&w1, &row, &role); + QCOMPARE(row, 5); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&w2, &row, &role); + QCOMPARE(row, 3); + QCOMPARE(int(role), int(QFormLayout::FieldRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&w3, &row, &role); + QCOMPARE(row, 3); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(&w4, &row, &role); + QCOMPARE(row, -1); + QCOMPARE(int(role), -123); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getWidgetPosition(0, &row, &role); + QCOMPARE(row, -1); + QCOMPARE(int(role), -123); + } +} + +void tst_QFormLayout::setLayout() +{ + QFormLayout layout; + + QHBoxLayout l1; + QHBoxLayout l2; + QHBoxLayout l3; + QHBoxLayout l4; + + QCOMPARE(layout.count(), 0); + QCOMPARE(layout.rowCount(), 0); + + layout.setLayout(5, QFormLayout::LabelRole, &l1); + QCOMPARE(layout.count(), 1); + QCOMPARE(layout.rowCount(), 6); + + layout.setLayout(3, QFormLayout::FieldRole, &l2); + layout.setLayout(3, QFormLayout::LabelRole, &l3); + QCOMPARE(layout.count(), 3); + QCOMPARE(layout.rowCount(), 6); + + // should be ignored and generate warnings + layout.setLayout(3, QFormLayout::FieldRole, &l4); + layout.setLayout(-1, QFormLayout::FieldRole, &l4); + QCOMPARE(layout.count(), 3); + QCOMPARE(layout.rowCount(), 6); + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(&l1, &row, &role); + QCOMPARE(row, 5); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(&l2, &row, &role); + QCOMPARE(row, 3); + QCOMPARE(int(role), int(QFormLayout::FieldRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(&l3, &row, &role); + QCOMPARE(row, 3); + QCOMPARE(int(role), int(QFormLayout::LabelRole)); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(&l4, &row, &role); + QCOMPARE(row, -1); + QCOMPARE(int(role), -123); + } + + { + int row = -1; + QFormLayout::ItemRole role = QFormLayout::ItemRole(-123); + layout.getLayoutPosition(0, &row, &role); + QCOMPARE(row, -1); + QCOMPARE(int(role), -123); + } +} + +void tst_QFormLayout::itemAt() +{ + QFormLayout layout; + + QWidget w1; + QWidget w2; + QWidget w3; + QWidget w4; + QWidget w5; + QHBoxLayout l6; + + layout.setWidget(5, QFormLayout::LabelRole, &w1); + layout.setWidget(3, QFormLayout::FieldRole, &w2); + layout.setWidget(3, QFormLayout::LabelRole, &w3); + layout.addRow(&w4, &w5); + layout.addRow("Foo:", &l6); + + QCOMPARE(layout.count(), 7); + + QBitArray scoreBoard(7); + for (int i = 0; i < 7; ++i) { + QLayoutItem *item = layout.itemAt(i); + QVERIFY(item != 0); + + if (item->widget() == &w1) { + scoreBoard[0] = true; + } else if (item->widget() == &w2) { + scoreBoard[1] = true; + } else if (item->widget() == &w3) { + scoreBoard[2] = true; + } else if (item->widget() == &w4) { + scoreBoard[3] = true; + } else if (item->widget() == &w5) { + scoreBoard[4] = true; + } else if (item->layout() == &l6) { + scoreBoard[5] = true; + } else if (qobject_cast(item->widget())) { + scoreBoard[6] = true; + } + } + QCOMPARE(scoreBoard.count(false), 0); +} + +void tst_QFormLayout::takeAt() +{ + QFormLayout layout; + + QWidget w1; + QWidget w2; + QWidget w3; + QWidget w4; + QWidget w5; + QHBoxLayout l6; + + layout.setWidget(5, QFormLayout::LabelRole, &w1); + layout.setWidget(3, QFormLayout::FieldRole, &w2); + layout.setWidget(3, QFormLayout::LabelRole, &w3); + layout.addRow(&w4, &w5); + layout.addRow("Foo:", &l6); + + QCOMPARE(layout.count(), 7); + + for (int i = 6; i >= 0; --i) { + layout.takeAt(0); + QCOMPARE(layout.count(), i); + } +} + +void tst_QFormLayout::layoutAlone() +{ + QWidget w; + QFormLayout layout; + layout.setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + w.setLayout(&layout); + QLabel label("Here is a strange test case"); + layout.setWidget(0, QFormLayout::LabelRole, &label); + QHBoxLayout hlay; + layout.setLayout(1, QFormLayout::LabelRole, &hlay); + QCOMPARE(layout.count(), 2); + w.show(); + layout.activate(); + QTest::qWait(500); +} + +QTEST_MAIN(tst_QFormLayout) + +#include "tst_qformlayout.moc" diff --git a/tests/auto/widgets/kernel/qgridlayout/.gitignore b/tests/auto/widgets/kernel/qgridlayout/.gitignore new file mode 100644 index 0000000000..bce8f2f91e --- /dev/null +++ b/tests/auto/widgets/kernel/qgridlayout/.gitignore @@ -0,0 +1 @@ +tst_qgridlayout diff --git a/tests/auto/widgets/kernel/qgridlayout/qgridlayout.pro b/tests/auto/widgets/kernel/qgridlayout/qgridlayout.pro new file mode 100644 index 0000000000..6bd42fe432 --- /dev/null +++ b/tests/auto/widgets/kernel/qgridlayout/qgridlayout.pro @@ -0,0 +1,10 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += core-private gui-private + +SOURCES += tst_qgridlayout.cpp +FORMS += sortdialog.ui + + + diff --git a/tests/auto/widgets/kernel/qgridlayout/sortdialog.ui b/tests/auto/widgets/kernel/qgridlayout/sortdialog.ui new file mode 100644 index 0000000000..04af84d01b --- /dev/null +++ b/tests/auto/widgets/kernel/qgridlayout/sortdialog.ui @@ -0,0 +1,135 @@ + + + + + SortDialog + + + + 0 + 0 + 304 + 370 + + + + Sort + + + + 8 + + + 6 + + + + + 0 + + + 6 + + + + + OK + + + true + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + &More + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + 8 + + + 6 + + + + + + 0 + 100 + + + + + None + + + + + + + + + + + + primaryColumnCombo + okButton + moreButton + + + + + okButton + clicked() + SortDialog + accept() + + + 257 + 25 + + + 283 + 268 + + + + + diff --git a/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp new file mode 100644 index 0000000000..100b7eb892 --- /dev/null +++ b/tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp @@ -0,0 +1,1646 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +//#include + +#include +#include +#include +#include +#include + +#include "../../../platformquirks.h" + +//TESTED_CLASS= +//TESTED_FILES=gui/kernel/qlayout.cpp gui/kernel/qlayout.h + + +class tst_QGridLayout : public QObject +{ +Q_OBJECT + +public: + tst_QGridLayout(); + virtual ~tst_QGridLayout(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void getItemPosition(); + void itemAtPosition(); + void badDistributionBug(); + void setMinAndMaxSize(); + void spacingAndSpacers(); + + void spacingsAndMargins(); + void spacingsAndMargins_data(); + void minMaxSize_data(); + void minMaxSize(); + + void styleDependentSpacingsAndMargins_data(); + void styleDependentSpacingsAndMargins(); + void layoutSpacingImplementation_data(); + void layoutSpacingImplementation(); + void spacing(); + void spacerWithSpacing(); + void contentsRect(); + void distributeMultiCell(); + +private: + QWidget *testWidget; + QGridLayout *testLayout; + QWidget *w1; + QWidget *w2; + QWidget *w3; + QSpacerItem *sp; + + QGridLayout *m_grid; + QWidget *m_toplevel; +}; + + +tst_QGridLayout::tst_QGridLayout() +{ + m_grid = 0; + m_toplevel = 0; +} + +tst_QGridLayout::~tst_QGridLayout() +{ + delete m_toplevel; +} + +void tst_QGridLayout::initTestCase() +{ +#ifdef Q_OS_WINCE //disable magic for WindowsCE + qApp->setAutoMaximizeThreshold(-1); +#endif + // Create the test class + testWidget = new QWidget(0); + + testLayout = new QGridLayout(testWidget); + + w1 = new QWidget(testWidget); + w1->setPalette(QPalette(Qt::red)); + testLayout->addWidget(w1, 0, 0); + + w2 = new QWidget(testWidget); + testLayout->addWidget(w2, 1, 1, 2, 2); + w2->setPalette(QPalette(Qt::green)); + + w3 = new QWidget(testWidget); + testLayout->addWidget(w3, 0, 1, 1, 2); + w3->setPalette(QPalette(Qt::blue)); + + sp = new QSpacerItem(4, 4); + testLayout->addItem(sp, 1, 3, 2, 1); + + testWidget->resize( 200, 200 ); + testWidget->show(); +} + +void tst_QGridLayout::cleanupTestCase() +{ + delete testWidget; + testWidget = 0; +} + +void tst_QGridLayout::init() +{ +} + +void tst_QGridLayout::cleanup() +{ +} + +void tst_QGridLayout::getItemPosition() +{ + QLayoutItem *item; + int counter = 0; + + bool seenW1 = false; + bool seenW2 = false; + bool seenW3 = false; + bool seenSpacer = false; + + while ((item = testLayout->itemAt(counter))) { + QWidget *w = item->widget(); + int r,c,rs,cs; + testLayout->getItemPosition(counter, &r, &c, &rs, &cs); + +// qDebug() << "item" << counter << "has" <itemAtPosition(row, col); + QVERIFY(item == table[row][col] + || (item && item->widget() == table[row][col])); + } + } +} + +#include "ui_sortdialog.h" + +void tst_QGridLayout::badDistributionBug() +{ + QDialog dialog; + Ui::SortDialog ui; + ui.setupUi(&dialog); + ui.gridLayout->setMargin(0); + ui.gridLayout->setSpacing(0); + ui.vboxLayout->setMargin(0); + ui.vboxLayout->setSpacing(0); + ui.okButton->setFixedHeight(20); + ui.moreButton->setFixedHeight(20); + ui.primaryGroupBox->setAttribute(Qt::WA_LayoutUsesWidgetRect); + ui.primaryGroupBox->setFixedHeight(200); + + QSize minSize = dialog.layout()->minimumSize(); + QCOMPARE(minSize.height(), 200); +} + +void tst_QGridLayout::setMinAndMaxSize() +{ + QWidget widget; + QGridLayout layout(&widget); + layout.setMargin(0); + layout.setSpacing(0); + layout.setSizeConstraint(QLayout::SetMinAndMaxSize); + widget.show(); + + QWidget leftChild; + leftChild.setPalette(QPalette(Qt::red)); + leftChild.setMinimumSize(100, 100); + leftChild.setMaximumSize(200, 200); + layout.addWidget(&leftChild, 0, 0); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); + QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); + + QWidget rightChild; + rightChild.setPalette(QPalette(Qt::green)); + rightChild.setMinimumSize(100, 100); + rightChild.setMaximumSize(200, 200); + layout.addWidget(&rightChild, 0, 2); + QApplication::sendPostedEvents(0, 0); + + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth()); + QCOMPARE(widget.minimumHeight(), + qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); + QCOMPARE(widget.maximumWidth(), + leftChild.maximumWidth() + rightChild.maximumWidth()); + QCOMPARE(widget.maximumHeight(), + qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); + + + static const int colMin = 100; + layout.setColumnMinimumWidth(1, colMin); + QCOMPARE(layout.columnMinimumWidth(1), colMin); + + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); + QCOMPARE(widget.maximumWidth(), + leftChild.maximumWidth() + rightChild.maximumWidth() + colMin); + QCOMPARE(widget.minimumHeight(), + qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); + QCOMPARE(widget.maximumHeight(), + qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); + + + + layout.setColumnStretch(1,1); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); + QCOMPARE(widget.maximumWidth(), QLAYOUTSIZE_MAX); + QCOMPARE(widget.minimumHeight(), + qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); + QCOMPARE(widget.maximumHeight(), + qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); + + + + layout.setColumnStretch(1,0); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); + QCOMPARE(widget.maximumWidth(), + leftChild.maximumWidth() + rightChild.maximumWidth() + colMin); + QCOMPARE(widget.minimumHeight(), + qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); + QCOMPARE(widget.maximumHeight(), + qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); + + + + layout.setColumnMinimumWidth(1, 0); + + static const int spacerS = 250; + QSpacerItem *spacer = new QSpacerItem(spacerS, spacerS); + layout.addItem(spacer, 0, 1); + QApplication::sendPostedEvents(0, 0); + + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth() + spacerS); + QCOMPARE(widget.maximumWidth(), QLAYOUTSIZE_MAX); + QCOMPARE(widget.minimumHeight(), + qMax(qMax(leftChild.minimumHeight(), rightChild.minimumHeight()), spacerS)); + QCOMPARE(widget.maximumHeight(), + qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); + + + spacer->changeSize(spacerS, spacerS, QSizePolicy::Fixed, QSizePolicy::Minimum); + layout.invalidate(); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumWidth(), + leftChild.minimumWidth() + rightChild.minimumWidth() + spacerS); + QCOMPARE(widget.maximumWidth(), + leftChild.maximumWidth() + rightChild.maximumWidth() + spacerS); + + + layout.removeItem(spacer); + + rightChild.hide(); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); + QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); + + rightChild.show(); + layout.removeWidget(&rightChild); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); + QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); + + QWidget bottomChild(&widget); + bottomChild.setPalette(QPalette(Qt::green)); + bottomChild.setMinimumSize(100, 100); + bottomChild.setMaximumSize(200, 200); + layout.addWidget(&bottomChild, 1, 0); + QApplication::sendPostedEvents(0, 0); + + QCOMPARE(widget.minimumHeight(), + leftChild.minimumHeight() + bottomChild.minimumHeight()); + QCOMPARE(widget.minimumWidth(), + qMax(leftChild.minimumWidth(), bottomChild.minimumWidth())); + QCOMPARE(widget.maximumHeight(), + leftChild.maximumHeight() + bottomChild.maximumHeight()); + QCOMPARE(widget.maximumWidth(), + qMax(leftChild.maximumWidth(), bottomChild.maximumWidth())); + + bottomChild.hide(); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); + QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); + + bottomChild.show(); + layout.removeWidget(&bottomChild); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); + QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); +} + + +class SizeHinter : public QWidget +{ +public: + SizeHinter(const QSize &s, QWidget *parent = 0) + : QWidget(parent), sh(s) { } + SizeHinter(int w, int h, QWidget *parent = 0) + : QWidget(parent), sh(QSize(w,h)) {} + void setSizeHint(QSize s) { sh = s; } + QSize sizeHint() const { return sh; } +private: + QSize sh; +}; + +void tst_QGridLayout::spacingAndSpacers() +{ + QWidget widget; + QGridLayout layout(&widget); + layout.setMargin(0); + layout.setSpacing(0); + widget.show(); + + QSize expectedSizeHint; + + SizeHinter leftChild(100,100); + leftChild.setPalette(QPalette(Qt::red)); + layout.addWidget(&leftChild, 0, 0); + QApplication::sendPostedEvents(0, 0); + expectedSizeHint = leftChild.sizeHint(); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + + SizeHinter rightChild(200,100); + rightChild.setPalette(QPalette(Qt::green)); + layout.addWidget(&rightChild, 0, 2); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(rightChild.sizeHint(), QSize(200,100)); + + expectedSizeHint += QSize(rightChild.sizeHint().width(), 0); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + layout.setColumnMinimumWidth(1, 100); + widget.adjustSize(); + expectedSizeHint += QSize(100,0); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + rightChild.hide(); + QApplication::sendPostedEvents(0, 0); + expectedSizeHint -= QSize(rightChild.sizeHint().width(), 0); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + + layout.setColumnMinimumWidth(1, 0); + expectedSizeHint -= QSize(100, 0); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + rightChild.show(); + +#if 0 + leftChild.setMaximumWidth(200); + rightChild.setMaximumWidth(200); + + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.maximumWidth(), leftChild.maximumWidth() + rightChild.maximumWidth()); +#endif + + layout.removeWidget(&rightChild); + QApplication::sendPostedEvents(0, 0); + QCOMPARE(widget.sizeHint(), expectedSizeHint); + + +} + + +class Qt42Style : public QWindowsStyle +{ + Q_OBJECT +public: + Qt42Style() : QWindowsStyle() + { + spacing = 6; + margin = 9; + margin_toplevel = 11; + } + + virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, + const QWidget * widget = 0 ) const; + + int spacing; + int margin; + int margin_toplevel; + +}; + +int Qt42Style::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, + const QWidget * widget /*= 0*/ ) const +{ + switch (metric) { + case PM_DefaultLayoutSpacing: + return spacing; + break; + case PM_DefaultTopLevelMargin: + return margin_toplevel; + break; + case PM_DefaultChildMargin: + return margin; + break; + default: + break; + } + return QWindowsStyle::pixelMetric(metric, option, widget); +} + + +typedef QList PointList; +Q_DECLARE_METATYPE(PointList) + + +class SizeHinterFrame : public QLabel +{ +public: + SizeHinterFrame(QWidget *parent = 0) + : QLabel(parent) + { + init(-1); + } + + SizeHinterFrame(const QSize &s, int numPixels = -1) + : QLabel(0), sh(s) { + init(numPixels); + } + + + SizeHinterFrame(int w, int h) + : QLabel(0), sh(QSize(w,h)) + { + init(-1); + } + + void setSizeHint(const QSize &s) { sh = s; } + QSize sizeHint() const { return sh; } + void setMinimumSizeHint(const QSize &s) { msh = s; } + QSize minimumSizeHint() const { return msh; } + + virtual int heightForWidth(int width) const; + + void setNumberOfPixels(int numPixels) { + m_numPixels = numPixels; + QSizePolicy sp = sizePolicy(); + sp.setHeightForWidth(m_numPixels != -1); + setSizePolicy(sp); + } +private: + void init(int numPixels = -1){ + setText(QString::fromAscii("(%1,%2)").arg(sh.width()).arg(sh.height())); + setFrameStyle(QFrame::Box | QFrame::Plain); + setNumberOfPixels(numPixels); + } +private: + QSize sh; + QSize msh; + int m_numPixels; +}; + +int SizeHinterFrame::heightForWidth(int width) const +{ + // Special hack if m_numPixels == -2 then we report that we are heightForWidth aware, but we + // return sizeHint().width() so that it should be laid out as if we had't any hfw. + // This enables us to run the tests twice and to see if we get the same results with hfw as without hfw. + if (m_numPixels == -2) { + return sizeHint().height(); + } + if (m_numPixels == -1 || width == 0) return -1; + // this widget should always cover the same amount of pixels (provided that we don't get any rounding errors) + return (m_numPixels)/width; +} + +void tst_QGridLayout::spacingsAndMargins_data() +{ + // input + QTest::addColumn("columns"); + QTest::addColumn("rows"); + QTest::addColumn("sizehint"); + // expected + QTest::addColumn("expectedpositions"); + + int child_offset_y = 11 + 100 + 6 + 9 ; + QTest::newRow("1x1 grid") << 1 << 1 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + // children + << QPoint( 20, child_offset_y) + ); + + QTest::newRow("2x1 grid") << 2 << 1 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11 + 100 + 6, 11) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20 + 100 + 6, child_offset_y) + ); + + QTest::newRow("3x1 grid") << 3 << 1 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11 + 100 + 6, 11) + << QPoint( 11 + 100 + 6 + 100 + 6, 11) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20 + 100 + 6, child_offset_y) + << QPoint( 20 + 100 + 6 + 100 + 6, child_offset_y) + ); + + child_offset_y = 11 + 9 + 100 + 6 + 100 + 6; + QTest::newRow("1x2 grid") << 1 << 2 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11, 11 + 100 + 6) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20, child_offset_y + 100 + 6) + ); +#if defined (Q_OS_WINCE) //There is not enough screenspace to run the test in original size on Windows CE. We use smaller widgets. + child_offset_y = 11 + 9 + 50 + 6 + 50 + 6 + 50 + 6; + QTest::newRow("1x3 grid") << 1 << 3 << QSize(50, 50) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11, 11 + 50 + 6) + << QPoint( 11, 11 + 50 + 6 + 50 + 6) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20, child_offset_y + 50 + 6) + << QPoint( 20, child_offset_y + 50 + 6 + 50 + 6) + ); +#else + child_offset_y = 11 + 9 + 100 + 6 + 100 + 6 + 100 + 6; + QTest::newRow("1x3 grid") << 1 << 3 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11, 11 + 100 + 6) + << QPoint( 11, 11 + 100 + 6 + 100 + 6) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20, child_offset_y + 100 + 6) + << QPoint( 20, child_offset_y + 100 + 6 + 100 + 6) + ); +#endif + + child_offset_y = 11 + 9 + 100 + 6 + 100 + 6; + QTest::newRow("2x2 grid") << 2 << 2 << QSize(100, 100) + << (PointList() // toplevel + << QPoint( 11, 11) + << QPoint( 11 + 100 + 6, 11) + << QPoint( 11, 11 + 100 + 6) + << QPoint( 11 + 100 + 6, 11 + 100 + 6) + // children + << QPoint( 20, child_offset_y) + << QPoint( 20 + 100 + 6, child_offset_y) + << QPoint( 20, child_offset_y + 100 + 6) + << QPoint( 20 + 100 + 6, child_offset_y + 100 + 6) + ); +} + +void tst_QGridLayout::spacingsAndMargins() +{ +/* + The test tests a gridlayout as a child of a top-level widget, + and then a gridlayout as a child of a non-toplevel widget. + + The expectedpositions should then contain the list of widget positions in the + first gridlayout, then followed by a list of widget positions in the second gridlayout. +*/ + QFETCH(int, columns); + QFETCH(int, rows); + QFETCH(QSize, sizehint); + QFETCH(PointList, expectedpositions); + + + QApplication::setStyle(new Qt42Style); + QWidget toplevel; + if(PlatformQuirks::isAutoMaximizing()) + toplevel.setWindowFlags(Qt::X11BypassWindowManagerHint); + QVBoxLayout vbox(&toplevel); + QGridLayout grid1; + vbox.addLayout(&grid1); + + // a layout with a top-level parent widget + QList > sizehinters; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + SizeHinterFrame *sh = new SizeHinterFrame(sizehint); + sh->setMinimumSizeHint(sizehint); + sizehinters.append(sh); + grid1.addWidget(sh, i, j); + } + } + + // Add the child widget + QWidget widget; + vbox.addWidget(&widget); + QGridLayout grid2; + widget.setLayout(&grid2); + // add a layout to the child widget + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + SizeHinterFrame *sh = new SizeHinterFrame(sizehint); + sh->setMinimumSizeHint(sizehint); + sizehinters.append(sh); + grid2.addWidget(sh, i, j); + } + } + + grid1.setColumnStretch(columns-1, 1); + grid1.setRowStretch(rows-1, 1); + toplevel.show(); + toplevel.adjustSize(); + QApplication::processEvents(); + QTest::qWaitForWindowShown(&toplevel); + + QSize topsize = toplevel.size(); + QSize minimumsize = vbox.totalMinimumSize(); + + if (topsize.width() < minimumsize.width() || topsize.height() < minimumsize.height()) + QSKIP("The screen is too small to run this test case", SkipSingle); + +// We are relying on the order here... + for (int pi = 0; pi < sizehinters.count(); ++pi) { + QPoint pt = sizehinters.at(pi)->mapTo(&toplevel, QPoint(0, 0)); + QCOMPARE(pt, expectedpositions.at(pi)); + } +} + + + + +struct SizeInfo { + SizeInfo(const QPoint &expected, const QSize &sh, const QSize &minimumSize = QSize(), + const QSize &maximumSize = QSize(), int numPixelsToCover = -1) + { + expectedPos = expected; + sizeHint = sh; + minSize = minimumSize; + maxSize = maximumSize; + hfwNumPixels = numPixelsToCover; + } + + SizeInfo(const QRect &expected, const QSize &sh, const QSize &minimumSize = QSize(), + const QSize &maximumSize = QSize(), int numPixelsToCover = -1) + { + expectedPos = expected.topLeft(); + expectedSize = expected.size(); + sizeHint = sh; + minSize = minimumSize; + maxSize = maximumSize; + hfwNumPixels = numPixelsToCover; + } + SizeInfo(const SizeInfo& other) { + (*this)=other; + } + + SizeInfo &operator=(const SizeInfo& other) { + expectedPos = other.expectedPos; + expectedSize = other.expectedSize; + sizeHint = other.sizeHint; + minSize = other.minSize; + maxSize = other.maxSize; + hfwNumPixels = other.hfwNumPixels; + return (*this); + } + + QPoint expectedPos; + QSize expectedSize; + QSize sizeHint; + QSize minSize; + QSize maxSize; + int hfwNumPixels; +}; + + +typedef QList SizeInfoList; +Q_DECLARE_METATYPE(SizeInfoList) + + +void tst_QGridLayout::minMaxSize_data() +{ + // input + QTest::addColumn("stylename"); + QTest::addColumn("columns"); + QTest::addColumn("rows"); + QTest::addColumn("sizePolicy"); + QTest::addColumn("fixedSize"); + //input and expected output + QTest::addColumn("sizeinfos"); + + QTest::newRow("3x1 grid, extend to minimumSize") << QString() << 3 << 1 + << int(QSizePolicy::Minimum) << QSize(152, 50) << (SizeInfoList() + << SizeInfo(QRect(10, 10, 43, 30), QSize( 75, 75), QSize(0,0)) + << SizeInfo(QRect(10 + 45, 10, 43, 30), QSize(75, 75), QSize( 0, 0)) + << SizeInfo(QRect(10 + 45 + 44, 10, 42, 30), QSize(75, 75), QSize( 0, 0)) + ); + + QTest::newRow("1x1 grid, extend to minimumSize") << QString() << 1 << 1 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) + ); + QTest::newRow("2x1 grid, extend to minimumSize") << QString() << 2 << 1 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) + << SizeInfo(QPoint(10 + 100 + 1, 10), QSize( 90, 90)) + ); + QTest::newRow("1x2 grid, extend to minimumSize") << QString() << 1 << 2 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) + << SizeInfo(QPoint(10, 10 + 100 + 1), QSize( 90, 90)) + ); + QTest::newRow("2x1 grid, crop to maximumSize") << QString() << 2 << 1 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize(110,110), QSize(), QSize(100, 100)) + << SizeInfo(QPoint(10 + 100 + 1, 10), QSize( 90, 90)) + ); + QTest::newRow("1x2 grid, crop to maximumSize") << QString() << 1 << 2 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize(110,110), QSize(), QSize(100, 100)) + << SizeInfo(QPoint(10, 10 + 100 + 1), QSize( 90, 90)) + ); + QTest::newRow("1x3 grid, heightForWidth") << QString() << 1 << 3 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(10, 10), QSize(), QSize(200,100), QSize()) + << SizeInfo(QPoint(10, 10 + 100 + 1), QSize(100,100), QSize(), QSize(), 100*100) + << SizeInfo(QPoint(10, 10 + 100 + 1 + 50 + 1), QSize(100,100), QSize(), QSize(100, 100)) + ); + QTest::newRow("2x1 grid, extend to minimumSize") << QString::fromAscii("motif") << 2 << 1 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(11, 11), QSize( 90, 90), QSize(100,100)) + << SizeInfo(QPoint(11 + 100 + 6, 11), QSize( 90, 90)) + ); + QTest::newRow("2x1 grid, extend to minimumSize") << QString::fromAscii("windows") << 2 << 1 + << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() + << SizeInfo(QPoint(11, 11), QSize( 90, 90), QSize(100,100)) + << SizeInfo(QPoint(11 + 100 + 6, 11), QSize( 90, 90)) + ); + +} + +void tst_QGridLayout::minMaxSize() +{ +/* + The test tests a gridlayout as a child of a top-level widget +*/ + // input + QFETCH(QString, stylename); + QFETCH(int, columns); + QFETCH(int, rows); + QFETCH(int, sizePolicy); + QFETCH(QSize, fixedSize); + //input and expected output + QFETCH(SizeInfoList, sizeinfos); + + QStyle *style = 0; + if (stylename.isEmpty()) { + Qt42Style *s = new Qt42Style; + s->margin_toplevel = 10; + s->margin = 5; + s->spacing = 1; + style = static_cast(s); + }else{ + style = QStyleFactory::create(stylename); + if (!style) { + QSKIP( qPrintable(QString::fromLatin1("Qt has been compiled without style: %1").arg(stylename)), SkipSingle); + } + } + QApplication::setStyle(style); + if (!m_grid) + m_grid = new QGridLayout(); + if (!m_toplevel) + m_toplevel = new QWidget(); + if (fixedSize.isValid()) { + m_toplevel->setFixedSize(fixedSize); + } else { + m_toplevel->setMinimumSize(QSize(0,0)); + m_toplevel->setMaximumSize(QSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX)); + } + // Do a two-pass one using the real testdata, the other pass enables heightForWidth + // on the widget, but the heightForWidth() function just return sizeHint().width() + for (int pass = 0; pass < 2; ++pass) { + m_toplevel->hide(); + QApplication::processEvents(); + QTest::qWait(20); + // Test if removeItem uninitializes data properly + while (m_grid->count()) { + QLayoutItem *item = m_grid->itemAt(0); + m_grid->removeItem(item); + delete item->widget(); + delete item; + } + m_toplevel->setLayout(m_grid); + + // a layout with a top-level parent widget + QList > sizehinters; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + SizeInfo si = sizeinfos.at(sizehinters.count()); + int numpixels = si.hfwNumPixels; + if (pass == 1 && numpixels == -1) + numpixels = -2; //### yuk, (and don't fake it if it already tests sizehint) + SizeHinterFrame *sh = new SizeHinterFrame(si.sizeHint, numpixels); + QSizePolicy sp = sh->sizePolicy(); + sp.setHorizontalPolicy((QSizePolicy::Policy)sizePolicy); + sh->setSizePolicy(sp); + sh->setParent(m_toplevel); + if (si.minSize.isValid()) + sh->setMinimumSize(si.minSize); + if (si.maxSize.isValid()) + sh->setMaximumSize(si.maxSize); + sizehinters.append(sh); + m_grid->addWidget(sh, i, j); + } + } + + m_toplevel->show(); +#if defined(Q_WS_X11) + qt_x11_wait_for_window_manager(m_toplevel); // wait for the show +#endif + QTest::qWait(40); + m_toplevel->adjustSize(); + QTest::qWait(240); // wait for the implicit adjustSize + // If the following fails we might have to wait longer. + // If that does not help there is likely a problem with the implicit adjustSize in show() + if (!fixedSize.isValid()) { + // Note that this can fail if the desktop has large fonts on windows. + QTRY_COMPARE(m_toplevel->size(), m_toplevel->sizeHint()); + } + // We are relying on the order here... + for (int pi = 0; pi < sizehinters.count(); ++pi) { + QPoint pt = sizehinters.at(pi)->mapTo(m_toplevel, QPoint(0, 0)); + QCOMPARE(pt, sizeinfos.at(pi).expectedPos); + } + } +} + + +class CustomLayoutStyle : public QWindowsStyle +{ + Q_OBJECT +public: + CustomLayoutStyle() : QWindowsStyle() + { + hspacing = 5; + vspacing = 10; + reimplementSubelementRect = false; + } + + virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, + const QWidget * widget = 0 ) const; + virtual QRect subElementRect(SubElement sr, const QStyleOption *opt, + const QWidget *widget) const; + + int hspacing; + int vspacing; + bool reimplementSubelementRect; + +protected slots: + int layoutSpacingImplementation(QSizePolicy::ControlType control1, + QSizePolicy::ControlType control2, + Qt::Orientation orientation, + const QStyleOption *option = 0, + const QWidget *widget = 0) const; + +}; + +QRect CustomLayoutStyle::subElementRect(SubElement sr, const QStyleOption *opt, + const QWidget *widget) const +{ + QRect rect; + if (reimplementSubelementRect) { + switch (sr) { + case SE_FrameLayoutItem: + rect = opt->rect; + rect.adjust(+4, +9, -4, 0); // The hspacing=5 and vspacing=10, so we keep it safe. + break; + case SE_GroupBoxLayoutItem: + rect = opt->rect.adjusted(0, +10, 0, 0); + break; + default: + break; + } + } + if (rect.isNull()) + rect = QWindowsStyle::subElementRect(sr, opt, widget); + return rect; +} + +#define CT1(c) CT2(c, c) +#define CT2(c1, c2) ((uint)c1 << 16) | (uint)c2 + +int CustomLayoutStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1, + QSizePolicy::ControlType control2, + Qt::Orientation orientation, + const QStyleOption * /*option = 0*/, + const QWidget * /*widget = 0*/) const +{ + if (orientation == Qt::Horizontal) { + switch (CT2(control1, control2)) { + case CT1(QSizePolicy::PushButton): + return 2; + break; + } + return 5; + } else { + switch (CT2(control1, control2)) { + case CT1(QSizePolicy::RadioButton): + return 2; + break; + + } + return 10; + } +} + +int CustomLayoutStyle::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, + const QWidget * widget /*= 0*/ ) const +{ + switch (metric) { + case PM_LayoutLeftMargin: + return 0; + break; + case PM_LayoutTopMargin: + return 3; + break; + case PM_LayoutRightMargin: + return 6; + break; + case PM_LayoutBottomMargin: + return 9; + break; + case PM_LayoutHorizontalSpacing: + return hspacing; + case PM_LayoutVerticalSpacing: + return vspacing; + break; + default: + break; + } + return QWindowsStyle::pixelMetric(metric, option, widget); +} + +void tst_QGridLayout::styleDependentSpacingsAndMargins_data() +{ + // input + QTest::addColumn("columns"); + QTest::addColumn("rows"); + QTest::addColumn("sizehint"); + // expected + QTest::addColumn("expectedpositions"); + + QTest::newRow("1x1 grid") << 1 << 1 << QSize(100, 100) + << (PointList() << QPoint(0, 3) ); + QTest::newRow("2x1 grid") << 2 << 1 << QSize(100, 100) + << (PointList() << QPoint(0, 3) + << QPoint(0+100+5, 3)); + QTest::newRow("3x1 grid") << 3 << 1 << QSize(100, 100) + << (PointList() << QPoint(0, 3) + << QPoint(0+100+5, 3) + << QPoint(0 + 2*105, 3)); + QTest::newRow("1x2 grid") << 1 << 2 << QSize(100, 100) + << (PointList() << QPoint(0, 3) + << QPoint(0, 3+100+10)); + QTest::newRow("1x3 grid") << 1 << 3 << QSize(100, 100) + << (PointList() << QPoint(0, 3) + << QPoint(0, 3+100+10) + << QPoint(0, 3+2*110)); + QTest::newRow("2x2 grid") << 2 << 2 << QSize(100, 100) + << (PointList() << QPoint(0, 3) << QPoint(0+100+5, 3) + << QPoint(0, 3+100+10) << QPoint(0+100+5, 3+100+10)); +} + + +void tst_QGridLayout::styleDependentSpacingsAndMargins() +{ + QFETCH(int, columns); + QFETCH(int, rows); + QFETCH(QSize, sizehint); + QFETCH(PointList, expectedpositions); + + QApplication::setStyle(new CustomLayoutStyle()); + QWidget widget; + QGridLayout layout(&widget); + QList > sizehinters; + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + SizeHinterFrame *sh = new SizeHinterFrame(sizehint); + sh->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + sh->setParent(&widget); + sizehinters.append(sh); + layout.addWidget(sh, i, j); + } + } + layout.setColumnStretch(columns, 1); + layout.setRowStretch(rows, 1); + widget.show(); + widget.adjustSize(); + QApplication::processEvents(); + + for (int pi = 0; pi < expectedpositions.count(); ++pi) { + QCOMPARE(sizehinters.at(pi)->pos(), expectedpositions.at(pi)); + } +} + +void tst_QGridLayout::layoutSpacingImplementation_data() +{ + QTest::addColumn("widget"); + // expected + QTest::addColumn("expectedpositions"); + QTest::addColumn("hSpacing"); + QTest::addColumn("vSpacing"); + QTest::addColumn("customSubElementRect"); + + CustomLayoutStyle *style = new CustomLayoutStyle(); + { + // If the layoutSpacing is negative, the layouting code will call + // layoutSpacingImplementation() + style->hspacing = -1; + style->vspacing = -1; + style->reimplementSubelementRect = false; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QVBoxLayout *layout = new QVBoxLayout(); + QRadioButton *rb1 = new QRadioButton(QLatin1String("Radio 1"), w); + QRadioButton *rb2 = new QRadioButton(QLatin1String("Radio 2"), w); + QRadioButton *rb3 = new QRadioButton(QLatin1String("Radio 3"), w); + layout->addWidget(rb1, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(rb2, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(rb3, 0, Qt::AlignTop | Qt::AlignLeft); + + QPushButton *b1 = new QPushButton(QLatin1String("Push 1"), w); + QPushButton *b2 = new QPushButton(QLatin1String("Push 2"), w); + QPushButton *b3 = new QPushButton(QLatin1String("Push 3"), w); + layout->addWidget(b1, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(b2, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(b3, 0, Qt::AlignTop | Qt::AlignLeft); + + layout->addStretch(1); + w->setLayout(layout); + int rh = rb1->sizeHint().height(); + int ph = b1->sizeHint().height(); + QTest::newRow("1x6, radio + push buttons") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0, 3 + rh + 2) + << QPoint(0, 3 + 2*(rh + 2)) + << QPoint(0, 3 + 2*(rh + 2) + (rh + 10)) + << QPoint(0, 3 + 2*(rh + 2) + (rh + 10 + ph + 10)) + << QPoint(0, 3 + 2*(rh + 2) + rh + 10 + 2*(ph + 10))) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + { + style->hspacing = -1; + style->vspacing = -1; + style->reimplementSubelementRect = false; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QHBoxLayout *layout = new QHBoxLayout(); + QLineEdit *le1 = new QLineEdit(w); + QLineEdit *le2 = new QLineEdit(w); + QLineEdit *le3 = new QLineEdit(w); + layout->addWidget(le1, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(le2, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(le3, 0, Qt::AlignTop | Qt::AlignLeft); + + QPushButton *b1 = new QPushButton(QLatin1String("Push 1"), w); + QPushButton *b2 = new QPushButton(QLatin1String("Push 2"), w); + QPushButton *b3 = new QPushButton(QLatin1String("Push 3"), w); + layout->addWidget(b1, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(b2, 0, Qt::AlignTop | Qt::AlignLeft); + layout->addWidget(b3, 0, Qt::AlignTop | Qt::AlignLeft); + + layout->addStretch(1); + w->setLayout(layout); + int lw = le1->sizeHint().width(); + int pw = b1->sizeHint().width(); + QTest::newRow("6x1, line edit + push buttons") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0 + lw + 5, 3) + << QPoint(0 + 2*(lw + 5), 3) + << QPoint(0 + 3*(lw + 5), 3) + << QPoint(0 + 3*(lw + 5) + 1*(pw + 2), 3) + << QPoint(0 + 3*(lw + 5) + 2*(pw + 2), 3)) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + + { + style->hspacing = 5; + style->vspacing = 10; + style->reimplementSubelementRect = true; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QVBoxLayout *layout = new QVBoxLayout(); + QPushButton *pb1 = new QPushButton(QLatin1String("Push 1"), w); + + QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1"), w); + + QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1"), g1); + QVBoxLayout *g1layout = new QVBoxLayout(); + g1layout->addWidget(rb); + g1->setLayout(g1layout); + + QPushButton *pb3 = new QPushButton(QLatin1String("Push 3"), w); + + layout->addWidget(pb1); + layout->addWidget(g1 ); + layout->addWidget(pb3); + + w->setLayout(layout); + QSize psh = pb1->sizeHint(); + QSize gsh = g1->sizeHint(); + + QTest::newRow("subElementRect1") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0, 3 + psh.height() + 10 - 10) + << QPoint(0, 3 + psh.height() + 10 - 10 + gsh.height() + 10) + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + + { + style->hspacing = 5; + style->vspacing = 10; + style->reimplementSubelementRect = true; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QGridLayout *layout = new QGridLayout(); + QPushButton *pb1 = new QPushButton(QLatin1String("Push 1"), w); + QPushButton *pb2 = new QPushButton(QLatin1String("Push 2"), w); + QPushButton *pb3 = new QPushButton(QLatin1String("Push 3"), w); + QPushButton *pb4 = new QPushButton(QLatin1String("Push 4"), w); + + layout->addWidget(pb1, 0, 0); + layout->addWidget(pb2, 0, 1); + layout->addWidget(pb3, 0, 2); + layout->addWidget(pb4, 1, 0, Qt::AlignTop); + + + QFrame *f1 = new QFrame(w); + f1->setFrameStyle(QFrame::Box | QFrame::Plain); + f1->setMinimumSize(100, 20); + f1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + layout->addWidget(f1, 1, 1, Qt::AlignTop); + + + QPushButton *pb6 = new QPushButton(QLatin1String("Push 6"), w); + QPushButton *pb7 = new QPushButton(QLatin1String("Push 7"), w); + QPushButton *pb8 = new QPushButton(QLatin1String("Push 8"), w); + QPushButton *pb9 = new QPushButton(QLatin1String("Push 9"), w); + layout->addWidget(pb6, 1, 2, Qt::AlignTop); + layout->addWidget(pb7, 2, 0, Qt::AlignTop); + layout->addWidget(pb8, 2, 1, Qt::AlignTop); + layout->addWidget(pb9, 2, 2, Qt::AlignTop); + + layout->setColumnStretch(2, 1); + layout->setRowStretch(2, 1); + w->setLayout(layout); + int c[3]; + c[0] = pb1->sizeHint().width(); + c[1] = f1->minimumSize().width() - 2*4; + c[2] = pb3->sizeHint().width(); + + int r[3]; + r[0] = pb1->sizeHint().height(); + r[1] = pb4->sizeHint().height(); + r[2] = pb7->sizeHint().height(); + + + QTest::newRow("subElementRect2") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0 + c[0] + 5, 3) + << QPoint(0 + c[0] + 5 + c[1] + 5, 3) + + << QPoint(0, 3 + r[0] + 10) + << QPoint(0 + c[0] + 5 - 4, 3 + r[0] + 10 - 9) + << QPoint(0 + c[0] + 5 + c[1] + 5, 3 + r[0] + 10) + + << QPoint(0, 3 + r[0] + 10 + r[1] + 10) + << QPoint(0 + c[0] + 5, 3 + r[0] + 10 + r[1] + 10) + << QPoint(0 + c[0] + 5 + c[1] + 5, 3 + r[0] + 10 + r[1] + 10) + + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + { + style->hspacing = 5; + style->vspacing = 10; + style->reimplementSubelementRect = true; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QVBoxLayout *layout = new QVBoxLayout(); + QPushButton *pb1 = new QPushButton(QLatin1String("Push 1"), w); + + QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1"), w); + + QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1"), g1); + QVBoxLayout *g1layout = new QVBoxLayout(); + g1layout->addWidget(rb); + g1->setLayout(g1layout); + + QPushButton *pb3 = new QPushButton(QLatin1String("Push 3"), w); + + pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); + g1->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); + pb3->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); + layout->addWidget(pb1); + layout->addWidget(g1 ); + layout->addWidget(pb3); + + w->setLayout(layout); + QSize psh = pb1->sizeHint(); + QSize gsh = g1->sizeHint(); + + QTest::newRow("subElementRect1, use widgetRect") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0, 3 + psh.height() + 10) + << QPoint(0, 3 + psh.height() + 10 + gsh.height() + 10) + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + + { + style->hspacing = 5; + style->vspacing = 10; + style->reimplementSubelementRect = true; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QVBoxLayout *layout = new QVBoxLayout(); + QPushButton *pb1 = new QPushButton(QLatin1String("Push 1"), w); + + QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1"), w); + + QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1"), g1); + QVBoxLayout *g1layout = new QVBoxLayout(); + g1layout->addWidget(rb); + g1->setLayout(g1layout); + + QPushButton *pb3 = new QPushButton(QLatin1String("Push 3"), w); + + pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); + g1->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); + pb3->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); + layout->addWidget(pb1); + layout->addWidget(g1 ); + layout->addWidget(pb3); + + w->setLayout(layout); + QSize psh = pb1->sizeHint(); + QSize gsh = g1->sizeHint(); + + QTest::newRow("subElementRect1, use layoutItemRect") + << w << (PointList() + << QPoint(0, 3) + << QPoint(0, 3 + psh.height() + 10 - 10) + << QPoint(0, 3 + psh.height() + 10 - 10 + gsh.height() + 10) + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + + { + /* A 3x4 gridlayout, modified arrowpad example: + * [PB] + * [PB] [PB] + * |PB| + * | | + * | | + * + * Here the bottom pushbutton has a span + */ + style->hspacing = -1; + style->vspacing = -1; + style->reimplementSubelementRect = false; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QGridLayout *layout = new QGridLayout(); + QPushButton *left = new QPushButton(w); + QPushButton *up = new QPushButton(w); + QPushButton *right = new QPushButton(w); + QPushButton *down = new QPushButton(w); + + layout->addWidget(up, 0, 1); + layout->addWidget(left, 1, 0); + layout->addWidget(right, 1, 2); + layout->addWidget(down, 2, 1, 3, 1); + + w->setLayout(layout); + int pw = up->sizeHint().width(); + int ph = up->sizeHint().height(); + QTest::newRow("arrowpad with span") + << w << (PointList() + << QPoint(0 + pw + 5, 3) + << QPoint(0, 3 + ph + 10) + << QPoint(0 + pw + 5 + pw + 5, 3 + ph + 10) + << QPoint(0 + pw + 5, 3 + ph + 10 + ph + 10) + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + + + for (int yoff = 0; yoff < 5; ++yoff) + { + for (int xoff = 0; xoff < 5; ++xoff) { + /* A 3x4 gridlayout, modified arrowpad example: + * [empty cells] + * [PB] + * [PB] [PB] + * [PB] + * + * It has 0-4 empty rows at the top and 0-4 empty columns to the left. + */ + style->hspacing = -1; + style->vspacing = -1; + style->reimplementSubelementRect = false; + QApplication::setStyle(style); + QWidget *w = new QWidget(); + QGridLayout *layout = new QGridLayout(); + QPushButton *left = new QPushButton(w); + QPushButton *up = new QPushButton(w); + QPushButton *right = new QPushButton(w); + QPushButton *down = new QPushButton(w); + + layout->addWidget(up, yoff + 0, xoff + 1); + layout->addWidget(left, yoff + 1, xoff + 0); + layout->addWidget(right, yoff + 1, xoff + 2); + layout->addWidget(down, yoff + 2, xoff + 1, 3, 1); + + w->setLayout(layout); + int pw = up->sizeHint().width(); + int ph = up->sizeHint().height(); + QByteArray testName = QString::fromAscii("arrowpad with %1 empty rows, %2 empty columns").arg(yoff).arg(xoff).toLatin1(); + QTest::newRow(testName.data()) + << w << (PointList() + << QPoint(0 + pw + 5, 3) + << QPoint(0, 3 + ph + 10) + << QPoint(0 + pw + 5 + pw + 5, 3 + ph + 10) + << QPoint(0 + pw + 5, 3 + ph + 10 + ph + 10) + ) + << style->hspacing << style->vspacing << style->reimplementSubelementRect; + } + } + +} + +void tst_QGridLayout::layoutSpacingImplementation() +{ + QFETCH(QWidget *, widget); + QFETCH(PointList, expectedpositions); + QFETCH(int, hSpacing); + QFETCH(int, vSpacing); + QFETCH(bool, customSubElementRect); + + QWidget toplevel; + + CustomLayoutStyle *style = new CustomLayoutStyle(); + style->hspacing = hSpacing; + style->vspacing = vSpacing; + style->reimplementSubelementRect = customSubElementRect; + QApplication::setStyle(style); + widget->setParent(&toplevel); + widget->resize(widget->sizeHint()); + toplevel.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&toplevel); // wait for the show +#endif + + QLayout *layout = widget->layout(); + QVERIFY(layout); + //QTest::qWait(2000); + for (int pi = 0; pi < expectedpositions.count(); ++pi) { + QLayoutItem *item = layout->itemAt(pi); + //qDebug() << item->widget()->pos(); + QCOMPARE(item->widget()->pos(), expectedpositions.at(pi)); + } +} + +void tst_QGridLayout::spacing() +{ + QWidget w; + CustomLayoutStyle *style = new CustomLayoutStyle(); + style->hspacing = 5; + style->vspacing = 10; + w.setStyle(style); + QGridLayout grid(&w); + QCOMPARE(style->hspacing, grid.horizontalSpacing()); + QCOMPARE(style->vspacing, grid.verticalSpacing()); + + QCOMPARE(grid.spacing(), -1); + grid.setVerticalSpacing(5); + QCOMPARE(5, grid.horizontalSpacing()); + QCOMPARE(5, grid.verticalSpacing()); + QCOMPARE(grid.spacing(), 5); + grid.setVerticalSpacing(-1); + QCOMPARE(style->hspacing, grid.horizontalSpacing()); + QCOMPARE(style->vspacing, grid.verticalSpacing()); + + style->hspacing = 5; + style->vspacing = 5; + QCOMPARE(grid.spacing(), 5); + + + grid.setHorizontalSpacing(20); + QCOMPARE(grid.spacing(), -1); + style->vspacing = 20; + QCOMPARE(grid.horizontalSpacing(), 20); + QCOMPARE(grid.verticalSpacing(), 20); + QCOMPARE(grid.spacing(), 20); + grid.setHorizontalSpacing(-1); + QCOMPARE(grid.spacing(), -1); + style->hspacing = 20; + QCOMPARE(grid.spacing(), 20); + + + delete style; +} + +void populate(QGridLayout *layout, int row, int kind) +{ + if (kind == 0) { + QWidget *widget = new QWidget; + widget->setFixedSize(100, 100); + layout->addWidget(widget, row, 0); + } else if (kind == 1) { + layout->addItem(new QSpacerItem(10, 10), row, 0); + } +} + +void tst_QGridLayout::spacerWithSpacing() +{ + // Tests all combinations of widget (w), spacer (s) and no layoutitem (-) + // to see if they are laid out correctly. + // Note that a combination of "s-" or "-s" should only give the height of "s" + const int expectedHeight[] = { + 302,// www + 211,// wws + 201,// ww- + 211,// wsw + 120,// wss + 110,// ws- + 201,// w-w + 110,// w-s + 100,// w-- + 211,// sww + 120,// sws + 110,// sw- + 120,// ssw + 30,// sss + 20,// ss- + 110,// s-w + 20,// s-s + 10,// s-- + 201,// -ww + 110,// -ws + 100,// -w- + 110,// -sw + 20,// -ss + 10,// -s- + 100,// --w + 10,// --s + 000 // --- + }; + int ii = 0; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + QWidget window; + QGridLayout layout(&window); + layout.setSpacing(1); + layout.setMargin(0); + populate(&layout, 0, i); + populate(&layout, 1, j); + populate(&layout, 2, k); + QCOMPARE(window.sizeHint().height(), expectedHeight[ii]); +#if 0 + const char T[] = "ws-"; + qWarning("%c%c%c: %.3d", i[T], j[T], k[T], window.sizeHint().height()); +#endif + ++ii; + } + } + } +} + +void tst_QGridLayout::contentsRect() +{ + QWidget w; + QGridLayout grid; + w.setLayout(&grid); + grid.addWidget(new QPushButton(&w)); + w.show(); +#if defined(Q_WS_X11) + qt_x11_wait_for_window_manager(&w); // wait for the show +#endif + int l, t, r, b; + grid.getContentsMargins(&l, &t, &r, &b); + QRect geom = grid.geometry(); + + QCOMPARE(geom.adjusted(+l, +t, -r, -b), grid.contentsRect()); + +} + +void tst_QGridLayout::distributeMultiCell() +{ + QWidget w; + Qt42Style *style = new Qt42Style(); + style->spacing = 9; + + w.setStyle(style); + QGridLayout grid; + w.setLayout(&grid); + + SizeHinter le1(200, 20, &w); + le1.setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + SizeHinter le2(200, 20, &w); + le2.setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + SizeHinter box(80, 57, &w); + box.setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); + box.setMinimumSize(80, 57); + + grid.addWidget(&le1, 0, 0, 1, 1); + grid.addWidget(&le2, 1, 0, 1, 1); + grid.addWidget(&box, 0, 1, 2, 1); + + QCOMPARE(box.sizeHint().height(), 57); + QCOMPARE(w.sizeHint().height(), 11 + 57 + 11); +} + +QTEST_MAIN(tst_QGridLayout) +#include "tst_qgridlayout.moc" diff --git a/tests/auto/widgets/kernel/qinputcontext/qinputcontext.pro b/tests/auto/widgets/kernel/qinputcontext/qinputcontext.pro new file mode 100644 index 0000000000..cdadb0c5ed --- /dev/null +++ b/tests/auto/widgets/kernel/qinputcontext/qinputcontext.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qinputcontext.cpp + +mac*:CONFIG+=insignificant_test + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/widgets/kernel/qinputcontext/tst_qinputcontext.cpp b/tests/auto/widgets/kernel/qinputcontext/tst_qinputcontext.cpp new file mode 100644 index 0000000000..9b6452851e --- /dev/null +++ b/tests/auto/widgets/kernel/qinputcontext/tst_qinputcontext.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef QT_WEBKIT_LIB +#include +#include +#endif + +class tst_QInputContext : public QObject +{ +Q_OBJECT + +public: + tst_QInputContext() : m_phoneIsQwerty(false) {} + virtual ~tst_QInputContext() {} + +public slots: + void cleanupTestCase() {} + void init() {} + void cleanup() {} +private slots: + void maximumTextLength(); + void filterMouseEvents(); + void requestSoftwareInputPanel(); + void closeSoftwareInputPanel(); + void selections(); + void focusProxy(); + +private: + bool m_phoneIsQwerty; +}; + +void tst_QInputContext::maximumTextLength() +{ + QLineEdit le; + + le.setMaxLength(15); + QVariant variant = le.inputMethodQuery(Qt::ImMaximumTextLength); + QVERIFY(variant.isValid()); + QCOMPARE(variant.toInt(), 15); + + QPlainTextEdit pte; + // For BC/historical reasons, QPlainTextEdit::inputMethodQuery is protected. + variant = static_cast(&pte)->inputMethodQuery(Qt::ImMaximumTextLength); + QVERIFY(!variant.isValid()); +} + +class QFilterInputContext : public QInputContext +{ +public: + QFilterInputContext() {} + ~QFilterInputContext() {} + + QString identifierName() { return QString(); } + QString language() { return QString(); } + + void reset() {} + + bool isComposing() const { return false; } + + bool filterEvent( const QEvent *event ) + { + lastTypes.append(event->type()); + return false; + } + +public: + QList lastTypes; +}; + +void tst_QInputContext::filterMouseEvents() +{ + QLineEdit le; + le.show(); + QApplication::setActiveWindow(&le); + + QFilterInputContext *ic = new QFilterInputContext; + qApp->setInputContext(ic); + QTest::mouseClick(&le, Qt::LeftButton); + + QVERIFY(ic->lastTypes.indexOf(QEvent::MouseButtonRelease) >= 0); +} + +class RequestSoftwareInputPanelStyle : public QWindowsStyle +{ +public: + RequestSoftwareInputPanelStyle() + : m_rsipBehavior(RSIP_OnMouseClickAndAlreadyFocused) + { +#ifdef Q_OS_WINCE + qApp->setAutoSipEnabled(true); +#endif + } + ~RequestSoftwareInputPanelStyle() + { + } + + int styleHint(StyleHint hint, const QStyleOption *opt = 0, + const QWidget *widget = 0, QStyleHintReturn* returnData = 0) const + { + if (hint == SH_RequestSoftwareInputPanel) { + return m_rsipBehavior; + } else { + return QWindowsStyle::styleHint(hint, opt, widget, returnData); + } + } + + RequestSoftwareInputPanel m_rsipBehavior; +}; + +void tst_QInputContext::requestSoftwareInputPanel() +{ + QStyle *oldStyle = qApp->style(); + oldStyle->setParent(this); // Prevent it being deleted. + RequestSoftwareInputPanelStyle *newStyle = new RequestSoftwareInputPanelStyle; + qApp->setStyle(newStyle); + + QWidget w; + QLayout *layout = new QVBoxLayout; + QLineEdit *le1, *le2; + le1 = new QLineEdit; + le2 = new QLineEdit; + layout->addWidget(le1); + layout->addWidget(le2); + w.setLayout(layout); + + QFilterInputContext *ic = new QFilterInputContext; + qApp->setInputContext(ic); + + w.show(); + QApplication::setActiveWindow(&w); + + // Testing single click panel activation. + newStyle->m_rsipBehavior = QStyle::RSIP_OnMouseClick; + QTest::mouseClick(le2, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::RequestSoftwareInputPanel) >= 0); + ic->lastTypes.clear(); + + // Testing double click panel activation. + newStyle->m_rsipBehavior = QStyle::RSIP_OnMouseClickAndAlreadyFocused; + QTest::mouseClick(le1, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::RequestSoftwareInputPanel) < 0); + QTest::mouseClick(le1, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::RequestSoftwareInputPanel) >= 0); + ic->lastTypes.clear(); + + // Testing right mouse button + QTest::mouseClick(le1, Qt::RightButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::RequestSoftwareInputPanel) < 0); + + qApp->setStyle(oldStyle); + oldStyle->setParent(qApp); +} + +void tst_QInputContext::closeSoftwareInputPanel() +{ + QWidget w; + QLayout *layout = new QVBoxLayout; + QLineEdit *le1, *le2; + QRadioButton *rb; + le1 = new QLineEdit; + le2 = new QLineEdit; + rb = new QRadioButton; + layout->addWidget(le1); + layout->addWidget(le2); + layout->addWidget(rb); + w.setLayout(layout); + + QFilterInputContext *ic = new QFilterInputContext; + qApp->setInputContext(ic); + + w.show(); + QApplication::setActiveWindow(&w); + + // Testing that panel doesn't close between two input methods aware widgets. + QTest::mouseClick(le1, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QTest::mouseClick(le2, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::CloseSoftwareInputPanel) < 0); + + // Testing that panel closes when focusing non-aware widget. + QTest::mouseClick(rb, Qt::LeftButton, Qt::NoModifier, QPoint(5, 5)); + QVERIFY(ic->lastTypes.indexOf(QEvent::CloseSoftwareInputPanel) >= 0); +} + +void tst_QInputContext::selections() +{ + QLineEdit le; + le.setText("Test text"); + le.setSelection(2, 2); + QCOMPARE(le.inputMethodQuery(Qt::ImCursorPosition).toInt(), 4); + QCOMPARE(le.inputMethodQuery(Qt::ImAnchorPosition).toInt(), 2); + + QList attributes; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 5, 3, QVariant())); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(&le, &event); + QCOMPARE(le.cursorPosition(), 8); + QCOMPARE(le.selectionStart(), 5); + QCOMPARE(le.inputMethodQuery(Qt::ImCursorPosition).toInt(), 8); + QCOMPARE(le.inputMethodQuery(Qt::ImAnchorPosition).toInt(), 5); +} + +void tst_QInputContext::focusProxy() +{ + QWidget toplevel(0, Qt::X11BypassWindowManagerHint); toplevel.setObjectName("toplevel"); + QWidget w(&toplevel); w.setObjectName("w"); + QWidget proxy(&w); proxy.setObjectName("proxy"); + QWidget proxy2(&w); proxy2.setObjectName("proxy2"); + w.setFocusProxy(&proxy); + w.setAttribute(Qt::WA_InputMethodEnabled); + toplevel.show(); + QApplication::setActiveWindow(&toplevel); + QTest::qWaitForWindowShown(&toplevel); + w.setFocus(); + w.setAttribute(Qt::WA_NativeWindow); // we shouldn't crash! + + proxy.setAttribute(Qt::WA_InputMethodEnabled); + proxy2.setAttribute(Qt::WA_InputMethodEnabled); + + proxy2.setFocus(); + w.setFocus(); + + QInputContext *gic = qApp->inputContext(); + QVERIFY(gic); + QCOMPARE(gic->focusWidget(), &proxy); + + // then change the focus proxy and check that input context is valid + QVERIFY(w.hasFocus()); + QVERIFY(proxy.hasFocus()); + QVERIFY(!proxy2.hasFocus()); + w.setFocusProxy(&proxy2); + QVERIFY(!w.hasFocus()); + QVERIFY(proxy.hasFocus()); + QVERIFY(!proxy2.hasFocus()); + QCOMPARE(gic->focusWidget(), &proxy); +} + +#ifdef QT_WEBKIT_LIB +class AutoWebView : public QWebView +{ + Q_OBJECT + +public: + AutoWebView() + : m_length(0) + , m_mode(QLineEdit::Normal) + { + updatePage(); + } + ~AutoWebView() {} + + void updatePage() + { + // The update might reset the input method parameters. + bool imEnabled = testAttribute(Qt::WA_InputMethodEnabled); + Qt::InputMethodHints hints = inputMethodHints(); + + QString page = "" + "
"; + if (m_mode == QLineEdit::Password) + page = page.arg("password"); + else + page = page.arg("text"); + + if (m_length == 0) + page = page.arg(""); + else + page = page.arg("maxlength=\"" + QString::number(m_length) + "\""); + + setHtml(page); + + setAttribute(Qt::WA_InputMethodEnabled, imEnabled); + setInputMethodHints(hints); + } + void setMaxLength(int length) + { + m_length = length; + updatePage(); + } + void setEchoMode(QLineEdit::EchoMode mode) + { + m_mode = mode; + updatePage(); + } + + int m_length; + QLineEdit::EchoMode m_mode; +}; + +class AutoGraphicsWebView : public QGraphicsView +{ + Q_OBJECT + +public: + AutoGraphicsWebView() + : m_length(0) + , m_mode(QLineEdit::Normal) + { + m_scene.addItem(&m_view); + setScene(&m_scene); + m_view.setFocus(); + updatePage(); + } + ~AutoGraphicsWebView() {} + + void updatePage() + { + // The update might reset the input method parameters. + bool imEnabled = testAttribute(Qt::WA_InputMethodEnabled); + Qt::InputMethodHints hints = inputMethodHints(); + + QString page = "" + "
"; + if (m_mode == QLineEdit::Password) + page = page.arg("password"); + else + page = page.arg("text"); + + if (m_length == 0) + page = page.arg(""); + else + page = page.arg("maxlength=\"" + QString::number(m_length) + "\""); + + m_view.setHtml(page); + + setAttribute(Qt::WA_InputMethodEnabled, imEnabled); + setInputMethodHints(hints); + } + void setMaxLength(int length) + { + m_length = length; + updatePage(); + } + void setEchoMode(QLineEdit::EchoMode mode) + { + m_mode = mode; + updatePage(); + } + + int m_length; + QLineEdit::EchoMode m_mode; + QGraphicsScene m_scene; + QGraphicsWebView m_view; +}; +#endif // QT_WEBKIT_LIB + +QTEST_MAIN(tst_QInputContext) +#include "tst_qinputcontext.moc" diff --git a/tests/auto/widgets/kernel/qlayout/.gitignore b/tests/auto/widgets/kernel/qlayout/.gitignore new file mode 100644 index 0000000000..cc058e7cc3 --- /dev/null +++ b/tests/auto/widgets/kernel/qlayout/.gitignore @@ -0,0 +1 @@ +tst_qlayout diff --git a/tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize b/tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize new file mode 100644 index 0000000000..2d3ba2e72f --- /dev/null +++ b/tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize @@ -0,0 +1,1792 @@ +0 0 0 0 0 0 0 +1 0 1 0 0 0 524287 +2 0 2 0 0 0 524287 +3 0 4 0 0 0 524287 +4 0 0 0 10 0 0 +5 0 1 0 10 0 524287 +6 0 2 0 10 0 524287 +7 0 4 0 10 0 524287 +8 0 0 0 20 0 0 +9 0 1 0 20 0 524287 +10 0 2 0 20 0 524287 +11 0 4 0 20 0 524287 +12 0 0 0 16777215 0 0 +13 0 1 0 16777215 0 524287 +14 0 2 0 16777215 0 524287 +15 0 4 0 16777215 0 524287 +16 0 0 0 0 10 10 +17 0 1 0 0 10 524287 +18 0 2 0 0 10 524287 +19 0 4 0 0 10 524287 +20 0 0 0 10 10 10 +21 0 1 0 10 10 524287 +22 0 2 0 10 10 524287 +23 0 4 0 10 10 524287 +24 0 0 0 20 10 10 +25 0 1 0 20 10 524287 +26 0 2 0 20 10 524287 +27 0 4 0 20 10 524287 +28 0 0 0 16777215 10 10 +29 0 1 0 16777215 10 524287 +30 0 2 0 16777215 10 524287 +31 0 4 0 16777215 10 524287 +32 0 0 0 0 20 20 +33 0 1 0 0 20 524287 +34 0 2 0 0 20 524287 +35 0 4 0 0 20 524287 +36 0 0 0 10 20 20 +37 0 1 0 10 20 524287 +38 0 2 0 10 20 524287 +39 0 4 0 10 20 524287 +40 0 0 0 20 20 20 +41 0 1 0 20 20 524287 +42 0 2 0 20 20 524287 +43 0 4 0 20 20 524287 +44 0 0 0 16777215 20 20 +45 0 1 0 16777215 20 524287 +46 0 2 0 16777215 20 524287 +47 0 4 0 16777215 20 524287 +48 0 0 0 0 16777215 0 +49 0 1 0 0 16777215 524287 +50 0 2 0 0 16777215 524287 +51 0 4 0 0 16777215 524287 +52 0 0 0 10 16777215 10 +53 0 1 0 10 16777215 524287 +54 0 2 0 10 16777215 524287 +55 0 4 0 10 16777215 524287 +56 0 0 0 20 16777215 20 +57 0 1 0 20 16777215 524287 +58 0 2 0 20 16777215 524287 +59 0 4 0 20 16777215 524287 +60 0 0 0 16777215 16777215 16777215 +61 0 1 0 16777215 16777215 524287 +62 0 2 0 16777215 16777215 524287 +63 0 4 0 16777215 16777215 524287 +64 0 0 10 0 0 0 +65 0 1 10 0 0 524287 +66 0 2 10 0 0 524287 +67 0 4 10 0 0 524287 +68 0 0 10 10 0 0 +69 0 1 10 10 0 524287 +70 0 2 10 10 0 524287 +71 0 4 10 10 0 524287 +72 0 0 10 20 0 0 +73 0 1 10 20 0 524287 +74 0 2 10 20 0 524287 +75 0 4 10 20 0 524287 +76 0 0 10 16777215 0 0 +77 0 1 10 16777215 0 524287 +78 0 2 10 16777215 0 524287 +79 0 4 10 16777215 0 524287 +80 0 0 10 0 10 10 +81 0 1 10 0 10 524287 +82 0 2 10 0 10 524287 +83 0 4 10 0 10 524287 +84 0 0 10 10 10 10 +85 0 1 10 10 10 524287 +86 0 2 10 10 10 524287 +87 0 4 10 10 10 524287 +88 0 0 10 20 10 10 +89 0 1 10 20 10 524287 +90 0 2 10 20 10 524287 +91 0 4 10 20 10 524287 +92 0 0 10 16777215 10 10 +93 0 1 10 16777215 10 524287 +94 0 2 10 16777215 10 524287 +95 0 4 10 16777215 10 524287 +96 0 0 10 0 20 20 +97 0 1 10 0 20 524287 +98 0 2 10 0 20 524287 +99 0 4 10 0 20 524287 +100 0 0 10 10 20 20 +101 0 1 10 10 20 524287 +102 0 2 10 10 20 524287 +103 0 4 10 10 20 524287 +104 0 0 10 20 20 20 +105 0 1 10 20 20 524287 +106 0 2 10 20 20 524287 +107 0 4 10 20 20 524287 +108 0 0 10 16777215 20 20 +109 0 1 10 16777215 20 524287 +110 0 2 10 16777215 20 524287 +111 0 4 10 16777215 20 524287 +112 0 0 10 0 16777215 10 +113 0 1 10 0 16777215 524287 +114 0 2 10 0 16777215 524287 +115 0 4 10 0 16777215 524287 +116 0 0 10 10 16777215 10 +117 0 1 10 10 16777215 524287 +118 0 2 10 10 16777215 524287 +119 0 4 10 10 16777215 524287 +120 0 0 10 20 16777215 20 +121 0 1 10 20 16777215 524287 +122 0 2 10 20 16777215 524287 +123 0 4 10 20 16777215 524287 +124 0 0 10 16777215 16777215 16777215 +125 0 1 10 16777215 16777215 524287 +126 0 2 10 16777215 16777215 524287 +127 0 4 10 16777215 16777215 524287 +128 0 0 20 0 0 0 +129 0 1 20 0 0 524287 +130 0 2 20 0 0 524287 +131 0 4 20 0 0 524287 +132 0 0 20 10 0 0 +133 0 1 20 10 0 524287 +134 0 2 20 10 0 524287 +135 0 4 20 10 0 524287 +136 0 0 20 20 0 0 +137 0 1 20 20 0 524287 +138 0 2 20 20 0 524287 +139 0 4 20 20 0 524287 +140 0 0 20 16777215 0 0 +141 0 1 20 16777215 0 524287 +142 0 2 20 16777215 0 524287 +143 0 4 20 16777215 0 524287 +144 0 0 20 0 10 10 +145 0 1 20 0 10 524287 +146 0 2 20 0 10 524287 +147 0 4 20 0 10 524287 +148 0 0 20 10 10 10 +149 0 1 20 10 10 524287 +150 0 2 20 10 10 524287 +151 0 4 20 10 10 524287 +152 0 0 20 20 10 10 +153 0 1 20 20 10 524287 +154 0 2 20 20 10 524287 +155 0 4 20 20 10 524287 +156 0 0 20 16777215 10 10 +157 0 1 20 16777215 10 524287 +158 0 2 20 16777215 10 524287 +159 0 4 20 16777215 10 524287 +160 0 0 20 0 20 20 +161 0 1 20 0 20 524287 +162 0 2 20 0 20 524287 +163 0 4 20 0 20 524287 +164 0 0 20 10 20 20 +165 0 1 20 10 20 524287 +166 0 2 20 10 20 524287 +167 0 4 20 10 20 524287 +168 0 0 20 20 20 20 +169 0 1 20 20 20 524287 +170 0 2 20 20 20 524287 +171 0 4 20 20 20 524287 +172 0 0 20 16777215 20 20 +173 0 1 20 16777215 20 524287 +174 0 2 20 16777215 20 524287 +175 0 4 20 16777215 20 524287 +176 0 0 20 0 16777215 20 +177 0 1 20 0 16777215 524287 +178 0 2 20 0 16777215 524287 +179 0 4 20 0 16777215 524287 +180 0 0 20 10 16777215 20 +181 0 1 20 10 16777215 524287 +182 0 2 20 10 16777215 524287 +183 0 4 20 10 16777215 524287 +184 0 0 20 20 16777215 20 +185 0 1 20 20 16777215 524287 +186 0 2 20 20 16777215 524287 +187 0 4 20 20 16777215 524287 +188 0 0 20 16777215 16777215 16777215 +189 0 1 20 16777215 16777215 524287 +190 0 2 20 16777215 16777215 524287 +191 0 4 20 16777215 16777215 524287 +192 0 0 16777215 0 0 0 +193 0 1 16777215 0 0 524287 +194 0 2 16777215 0 0 524287 +195 0 4 16777215 0 0 524287 +196 0 0 16777215 10 0 0 +197 0 1 16777215 10 0 524287 +198 0 2 16777215 10 0 524287 +199 0 4 16777215 10 0 524287 +200 0 0 16777215 20 0 0 +201 0 1 16777215 20 0 524287 +202 0 2 16777215 20 0 524287 +203 0 4 16777215 20 0 524287 +204 0 0 16777215 16777215 0 0 +205 0 1 16777215 16777215 0 524287 +206 0 2 16777215 16777215 0 524287 +207 0 4 16777215 16777215 0 524287 +208 0 0 16777215 0 10 10 +209 0 1 16777215 0 10 524287 +210 0 2 16777215 0 10 524287 +211 0 4 16777215 0 10 524287 +212 0 0 16777215 10 10 10 +213 0 1 16777215 10 10 524287 +214 0 2 16777215 10 10 524287 +215 0 4 16777215 10 10 524287 +216 0 0 16777215 20 10 10 +217 0 1 16777215 20 10 524287 +218 0 2 16777215 20 10 524287 +219 0 4 16777215 20 10 524287 +220 0 0 16777215 16777215 10 10 +221 0 1 16777215 16777215 10 524287 +222 0 2 16777215 16777215 10 524287 +223 0 4 16777215 16777215 10 524287 +224 0 0 16777215 0 20 20 +225 0 1 16777215 0 20 524287 +226 0 2 16777215 0 20 524287 +227 0 4 16777215 0 20 524287 +228 0 0 16777215 10 20 20 +229 0 1 16777215 10 20 524287 +230 0 2 16777215 10 20 524287 +231 0 4 16777215 10 20 524287 +232 0 0 16777215 20 20 20 +233 0 1 16777215 20 20 524287 +234 0 2 16777215 20 20 524287 +235 0 4 16777215 20 20 524287 +236 0 0 16777215 16777215 20 20 +237 0 1 16777215 16777215 20 524287 +238 0 2 16777215 16777215 20 524287 +239 0 4 16777215 16777215 20 524287 +240 0 0 16777215 0 16777215 16777215 +241 0 1 16777215 0 16777215 524287 +242 0 2 16777215 0 16777215 524287 +243 0 4 16777215 0 16777215 524287 +244 0 0 16777215 10 16777215 16777215 +245 0 1 16777215 10 16777215 524287 +246 0 2 16777215 10 16777215 524287 +247 0 4 16777215 10 16777215 524287 +248 0 0 16777215 20 16777215 16777215 +249 0 1 16777215 20 16777215 524287 +250 0 2 16777215 20 16777215 524287 +251 0 4 16777215 20 16777215 524287 +252 0 0 16777215 16777215 16777215 16777215 +253 0 1 16777215 16777215 16777215 524287 +254 0 2 16777215 16777215 16777215 524287 +255 0 4 16777215 16777215 16777215 524287 +256 1 0 0 0 0 0 +257 1 1 0 0 0 524287 +258 1 2 0 0 0 524287 +259 1 4 0 0 0 524287 +260 1 0 0 10 0 0 +261 1 1 0 10 0 524287 +262 1 2 0 10 0 524287 +263 1 4 0 10 0 524287 +264 1 0 0 20 0 0 +265 1 1 0 20 0 524287 +266 1 2 0 20 0 524287 +267 1 4 0 20 0 524287 +268 1 0 0 16777215 0 0 +269 1 1 0 16777215 0 524287 +270 1 2 0 16777215 0 524287 +271 1 4 0 16777215 0 524287 +272 1 0 0 0 10 10 +273 1 1 0 0 10 524287 +274 1 2 0 0 10 524287 +275 1 4 0 0 10 524287 +276 1 0 0 10 10 10 +277 1 1 0 10 10 524287 +278 1 2 0 10 10 524287 +279 1 4 0 10 10 524287 +280 1 0 0 20 10 10 +281 1 1 0 20 10 524287 +282 1 2 0 20 10 524287 +283 1 4 0 20 10 524287 +284 1 0 0 16777215 10 10 +285 1 1 0 16777215 10 524287 +286 1 2 0 16777215 10 524287 +287 1 4 0 16777215 10 524287 +288 1 0 0 0 20 20 +289 1 1 0 0 20 524287 +290 1 2 0 0 20 524287 +291 1 4 0 0 20 524287 +292 1 0 0 10 20 20 +293 1 1 0 10 20 524287 +294 1 2 0 10 20 524287 +295 1 4 0 10 20 524287 +296 1 0 0 20 20 20 +297 1 1 0 20 20 524287 +298 1 2 0 20 20 524287 +299 1 4 0 20 20 524287 +300 1 0 0 16777215 20 20 +301 1 1 0 16777215 20 524287 +302 1 2 0 16777215 20 524287 +303 1 4 0 16777215 20 524287 +304 1 0 0 0 16777215 16777215 +305 1 1 0 0 16777215 524287 +306 1 2 0 0 16777215 524287 +307 1 4 0 0 16777215 524287 +308 1 0 0 10 16777215 16777215 +309 1 1 0 10 16777215 524287 +310 1 2 0 10 16777215 524287 +311 1 4 0 10 16777215 524287 +312 1 0 0 20 16777215 16777215 +313 1 1 0 20 16777215 524287 +314 1 2 0 20 16777215 524287 +315 1 4 0 20 16777215 524287 +316 1 0 0 16777215 16777215 16777215 +317 1 1 0 16777215 16777215 524287 +318 1 2 0 16777215 16777215 524287 +319 1 4 0 16777215 16777215 524287 +320 1 0 10 0 0 0 +321 1 1 10 0 0 524287 +322 1 2 10 0 0 524287 +323 1 4 10 0 0 524287 +324 1 0 10 10 0 0 +325 1 1 10 10 0 524287 +326 1 2 10 10 0 524287 +327 1 4 10 10 0 524287 +328 1 0 10 20 0 0 +329 1 1 10 20 0 524287 +330 1 2 10 20 0 524287 +331 1 4 10 20 0 524287 +332 1 0 10 16777215 0 0 +333 1 1 10 16777215 0 524287 +334 1 2 10 16777215 0 524287 +335 1 4 10 16777215 0 524287 +336 1 0 10 0 10 10 +337 1 1 10 0 10 524287 +338 1 2 10 0 10 524287 +339 1 4 10 0 10 524287 +340 1 0 10 10 10 10 +341 1 1 10 10 10 524287 +342 1 2 10 10 10 524287 +343 1 4 10 10 10 524287 +344 1 0 10 20 10 10 +345 1 1 10 20 10 524287 +346 1 2 10 20 10 524287 +347 1 4 10 20 10 524287 +348 1 0 10 16777215 10 10 +349 1 1 10 16777215 10 524287 +350 1 2 10 16777215 10 524287 +351 1 4 10 16777215 10 524287 +352 1 0 10 0 20 20 +353 1 1 10 0 20 524287 +354 1 2 10 0 20 524287 +355 1 4 10 0 20 524287 +356 1 0 10 10 20 20 +357 1 1 10 10 20 524287 +358 1 2 10 10 20 524287 +359 1 4 10 10 20 524287 +360 1 0 10 20 20 20 +361 1 1 10 20 20 524287 +362 1 2 10 20 20 524287 +363 1 4 10 20 20 524287 +364 1 0 10 16777215 20 20 +365 1 1 10 16777215 20 524287 +366 1 2 10 16777215 20 524287 +367 1 4 10 16777215 20 524287 +368 1 0 10 0 16777215 16777215 +369 1 1 10 0 16777215 524287 +370 1 2 10 0 16777215 524287 +371 1 4 10 0 16777215 524287 +372 1 0 10 10 16777215 16777215 +373 1 1 10 10 16777215 524287 +374 1 2 10 10 16777215 524287 +375 1 4 10 10 16777215 524287 +376 1 0 10 20 16777215 16777215 +377 1 1 10 20 16777215 524287 +378 1 2 10 20 16777215 524287 +379 1 4 10 20 16777215 524287 +380 1 0 10 16777215 16777215 16777215 +381 1 1 10 16777215 16777215 524287 +382 1 2 10 16777215 16777215 524287 +383 1 4 10 16777215 16777215 524287 +384 1 0 20 0 0 0 +385 1 1 20 0 0 524287 +386 1 2 20 0 0 524287 +387 1 4 20 0 0 524287 +388 1 0 20 10 0 0 +389 1 1 20 10 0 524287 +390 1 2 20 10 0 524287 +391 1 4 20 10 0 524287 +392 1 0 20 20 0 0 +393 1 1 20 20 0 524287 +394 1 2 20 20 0 524287 +395 1 4 20 20 0 524287 +396 1 0 20 16777215 0 0 +397 1 1 20 16777215 0 524287 +398 1 2 20 16777215 0 524287 +399 1 4 20 16777215 0 524287 +400 1 0 20 0 10 10 +401 1 1 20 0 10 524287 +402 1 2 20 0 10 524287 +403 1 4 20 0 10 524287 +404 1 0 20 10 10 10 +405 1 1 20 10 10 524287 +406 1 2 20 10 10 524287 +407 1 4 20 10 10 524287 +408 1 0 20 20 10 10 +409 1 1 20 20 10 524287 +410 1 2 20 20 10 524287 +411 1 4 20 20 10 524287 +412 1 0 20 16777215 10 10 +413 1 1 20 16777215 10 524287 +414 1 2 20 16777215 10 524287 +415 1 4 20 16777215 10 524287 +416 1 0 20 0 20 20 +417 1 1 20 0 20 524287 +418 1 2 20 0 20 524287 +419 1 4 20 0 20 524287 +420 1 0 20 10 20 20 +421 1 1 20 10 20 524287 +422 1 2 20 10 20 524287 +423 1 4 20 10 20 524287 +424 1 0 20 20 20 20 +425 1 1 20 20 20 524287 +426 1 2 20 20 20 524287 +427 1 4 20 20 20 524287 +428 1 0 20 16777215 20 20 +429 1 1 20 16777215 20 524287 +430 1 2 20 16777215 20 524287 +431 1 4 20 16777215 20 524287 +432 1 0 20 0 16777215 16777215 +433 1 1 20 0 16777215 524287 +434 1 2 20 0 16777215 524287 +435 1 4 20 0 16777215 524287 +436 1 0 20 10 16777215 16777215 +437 1 1 20 10 16777215 524287 +438 1 2 20 10 16777215 524287 +439 1 4 20 10 16777215 524287 +440 1 0 20 20 16777215 16777215 +441 1 1 20 20 16777215 524287 +442 1 2 20 20 16777215 524287 +443 1 4 20 20 16777215 524287 +444 1 0 20 16777215 16777215 16777215 +445 1 1 20 16777215 16777215 524287 +446 1 2 20 16777215 16777215 524287 +447 1 4 20 16777215 16777215 524287 +448 1 0 16777215 0 0 0 +449 1 1 16777215 0 0 524287 +450 1 2 16777215 0 0 524287 +451 1 4 16777215 0 0 524287 +452 1 0 16777215 10 0 0 +453 1 1 16777215 10 0 524287 +454 1 2 16777215 10 0 524287 +455 1 4 16777215 10 0 524287 +456 1 0 16777215 20 0 0 +457 1 1 16777215 20 0 524287 +458 1 2 16777215 20 0 524287 +459 1 4 16777215 20 0 524287 +460 1 0 16777215 16777215 0 0 +461 1 1 16777215 16777215 0 524287 +462 1 2 16777215 16777215 0 524287 +463 1 4 16777215 16777215 0 524287 +464 1 0 16777215 0 10 10 +465 1 1 16777215 0 10 524287 +466 1 2 16777215 0 10 524287 +467 1 4 16777215 0 10 524287 +468 1 0 16777215 10 10 10 +469 1 1 16777215 10 10 524287 +470 1 2 16777215 10 10 524287 +471 1 4 16777215 10 10 524287 +472 1 0 16777215 20 10 10 +473 1 1 16777215 20 10 524287 +474 1 2 16777215 20 10 524287 +475 1 4 16777215 20 10 524287 +476 1 0 16777215 16777215 10 10 +477 1 1 16777215 16777215 10 524287 +478 1 2 16777215 16777215 10 524287 +479 1 4 16777215 16777215 10 524287 +480 1 0 16777215 0 20 20 +481 1 1 16777215 0 20 524287 +482 1 2 16777215 0 20 524287 +483 1 4 16777215 0 20 524287 +484 1 0 16777215 10 20 20 +485 1 1 16777215 10 20 524287 +486 1 2 16777215 10 20 524287 +487 1 4 16777215 10 20 524287 +488 1 0 16777215 20 20 20 +489 1 1 16777215 20 20 524287 +490 1 2 16777215 20 20 524287 +491 1 4 16777215 20 20 524287 +492 1 0 16777215 16777215 20 20 +493 1 1 16777215 16777215 20 524287 +494 1 2 16777215 16777215 20 524287 +495 1 4 16777215 16777215 20 524287 +496 1 0 16777215 0 16777215 16777215 +497 1 1 16777215 0 16777215 524287 +498 1 2 16777215 0 16777215 524287 +499 1 4 16777215 0 16777215 524287 +500 1 0 16777215 10 16777215 16777215 +501 1 1 16777215 10 16777215 524287 +502 1 2 16777215 10 16777215 524287 +503 1 4 16777215 10 16777215 524287 +504 1 0 16777215 20 16777215 16777215 +505 1 1 16777215 20 16777215 524287 +506 1 2 16777215 20 16777215 524287 +507 1 4 16777215 20 16777215 524287 +508 1 0 16777215 16777215 16777215 16777215 +509 1 1 16777215 16777215 16777215 524287 +510 1 2 16777215 16777215 16777215 524287 +511 1 4 16777215 16777215 16777215 524287 +512 4 0 0 0 0 0 +513 4 1 0 0 0 524287 +514 4 2 0 0 0 524287 +515 4 4 0 0 0 524287 +516 4 0 0 10 0 0 +517 4 1 0 10 0 524287 +518 4 2 0 10 0 524287 +519 4 4 0 10 0 524287 +520 4 0 0 20 0 0 +521 4 1 0 20 0 524287 +522 4 2 0 20 0 524287 +523 4 4 0 20 0 524287 +524 4 0 0 16777215 0 0 +525 4 1 0 16777215 0 524287 +526 4 2 0 16777215 0 524287 +527 4 4 0 16777215 0 524287 +528 4 0 0 0 10 10 +529 4 1 0 0 10 524287 +530 4 2 0 0 10 524287 +531 4 4 0 0 10 524287 +532 4 0 0 10 10 10 +533 4 1 0 10 10 524287 +534 4 2 0 10 10 524287 +535 4 4 0 10 10 524287 +536 4 0 0 20 10 10 +537 4 1 0 20 10 524287 +538 4 2 0 20 10 524287 +539 4 4 0 20 10 524287 +540 4 0 0 16777215 10 10 +541 4 1 0 16777215 10 524287 +542 4 2 0 16777215 10 524287 +543 4 4 0 16777215 10 524287 +544 4 0 0 0 20 20 +545 4 1 0 0 20 524287 +546 4 2 0 0 20 524287 +547 4 4 0 0 20 524287 +548 4 0 0 10 20 20 +549 4 1 0 10 20 524287 +550 4 2 0 10 20 524287 +551 4 4 0 10 20 524287 +552 4 0 0 20 20 20 +553 4 1 0 20 20 524287 +554 4 2 0 20 20 524287 +555 4 4 0 20 20 524287 +556 4 0 0 16777215 20 20 +557 4 1 0 16777215 20 524287 +558 4 2 0 16777215 20 524287 +559 4 4 0 16777215 20 524287 +560 4 0 0 0 16777215 0 +561 4 1 0 0 16777215 524287 +562 4 2 0 0 16777215 524287 +563 4 4 0 0 16777215 524287 +564 4 0 0 10 16777215 10 +565 4 1 0 10 16777215 524287 +566 4 2 0 10 16777215 524287 +567 4 4 0 10 16777215 524287 +568 4 0 0 20 16777215 20 +569 4 1 0 20 16777215 524287 +570 4 2 0 20 16777215 524287 +571 4 4 0 20 16777215 524287 +572 4 0 0 16777215 16777215 16777215 +573 4 1 0 16777215 16777215 524287 +574 4 2 0 16777215 16777215 524287 +575 4 4 0 16777215 16777215 524287 +576 4 0 10 0 0 0 +577 4 1 10 0 0 524287 +578 4 2 10 0 0 524287 +579 4 4 10 0 0 524287 +580 4 0 10 10 0 0 +581 4 1 10 10 0 524287 +582 4 2 10 10 0 524287 +583 4 4 10 10 0 524287 +584 4 0 10 20 0 0 +585 4 1 10 20 0 524287 +586 4 2 10 20 0 524287 +587 4 4 10 20 0 524287 +588 4 0 10 16777215 0 0 +589 4 1 10 16777215 0 524287 +590 4 2 10 16777215 0 524287 +591 4 4 10 16777215 0 524287 +592 4 0 10 0 10 10 +593 4 1 10 0 10 524287 +594 4 2 10 0 10 524287 +595 4 4 10 0 10 524287 +596 4 0 10 10 10 10 +597 4 1 10 10 10 524287 +598 4 2 10 10 10 524287 +599 4 4 10 10 10 524287 +600 4 0 10 20 10 10 +601 4 1 10 20 10 524287 +602 4 2 10 20 10 524287 +603 4 4 10 20 10 524287 +604 4 0 10 16777215 10 10 +605 4 1 10 16777215 10 524287 +606 4 2 10 16777215 10 524287 +607 4 4 10 16777215 10 524287 +608 4 0 10 0 20 20 +609 4 1 10 0 20 524287 +610 4 2 10 0 20 524287 +611 4 4 10 0 20 524287 +612 4 0 10 10 20 20 +613 4 1 10 10 20 524287 +614 4 2 10 10 20 524287 +615 4 4 10 10 20 524287 +616 4 0 10 20 20 20 +617 4 1 10 20 20 524287 +618 4 2 10 20 20 524287 +619 4 4 10 20 20 524287 +620 4 0 10 16777215 20 20 +621 4 1 10 16777215 20 524287 +622 4 2 10 16777215 20 524287 +623 4 4 10 16777215 20 524287 +624 4 0 10 0 16777215 10 +625 4 1 10 0 16777215 524287 +626 4 2 10 0 16777215 524287 +627 4 4 10 0 16777215 524287 +628 4 0 10 10 16777215 10 +629 4 1 10 10 16777215 524287 +630 4 2 10 10 16777215 524287 +631 4 4 10 10 16777215 524287 +632 4 0 10 20 16777215 20 +633 4 1 10 20 16777215 524287 +634 4 2 10 20 16777215 524287 +635 4 4 10 20 16777215 524287 +636 4 0 10 16777215 16777215 16777215 +637 4 1 10 16777215 16777215 524287 +638 4 2 10 16777215 16777215 524287 +639 4 4 10 16777215 16777215 524287 +640 4 0 20 0 0 0 +641 4 1 20 0 0 524287 +642 4 2 20 0 0 524287 +643 4 4 20 0 0 524287 +644 4 0 20 10 0 0 +645 4 1 20 10 0 524287 +646 4 2 20 10 0 524287 +647 4 4 20 10 0 524287 +648 4 0 20 20 0 0 +649 4 1 20 20 0 524287 +650 4 2 20 20 0 524287 +651 4 4 20 20 0 524287 +652 4 0 20 16777215 0 0 +653 4 1 20 16777215 0 524287 +654 4 2 20 16777215 0 524287 +655 4 4 20 16777215 0 524287 +656 4 0 20 0 10 10 +657 4 1 20 0 10 524287 +658 4 2 20 0 10 524287 +659 4 4 20 0 10 524287 +660 4 0 20 10 10 10 +661 4 1 20 10 10 524287 +662 4 2 20 10 10 524287 +663 4 4 20 10 10 524287 +664 4 0 20 20 10 10 +665 4 1 20 20 10 524287 +666 4 2 20 20 10 524287 +667 4 4 20 20 10 524287 +668 4 0 20 16777215 10 10 +669 4 1 20 16777215 10 524287 +670 4 2 20 16777215 10 524287 +671 4 4 20 16777215 10 524287 +672 4 0 20 0 20 20 +673 4 1 20 0 20 524287 +674 4 2 20 0 20 524287 +675 4 4 20 0 20 524287 +676 4 0 20 10 20 20 +677 4 1 20 10 20 524287 +678 4 2 20 10 20 524287 +679 4 4 20 10 20 524287 +680 4 0 20 20 20 20 +681 4 1 20 20 20 524287 +682 4 2 20 20 20 524287 +683 4 4 20 20 20 524287 +684 4 0 20 16777215 20 20 +685 4 1 20 16777215 20 524287 +686 4 2 20 16777215 20 524287 +687 4 4 20 16777215 20 524287 +688 4 0 20 0 16777215 20 +689 4 1 20 0 16777215 524287 +690 4 2 20 0 16777215 524287 +691 4 4 20 0 16777215 524287 +692 4 0 20 10 16777215 20 +693 4 1 20 10 16777215 524287 +694 4 2 20 10 16777215 524287 +695 4 4 20 10 16777215 524287 +696 4 0 20 20 16777215 20 +697 4 1 20 20 16777215 524287 +698 4 2 20 20 16777215 524287 +699 4 4 20 20 16777215 524287 +700 4 0 20 16777215 16777215 16777215 +701 4 1 20 16777215 16777215 524287 +702 4 2 20 16777215 16777215 524287 +703 4 4 20 16777215 16777215 524287 +704 4 0 16777215 0 0 0 +705 4 1 16777215 0 0 524287 +706 4 2 16777215 0 0 524287 +707 4 4 16777215 0 0 524287 +708 4 0 16777215 10 0 0 +709 4 1 16777215 10 0 524287 +710 4 2 16777215 10 0 524287 +711 4 4 16777215 10 0 524287 +712 4 0 16777215 20 0 0 +713 4 1 16777215 20 0 524287 +714 4 2 16777215 20 0 524287 +715 4 4 16777215 20 0 524287 +716 4 0 16777215 16777215 0 0 +717 4 1 16777215 16777215 0 524287 +718 4 2 16777215 16777215 0 524287 +719 4 4 16777215 16777215 0 524287 +720 4 0 16777215 0 10 10 +721 4 1 16777215 0 10 524287 +722 4 2 16777215 0 10 524287 +723 4 4 16777215 0 10 524287 +724 4 0 16777215 10 10 10 +725 4 1 16777215 10 10 524287 +726 4 2 16777215 10 10 524287 +727 4 4 16777215 10 10 524287 +728 4 0 16777215 20 10 10 +729 4 1 16777215 20 10 524287 +730 4 2 16777215 20 10 524287 +731 4 4 16777215 20 10 524287 +732 4 0 16777215 16777215 10 10 +733 4 1 16777215 16777215 10 524287 +734 4 2 16777215 16777215 10 524287 +735 4 4 16777215 16777215 10 524287 +736 4 0 16777215 0 20 20 +737 4 1 16777215 0 20 524287 +738 4 2 16777215 0 20 524287 +739 4 4 16777215 0 20 524287 +740 4 0 16777215 10 20 20 +741 4 1 16777215 10 20 524287 +742 4 2 16777215 10 20 524287 +743 4 4 16777215 10 20 524287 +744 4 0 16777215 20 20 20 +745 4 1 16777215 20 20 524287 +746 4 2 16777215 20 20 524287 +747 4 4 16777215 20 20 524287 +748 4 0 16777215 16777215 20 20 +749 4 1 16777215 16777215 20 524287 +750 4 2 16777215 16777215 20 524287 +751 4 4 16777215 16777215 20 524287 +752 4 0 16777215 0 16777215 16777215 +753 4 1 16777215 0 16777215 524287 +754 4 2 16777215 0 16777215 524287 +755 4 4 16777215 0 16777215 524287 +756 4 0 16777215 10 16777215 16777215 +757 4 1 16777215 10 16777215 524287 +758 4 2 16777215 10 16777215 524287 +759 4 4 16777215 10 16777215 524287 +760 4 0 16777215 20 16777215 16777215 +761 4 1 16777215 20 16777215 524287 +762 4 2 16777215 20 16777215 524287 +763 4 4 16777215 20 16777215 524287 +764 4 0 16777215 16777215 16777215 16777215 +765 4 1 16777215 16777215 16777215 524287 +766 4 2 16777215 16777215 16777215 524287 +767 4 4 16777215 16777215 16777215 524287 +768 5 0 0 0 0 0 +769 5 1 0 0 0 524287 +770 5 2 0 0 0 524287 +771 5 4 0 0 0 524287 +772 5 0 0 10 0 0 +773 5 1 0 10 0 524287 +774 5 2 0 10 0 524287 +775 5 4 0 10 0 524287 +776 5 0 0 20 0 0 +777 5 1 0 20 0 524287 +778 5 2 0 20 0 524287 +779 5 4 0 20 0 524287 +780 5 0 0 16777215 0 0 +781 5 1 0 16777215 0 524287 +782 5 2 0 16777215 0 524287 +783 5 4 0 16777215 0 524287 +784 5 0 0 0 10 10 +785 5 1 0 0 10 524287 +786 5 2 0 0 10 524287 +787 5 4 0 0 10 524287 +788 5 0 0 10 10 10 +789 5 1 0 10 10 524287 +790 5 2 0 10 10 524287 +791 5 4 0 10 10 524287 +792 5 0 0 20 10 10 +793 5 1 0 20 10 524287 +794 5 2 0 20 10 524287 +795 5 4 0 20 10 524287 +796 5 0 0 16777215 10 10 +797 5 1 0 16777215 10 524287 +798 5 2 0 16777215 10 524287 +799 5 4 0 16777215 10 524287 +800 5 0 0 0 20 20 +801 5 1 0 0 20 524287 +802 5 2 0 0 20 524287 +803 5 4 0 0 20 524287 +804 5 0 0 10 20 20 +805 5 1 0 10 20 524287 +806 5 2 0 10 20 524287 +807 5 4 0 10 20 524287 +808 5 0 0 20 20 20 +809 5 1 0 20 20 524287 +810 5 2 0 20 20 524287 +811 5 4 0 20 20 524287 +812 5 0 0 16777215 20 20 +813 5 1 0 16777215 20 524287 +814 5 2 0 16777215 20 524287 +815 5 4 0 16777215 20 524287 +816 5 0 0 0 16777215 16777215 +817 5 1 0 0 16777215 524287 +818 5 2 0 0 16777215 524287 +819 5 4 0 0 16777215 524287 +820 5 0 0 10 16777215 16777215 +821 5 1 0 10 16777215 524287 +822 5 2 0 10 16777215 524287 +823 5 4 0 10 16777215 524287 +824 5 0 0 20 16777215 16777215 +825 5 1 0 20 16777215 524287 +826 5 2 0 20 16777215 524287 +827 5 4 0 20 16777215 524287 +828 5 0 0 16777215 16777215 16777215 +829 5 1 0 16777215 16777215 524287 +830 5 2 0 16777215 16777215 524287 +831 5 4 0 16777215 16777215 524287 +832 5 0 10 0 0 0 +833 5 1 10 0 0 524287 +834 5 2 10 0 0 524287 +835 5 4 10 0 0 524287 +836 5 0 10 10 0 0 +837 5 1 10 10 0 524287 +838 5 2 10 10 0 524287 +839 5 4 10 10 0 524287 +840 5 0 10 20 0 0 +841 5 1 10 20 0 524287 +842 5 2 10 20 0 524287 +843 5 4 10 20 0 524287 +844 5 0 10 16777215 0 0 +845 5 1 10 16777215 0 524287 +846 5 2 10 16777215 0 524287 +847 5 4 10 16777215 0 524287 +848 5 0 10 0 10 10 +849 5 1 10 0 10 524287 +850 5 2 10 0 10 524287 +851 5 4 10 0 10 524287 +852 5 0 10 10 10 10 +853 5 1 10 10 10 524287 +854 5 2 10 10 10 524287 +855 5 4 10 10 10 524287 +856 5 0 10 20 10 10 +857 5 1 10 20 10 524287 +858 5 2 10 20 10 524287 +859 5 4 10 20 10 524287 +860 5 0 10 16777215 10 10 +861 5 1 10 16777215 10 524287 +862 5 2 10 16777215 10 524287 +863 5 4 10 16777215 10 524287 +864 5 0 10 0 20 20 +865 5 1 10 0 20 524287 +866 5 2 10 0 20 524287 +867 5 4 10 0 20 524287 +868 5 0 10 10 20 20 +869 5 1 10 10 20 524287 +870 5 2 10 10 20 524287 +871 5 4 10 10 20 524287 +872 5 0 10 20 20 20 +873 5 1 10 20 20 524287 +874 5 2 10 20 20 524287 +875 5 4 10 20 20 524287 +876 5 0 10 16777215 20 20 +877 5 1 10 16777215 20 524287 +878 5 2 10 16777215 20 524287 +879 5 4 10 16777215 20 524287 +880 5 0 10 0 16777215 16777215 +881 5 1 10 0 16777215 524287 +882 5 2 10 0 16777215 524287 +883 5 4 10 0 16777215 524287 +884 5 0 10 10 16777215 16777215 +885 5 1 10 10 16777215 524287 +886 5 2 10 10 16777215 524287 +887 5 4 10 10 16777215 524287 +888 5 0 10 20 16777215 16777215 +889 5 1 10 20 16777215 524287 +890 5 2 10 20 16777215 524287 +891 5 4 10 20 16777215 524287 +892 5 0 10 16777215 16777215 16777215 +893 5 1 10 16777215 16777215 524287 +894 5 2 10 16777215 16777215 524287 +895 5 4 10 16777215 16777215 524287 +896 5 0 20 0 0 0 +897 5 1 20 0 0 524287 +898 5 2 20 0 0 524287 +899 5 4 20 0 0 524287 +900 5 0 20 10 0 0 +901 5 1 20 10 0 524287 +902 5 2 20 10 0 524287 +903 5 4 20 10 0 524287 +904 5 0 20 20 0 0 +905 5 1 20 20 0 524287 +906 5 2 20 20 0 524287 +907 5 4 20 20 0 524287 +908 5 0 20 16777215 0 0 +909 5 1 20 16777215 0 524287 +910 5 2 20 16777215 0 524287 +911 5 4 20 16777215 0 524287 +912 5 0 20 0 10 10 +913 5 1 20 0 10 524287 +914 5 2 20 0 10 524287 +915 5 4 20 0 10 524287 +916 5 0 20 10 10 10 +917 5 1 20 10 10 524287 +918 5 2 20 10 10 524287 +919 5 4 20 10 10 524287 +920 5 0 20 20 10 10 +921 5 1 20 20 10 524287 +922 5 2 20 20 10 524287 +923 5 4 20 20 10 524287 +924 5 0 20 16777215 10 10 +925 5 1 20 16777215 10 524287 +926 5 2 20 16777215 10 524287 +927 5 4 20 16777215 10 524287 +928 5 0 20 0 20 20 +929 5 1 20 0 20 524287 +930 5 2 20 0 20 524287 +931 5 4 20 0 20 524287 +932 5 0 20 10 20 20 +933 5 1 20 10 20 524287 +934 5 2 20 10 20 524287 +935 5 4 20 10 20 524287 +936 5 0 20 20 20 20 +937 5 1 20 20 20 524287 +938 5 2 20 20 20 524287 +939 5 4 20 20 20 524287 +940 5 0 20 16777215 20 20 +941 5 1 20 16777215 20 524287 +942 5 2 20 16777215 20 524287 +943 5 4 20 16777215 20 524287 +944 5 0 20 0 16777215 16777215 +945 5 1 20 0 16777215 524287 +946 5 2 20 0 16777215 524287 +947 5 4 20 0 16777215 524287 +948 5 0 20 10 16777215 16777215 +949 5 1 20 10 16777215 524287 +950 5 2 20 10 16777215 524287 +951 5 4 20 10 16777215 524287 +952 5 0 20 20 16777215 16777215 +953 5 1 20 20 16777215 524287 +954 5 2 20 20 16777215 524287 +955 5 4 20 20 16777215 524287 +956 5 0 20 16777215 16777215 16777215 +957 5 1 20 16777215 16777215 524287 +958 5 2 20 16777215 16777215 524287 +959 5 4 20 16777215 16777215 524287 +960 5 0 16777215 0 0 0 +961 5 1 16777215 0 0 524287 +962 5 2 16777215 0 0 524287 +963 5 4 16777215 0 0 524287 +964 5 0 16777215 10 0 0 +965 5 1 16777215 10 0 524287 +966 5 2 16777215 10 0 524287 +967 5 4 16777215 10 0 524287 +968 5 0 16777215 20 0 0 +969 5 1 16777215 20 0 524287 +970 5 2 16777215 20 0 524287 +971 5 4 16777215 20 0 524287 +972 5 0 16777215 16777215 0 0 +973 5 1 16777215 16777215 0 524287 +974 5 2 16777215 16777215 0 524287 +975 5 4 16777215 16777215 0 524287 +976 5 0 16777215 0 10 10 +977 5 1 16777215 0 10 524287 +978 5 2 16777215 0 10 524287 +979 5 4 16777215 0 10 524287 +980 5 0 16777215 10 10 10 +981 5 1 16777215 10 10 524287 +982 5 2 16777215 10 10 524287 +983 5 4 16777215 10 10 524287 +984 5 0 16777215 20 10 10 +985 5 1 16777215 20 10 524287 +986 5 2 16777215 20 10 524287 +987 5 4 16777215 20 10 524287 +988 5 0 16777215 16777215 10 10 +989 5 1 16777215 16777215 10 524287 +990 5 2 16777215 16777215 10 524287 +991 5 4 16777215 16777215 10 524287 +992 5 0 16777215 0 20 20 +993 5 1 16777215 0 20 524287 +994 5 2 16777215 0 20 524287 +995 5 4 16777215 0 20 524287 +996 5 0 16777215 10 20 20 +997 5 1 16777215 10 20 524287 +998 5 2 16777215 10 20 524287 +999 5 4 16777215 10 20 524287 +1000 5 0 16777215 20 20 20 +1001 5 1 16777215 20 20 524287 +1002 5 2 16777215 20 20 524287 +1003 5 4 16777215 20 20 524287 +1004 5 0 16777215 16777215 20 20 +1005 5 1 16777215 16777215 20 524287 +1006 5 2 16777215 16777215 20 524287 +1007 5 4 16777215 16777215 20 524287 +1008 5 0 16777215 0 16777215 16777215 +1009 5 1 16777215 0 16777215 524287 +1010 5 2 16777215 0 16777215 524287 +1011 5 4 16777215 0 16777215 524287 +1012 5 0 16777215 10 16777215 16777215 +1013 5 1 16777215 10 16777215 524287 +1014 5 2 16777215 10 16777215 524287 +1015 5 4 16777215 10 16777215 524287 +1016 5 0 16777215 20 16777215 16777215 +1017 5 1 16777215 20 16777215 524287 +1018 5 2 16777215 20 16777215 524287 +1019 5 4 16777215 20 16777215 524287 +1020 5 0 16777215 16777215 16777215 16777215 +1021 5 1 16777215 16777215 16777215 524287 +1022 5 2 16777215 16777215 16777215 524287 +1023 5 4 16777215 16777215 16777215 524287 +1024 7 0 0 0 0 0 +1025 7 1 0 0 0 524287 +1026 7 2 0 0 0 524287 +1027 7 4 0 0 0 524287 +1028 7 0 0 10 0 0 +1029 7 1 0 10 0 524287 +1030 7 2 0 10 0 524287 +1031 7 4 0 10 0 524287 +1032 7 0 0 20 0 0 +1033 7 1 0 20 0 524287 +1034 7 2 0 20 0 524287 +1035 7 4 0 20 0 524287 +1036 7 0 0 16777215 0 0 +1037 7 1 0 16777215 0 524287 +1038 7 2 0 16777215 0 524287 +1039 7 4 0 16777215 0 524287 +1040 7 0 0 0 10 10 +1041 7 1 0 0 10 524287 +1042 7 2 0 0 10 524287 +1043 7 4 0 0 10 524287 +1044 7 0 0 10 10 10 +1045 7 1 0 10 10 524287 +1046 7 2 0 10 10 524287 +1047 7 4 0 10 10 524287 +1048 7 0 0 20 10 10 +1049 7 1 0 20 10 524287 +1050 7 2 0 20 10 524287 +1051 7 4 0 20 10 524287 +1052 7 0 0 16777215 10 10 +1053 7 1 0 16777215 10 524287 +1054 7 2 0 16777215 10 524287 +1055 7 4 0 16777215 10 524287 +1056 7 0 0 0 20 20 +1057 7 1 0 0 20 524287 +1058 7 2 0 0 20 524287 +1059 7 4 0 0 20 524287 +1060 7 0 0 10 20 20 +1061 7 1 0 10 20 524287 +1062 7 2 0 10 20 524287 +1063 7 4 0 10 20 524287 +1064 7 0 0 20 20 20 +1065 7 1 0 20 20 524287 +1066 7 2 0 20 20 524287 +1067 7 4 0 20 20 524287 +1068 7 0 0 16777215 20 20 +1069 7 1 0 16777215 20 524287 +1070 7 2 0 16777215 20 524287 +1071 7 4 0 16777215 20 524287 +1072 7 0 0 0 16777215 16777215 +1073 7 1 0 0 16777215 524287 +1074 7 2 0 0 16777215 524287 +1075 7 4 0 0 16777215 524287 +1076 7 0 0 10 16777215 16777215 +1077 7 1 0 10 16777215 524287 +1078 7 2 0 10 16777215 524287 +1079 7 4 0 10 16777215 524287 +1080 7 0 0 20 16777215 16777215 +1081 7 1 0 20 16777215 524287 +1082 7 2 0 20 16777215 524287 +1083 7 4 0 20 16777215 524287 +1084 7 0 0 16777215 16777215 16777215 +1085 7 1 0 16777215 16777215 524287 +1086 7 2 0 16777215 16777215 524287 +1087 7 4 0 16777215 16777215 524287 +1088 7 0 10 0 0 0 +1089 7 1 10 0 0 524287 +1090 7 2 10 0 0 524287 +1091 7 4 10 0 0 524287 +1092 7 0 10 10 0 0 +1093 7 1 10 10 0 524287 +1094 7 2 10 10 0 524287 +1095 7 4 10 10 0 524287 +1096 7 0 10 20 0 0 +1097 7 1 10 20 0 524287 +1098 7 2 10 20 0 524287 +1099 7 4 10 20 0 524287 +1100 7 0 10 16777215 0 0 +1101 7 1 10 16777215 0 524287 +1102 7 2 10 16777215 0 524287 +1103 7 4 10 16777215 0 524287 +1104 7 0 10 0 10 10 +1105 7 1 10 0 10 524287 +1106 7 2 10 0 10 524287 +1107 7 4 10 0 10 524287 +1108 7 0 10 10 10 10 +1109 7 1 10 10 10 524287 +1110 7 2 10 10 10 524287 +1111 7 4 10 10 10 524287 +1112 7 0 10 20 10 10 +1113 7 1 10 20 10 524287 +1114 7 2 10 20 10 524287 +1115 7 4 10 20 10 524287 +1116 7 0 10 16777215 10 10 +1117 7 1 10 16777215 10 524287 +1118 7 2 10 16777215 10 524287 +1119 7 4 10 16777215 10 524287 +1120 7 0 10 0 20 20 +1121 7 1 10 0 20 524287 +1122 7 2 10 0 20 524287 +1123 7 4 10 0 20 524287 +1124 7 0 10 10 20 20 +1125 7 1 10 10 20 524287 +1126 7 2 10 10 20 524287 +1127 7 4 10 10 20 524287 +1128 7 0 10 20 20 20 +1129 7 1 10 20 20 524287 +1130 7 2 10 20 20 524287 +1131 7 4 10 20 20 524287 +1132 7 0 10 16777215 20 20 +1133 7 1 10 16777215 20 524287 +1134 7 2 10 16777215 20 524287 +1135 7 4 10 16777215 20 524287 +1136 7 0 10 0 16777215 16777215 +1137 7 1 10 0 16777215 524287 +1138 7 2 10 0 16777215 524287 +1139 7 4 10 0 16777215 524287 +1140 7 0 10 10 16777215 16777215 +1141 7 1 10 10 16777215 524287 +1142 7 2 10 10 16777215 524287 +1143 7 4 10 10 16777215 524287 +1144 7 0 10 20 16777215 16777215 +1145 7 1 10 20 16777215 524287 +1146 7 2 10 20 16777215 524287 +1147 7 4 10 20 16777215 524287 +1148 7 0 10 16777215 16777215 16777215 +1149 7 1 10 16777215 16777215 524287 +1150 7 2 10 16777215 16777215 524287 +1151 7 4 10 16777215 16777215 524287 +1152 7 0 20 0 0 0 +1153 7 1 20 0 0 524287 +1154 7 2 20 0 0 524287 +1155 7 4 20 0 0 524287 +1156 7 0 20 10 0 0 +1157 7 1 20 10 0 524287 +1158 7 2 20 10 0 524287 +1159 7 4 20 10 0 524287 +1160 7 0 20 20 0 0 +1161 7 1 20 20 0 524287 +1162 7 2 20 20 0 524287 +1163 7 4 20 20 0 524287 +1164 7 0 20 16777215 0 0 +1165 7 1 20 16777215 0 524287 +1166 7 2 20 16777215 0 524287 +1167 7 4 20 16777215 0 524287 +1168 7 0 20 0 10 10 +1169 7 1 20 0 10 524287 +1170 7 2 20 0 10 524287 +1171 7 4 20 0 10 524287 +1172 7 0 20 10 10 10 +1173 7 1 20 10 10 524287 +1174 7 2 20 10 10 524287 +1175 7 4 20 10 10 524287 +1176 7 0 20 20 10 10 +1177 7 1 20 20 10 524287 +1178 7 2 20 20 10 524287 +1179 7 4 20 20 10 524287 +1180 7 0 20 16777215 10 10 +1181 7 1 20 16777215 10 524287 +1182 7 2 20 16777215 10 524287 +1183 7 4 20 16777215 10 524287 +1184 7 0 20 0 20 20 +1185 7 1 20 0 20 524287 +1186 7 2 20 0 20 524287 +1187 7 4 20 0 20 524287 +1188 7 0 20 10 20 20 +1189 7 1 20 10 20 524287 +1190 7 2 20 10 20 524287 +1191 7 4 20 10 20 524287 +1192 7 0 20 20 20 20 +1193 7 1 20 20 20 524287 +1194 7 2 20 20 20 524287 +1195 7 4 20 20 20 524287 +1196 7 0 20 16777215 20 20 +1197 7 1 20 16777215 20 524287 +1198 7 2 20 16777215 20 524287 +1199 7 4 20 16777215 20 524287 +1200 7 0 20 0 16777215 16777215 +1201 7 1 20 0 16777215 524287 +1202 7 2 20 0 16777215 524287 +1203 7 4 20 0 16777215 524287 +1204 7 0 20 10 16777215 16777215 +1205 7 1 20 10 16777215 524287 +1206 7 2 20 10 16777215 524287 +1207 7 4 20 10 16777215 524287 +1208 7 0 20 20 16777215 16777215 +1209 7 1 20 20 16777215 524287 +1210 7 2 20 20 16777215 524287 +1211 7 4 20 20 16777215 524287 +1212 7 0 20 16777215 16777215 16777215 +1213 7 1 20 16777215 16777215 524287 +1214 7 2 20 16777215 16777215 524287 +1215 7 4 20 16777215 16777215 524287 +1216 7 0 16777215 0 0 0 +1217 7 1 16777215 0 0 524287 +1218 7 2 16777215 0 0 524287 +1219 7 4 16777215 0 0 524287 +1220 7 0 16777215 10 0 0 +1221 7 1 16777215 10 0 524287 +1222 7 2 16777215 10 0 524287 +1223 7 4 16777215 10 0 524287 +1224 7 0 16777215 20 0 0 +1225 7 1 16777215 20 0 524287 +1226 7 2 16777215 20 0 524287 +1227 7 4 16777215 20 0 524287 +1228 7 0 16777215 16777215 0 0 +1229 7 1 16777215 16777215 0 524287 +1230 7 2 16777215 16777215 0 524287 +1231 7 4 16777215 16777215 0 524287 +1232 7 0 16777215 0 10 10 +1233 7 1 16777215 0 10 524287 +1234 7 2 16777215 0 10 524287 +1235 7 4 16777215 0 10 524287 +1236 7 0 16777215 10 10 10 +1237 7 1 16777215 10 10 524287 +1238 7 2 16777215 10 10 524287 +1239 7 4 16777215 10 10 524287 +1240 7 0 16777215 20 10 10 +1241 7 1 16777215 20 10 524287 +1242 7 2 16777215 20 10 524287 +1243 7 4 16777215 20 10 524287 +1244 7 0 16777215 16777215 10 10 +1245 7 1 16777215 16777215 10 524287 +1246 7 2 16777215 16777215 10 524287 +1247 7 4 16777215 16777215 10 524287 +1248 7 0 16777215 0 20 20 +1249 7 1 16777215 0 20 524287 +1250 7 2 16777215 0 20 524287 +1251 7 4 16777215 0 20 524287 +1252 7 0 16777215 10 20 20 +1253 7 1 16777215 10 20 524287 +1254 7 2 16777215 10 20 524287 +1255 7 4 16777215 10 20 524287 +1256 7 0 16777215 20 20 20 +1257 7 1 16777215 20 20 524287 +1258 7 2 16777215 20 20 524287 +1259 7 4 16777215 20 20 524287 +1260 7 0 16777215 16777215 20 20 +1261 7 1 16777215 16777215 20 524287 +1262 7 2 16777215 16777215 20 524287 +1263 7 4 16777215 16777215 20 524287 +1264 7 0 16777215 0 16777215 16777215 +1265 7 1 16777215 0 16777215 524287 +1266 7 2 16777215 0 16777215 524287 +1267 7 4 16777215 0 16777215 524287 +1268 7 0 16777215 10 16777215 16777215 +1269 7 1 16777215 10 16777215 524287 +1270 7 2 16777215 10 16777215 524287 +1271 7 4 16777215 10 16777215 524287 +1272 7 0 16777215 20 16777215 16777215 +1273 7 1 16777215 20 16777215 524287 +1274 7 2 16777215 20 16777215 524287 +1275 7 4 16777215 20 16777215 524287 +1276 7 0 16777215 16777215 16777215 16777215 +1277 7 1 16777215 16777215 16777215 524287 +1278 7 2 16777215 16777215 16777215 524287 +1279 7 4 16777215 16777215 16777215 524287 +1280 3 0 0 0 0 0 +1281 3 1 0 0 0 524287 +1282 3 2 0 0 0 524287 +1283 3 4 0 0 0 524287 +1284 3 0 0 10 0 0 +1285 3 1 0 10 0 524287 +1286 3 2 0 10 0 524287 +1287 3 4 0 10 0 524287 +1288 3 0 0 20 0 0 +1289 3 1 0 20 0 524287 +1290 3 2 0 20 0 524287 +1291 3 4 0 20 0 524287 +1292 3 0 0 16777215 0 0 +1293 3 1 0 16777215 0 524287 +1294 3 2 0 16777215 0 524287 +1295 3 4 0 16777215 0 524287 +1296 3 0 0 0 10 10 +1297 3 1 0 0 10 524287 +1298 3 2 0 0 10 524287 +1299 3 4 0 0 10 524287 +1300 3 0 0 10 10 10 +1301 3 1 0 10 10 524287 +1302 3 2 0 10 10 524287 +1303 3 4 0 10 10 524287 +1304 3 0 0 20 10 10 +1305 3 1 0 20 10 524287 +1306 3 2 0 20 10 524287 +1307 3 4 0 20 10 524287 +1308 3 0 0 16777215 10 10 +1309 3 1 0 16777215 10 524287 +1310 3 2 0 16777215 10 524287 +1311 3 4 0 16777215 10 524287 +1312 3 0 0 0 20 20 +1313 3 1 0 0 20 524287 +1314 3 2 0 0 20 524287 +1315 3 4 0 0 20 524287 +1316 3 0 0 10 20 20 +1317 3 1 0 10 20 524287 +1318 3 2 0 10 20 524287 +1319 3 4 0 10 20 524287 +1320 3 0 0 20 20 20 +1321 3 1 0 20 20 524287 +1322 3 2 0 20 20 524287 +1323 3 4 0 20 20 524287 +1324 3 0 0 16777215 20 20 +1325 3 1 0 16777215 20 524287 +1326 3 2 0 16777215 20 524287 +1327 3 4 0 16777215 20 524287 +1328 3 0 0 0 16777215 16777215 +1329 3 1 0 0 16777215 524287 +1330 3 2 0 0 16777215 524287 +1331 3 4 0 0 16777215 524287 +1332 3 0 0 10 16777215 16777215 +1333 3 1 0 10 16777215 524287 +1334 3 2 0 10 16777215 524287 +1335 3 4 0 10 16777215 524287 +1336 3 0 0 20 16777215 16777215 +1337 3 1 0 20 16777215 524287 +1338 3 2 0 20 16777215 524287 +1339 3 4 0 20 16777215 524287 +1340 3 0 0 16777215 16777215 16777215 +1341 3 1 0 16777215 16777215 524287 +1342 3 2 0 16777215 16777215 524287 +1343 3 4 0 16777215 16777215 524287 +1344 3 0 10 0 0 0 +1345 3 1 10 0 0 524287 +1346 3 2 10 0 0 524287 +1347 3 4 10 0 0 524287 +1348 3 0 10 10 0 0 +1349 3 1 10 10 0 524287 +1350 3 2 10 10 0 524287 +1351 3 4 10 10 0 524287 +1352 3 0 10 20 0 0 +1353 3 1 10 20 0 524287 +1354 3 2 10 20 0 524287 +1355 3 4 10 20 0 524287 +1356 3 0 10 16777215 0 0 +1357 3 1 10 16777215 0 524287 +1358 3 2 10 16777215 0 524287 +1359 3 4 10 16777215 0 524287 +1360 3 0 10 0 10 10 +1361 3 1 10 0 10 524287 +1362 3 2 10 0 10 524287 +1363 3 4 10 0 10 524287 +1364 3 0 10 10 10 10 +1365 3 1 10 10 10 524287 +1366 3 2 10 10 10 524287 +1367 3 4 10 10 10 524287 +1368 3 0 10 20 10 10 +1369 3 1 10 20 10 524287 +1370 3 2 10 20 10 524287 +1371 3 4 10 20 10 524287 +1372 3 0 10 16777215 10 10 +1373 3 1 10 16777215 10 524287 +1374 3 2 10 16777215 10 524287 +1375 3 4 10 16777215 10 524287 +1376 3 0 10 0 20 20 +1377 3 1 10 0 20 524287 +1378 3 2 10 0 20 524287 +1379 3 4 10 0 20 524287 +1380 3 0 10 10 20 20 +1381 3 1 10 10 20 524287 +1382 3 2 10 10 20 524287 +1383 3 4 10 10 20 524287 +1384 3 0 10 20 20 20 +1385 3 1 10 20 20 524287 +1386 3 2 10 20 20 524287 +1387 3 4 10 20 20 524287 +1388 3 0 10 16777215 20 20 +1389 3 1 10 16777215 20 524287 +1390 3 2 10 16777215 20 524287 +1391 3 4 10 16777215 20 524287 +1392 3 0 10 0 16777215 16777215 +1393 3 1 10 0 16777215 524287 +1394 3 2 10 0 16777215 524287 +1395 3 4 10 0 16777215 524287 +1396 3 0 10 10 16777215 16777215 +1397 3 1 10 10 16777215 524287 +1398 3 2 10 10 16777215 524287 +1399 3 4 10 10 16777215 524287 +1400 3 0 10 20 16777215 16777215 +1401 3 1 10 20 16777215 524287 +1402 3 2 10 20 16777215 524287 +1403 3 4 10 20 16777215 524287 +1404 3 0 10 16777215 16777215 16777215 +1405 3 1 10 16777215 16777215 524287 +1406 3 2 10 16777215 16777215 524287 +1407 3 4 10 16777215 16777215 524287 +1408 3 0 20 0 0 0 +1409 3 1 20 0 0 524287 +1410 3 2 20 0 0 524287 +1411 3 4 20 0 0 524287 +1412 3 0 20 10 0 0 +1413 3 1 20 10 0 524287 +1414 3 2 20 10 0 524287 +1415 3 4 20 10 0 524287 +1416 3 0 20 20 0 0 +1417 3 1 20 20 0 524287 +1418 3 2 20 20 0 524287 +1419 3 4 20 20 0 524287 +1420 3 0 20 16777215 0 0 +1421 3 1 20 16777215 0 524287 +1422 3 2 20 16777215 0 524287 +1423 3 4 20 16777215 0 524287 +1424 3 0 20 0 10 10 +1425 3 1 20 0 10 524287 +1426 3 2 20 0 10 524287 +1427 3 4 20 0 10 524287 +1428 3 0 20 10 10 10 +1429 3 1 20 10 10 524287 +1430 3 2 20 10 10 524287 +1431 3 4 20 10 10 524287 +1432 3 0 20 20 10 10 +1433 3 1 20 20 10 524287 +1434 3 2 20 20 10 524287 +1435 3 4 20 20 10 524287 +1436 3 0 20 16777215 10 10 +1437 3 1 20 16777215 10 524287 +1438 3 2 20 16777215 10 524287 +1439 3 4 20 16777215 10 524287 +1440 3 0 20 0 20 20 +1441 3 1 20 0 20 524287 +1442 3 2 20 0 20 524287 +1443 3 4 20 0 20 524287 +1444 3 0 20 10 20 20 +1445 3 1 20 10 20 524287 +1446 3 2 20 10 20 524287 +1447 3 4 20 10 20 524287 +1448 3 0 20 20 20 20 +1449 3 1 20 20 20 524287 +1450 3 2 20 20 20 524287 +1451 3 4 20 20 20 524287 +1452 3 0 20 16777215 20 20 +1453 3 1 20 16777215 20 524287 +1454 3 2 20 16777215 20 524287 +1455 3 4 20 16777215 20 524287 +1456 3 0 20 0 16777215 16777215 +1457 3 1 20 0 16777215 524287 +1458 3 2 20 0 16777215 524287 +1459 3 4 20 0 16777215 524287 +1460 3 0 20 10 16777215 16777215 +1461 3 1 20 10 16777215 524287 +1462 3 2 20 10 16777215 524287 +1463 3 4 20 10 16777215 524287 +1464 3 0 20 20 16777215 16777215 +1465 3 1 20 20 16777215 524287 +1466 3 2 20 20 16777215 524287 +1467 3 4 20 20 16777215 524287 +1468 3 0 20 16777215 16777215 16777215 +1469 3 1 20 16777215 16777215 524287 +1470 3 2 20 16777215 16777215 524287 +1471 3 4 20 16777215 16777215 524287 +1472 3 0 16777215 0 0 0 +1473 3 1 16777215 0 0 524287 +1474 3 2 16777215 0 0 524287 +1475 3 4 16777215 0 0 524287 +1476 3 0 16777215 10 0 0 +1477 3 1 16777215 10 0 524287 +1478 3 2 16777215 10 0 524287 +1479 3 4 16777215 10 0 524287 +1480 3 0 16777215 20 0 0 +1481 3 1 16777215 20 0 524287 +1482 3 2 16777215 20 0 524287 +1483 3 4 16777215 20 0 524287 +1484 3 0 16777215 16777215 0 0 +1485 3 1 16777215 16777215 0 524287 +1486 3 2 16777215 16777215 0 524287 +1487 3 4 16777215 16777215 0 524287 +1488 3 0 16777215 0 10 10 +1489 3 1 16777215 0 10 524287 +1490 3 2 16777215 0 10 524287 +1491 3 4 16777215 0 10 524287 +1492 3 0 16777215 10 10 10 +1493 3 1 16777215 10 10 524287 +1494 3 2 16777215 10 10 524287 +1495 3 4 16777215 10 10 524287 +1496 3 0 16777215 20 10 10 +1497 3 1 16777215 20 10 524287 +1498 3 2 16777215 20 10 524287 +1499 3 4 16777215 20 10 524287 +1500 3 0 16777215 16777215 10 10 +1501 3 1 16777215 16777215 10 524287 +1502 3 2 16777215 16777215 10 524287 +1503 3 4 16777215 16777215 10 524287 +1504 3 0 16777215 0 20 20 +1505 3 1 16777215 0 20 524287 +1506 3 2 16777215 0 20 524287 +1507 3 4 16777215 0 20 524287 +1508 3 0 16777215 10 20 20 +1509 3 1 16777215 10 20 524287 +1510 3 2 16777215 10 20 524287 +1511 3 4 16777215 10 20 524287 +1512 3 0 16777215 20 20 20 +1513 3 1 16777215 20 20 524287 +1514 3 2 16777215 20 20 524287 +1515 3 4 16777215 20 20 524287 +1516 3 0 16777215 16777215 20 20 +1517 3 1 16777215 16777215 20 524287 +1518 3 2 16777215 16777215 20 524287 +1519 3 4 16777215 16777215 20 524287 +1520 3 0 16777215 0 16777215 16777215 +1521 3 1 16777215 0 16777215 524287 +1522 3 2 16777215 0 16777215 524287 +1523 3 4 16777215 0 16777215 524287 +1524 3 0 16777215 10 16777215 16777215 +1525 3 1 16777215 10 16777215 524287 +1526 3 2 16777215 10 16777215 524287 +1527 3 4 16777215 10 16777215 524287 +1528 3 0 16777215 20 16777215 16777215 +1529 3 1 16777215 20 16777215 524287 +1530 3 2 16777215 20 16777215 524287 +1531 3 4 16777215 20 16777215 524287 +1532 3 0 16777215 16777215 16777215 16777215 +1533 3 1 16777215 16777215 16777215 524287 +1534 3 2 16777215 16777215 16777215 524287 +1535 3 4 16777215 16777215 16777215 524287 +1536 13 0 0 0 0 0 +1537 13 1 0 0 0 524287 +1538 13 2 0 0 0 524287 +1539 13 4 0 0 0 524287 +1540 13 0 0 10 0 0 +1541 13 1 0 10 0 524287 +1542 13 2 0 10 0 524287 +1543 13 4 0 10 0 524287 +1544 13 0 0 20 0 0 +1545 13 1 0 20 0 524287 +1546 13 2 0 20 0 524287 +1547 13 4 0 20 0 524287 +1548 13 0 0 16777215 0 0 +1549 13 1 0 16777215 0 524287 +1550 13 2 0 16777215 0 524287 +1551 13 4 0 16777215 0 524287 +1552 13 0 0 0 10 10 +1553 13 1 0 0 10 524287 +1554 13 2 0 0 10 524287 +1555 13 4 0 0 10 524287 +1556 13 0 0 10 10 10 +1557 13 1 0 10 10 524287 +1558 13 2 0 10 10 524287 +1559 13 4 0 10 10 524287 +1560 13 0 0 20 10 10 +1561 13 1 0 20 10 524287 +1562 13 2 0 20 10 524287 +1563 13 4 0 20 10 524287 +1564 13 0 0 16777215 10 10 +1565 13 1 0 16777215 10 524287 +1566 13 2 0 16777215 10 524287 +1567 13 4 0 16777215 10 524287 +1568 13 0 0 0 20 20 +1569 13 1 0 0 20 524287 +1570 13 2 0 0 20 524287 +1571 13 4 0 0 20 524287 +1572 13 0 0 10 20 20 +1573 13 1 0 10 20 524287 +1574 13 2 0 10 20 524287 +1575 13 4 0 10 20 524287 +1576 13 0 0 20 20 20 +1577 13 1 0 20 20 524287 +1578 13 2 0 20 20 524287 +1579 13 4 0 20 20 524287 +1580 13 0 0 16777215 20 20 +1581 13 1 0 16777215 20 524287 +1582 13 2 0 16777215 20 524287 +1583 13 4 0 16777215 20 524287 +1584 13 0 0 0 16777215 16777215 +1585 13 1 0 0 16777215 524287 +1586 13 2 0 0 16777215 524287 +1587 13 4 0 0 16777215 524287 +1588 13 0 0 10 16777215 16777215 +1589 13 1 0 10 16777215 524287 +1590 13 2 0 10 16777215 524287 +1591 13 4 0 10 16777215 524287 +1592 13 0 0 20 16777215 16777215 +1593 13 1 0 20 16777215 524287 +1594 13 2 0 20 16777215 524287 +1595 13 4 0 20 16777215 524287 +1596 13 0 0 16777215 16777215 16777215 +1597 13 1 0 16777215 16777215 524287 +1598 13 2 0 16777215 16777215 524287 +1599 13 4 0 16777215 16777215 524287 +1600 13 0 10 0 0 0 +1601 13 1 10 0 0 524287 +1602 13 2 10 0 0 524287 +1603 13 4 10 0 0 524287 +1604 13 0 10 10 0 0 +1605 13 1 10 10 0 524287 +1606 13 2 10 10 0 524287 +1607 13 4 10 10 0 524287 +1608 13 0 10 20 0 0 +1609 13 1 10 20 0 524287 +1610 13 2 10 20 0 524287 +1611 13 4 10 20 0 524287 +1612 13 0 10 16777215 0 0 +1613 13 1 10 16777215 0 524287 +1614 13 2 10 16777215 0 524287 +1615 13 4 10 16777215 0 524287 +1616 13 0 10 0 10 10 +1617 13 1 10 0 10 524287 +1618 13 2 10 0 10 524287 +1619 13 4 10 0 10 524287 +1620 13 0 10 10 10 10 +1621 13 1 10 10 10 524287 +1622 13 2 10 10 10 524287 +1623 13 4 10 10 10 524287 +1624 13 0 10 20 10 10 +1625 13 1 10 20 10 524287 +1626 13 2 10 20 10 524287 +1627 13 4 10 20 10 524287 +1628 13 0 10 16777215 10 10 +1629 13 1 10 16777215 10 524287 +1630 13 2 10 16777215 10 524287 +1631 13 4 10 16777215 10 524287 +1632 13 0 10 0 20 20 +1633 13 1 10 0 20 524287 +1634 13 2 10 0 20 524287 +1635 13 4 10 0 20 524287 +1636 13 0 10 10 20 20 +1637 13 1 10 10 20 524287 +1638 13 2 10 10 20 524287 +1639 13 4 10 10 20 524287 +1640 13 0 10 20 20 20 +1641 13 1 10 20 20 524287 +1642 13 2 10 20 20 524287 +1643 13 4 10 20 20 524287 +1644 13 0 10 16777215 20 20 +1645 13 1 10 16777215 20 524287 +1646 13 2 10 16777215 20 524287 +1647 13 4 10 16777215 20 524287 +1648 13 0 10 0 16777215 16777215 +1649 13 1 10 0 16777215 524287 +1650 13 2 10 0 16777215 524287 +1651 13 4 10 0 16777215 524287 +1652 13 0 10 10 16777215 16777215 +1653 13 1 10 10 16777215 524287 +1654 13 2 10 10 16777215 524287 +1655 13 4 10 10 16777215 524287 +1656 13 0 10 20 16777215 16777215 +1657 13 1 10 20 16777215 524287 +1658 13 2 10 20 16777215 524287 +1659 13 4 10 20 16777215 524287 +1660 13 0 10 16777215 16777215 16777215 +1661 13 1 10 16777215 16777215 524287 +1662 13 2 10 16777215 16777215 524287 +1663 13 4 10 16777215 16777215 524287 +1664 13 0 20 0 0 0 +1665 13 1 20 0 0 524287 +1666 13 2 20 0 0 524287 +1667 13 4 20 0 0 524287 +1668 13 0 20 10 0 0 +1669 13 1 20 10 0 524287 +1670 13 2 20 10 0 524287 +1671 13 4 20 10 0 524287 +1672 13 0 20 20 0 0 +1673 13 1 20 20 0 524287 +1674 13 2 20 20 0 524287 +1675 13 4 20 20 0 524287 +1676 13 0 20 16777215 0 0 +1677 13 1 20 16777215 0 524287 +1678 13 2 20 16777215 0 524287 +1679 13 4 20 16777215 0 524287 +1680 13 0 20 0 10 10 +1681 13 1 20 0 10 524287 +1682 13 2 20 0 10 524287 +1683 13 4 20 0 10 524287 +1684 13 0 20 10 10 10 +1685 13 1 20 10 10 524287 +1686 13 2 20 10 10 524287 +1687 13 4 20 10 10 524287 +1688 13 0 20 20 10 10 +1689 13 1 20 20 10 524287 +1690 13 2 20 20 10 524287 +1691 13 4 20 20 10 524287 +1692 13 0 20 16777215 10 10 +1693 13 1 20 16777215 10 524287 +1694 13 2 20 16777215 10 524287 +1695 13 4 20 16777215 10 524287 +1696 13 0 20 0 20 20 +1697 13 1 20 0 20 524287 +1698 13 2 20 0 20 524287 +1699 13 4 20 0 20 524287 +1700 13 0 20 10 20 20 +1701 13 1 20 10 20 524287 +1702 13 2 20 10 20 524287 +1703 13 4 20 10 20 524287 +1704 13 0 20 20 20 20 +1705 13 1 20 20 20 524287 +1706 13 2 20 20 20 524287 +1707 13 4 20 20 20 524287 +1708 13 0 20 16777215 20 20 +1709 13 1 20 16777215 20 524287 +1710 13 2 20 16777215 20 524287 +1711 13 4 20 16777215 20 524287 +1712 13 0 20 0 16777215 16777215 +1713 13 1 20 0 16777215 524287 +1714 13 2 20 0 16777215 524287 +1715 13 4 20 0 16777215 524287 +1716 13 0 20 10 16777215 16777215 +1717 13 1 20 10 16777215 524287 +1718 13 2 20 10 16777215 524287 +1719 13 4 20 10 16777215 524287 +1720 13 0 20 20 16777215 16777215 +1721 13 1 20 20 16777215 524287 +1722 13 2 20 20 16777215 524287 +1723 13 4 20 20 16777215 524287 +1724 13 0 20 16777215 16777215 16777215 +1725 13 1 20 16777215 16777215 524287 +1726 13 2 20 16777215 16777215 524287 +1727 13 4 20 16777215 16777215 524287 +1728 13 0 16777215 0 0 0 +1729 13 1 16777215 0 0 524287 +1730 13 2 16777215 0 0 524287 +1731 13 4 16777215 0 0 524287 +1732 13 0 16777215 10 0 0 +1733 13 1 16777215 10 0 524287 +1734 13 2 16777215 10 0 524287 +1735 13 4 16777215 10 0 524287 +1736 13 0 16777215 20 0 0 +1737 13 1 16777215 20 0 524287 +1738 13 2 16777215 20 0 524287 +1739 13 4 16777215 20 0 524287 +1740 13 0 16777215 16777215 0 0 +1741 13 1 16777215 16777215 0 524287 +1742 13 2 16777215 16777215 0 524287 +1743 13 4 16777215 16777215 0 524287 +1744 13 0 16777215 0 10 10 +1745 13 1 16777215 0 10 524287 +1746 13 2 16777215 0 10 524287 +1747 13 4 16777215 0 10 524287 +1748 13 0 16777215 10 10 10 +1749 13 1 16777215 10 10 524287 +1750 13 2 16777215 10 10 524287 +1751 13 4 16777215 10 10 524287 +1752 13 0 16777215 20 10 10 +1753 13 1 16777215 20 10 524287 +1754 13 2 16777215 20 10 524287 +1755 13 4 16777215 20 10 524287 +1756 13 0 16777215 16777215 10 10 +1757 13 1 16777215 16777215 10 524287 +1758 13 2 16777215 16777215 10 524287 +1759 13 4 16777215 16777215 10 524287 +1760 13 0 16777215 0 20 20 +1761 13 1 16777215 0 20 524287 +1762 13 2 16777215 0 20 524287 +1763 13 4 16777215 0 20 524287 +1764 13 0 16777215 10 20 20 +1765 13 1 16777215 10 20 524287 +1766 13 2 16777215 10 20 524287 +1767 13 4 16777215 10 20 524287 +1768 13 0 16777215 20 20 20 +1769 13 1 16777215 20 20 524287 +1770 13 2 16777215 20 20 524287 +1771 13 4 16777215 20 20 524287 +1772 13 0 16777215 16777215 20 20 +1773 13 1 16777215 16777215 20 524287 +1774 13 2 16777215 16777215 20 524287 +1775 13 4 16777215 16777215 20 524287 +1776 13 0 16777215 0 16777215 16777215 +1777 13 1 16777215 0 16777215 524287 +1778 13 2 16777215 0 16777215 524287 +1779 13 4 16777215 0 16777215 524287 +1780 13 0 16777215 10 16777215 16777215 +1781 13 1 16777215 10 16777215 524287 +1782 13 2 16777215 10 16777215 524287 +1783 13 4 16777215 10 16777215 524287 +1784 13 0 16777215 20 16777215 16777215 +1785 13 1 16777215 20 16777215 524287 +1786 13 2 16777215 20 16777215 524287 +1787 13 4 16777215 20 16777215 524287 +1788 13 0 16777215 16777215 16777215 16777215 +1789 13 1 16777215 16777215 16777215 524287 +1790 13 2 16777215 16777215 16777215 524287 +1791 13 4 16777215 16777215 16777215 524287 diff --git a/tests/auto/widgets/kernel/qlayout/qlayout.pro b/tests/auto/widgets/kernel/qlayout/qlayout.pro new file mode 100644 index 0000000000..28ca9dc86d --- /dev/null +++ b/tests/auto/widgets/kernel/qlayout/qlayout.pro @@ -0,0 +1,16 @@ +load(qttest_p4) + +QT += widgets widgets-private + +SOURCES += tst_qlayout.cpp +wince* { + addFiles.files = baseline + addFiles.path = . + DEPLOYMENT += addFiles +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" + + test_data.files = baseline/* + test_data.path = $${target.path}/baseline + INSTALLS += test_data +} diff --git a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp new file mode 100644 index 0000000000..ea25700568 --- /dev/null +++ b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAC +# include +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QLayout : public QObject +{ +Q_OBJECT + +public: + tst_QLayout(); + virtual ~tst_QLayout(); + +private slots: + void getSetCheck(); + void geometry(); + void smartMaxSize(); + void setLayoutBugs(); + void setContentsMargins(); + void layoutItemRect(); + void warnIfWrongParent(); + void controlTypes(); + void adjustSizeShouldMakeSureLayoutIsActivated(); +}; + +tst_QLayout::tst_QLayout() +{ +} + +tst_QLayout::~tst_QLayout() +{ +} + +// Testing get/set functions +void tst_QLayout::getSetCheck() +{ + QBoxLayout obj1(QBoxLayout::LeftToRight); + // QWidget * QLayout::menuBar() + // void QLayout::setMenuBar(QWidget *) + QMenuBar *var1 = new QMenuBar(); + obj1.setMenuBar(var1); + QCOMPARE(static_cast(var1), obj1.menuBar()); + obj1.setMenuBar((QWidget *)0); + QCOMPARE((QWidget *)0, obj1.menuBar()); + delete var1; +} + +class SizeHinterFrame : public QFrame +{ +public: + SizeHinterFrame(const QSize &sh, const QSize &msh = QSize()) + : QFrame(0), sh(sh), msh(msh) { + setFrameStyle(QFrame::Box | QFrame::Plain); + } + + + + void setSizeHint(const QSize &s) { sh = s; } + QSize sizeHint() const { return sh; } + QSize minimumSizeHint() const { return msh; } + +private: + QSize sh; + QSize msh; +}; + + +void tst_QLayout::geometry() +{ + // For QWindowsStyle we know that QWidgetItem::geometry() and QWidget::geometry() + // should be the same. + QApplication::setStyle(new QWindowsStyle); + QWidget topLevel; + QWidget w(&topLevel); + QVBoxLayout layout(&w); + SizeHinterFrame widget(QSize(100,100)); + layout.addWidget(&widget); + QLayoutItem *item = layout.itemAt(0); + topLevel.show(); + QApplication::processEvents(); + QCOMPARE(item->geometry().size(), QSize(100,100)); + + widget.setMinimumSize(QSize(110,110)); + QCOMPARE(item->geometry().size(), QSize(110,110)); + + widget.setMinimumSize(QSize(0,0)); + widget.setMaximumSize(QSize(90,90)); + widget.setSizeHint(QSize(100,100)); + QCOMPARE(item->geometry().size(), QSize(90,90)); +} + +void tst_QLayout::smartMaxSize() +{ + QVector expectedWidths; + + QFile f(QLatin1String(SRCDIR "/baseline/smartmaxsize")); + + QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Text), true); + + QTextStream stream(&f); + + while(!stream.atEnd()) { + QString line = stream.readLine(200); + expectedWidths.append(line.section(QLatin1Char(' '), 6, -1, QString::SectionSkipEmpty).toInt()); + } + f.close(); + + int sizeCombinations[] = { 0, 10, 20, QWIDGETSIZE_MAX}; + QSizePolicy::Policy policies[] = { QSizePolicy::Fixed, + QSizePolicy::Minimum, + QSizePolicy::Maximum, + QSizePolicy::Preferred, + QSizePolicy::Expanding, + QSizePolicy::MinimumExpanding, + QSizePolicy::Ignored + }; + Qt::Alignment alignments[] = { 0, + Qt::AlignLeft, + Qt::AlignRight, + Qt::AlignHCenter + }; + + int expectedIndex = 0; + int regressionCount = 0; + for (size_t p = 0; p < sizeof(policies)/sizeof(QSizePolicy::Policy); ++p) { + QSizePolicy sizePolicy; + sizePolicy.setHorizontalPolicy(policies[p]); + for (size_t min = 0; min < sizeof(sizeCombinations)/sizeof(int); ++min) { + int minSize = sizeCombinations[min]; + for (size_t max = 0; max < sizeof(sizeCombinations)/sizeof(int); ++max) { + int maxSize = sizeCombinations[max]; + for (size_t sh = 0; sh < sizeof(sizeCombinations)/sizeof(int); ++sh) { + int sizeHint = sizeCombinations[sh]; + for (size_t a = 0; a < sizeof(alignments)/sizeof(int); ++a) { + Qt::Alignment align = alignments[a]; + QSize sz = qSmartMaxSize(QSize(sizeHint, 1), QSize(minSize, 1), QSize(maxSize, 1), sizePolicy, align); + int width = sz.width(); +#if 0 + qDebug() << expectedIndex << sizePolicy.horizontalPolicy() << align << minSize << sizeHint << maxSize << width; +#else + int expectedWidth = expectedWidths[expectedIndex]; + if (width != expectedWidth) { + qDebug() << "error at index" << expectedIndex << ":" << sizePolicy.horizontalPolicy() << align << minSize << sizeHint << maxSize << width; + ++regressionCount; + } +#endif + ++expectedIndex; + } + } + } + } + } + QCOMPARE(regressionCount, 0); +} + +void tst_QLayout::setLayoutBugs() +{ + QWidget widget(0); + QHBoxLayout *hBoxLayout = new QHBoxLayout(&widget); + + for(int i = 0; i < 6; ++i) { + QPushButton *pushButton = new QPushButton("Press me!", &widget); + hBoxLayout->addWidget(pushButton); + } + + widget.setLayout(hBoxLayout); + QVERIFY(widget.layout() == hBoxLayout); + + QWidget containerWidget(0); + containerWidget.setLayout(widget.layout()); + QVERIFY(widget.layout() == 0); + QVERIFY(containerWidget.layout() == hBoxLayout); +} + +class MyLayout : public QLayout +{ + public: + MyLayout() : invalidated(false) {} + virtual void invalidate() {invalidated = true;} + bool invalidated; + QSize sizeHint() const {return QSize();} + void addItem(QLayoutItem*) {} + QLayoutItem* itemAt(int) const {return 0;} + QLayoutItem* takeAt(int) {return 0;} + int count() const {return 0;} +}; + +void tst_QLayout::setContentsMargins() +{ + MyLayout layout; + layout.invalidated = false; + int left, top, right, bottom; + + layout.setContentsMargins(52, 53, 54, 55); + QVERIFY(layout.invalidated); + layout.invalidated = false; + + layout.getContentsMargins(&left, &top, &right, &bottom); + QCOMPARE(left, 52); + QCOMPARE(top, 53); + QCOMPARE(right, 54); + QCOMPARE(bottom, 55); + + layout.setContentsMargins(52, 53, 54, 55); + QVERIFY(!layout.invalidated); +} + +class EventReceiver : public QObject +{ +public: + bool eventFilter(QObject *watched, QEvent *event) + { + if (event->type() == QEvent::Show) { + geom = static_cast(watched)->geometry(); + } + return false; + } + QRect geom; +}; + +void tst_QLayout::layoutItemRect() +{ +#ifdef Q_WS_MAC + if (qobject_cast(QApplication::style())) { + QWidget *window = new QWidget; + QRadioButton *radio = new QRadioButton(window); + QWidgetItem item(radio); + EventReceiver eventReceiver; + radio->installEventFilter(&eventReceiver); + + radio->show(); + QApplication::processEvents(); + QApplication::processEvents(); + QSize s = item.sizeHint(); + + item.setAlignment(Qt::AlignVCenter); + item.setGeometry(QRect(QPoint(0, 0), s)); + + QCOMPARE(radio->geometry().size(), radio->sizeHint()); + delete radio; + } +#endif +} + +void tst_QLayout::warnIfWrongParent() +{ + QWidget root; + QHBoxLayout lay; + lay.setParent(&root); + QTest::ignoreMessage(QtWarningMsg, "QLayout::parentWidget: A layout can only have another layout as a parent."); + QCOMPARE(lay.parentWidget(), static_cast(0)); +} + +void tst_QLayout::controlTypes() +{ + QVBoxLayout layout; + QCOMPARE(layout.controlTypes(), QSizePolicy::DefaultType); + QSizePolicy p; + QCOMPARE(p.controlType(),QSizePolicy::DefaultType); + +} + +void tst_QLayout::adjustSizeShouldMakeSureLayoutIsActivated() +{ + QWidget main; + + QVBoxLayout *const layout = new QVBoxLayout(&main); + layout->setMargin(0); + SizeHinterFrame *frame = new SizeHinterFrame(QSize(200, 10), QSize(200, 8)); + frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + layout->addWidget(frame); + + SizeHinterFrame *frame2 = new SizeHinterFrame(QSize(200, 10), QSize(200, 8)); + frame2->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + layout->addWidget(frame2); + + main.show(); + + frame2->hide(); + main.adjustSize(); + QCOMPARE(main.size(), QSize(200, 10)); +} + +QTEST_MAIN(tst_QLayout) +#include "tst_qlayout.moc" diff --git a/tests/auto/widgets/kernel/qsound/.gitignore b/tests/auto/widgets/kernel/qsound/.gitignore new file mode 100644 index 0000000000..c9d313c2cf --- /dev/null +++ b/tests/auto/widgets/kernel/qsound/.gitignore @@ -0,0 +1 @@ +tst_qsound diff --git a/tests/auto/widgets/kernel/qsound/4.wav b/tests/auto/widgets/kernel/qsound/4.wav new file mode 100644 index 0000000000..e31b060908 Binary files /dev/null and b/tests/auto/widgets/kernel/qsound/4.wav differ diff --git a/tests/auto/widgets/kernel/qsound/qsound.pro b/tests/auto/widgets/kernel/qsound/qsound.pro new file mode 100644 index 0000000000..18ebaf16a4 --- /dev/null +++ b/tests/auto/widgets/kernel/qsound/qsound.pro @@ -0,0 +1,10 @@ +load(qttest_p4) +SOURCES += tst_qsound.cpp + +wince* { + deploy.files += 4.wav + DEPLOYMENT += deploy + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} diff --git a/tests/auto/widgets/kernel/qsound/tst_qsound.cpp b/tests/auto/widgets/kernel/qsound/tst_qsound.cpp new file mode 100644 index 0000000000..7450549f47 --- /dev/null +++ b/tests/auto/widgets/kernel/qsound/tst_qsound.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +class tst_QSound : public QObject +{ + Q_OBJECT + +public: + tst_QSound( QObject* parent=0) : QObject(parent) {} + +private slots: + void checkFinished(); + + // Manual tests + void staticPlay(); +}; + +void tst_QSound::checkFinished() +{ +#if defined(Q_WS_QPA) + QSKIP("QSound is not implemented on Lighthouse", SkipAll); +#else + QSound sound(SRCDIR"4.wav"); + sound.setLoops(3); + sound.play(); + QTest::qWait(5000); + +#if defined(Q_WS_QWS) + QEXPECT_FAIL("", "QSound buggy on embedded (task QTBUG-157)", Abort); +#endif + QVERIFY(sound.isFinished() ); +#endif +} + +void tst_QSound::staticPlay() +{ + QSKIP("Test disabled -- only for manual purposes", SkipAll); +#if !defined(Q_WS_QPA) + // Check that you hear sound with static play also. + QSound::play(SRCDIR"4.wav"); + QTest::qWait(2000); +#endif +} + +QTEST_MAIN(tst_QSound); +#include "tst_qsound.moc" diff --git a/tests/auto/widgets/kernel/qstackedlayout/.gitignore b/tests/auto/widgets/kernel/qstackedlayout/.gitignore new file mode 100644 index 0000000000..4dca3e87bd --- /dev/null +++ b/tests/auto/widgets/kernel/qstackedlayout/.gitignore @@ -0,0 +1 @@ +tst_qstackedlayout diff --git a/tests/auto/widgets/kernel/qstackedlayout/qstackedlayout.pro b/tests/auto/widgets/kernel/qstackedlayout/qstackedlayout.pro new file mode 100644 index 0000000000..30f074d9b1 --- /dev/null +++ b/tests/auto/widgets/kernel/qstackedlayout/qstackedlayout.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qstackedlayout.cpp + + + diff --git a/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp new file mode 100644 index 0000000000..de734877d7 --- /dev/null +++ b/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES=gui/kernel/qlayout.cpp gui/kernel/qlayout.h + +class tst_QStackedLayout : public QObject +{ + Q_OBJECT + +public: + tst_QStackedLayout(); + virtual ~tst_QStackedLayout(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void testCase(); + void deleteCurrent(); + void removeWidget(); + void keepFocusAfterSetCurrent(); + +private: + QWidget *testWidget; +}; + +// Testing get/set functions +void tst_QStackedLayout::getSetCheck() +{ + QStackedLayout obj1; + // int QStackedLayout::currentIndex() + // void QStackedLayout::setCurrentIndex(int) + obj1.setCurrentIndex(0); + QCOMPARE(-1, obj1.currentIndex()); + obj1.setCurrentIndex(INT_MIN); + QCOMPARE(-1, obj1.currentIndex()); + obj1.setCurrentIndex(INT_MAX); + QCOMPARE(-1, obj1.currentIndex()); + + // QWidget * QStackedLayout::currentWidget() + // void QStackedLayout::setCurrentWidget(QWidget *) + QWidget *var2 = new QWidget(); + obj1.addWidget(var2); + obj1.setCurrentWidget(var2); + QCOMPARE(var2, obj1.currentWidget()); + + obj1.setCurrentWidget((QWidget *)0); + QCOMPARE(obj1.currentWidget(), var2); + + delete var2; +} + + +tst_QStackedLayout::tst_QStackedLayout() + : testWidget(0) +{ +} + +tst_QStackedLayout::~tst_QStackedLayout() +{ +} + +void tst_QStackedLayout::initTestCase() +{ +} + +void tst_QStackedLayout::cleanupTestCase() +{ +} + +void tst_QStackedLayout::init() +{ + if (testWidget) { + delete testWidget; + testWidget = 0; + } + testWidget = new QWidget(0); + testWidget->resize( 200, 200 ); + testWidget->show(); + + // make sure the tests work with focus follows mouse + QCursor::setPos(testWidget->geometry().center()); + testWidget->activateWindow(); + QApplication::syncX(); + QTest::qWait(250); +} + +void tst_QStackedLayout::cleanup() +{ + delete testWidget; + testWidget = 0; +} + + +void tst_QStackedLayout::testCase() +{ + QStackedLayout onStack(testWidget); + QStackedLayout *testLayout = &onStack; + testWidget->setLayout(testLayout); + + QSignalSpy spy(testLayout,SIGNAL(currentChanged(int))); + + // Nothing in layout + QCOMPARE(testLayout->currentIndex(), -1); + QCOMPARE(testLayout->currentWidget(), static_cast(0)); + QCOMPARE(testLayout->count(), 0); + + // One widget added to layout + QWidget *w1 = new QWidget(testWidget); + testLayout->addWidget(w1); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toInt(), 0); + spy.clear(); + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w1); + QCOMPARE(testLayout->count(), 1); + + // Another widget added to layout + QWidget *w2 = new QWidget(testWidget); + testLayout->addWidget(w2); + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w1); + QCOMPARE(testLayout->indexOf(w2), 1); + QCOMPARE(testLayout->count(), 2); + + // Change the current index + testLayout->setCurrentIndex(1); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toInt(), 1); + spy.clear(); + QCOMPARE(testLayout->currentIndex(), 1); + QCOMPARE(testLayout->currentWidget(), w2); + + // First widget removed from layout + testLayout->removeWidget(w1); + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w2); + QCOMPARE(testLayout->count(), 1); + + // Second widget removed from layout; back to nothing + testLayout->removeWidget(w2); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).toInt(), -1); + spy.clear(); + QCOMPARE(testLayout->currentIndex(), -1); + QCOMPARE(testLayout->currentWidget(), static_cast(0)); + QCOMPARE(testLayout->count(), 0); + + // Another widget inserted at current index. + // Current index should become current index + 1, but the + // current widget should stay the same + testLayout->addWidget(w1); + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w1); + testLayout->insertWidget(0, w2); + QCOMPARE(testLayout->currentIndex(), 1); + QCOMPARE(testLayout->currentWidget(), w1); + QVERIFY(w1->isVisible()); + QVERIFY(!w2->isVisible()); + + testLayout->setCurrentWidget(w2); + // Another widget added, so we have: w2, w1, w3 with w2 current + QWidget *w3 = new QWidget(testWidget); + testLayout->addWidget(w3); + QCOMPARE(testLayout->indexOf(w2), 0); + QCOMPARE(testLayout->indexOf(w1), 1); + QCOMPARE(testLayout->indexOf(w3), 2); + + // Set index to 1 and remove that widget (w1). + // Then, current index should still be 1, but w3 + // should be the new current widget. + testLayout->setCurrentIndex(1); + testLayout->removeWidget(w1); + QCOMPARE(testLayout->currentIndex(), 1); + QCOMPARE(testLayout->currentWidget(), w3); + QVERIFY(w3->isVisible()); + + // Remove the current widget (w3). + // Since it's the last one in the list, current index should now + // become 0 and w2 becomes the current widget. + testLayout->removeWidget(w3); + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w2); + QVERIFY(w2->isVisible()); + + // Make sure index is decremented when we remove a widget at index < current index + testLayout->addWidget(w1); + testLayout->addWidget(w3); + testLayout->setCurrentIndex(2); + testLayout->removeWidget(w2); // At index 0 + QCOMPARE(testLayout->currentIndex(), 1); + QCOMPARE(testLayout->currentWidget(), w3); + QVERIFY(w3->isVisible()); + testLayout->removeWidget(w1); // At index 0 + QCOMPARE(testLayout->currentIndex(), 0); + QCOMPARE(testLayout->currentWidget(), w3); + QVERIFY(w3->isVisible()); + testLayout->removeWidget(w3); + QCOMPARE(testLayout->currentIndex(), -1); + QCOMPARE(testLayout->currentWidget(), static_cast(0)); +} + +void tst_QStackedLayout::deleteCurrent() +{ + QStackedLayout *testLayout = new QStackedLayout(testWidget); + + QWidget *w1 = new QWidget; + testLayout->addWidget(w1); + QWidget *w2 = new QWidget; + testLayout->addWidget(w2); + QCOMPARE(testLayout->currentWidget(), w1); + delete testLayout->currentWidget(); + QCOMPARE(testLayout->currentWidget(), w2); +} + +void tst_QStackedLayout::removeWidget() +{ + if (testWidget->layout()) delete testWidget->layout(); + QVBoxLayout *vbox = new QVBoxLayout(testWidget); + + QPushButton *top = new QPushButton("top", testWidget); //add another widget that can receive focus + top->setObjectName("top"); + vbox->addWidget(top); + + QStackedLayout *testLayout = new QStackedLayout(); + QPushButton *w1 = new QPushButton("1st", testWidget); + w1->setObjectName("1st"); + testLayout->addWidget(w1); + QPushButton *w2 = new QPushButton("2nd", testWidget); + w2->setObjectName("2nd"); + testLayout->addWidget(w2); + vbox->addLayout(testLayout); + top->setFocus(); + QTest::qWait(100); + top->activateWindow(); + QTest::qWait(100); + int i =0; + for (;;) { + if (QApplication::focusWidget() == top) + break; + else if (i >= 5) + QSKIP("Can't get focus", SkipSingle); + QTest::qWait(100); + ++i; + } + QCOMPARE(QApplication::focusWidget(), static_cast(top)); + + // focus should stay at the 'top' widget + testLayout->removeWidget(w1); + + QCOMPARE(QApplication::focusWidget(), static_cast(top)); +} + +class LineEdit : public QLineEdit +{ +public: + LineEdit() : hasFakeEditFocus(false) + { } + + bool hasFakeEditFocus; + +protected: + bool isSingleFocusWidget() const + { + const QWidget *w = this; + while ((w = w->nextInFocusChain()) != this) { + if (w->isVisible() && static_cast(w->focusProxy()) != this + && w->focusPolicy() & Qt::TabFocus) { + return false; + } + } + return true; + } + + void focusInEvent(QFocusEvent *event) + { + QLineEdit::focusInEvent(event); + hasFakeEditFocus = isSingleFocusWidget(); + } + + void focusOutEvent(QFocusEvent *event) + { + hasFakeEditFocus = false; + QLineEdit::focusOutEvent(event); + } +}; + +void tst_QStackedLayout::keepFocusAfterSetCurrent() +{ + if (testWidget->layout()) delete testWidget->layout(); + QStackedLayout *stackLayout = new QStackedLayout(testWidget); + testWidget->setFocusPolicy(Qt::NoFocus); + + LineEdit *edit1 = new LineEdit; + LineEdit *edit2 = new LineEdit; + stackLayout->addWidget(edit1); + stackLayout->addWidget(edit2); + + stackLayout->setCurrentIndex(0); + + testWidget->show(); + QApplication::setActiveWindow(testWidget); + QTest::qWaitForWindowShown(testWidget); + QApplication::processEvents(); + + edit1->setFocus(); + edit1->activateWindow(); + QTest::qWait(25); + + QTRY_VERIFY(edit1->hasFocus()); + + stackLayout->setCurrentIndex(1); + QVERIFY(!edit1->hasFocus()); + QVERIFY(edit2->hasFocus()); + QVERIFY(edit2->hasFakeEditFocus); +} + +QTEST_MAIN(tst_QStackedLayout) +#include "tst_qstackedlayout.moc" + diff --git a/tests/auto/widgets/kernel/qtooltip/.gitignore b/tests/auto/widgets/kernel/qtooltip/.gitignore new file mode 100644 index 0000000000..552a2a5dc6 --- /dev/null +++ b/tests/auto/widgets/kernel/qtooltip/.gitignore @@ -0,0 +1 @@ +tst_qtooltip diff --git a/tests/auto/widgets/kernel/qtooltip/qtooltip.pro b/tests/auto/widgets/kernel/qtooltip/qtooltip.pro new file mode 100644 index 0000000000..4da8917921 --- /dev/null +++ b/tests/auto/widgets/kernel/qtooltip/qtooltip.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qtooltip.cpp + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp new file mode 100644 index 0000000000..3ff31ead62 --- /dev/null +++ b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QToolTip : public QObject +{ + Q_OBJECT + +public: + tst_QToolTip() {} + virtual ~tst_QToolTip() {} + +public slots: + void initTestCase() {} + void cleanupTestCase() {} + void init() {} + void cleanup() {} + +private slots: + + // task-specific tests below me + void task183679_data(); + void task183679(); + void whatsThis(); + void setPalette(); +}; + +class Widget_task183679 : public QWidget +{ + Q_OBJECT +public: + Widget_task183679(QWidget *parent = 0) : QWidget(parent) {} + + void showDelayedToolTip(int msecs) + { + QTimer::singleShot(msecs, this, SLOT(showToolTip())); + } + +private slots: + void showToolTip() + { + QToolTip::showText(mapToGlobal(QPoint(0, 0)), "tool tip text", this); + } +}; + +Q_DECLARE_METATYPE(Qt::Key) + +void tst_QToolTip::task183679_data() +{ + QTest::addColumn("key"); + QTest::addColumn("visible"); +#ifdef Q_WS_MAC + const bool visibleAfterNonModifier = false; +#else + const bool visibleAfterNonModifier = true; +#endif + QTest::newRow("non-modifier") << Qt::Key_A << visibleAfterNonModifier; + QTest::newRow("Shift") << Qt::Key_Shift << true; + QTest::newRow("Control") << Qt::Key_Control << true; + QTest::newRow("Alt") << Qt::Key_Alt << true; + QTest::newRow("Meta") << Qt::Key_Meta << true; +} + +void tst_QToolTip::task183679() +{ + QFETCH(Qt::Key, key); + QFETCH(bool, visible); + + Widget_task183679 widget; + widget.show(); + QApplication::setActiveWindow(&widget); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(30); + + + widget.showDelayedToolTip(100); + QTest::qWait(300); + QTRY_VERIFY(QToolTip::isVisible()); + + QTest::keyPress(&widget, key); + + // Important: the following delay must be larger than the duration of the timer potentially + // initiated by the key press (currently 300 msecs), but smaller than the minimum + // auto-close timeout (currently 10000 msecs) + QTest::qWait(1500); + + QCOMPARE(QToolTip::isVisible(), visible); +} + +#include + +void tst_QToolTip::whatsThis() +{ + qApp->setStyleSheet( "QWidget { font-size: 72px; }" ); + QWhatsThis::showText(QPoint(0,0), "THis is text"); + QTest::qWait(400); + QWidget *whatsthis = 0; + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->inherits("QWhatsThat")) { + whatsthis = widget; + break; + } + } + QVERIFY(whatsthis); + QVERIFY(whatsthis->isVisible()); + QVERIFY(whatsthis->height() > 100); // Test QTBUG-2416 + qApp->setStyleSheet(""); +} + + +void tst_QToolTip::setPalette() +{ + //the previous test may still have a tooltip pending for deletion + QVERIFY(!QToolTip::isVisible()); + + QToolTip::showText(QPoint(), "tool tip text", 0); + + QTRY_VERIFY(QToolTip::isVisible()); + + QWidget *toolTip = 0; + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->windowType() == Qt::ToolTip + && widget->objectName() == QLatin1String("qtooltip_label")) + { + toolTip = widget; + break; + } + } + + QVERIFY(toolTip); + QTRY_VERIFY(toolTip->isVisible()); + + const QPalette oldPalette = toolTip->palette(); + QPalette newPalette = oldPalette; + newPalette.setColor(QPalette::ToolTipBase, Qt::red); + newPalette.setColor(QPalette::ToolTipText, Qt::blue); + QToolTip::setPalette(newPalette); + QCOMPARE(toolTip->palette(), newPalette); +} + +QTEST_MAIN(tst_QToolTip) +#include "tst_qtooltip.moc" diff --git a/tests/auto/widgets/kernel/qwidget/.gitignore b/tests/auto/widgets/kernel/qwidget/.gitignore new file mode 100644 index 0000000000..82a0ac9eba --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/.gitignore @@ -0,0 +1 @@ +tst_qwidget diff --git a/tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat b/tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat new file mode 100644 index 0000000000..9802ee8b9e Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat differ diff --git a/tests/auto/widgets/kernel/qwidget/geometry-maximized.dat b/tests/auto/widgets/kernel/qwidget/geometry-maximized.dat new file mode 100644 index 0000000000..df5bc2f94e Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/geometry-maximized.dat differ diff --git a/tests/auto/widgets/kernel/qwidget/geometry.dat b/tests/auto/widgets/kernel/qwidget/geometry.dat new file mode 100644 index 0000000000..e5dcb2dc44 Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/geometry.dat differ diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.pro b/tests/auto/widgets/kernel/qwidget/qwidget.pro new file mode 100644 index 0000000000..9c34e0c254 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/qwidget.pro @@ -0,0 +1,23 @@ +load(qttest_p4) + +QT += widgets core-private gui-private widgets-private + +SOURCES += tst_qwidget.cpp +RESOURCES = qwidget.qrc + +aix-g++*:QMAKE_CXXFLAGS+=-fpermissive + +CONFIG += x11inc + +mac:!qpa { + LIBS += -framework Security -framework AppKit -framework Carbon + OBJECTIVE_SOURCES += tst_qwidget_mac_helpers.mm +} + +x11 { + LIBS += $$QMAKE_LIBS_X11 +} + +!wince*:win32: LIBS += -luser32 -lgdi32 + +CONFIG+=insignificant_test diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.qrc b/tests/auto/widgets/kernel/qwidget/qwidget.qrc new file mode 100644 index 0000000000..1399c4c9db --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/qwidget.qrc @@ -0,0 +1,7 @@ + + + geometry.dat + geometry-maximized.dat + geometry-fullscreen.dat + + diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap new file mode 100644 index 0000000000..b3473cdefe Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data0.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap new file mode 100644 index 0000000000..10007733ca Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data1.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap new file mode 100644 index 0000000000..cde5964a30 Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data2.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap new file mode 100644 index 0000000000..23ea1410e4 Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Motif_data3.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap new file mode 100644 index 0000000000..a8918c1d1b Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data0.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap new file mode 100644 index 0000000000..0981cf5dd1 Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data1.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap new file mode 100644 index 0000000000..75d09136cf Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data2.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap new file mode 100644 index 0000000000..f58f74d030 Binary files /dev/null and b/tests/auto/widgets/kernel/qwidget/testdata/paintEvent/res_Windows_data3.qsnap differ diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp new file mode 100644 index 0000000000..ded0c5e061 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -0,0 +1,9472 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef Q_WS_QWS +# include +#endif + +// I *MUST* have QtTest afterwards or this test won't work with newer headers +#if defined(Q_WS_MAC) +# include +#undef verify +#include "tst_qwidget_mac_helpers.h" // Abstract the ObjC stuff out so not everyone must run an ObjC++ compile. +#endif + +#include + +#if defined(Q_OS_WIN) +# include +# include +# include +# include + +static HWND winHandleOf(const QWidget *w) +{ + static QPlatformNativeInterface *nativeInterface + = QGuiApplicationPrivate::instance()->platformIntegration()->nativeInterface(); + if (void *handle = nativeInterface->nativeResourceForWindow("handle", w->window()->windowHandle())) + return reinterpret_cast(handle); + qWarning() << "Cannot obtain native handle for " << w; + return 0; +} +#endif + +#if defined(Q_WS_WIN) +# include +# if !defined(Q_OS_WINCE) +#define Q_CHECK_PAINTEVENTS \ + if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \ + QSKIP("desktop is not visible, this test would fail", SkipSingle); +# else +# define Q_CHECK_PAINTEVENTS +# endif +#elif defined(Q_WS_X11) +# include +# include +#elif defined(Q_WS_QWS) +# include +#endif + +#if !defined(Q_WS_WIN) +#define Q_CHECK_PAINTEVENTS +#endif + +#if defined(Q_OS_WINCE_WM) +#include +// taken from qguifunctions_wce.cpp +#define SPI_GETPLATFORMTYPE 257 +bool qt_wince_is_platform(const QString &platformString) { + wchar_t tszPlatform[64]; + if (SystemParametersInfo(SPI_GETPLATFORMTYPE, + sizeof(tszPlatform)/sizeof(*tszPlatform),tszPlatform,0)) + if (0 == _tcsicmp(reinterpret_cast (platformString.utf16()), tszPlatform)) + return true; + return false; +} +bool qt_wince_is_smartphone() { + return qt_wince_is_platform(QString::fromLatin1("Smartphone")); +} +#endif + +#ifdef Q_WS_MAC +#include +bool macHasAccessToWindowsServer() +{ + SecuritySessionId mySession; + SessionAttributeBits sessionInfo; + SessionGetInfo(callerSecuritySession, &mySession, &sessionInfo); + return (sessionInfo & sessionHasGraphicAccess); +} +#endif + + +#if defined(Bool) +#undef Bool +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QWidget : public QObject +{ + Q_OBJECT + +public: + tst_QWidget(); + virtual ~tst_QWidget(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void fontPropagation(); + void fontPropagation2(); + void palettePropagation(); + void palettePropagation2(); + void enabledPropagation(); +#ifndef QT_NO_DRAGANDDROP + void acceptDropsPropagation(); +#endif + void isEnabledTo(); + void visible(); + void visible_setWindowOpacity(); + void isVisibleTo(); + void isHidden(); + void fonts(); + void mapFromAndTo_data(); + void mapFromAndTo(); + void focusChainOnHide(); + void focusChainOnReparent(); + void setTabOrder(); +#ifdef Q_WS_WIN + void activation(); +#endif + void reparent(); +#ifndef Q_WS_X11 + void windowState(); +#endif + void showMaximized(); + void showFullScreen(); + void showMinimized(); + void showMinimizedKeepsFocus(); +#ifndef Q_WS_QWS + void icon(); +#endif + void hideWhenFocusWidgetIsChild(); +#ifndef Q_OS_IRIX + void normalGeometry(); +#endif + void setGeometry(); +#ifndef Q_OS_WINCE + void windowOpacity(); +#endif + void raise(); + void lower(); +#ifndef QT_MAC_USE_COCOA + void stackUnder(); +#endif + void testContentsPropagation(); +#ifndef Q_OS_IRIX + void saveRestoreGeometry(); + void restoreVersion1Geometry_data(); + void restoreVersion1Geometry(); +#endif + + void widgetAt(); +#ifdef Q_WS_MAC + void retainHIView(); + void sheetOpacity(); + void setMask(); +#endif + void optimizedResizeMove(); + void optimizedResize_topLevel(); + void resizeEvent(); + void task110173(); + + void testDeletionInEventHandlers(); + + void childDeletesItsSibling(); + + void setMinimumSize(); + void setMaximumSize(); + void setFixedSize(); + + void ensureCreated(); + void winIdChangeEvent(); + void persistentWinId(); + void showNativeChild(); + void qobject_castInDestroyedSlot(); + + void showHideEvent_data(); + void showHideEvent(); + + void lostUpdatesOnHide(); + + void update(); + void isOpaque(); + +#ifndef Q_WS_MAC + void scroll(); +#endif + +#ifndef Q_WS_X11 + // tests QWidget::setGeometry() + void setWindowGeometry_data(); + void setWindowGeometry(); +#endif + +#if !defined(Q_WS_X11) && !defined(Q_OS_IRIX) + // tests QWidget::move() and resize() + void windowMoveResize_data(); + void windowMoveResize(); +#endif + + void moveChild_data(); + void moveChild(); + void showAndMoveChild(); + +#ifndef QT_MAC_USE_COCOA + void subtractOpaqueSiblings(); +#endif + +#ifdef Q_WS_WIN + void getDC(); +#ifndef Q_OS_WINCE + void setGeometry_win(); +#endif +#endif + + void setLocale(); + void deleteStyle(); + void multipleToplevelFocusCheck(); + void setFocus(); + void setCursor(); + void setToolTip(); + void testWindowIconChangeEventPropagation(); +#ifdef Q_WS_X11 + void minAndMaxSizeWithX11BypassWindowManagerHint(); + void showHideShow(); + void clean_qt_x11_enforce_cursor(); +#endif + + void compatibilityChildInsertedEvents(); + void render(); + void renderInvisible(); + void renderWithPainter(); + void render_task188133(); + void render_task211796(); + void render_task217815(); +#ifndef Q_OS_WINCE + void render_windowOpacity(); +#endif + void render_systemClip(); + void render_systemClip2_data(); + void render_systemClip2(); + void render_systemClip3_data(); + void render_systemClip3(); + void render_task252837(); + void render_worldTransform(); + + void setContentsMargins(); + +#ifndef Q_OS_IRIX + void moveWindowInShowEvent_data(); + void moveWindowInShowEvent(); +#endif + + void repaintWhenChildDeleted(); + void hideOpaqueChildWhileHidden(); +#if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS) + void updateWhileMinimized(); +#endif +#if defined(Q_WS_WIN) || defined(Q_WS_X11) + void alienWidgets(); +#endif + void adjustSize(); + void adjustSize_data(); + void updateGeometry(); + void updateGeometry_data(); + void sendUpdateRequestImmediately(); +#ifndef Q_OS_IRIX + void doubleRepaint(); +#endif +#ifndef Q_WS_MAC + void resizeInPaintEvent(); + void opaqueChildren(); +#endif + + void setMaskInResizeEvent(); + void moveInResizeEvent(); + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) + // We don't support immediate repaint right after show on + // other platforms. Must be compatible with Qt 4.3. + void immediateRepaintAfterShow(); + void immediateRepaintAfterInvalidateBuffer(); +#endif + void effectiveWinId(); + void effectiveWinId2(); + void customDpi(); + void customDpiProperty(); + + void quitOnCloseAttribute(); + void moveRect(); + +#if defined (Q_WS_WIN) + void gdiPainting(); + void paintOnScreenPossible(); +#endif + void reparentStaticWidget(); + void QTBUG6883_reparentStaticWidget2(); +#ifdef Q_WS_QWS + void updateOutsideSurfaceClip(); +#endif + void translucentWidget(); + + void setClearAndResizeMask(); + void maskedUpdate(); +#if defined(Q_WS_X11) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE_WM)) || defined(Q_WS_QWS) || defined(Q_WS_QPA) + void syntheticEnterLeave(); + void taskQTBUG_4055_sendSyntheticEnterLeave(); +#endif + void windowFlags(); + void initialPosForDontShowOnScreenWidgets(); +#ifdef Q_WS_X11 + void paintOutsidePaintEvent(); +#endif + void updateOnDestroyedSignal(); + void toplevelLineEditFocus(); + void inputFocus_task257832(); + + void focusWidget_task254563(); +#ifndef Q_OS_WINCE_WM + void rectOutsideCoordinatesLimit_task144779(); +#endif + void setGraphicsEffect(); + +#ifdef QT_BUILD_INTERNAL + void destroyBackingStore(); +#endif + + void activateWindow(); + + void openModal_taskQTBUG_5804(); + + void focusProxyAndInputMethods(); +#ifdef QT_BUILD_INTERNAL + void scrollWithoutBackingStore(); +#endif + + void taskQTBUG_7532_tabOrderWithFocusProxy(); + void movedAndResizedAttributes(); + void childAt(); +#ifdef Q_WS_MAC + void childAt_unifiedToolBar(); + void taskQTBUG_11373(); +#endif + void taskQTBUG_17333_ResizeInfiniteRecursion(); + + void nativeChildFocus(); + +private: + bool ensureScreenSize(int width, int height); + QWidget *testWidget; +}; + +bool tst_QWidget::ensureScreenSize(int width, int height) +{ + QSize available; +#ifdef Q_WS_QWS + available = QDesktopWidget().availableGeometry().size(); + if (available.width() < width || available.height() < height) { + QScreen *screen = QScreen::instance(); + if (!screen) + return false; + screen->setMode(width, height, screen->depth()); + } +#endif // Q_WS_QWS + + available = QDesktopWidget().availableGeometry().size(); + return (available.width() >= width && available.height() >= height); +} + +class MyInputContext : public QInputContext +{ +public: + MyInputContext() : QInputContext() {} + QString identifierName() { return QString("NoName"); } + QString language() { return QString("NoLanguage"); } + void reset() {} + bool isComposing() const { return false; } +}; + +// Testing get/set functions +void tst_QWidget::getSetCheck() +{ + QWidget obj1; + QWidget child1(&obj1); + // QStyle * QWidget::style() + // void QWidget::setStyle(QStyle *) + QWindowsStyle *var1 = new QWindowsStyle; + obj1.setStyle(var1); + QCOMPARE(static_cast(var1), obj1.style()); + obj1.setStyle((QStyle *)0); + QVERIFY(var1 != obj1.style()); + QVERIFY(0 != obj1.style()); // style can never be 0 for a widget + + // int QWidget::minimumWidth() + // void QWidget::setMinimumWidth(int) + obj1.setMinimumWidth(0); + QCOMPARE(obj1.minimumWidth(), 0); + obj1.setMinimumWidth(INT_MIN); + QCOMPARE(obj1.minimumWidth(), 0); // A widgets width can never be less than 0 + obj1.setMinimumWidth(INT_MAX); +#ifndef Q_WS_QWS //QWS doesn't allow toplevels to be bigger than the screen + QCOMPARE(obj1.minimumWidth(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium +#endif + + child1.setMinimumWidth(0); + QCOMPARE(child1.minimumWidth(), 0); + child1.setMinimumWidth(INT_MIN); + QCOMPARE(child1.minimumWidth(), 0); // A widgets width can never be less than 0 + child1.setMinimumWidth(INT_MAX); + QCOMPARE(child1.minimumWidth(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium + + // int QWidget::minimumHeight() + // void QWidget::setMinimumHeight(int) + obj1.setMinimumHeight(0); + QCOMPARE(obj1.minimumHeight(), 0); + obj1.setMinimumHeight(INT_MIN); + QCOMPARE(obj1.minimumHeight(), 0); // A widgets height can never be less than 0 + obj1.setMinimumHeight(INT_MAX); +#ifndef Q_WS_QWS //QWS doesn't allow toplevels to be bigger than the screen + QCOMPARE(obj1.minimumHeight(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium +#endif + + child1.setMinimumHeight(0); + QCOMPARE(child1.minimumHeight(), 0); + child1.setMinimumHeight(INT_MIN); + QCOMPARE(child1.minimumHeight(), 0); // A widgets height can never be less than 0 + child1.setMinimumHeight(INT_MAX); + QCOMPARE(child1.minimumHeight(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium + + // int QWidget::maximumWidth() + // void QWidget::setMaximumWidth(int) + obj1.setMaximumWidth(0); + QCOMPARE(obj1.maximumWidth(), 0); + obj1.setMaximumWidth(INT_MIN); + QCOMPARE(obj1.maximumWidth(), 0); // A widgets width can never be less than 0 + obj1.setMaximumWidth(INT_MAX); + QCOMPARE(obj1.maximumWidth(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX + + // int QWidget::maximumHeight() + // void QWidget::setMaximumHeight(int) + obj1.setMaximumHeight(0); + QCOMPARE(obj1.maximumHeight(), 0); + obj1.setMaximumHeight(INT_MIN); + QCOMPARE(obj1.maximumHeight(), 0); // A widgets height can never be less than 0 + obj1.setMaximumHeight(INT_MAX); + QCOMPARE(obj1.maximumHeight(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX + + // back to normal + obj1.setMinimumWidth(0); + obj1.setMinimumHeight(0); + obj1.setMaximumWidth(QWIDGETSIZE_MAX); + obj1.setMaximumHeight(QWIDGETSIZE_MAX); + + // const QPalette & QWidget::palette() + // void QWidget::setPalette(const QPalette &) + QPalette var6; + obj1.setPalette(var6); + QCOMPARE(var6, obj1.palette()); + obj1.setPalette(QPalette()); + QCOMPARE(QPalette(), obj1.palette()); + + // const QFont & QWidget::font() + // void QWidget::setFont(const QFont &) + QFont var7; + obj1.setFont(var7); + QCOMPARE(var7, obj1.font()); + obj1.setFont(QFont()); + QCOMPARE(QFont(), obj1.font()); + + // qreal QWidget::windowOpacity() + // void QWidget::setWindowOpacity(qreal) + obj1.setWindowOpacity(0.0); + QCOMPARE(0.0, obj1.windowOpacity()); + obj1.setWindowOpacity(1.1f); + QCOMPARE(1.0, obj1.windowOpacity()); // 1.0 is the fullest opacity possible + + // QWidget * QWidget::focusProxy() + // void QWidget::setFocusProxy(QWidget *) + QWidget *var9 = new QWidget(); + obj1.setFocusProxy(var9); + QCOMPARE(var9, obj1.focusProxy()); + obj1.setFocusProxy((QWidget *)0); + QCOMPARE((QWidget *)0, obj1.focusProxy()); + delete var9; + + // const QRect & QWidget::geometry() + // void QWidget::setGeometry(const QRect &) + qApp->processEvents(); + QRect var10(10, 10, 100, 100); + obj1.setGeometry(var10); + qApp->processEvents(); + qDebug() << obj1.geometry(); + QCOMPARE(var10, obj1.geometry()); + obj1.setGeometry(QRect(0,0,0,0)); + qDebug() << obj1.geometry(); + QCOMPARE(QRect(0,0,0,0), obj1.geometry()); + + // QLayout * QWidget::layout() + // void QWidget::setLayout(QLayout *) + QBoxLayout *var11 = new QBoxLayout(QBoxLayout::LeftToRight); + obj1.setLayout(var11); + QCOMPARE(static_cast(var11), obj1.layout()); + obj1.setLayout((QLayout *)0); + QCOMPARE(static_cast(var11), obj1.layout()); // You cannot set a 0-pointer layout, that keeps the current + delete var11; // This will remove the layout from the widget + QCOMPARE((QLayout *)0, obj1.layout()); + + // bool QWidget::acceptDrops() + // void QWidget::setAcceptDrops(bool) + obj1.setAcceptDrops(false); + QCOMPARE(false, obj1.acceptDrops()); + obj1.setAcceptDrops(true); + QCOMPARE(true, obj1.acceptDrops()); + + // QInputContext * QWidget::inputContext() + MyInputContext *var13 = new MyInputContext; + qApp->setInputContext(var13); + QCOMPARE((QInputContext *)0, obj1.inputContext()); // The widget by default doesn't have the WA_InputMethodEnabled attribute + obj1.setAttribute(Qt::WA_InputMethodEnabled); + QCOMPARE(static_cast(var13), obj1.inputContext()); + + // bool QWidget::autoFillBackground() + // void QWidget::setAutoFillBackground(bool) + obj1.setAutoFillBackground(false); + QCOMPARE(false, obj1.autoFillBackground()); + obj1.setAutoFillBackground(true); + QCOMPARE(true, obj1.autoFillBackground()); + + delete var1; +#if defined (Q_WS_WIN) && !defined(Q_OS_WINCE) + obj1.setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + HWND handle = obj1.winId(); + long flags = GetWindowLong(handle, GWL_STYLE); + QVERIFY(flags & WS_POPUP); +#endif +} + +tst_QWidget::tst_QWidget() +{ + QFont font; + font.setBold(true); + font.setPointSize(42); + qApp->setFont(font, "QPropagationTestWidget"); + + QPalette palette; + palette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + palette.setColor(QPalette::Text, QColor(21, 22, 23)); + qApp->setPalette(palette, "QPropagationTestWidget"); + + testWidget = 0; +} + +tst_QWidget::~tst_QWidget() +{ +} + +class BezierViewer : public QWidget { +public: + BezierViewer( QWidget* parent=0, const char* name=0 ); + void paintEvent( QPaintEvent* ); + void setPoints( const QPolygonF& poly ); +private: + QPolygonF points; + +}; + +void tst_QWidget::initTestCase() +{ +#ifdef Q_OS_WINCE //disable magic for WindowsCE + qApp->setAutoMaximizeThreshold(-1); +#endif + // Create the test class + testWidget = new BezierViewer( 0, "testObject"); + testWidget->resize(200,200); + testWidget->show(); + QTest::qWaitForWindowShown(testWidget); + QTest::qWait(50); +} + +void tst_QWidget::cleanupTestCase() +{ + delete testWidget; + testWidget = 0; +} + +void tst_QWidget::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. + testWidget->setFont(QFont()); + testWidget->setPalette(QPalette()); +} + +void tst_QWidget::cleanup() +{ +} + +// Helper class... + +BezierViewer::BezierViewer( QWidget* parent, const char* name ) + : QWidget( parent ) +{ + setObjectName(name); + QPalette pal; + pal.setColor(backgroundRole(), Qt::white); + setPalette(pal); +} + + +void BezierViewer::setPoints( const QPolygonF& a ) +{ + points = a; +} + +#include "private/qbezier_p.h" +void BezierViewer::paintEvent( QPaintEvent* ) +{ + if ( points.size() != 4 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QPolygon::bezier: The array must have 4 control points" ); +#endif + return; + } + + /* Calculate Bezier curve */ + QPolygonF bezier = QBezier::fromPoints(points.at(0),points.at(1),points.at(2),points.at(3)).toPolygon(); + + QPainter painter( this ); + + /* Calculate scale to fit in window */ + QRectF br = bezier.boundingRect() | points.boundingRect(); + QRectF pr = rect(); + int scl = qMax( qMin(pr.width()/br.width(), pr.height()/br.height()), qreal(1.) ); + int border = scl-1; + + /* Scale Bezier curve vertices */ + for ( QPolygonF::Iterator it = bezier.begin(); it != bezier.end(); ++it ) { + it->setX( (it->x()-br.x()) * scl + border ); + it->setY( (it->y()-br.y()) * scl + border ); + } + + /* Draw grid */ + painter.setPen( Qt::lightGray ); + int i; + for ( i = border; i <= pr.width(); i += scl ) { + painter.drawLine( i, 0, i, pr.height() ); + } + for ( int j = border; j <= pr.height(); j += scl ) { + painter.drawLine( 0, j, pr.width(), j ); + } + + /* Write number of vertices */ + painter.setPen( Qt::red ); + painter.setFont( QFont("Helvetica", 14, QFont::DemiBold, TRUE ) ); + QString caption; + caption.setNum( bezier.size() ); + caption += QString::fromLatin1( " vertices" ); + painter.drawText( 10, pr.height()-10, caption ); + + /* Draw Bezier curve */ + painter.setPen( Qt::black ); + painter.drawPolyline( bezier ); + + /* Scale and draw control points */ + painter.setPen( Qt::darkGreen ); + for ( QPolygonF::Iterator p1 = points.begin(); p1 != points.end(); ++p1 ) { + int x = (p1->x()-br.x()) * scl + border; + int y = (p1->y()-br.y()) * scl + border; + painter.drawLine( x-4, y-4, x+4, y+4 ); + painter.drawLine( x+4, y-4, x-4, y+4 ); + } + + /* Draw vertices */ + painter.setPen( Qt::red ); + painter.setBrush( Qt::red ); + for ( QPolygonF::Iterator p2 = bezier.begin(); p2 != bezier.end(); ++p2 ) + painter.drawEllipse( p2->x()-1, p2->y()-1, 3, 3 ); +} + +void tst_QWidget::fontPropagation() +{ + QFont font = testWidget->font(); + QWidget* childWidget = new QWidget( testWidget ); + childWidget->show(); + QCOMPARE( font, childWidget->font() ); + + font.setBold( TRUE ); + testWidget->setFont( font ); + QCOMPARE( font, testWidget->font() ); + QCOMPARE( font, childWidget->font() ); + + QFont newFont = font; + newFont.setItalic( TRUE ); + childWidget->setFont( newFont ); + QWidget* grandChildWidget = new QWidget( childWidget ); + QCOMPARE( font, testWidget->font() ); + QCOMPARE( newFont, grandChildWidget->font() ); + + font.setUnderline( TRUE ); + testWidget->setFont( font ); + + // the child and grand child should now have merged bold and + // underline + newFont.setUnderline( TRUE ); + + QCOMPARE( newFont, childWidget->font() ); + QCOMPARE( newFont, grandChildWidget->font() ); + + // make sure font propagation continues working after reparenting + font = testWidget->font(); + font.setPointSize(font.pointSize() + 2); + testWidget->setFont(font); + + QWidget *one = new QWidget(testWidget); + QWidget *two = new QWidget(one); + QWidget *three = new QWidget(two); + QWidget *four = new QWidget(two); + + four->setParent(three); + four->move(QPoint(0,0)); + + font.setPointSize(font.pointSize() + 2); + testWidget->setFont(font); + + QCOMPARE(testWidget->font(), one->font()); + QCOMPARE(one->font(), two->font()); + QCOMPARE(two->font(), three->font()); + QCOMPARE(three->font(), four->font()); + + QVERIFY(testWidget->testAttribute(Qt::WA_SetFont)); + QVERIFY(! one->testAttribute(Qt::WA_SetFont)); + QVERIFY(! two->testAttribute(Qt::WA_SetFont)); + QVERIFY(! three->testAttribute(Qt::WA_SetFont)); + QVERIFY(! four->testAttribute(Qt::WA_SetFont)); + + font.setPointSize(font.pointSize() + 2); + one->setFont(font); + + QCOMPARE(one->font(), two->font()); + QCOMPARE(two->font(), three->font()); + QCOMPARE(three->font(), four->font()); + + QVERIFY(one->testAttribute(Qt::WA_SetFont)); + QVERIFY(! two->testAttribute(Qt::WA_SetFont)); + QVERIFY(! three->testAttribute(Qt::WA_SetFont)); + QVERIFY(! four->testAttribute(Qt::WA_SetFont)); + + font.setPointSize(font.pointSize() + 2); + two->setFont(font); + + QCOMPARE(two->font(), three->font()); + QCOMPARE(three->font(), four->font()); + + QVERIFY(two->testAttribute(Qt::WA_SetFont)); + QVERIFY(! three->testAttribute(Qt::WA_SetFont)); + QVERIFY(! four->testAttribute(Qt::WA_SetFont)); + + font.setPointSize(font.pointSize() + 2); + three->setFont(font); + + QCOMPARE(three->font(), four->font()); + + QVERIFY(three->testAttribute(Qt::WA_SetFont)); + QVERIFY(! four->testAttribute(Qt::WA_SetFont)); + + font.setPointSize(font.pointSize() + 2); + four->setFont(font); + + QVERIFY(four->testAttribute(Qt::WA_SetFont)); +} + +class QPropagationTestWidget : public QWidget +{ + Q_OBJECT +public: + QPropagationTestWidget(QWidget *parent = 0) + : QWidget(parent) + { } +}; + +void tst_QWidget::fontPropagation2() +{ + // ! Note, the code below is executed in tst_QWidget's constructor. + // QFont font; + // font.setBold(true); + // font.setPointSize(42); + // qApp->setFont(font, "QPropagationTestWidget"); + + QWidget *root = new QWidget; + QWidget *child0 = new QWidget(root); + QWidget *child1 = new QWidget(child0); + QWidget *child2 = new QPropagationTestWidget(child1); + QWidget *child3 = new QWidget(child2); + QWidget *child4 = new QWidget(child3); + QWidget *child5 = new QWidget(child4); + root->show(); + + // Check that only the application fonts apply. + QCOMPARE(root->font(), QApplication::font()); + QCOMPARE(child0->font(), QApplication::font()); + QCOMPARE(child1->font(), QApplication::font()); + QCOMPARE(child2->font().pointSize(), 42); + QVERIFY(child2->font().bold()); + QCOMPARE(child3->font().pointSize(), 42); + QVERIFY(child3->font().bold()); + QCOMPARE(child4->font().pointSize(), 42); + QVERIFY(child4->font().bold()); + QCOMPARE(child5->font().pointSize(), 42); + QVERIFY(child5->font().bold()); + + // Set child0's font size to 15, and remove bold on child4. + QFont font; + font.setPointSize(15); + child0->setFont(font); + QFont unboldFont; + unboldFont.setBold(false); + child4->setFont(unboldFont); + + // Check that the above settings propagate correctly. + QCOMPARE(root->font(), QApplication::font()); + QCOMPARE(child0->font().pointSize(), 15); + QVERIFY(!child0->font().bold()); + QCOMPARE(child1->font().pointSize(), 15); + QVERIFY(!child1->font().bold()); + QCOMPARE(child2->font().pointSize(), 15); + QVERIFY(child2->font().bold()); + QCOMPARE(child3->font().pointSize(), 15); + QVERIFY(child3->font().bold()); + QCOMPARE(child4->font().pointSize(), 15); + QVERIFY(!child4->font().bold()); + QCOMPARE(child5->font().pointSize(), 15); + QVERIFY(!child5->font().bold()); + + // Replace the app font for child2. Italic should propagate + // but the size should still be ignored. The previous bold + // setting is gone. + QFont italicSizeFont; + italicSizeFont.setItalic(true); + italicSizeFont.setPointSize(33); + qApp->setFont(italicSizeFont, "QPropagationTestWidget"); + + // Check that this propagates correctly. + QCOMPARE(root->font(), QApplication::font()); + QCOMPARE(child0->font().pointSize(), 15); + QVERIFY(!child0->font().bold()); + QVERIFY(!child0->font().italic()); + QCOMPARE(child1->font().pointSize(), 15); + QVERIFY(!child1->font().bold()); + QVERIFY(!child1->font().italic()); + QCOMPARE(child2->font().pointSize(), 15); + QVERIFY(!child2->font().bold()); + QVERIFY(child2->font().italic()); + QCOMPARE(child3->font().pointSize(), 15); + QVERIFY(!child3->font().bold()); + QVERIFY(child3->font().italic()); + QCOMPARE(child4->font().pointSize(), 15); + QVERIFY(!child4->font().bold()); + QVERIFY(child4->font().italic()); + QCOMPARE(child5->font().pointSize(), 15); + QVERIFY(!child5->font().bold()); + QVERIFY(child5->font().italic()); +} + +void tst_QWidget::palettePropagation() +{ + QPalette palette = testWidget->palette(); + QWidget* childWidget = new QWidget( testWidget ); + childWidget->show(); + QCOMPARE( palette, childWidget->palette() ); + + palette.setColor( QPalette::Base, Qt::red ); + testWidget->setPalette( palette ); + QCOMPARE( palette, testWidget->palette() ); + QCOMPARE( palette, childWidget->palette() ); + + QPalette newPalette = palette; + newPalette.setColor( QPalette::Highlight, Qt::green ); + childWidget->setPalette( newPalette ); + QWidget* grandChildWidget = new QWidget( childWidget ); + QCOMPARE( palette, testWidget->palette() ); + QCOMPARE( newPalette, grandChildWidget->palette() ); + + palette.setColor( QPalette::Text, Qt::blue ); + testWidget->setPalette( palette ); + + // the child and grand child should now have merged green + // highlight and blue text + newPalette.setColor( QPalette::Text, Qt::blue); + + QCOMPARE( newPalette, childWidget->palette() ); + QCOMPARE( newPalette, grandChildWidget->palette() ); +} + +void tst_QWidget::palettePropagation2() +{ + // ! Note, the code below is executed in tst_QWidget's constructor. + // QPalette palette; + // font.setColor(QPalette::ToolTipBase, QColor(12, 13, 14)); + // font.setColor(QPalette::Text, QColor(21, 22, 23)); + // qApp->setPalette(palette, "QPropagationTestWidget"); + + QWidget *root = new QWidget; + QWidget *child0 = new QWidget(root); + QWidget *child1 = new QWidget(child0); + QWidget *child2 = new QPropagationTestWidget(child1); + QWidget *child3 = new QWidget(child2); + QWidget *child4 = new QWidget(child3); + QWidget *child5 = new QWidget(child4); + root->show(); + QTest::qWait(100); + + // These colors are unlikely to be imposed on the default palette of + // QWidget ;-). + QColor sysPalText(21, 22, 23); + QColor sysPalToolTipBase(12, 13, 14); + QColor overridePalText(42, 43, 44); + QColor overridePalToolTipBase(45, 46, 47); + QColor sysPalButton(99, 98, 97); + + // Check that only the application fonts apply. + QPalette appPal = QApplication::palette(); + QCOMPARE(root->palette(), appPal); + QCOMPARE(child0->palette(), appPal); + QCOMPARE(child1->palette(), appPal); + QCOMPARE(child2->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child2->palette().color(QPalette::Text), sysPalText); + QCOMPARE(child2->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child3->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child3->palette().color(QPalette::Text), sysPalText); + QCOMPARE(child3->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child4->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child4->palette().color(QPalette::Text), sysPalText); + QCOMPARE(child4->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child5->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child5->palette().color(QPalette::Text), sysPalText); + QCOMPARE(child5->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + + // Set child0's Text, and set ToolTipBase on child4. + QPalette textPalette; + textPalette.setColor(QPalette::Text, overridePalText); + child0->setPalette(textPalette); + QPalette toolTipPalette; + toolTipPalette.setColor(QPalette::ToolTipBase, overridePalToolTipBase); + child4->setPalette(toolTipPalette); + + // Check that the above settings propagate correctly. + QCOMPARE(root->palette(), appPal); + QCOMPARE(child0->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child0->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child0->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child1->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child1->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child1->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child2->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child2->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child2->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child3->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child3->palette().color(QPalette::ToolTipBase), sysPalToolTipBase); + QCOMPARE(child3->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child4->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child4->palette().color(QPalette::ToolTipBase), overridePalToolTipBase); + QCOMPARE(child4->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child5->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child5->palette().color(QPalette::ToolTipBase), overridePalToolTipBase); + QCOMPARE(child5->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + + // Replace the app palette for child2. Button should propagate but Text + // should still be ignored. The previous ToolTipBase setting is gone. + QPalette buttonPalette; + buttonPalette.setColor(QPalette::ToolTipText, sysPalButton); + qApp->setPalette(buttonPalette, "QPropagationTestWidget"); + + // Check that the above settings propagate correctly. + QCOMPARE(root->palette(), appPal); + QCOMPARE(child0->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child0->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child0->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child1->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child1->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child1->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText)); + QCOMPARE(child2->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child2->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child2->palette().color(QPalette::ToolTipText), sysPalButton); + QCOMPARE(child3->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child3->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase)); + QCOMPARE(child3->palette().color(QPalette::ToolTipText), sysPalButton); + QCOMPARE(child4->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child4->palette().color(QPalette::ToolTipBase), overridePalToolTipBase); + QCOMPARE(child4->palette().color(QPalette::ToolTipText), sysPalButton); + QCOMPARE(child5->palette().color(QPalette::Text), overridePalText); + QCOMPARE(child5->palette().color(QPalette::ToolTipBase), overridePalToolTipBase); + QCOMPARE(child5->palette().color(QPalette::ToolTipText), sysPalButton); +} + +void tst_QWidget::enabledPropagation() +{ + QWidget* childWidget = new QWidget( testWidget ); + childWidget->show(); + QVERIFY( testWidget->isEnabled() ); + QVERIFY( childWidget->isEnabled() ); + + testWidget->setEnabled( FALSE ); + QVERIFY( !testWidget->isEnabled() ); + QVERIFY( !childWidget->isEnabled() ); + + testWidget->setDisabled( FALSE ); + QVERIFY( testWidget->isEnabled() ); + QVERIFY( childWidget->isEnabled() ); + + QWidget* grandChildWidget = new QWidget( childWidget ); + QVERIFY( grandChildWidget->isEnabled() ); + + testWidget->setDisabled( TRUE ); + QVERIFY( !testWidget->isEnabled() ); + QVERIFY( !childWidget->isEnabled() ); + QVERIFY( !grandChildWidget->isEnabled() ); + + grandChildWidget->setEnabled( FALSE ); + testWidget->setEnabled( TRUE ); + QVERIFY( testWidget->isEnabled() ); + QVERIFY( childWidget->isEnabled() ); + QVERIFY( !grandChildWidget->isEnabled() ); + + grandChildWidget->setEnabled( TRUE ); + testWidget->setEnabled( FALSE ); + childWidget->setDisabled( TRUE ); + testWidget->setEnabled( TRUE ); + QVERIFY( testWidget->isEnabled() ); + QVERIFY( !childWidget->isEnabled() ); + QVERIFY( !grandChildWidget->isEnabled() ); +} + +// Drag'n drop disabled in this build. +#ifndef QT_NO_DRAGANDDROP +void tst_QWidget::acceptDropsPropagation() +{ + QWidget *childWidget = new QWidget(testWidget); + childWidget->show(); + QVERIFY(!testWidget->acceptDrops()); + QVERIFY(!childWidget->acceptDrops()); + + testWidget->setAcceptDrops(true); + QVERIFY(testWidget->acceptDrops()); + QVERIFY(!childWidget->acceptDrops()); + QVERIFY(childWidget->testAttribute(Qt::WA_DropSiteRegistered)); + + testWidget->setAcceptDrops(false); + QVERIFY(!testWidget->acceptDrops()); + QVERIFY(!childWidget->acceptDrops()); + QVERIFY(!childWidget->testAttribute(Qt::WA_DropSiteRegistered)); + + QWidget *grandChildWidget = new QWidget(childWidget); + QVERIFY(!grandChildWidget->acceptDrops()); + QVERIFY(!grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered)); + + testWidget->setAcceptDrops(true); + QVERIFY(testWidget->acceptDrops()); + QVERIFY(!childWidget->acceptDrops()); + QVERIFY(childWidget->testAttribute(Qt::WA_DropSiteRegistered)); + QVERIFY(!grandChildWidget->acceptDrops()); + QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered)); + + grandChildWidget->setAcceptDrops(true); + testWidget->setAcceptDrops(false); + QVERIFY(!testWidget->acceptDrops()); + QVERIFY(!childWidget->acceptDrops()); + QVERIFY(grandChildWidget->acceptDrops()); + QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered)); + + grandChildWidget->setAcceptDrops(false); + QVERIFY(!grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered)); + testWidget->setAcceptDrops(true); + childWidget->setAcceptDrops(true); + testWidget->setAcceptDrops(false); + QVERIFY(!testWidget->acceptDrops()); + QVERIFY(childWidget->acceptDrops()); + QVERIFY(!grandChildWidget->acceptDrops()); + QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered)); +} +#endif + +void tst_QWidget::isEnabledTo() +{ + QWidget* childWidget = new QWidget( testWidget ); + QWidget* grandChildWidget = new QWidget( childWidget ); + + QVERIFY( childWidget->isEnabledTo( testWidget ) ); + QVERIFY( grandChildWidget->isEnabledTo( testWidget ) ); + + childWidget->setEnabled( FALSE ); + QVERIFY( !childWidget->isEnabledTo( testWidget ) ); + QVERIFY( grandChildWidget->isEnabledTo( childWidget ) ); + QVERIFY( !grandChildWidget->isEnabledTo( testWidget ) ); +} + +void tst_QWidget::visible() +{ + // Ensure that the testWidget is hidden for this test at the + // start + + testWidget->hide(); + QVERIFY( !testWidget->isVisible() ); + QWidget* childWidget = new QWidget( testWidget ); + QVERIFY( !childWidget->isVisible() ); + + testWidget->show(); + QVERIFY( testWidget->isVisible() ); + QVERIFY( childWidget->isVisible() ); + + QWidget* grandChildWidget = new QWidget( childWidget ); + QVERIFY( !grandChildWidget->isVisible() ); + grandChildWidget->show(); + QVERIFY( grandChildWidget->isVisible() ); + + grandChildWidget->hide(); + testWidget->hide(); + testWidget->show(); + QVERIFY( !grandChildWidget->isVisible() ); + QVERIFY( testWidget->isVisible() ); + QVERIFY( childWidget->isVisible() ); + + grandChildWidget->show(); + childWidget->hide(); + testWidget->hide(); + testWidget->show(); + QVERIFY( testWidget->isVisible() ); + QVERIFY( !childWidget->isVisible() ); + QVERIFY( !grandChildWidget->isVisible() ); + + grandChildWidget->show(); + QVERIFY( !grandChildWidget->isVisible() ); +} + +void tst_QWidget::setLocale() +{ + QWidget w; + QCOMPARE(w.locale(), QLocale()); + + w.setLocale(QLocale::Italian); + QCOMPARE(w.locale(), QLocale(QLocale::Italian)); + + QWidget child1(&w); + QCOMPARE(child1.locale(), QLocale(QLocale::Italian)); + + w.unsetLocale(); + QCOMPARE(w.locale(), QLocale()); + QCOMPARE(child1.locale(), QLocale()); + + w.setLocale(QLocale::French); + QCOMPARE(w.locale(), QLocale(QLocale::French)); + QCOMPARE(child1.locale(), QLocale(QLocale::French)); + + child1.setLocale(QLocale::Italian); + QCOMPARE(w.locale(), QLocale(QLocale::French)); + QCOMPARE(child1.locale(), QLocale(QLocale::Italian)); + + child1.unsetLocale(); + QCOMPARE(w.locale(), QLocale(QLocale::French)); + QCOMPARE(child1.locale(), QLocale(QLocale::French)); + + QWidget child2; + QCOMPARE(child2.locale(), QLocale()); + child2.setParent(&w); + QCOMPARE(child2.locale(), QLocale(QLocale::French)); +} + +void tst_QWidget::visible_setWindowOpacity() +{ + testWidget->hide(); + QVERIFY( !testWidget->isVisible() ); + testWidget->setWindowOpacity(0.5); +#ifdef Q_OS_WIN + QVERIFY(::IsWindowVisible(winHandleOf(testWidget)) == FALSE); +#endif + testWidget->setWindowOpacity(1.0); +} + +void tst_QWidget::isVisibleTo() +{ + // Ensure that the testWidget is hidden for this test at the + // start + + testWidget->hide(); + QWidget* childWidget = new QWidget( testWidget ); + QVERIFY( childWidget->isVisibleTo( testWidget ) ); + childWidget->hide(); + QVERIFY( !childWidget->isVisibleTo( testWidget ) ); + + QWidget* grandChildWidget = new QWidget( childWidget ); + QVERIFY( !grandChildWidget->isVisibleTo( testWidget ) ); + QVERIFY( grandChildWidget->isVisibleTo( childWidget ) ); + + testWidget->show(); + childWidget->show(); + + QVERIFY( childWidget->isVisibleTo( testWidget ) ); + grandChildWidget->hide(); + QVERIFY( !grandChildWidget->isVisibleTo( childWidget ) ); + QVERIFY( !grandChildWidget->isVisibleTo( testWidget ) ); + +} + +void tst_QWidget::isHidden() +{ + // Ensure that the testWidget is hidden for this test at the + // start + + testWidget->hide(); + QVERIFY( testWidget->isHidden() ); + QWidget* childWidget = new QWidget( testWidget ); + QVERIFY( !childWidget->isHidden() ); + + testWidget->show(); + QVERIFY( !testWidget->isHidden() ); + QVERIFY( !childWidget->isHidden() ); + + QWidget* grandChildWidget = new QWidget( childWidget ); + QVERIFY( grandChildWidget->isHidden() ); + grandChildWidget->show(); + QVERIFY( !grandChildWidget->isHidden() ); + + grandChildWidget->hide(); + testWidget->hide(); + testWidget->show(); + QVERIFY( grandChildWidget->isHidden() ); + QVERIFY( !testWidget->isHidden() ); + QVERIFY( !childWidget->isHidden() ); + + grandChildWidget->show(); + childWidget->hide(); + testWidget->hide(); + testWidget->show(); + QVERIFY( !testWidget->isHidden() ); + QVERIFY( childWidget->isHidden() ); + QVERIFY( !grandChildWidget->isHidden() ); + + grandChildWidget->show(); + QVERIFY( !grandChildWidget->isHidden() ); +} + +void tst_QWidget::fonts() +{ + // Tests setFont(), ownFont() and unsetFont() + QWidget* cleanTestWidget = new QWidget( testWidget ); + QFont originalFont = cleanTestWidget->font(); + + QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) ); + cleanTestWidget->setFont(QFont()); + QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) ); + + QFont newFont( "times", 18 ); + cleanTestWidget->setFont( newFont ); + newFont = newFont.resolve( testWidget->font() ); + + QVERIFY( cleanTestWidget->testAttribute(Qt::WA_SetFont) ); + QVERIFY( cleanTestWidget->font() == newFont ); + + cleanTestWidget->setFont(QFont()); + QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) ); + QVERIFY( cleanTestWidget->font() == originalFont ); +} + +void tst_QWidget::mapFromAndTo_data() +{ + QTest::addColumn("windowHidden"); + QTest::addColumn("subWindow1Hidden"); + QTest::addColumn("subWindow2Hidden"); + QTest::addColumn("subSubWindowHidden"); + QTest::addColumn("windowMinimized"); + QTest::addColumn("subWindow1Minimized"); + + QTest::newRow("window 1 sub1 1 sub2 1 subsub 1") << false << false << false << false << false << false; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 1") << true << false << false << false << false << false; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 1") << false << true << false << false << false << false; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 1") << true << true << false << false << false << false; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 1") << false << false << true << false << false << false; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 1") << true << false << true << false << false << false; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 1") << false << true << true << false << false << false; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 1") << true << true << true << false << false << false; + QTest::newRow("window 1 sub1 1 sub2 1 subsub 0") << false << false << false << true << false << false; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 0") << true << false << false << true << false << false; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 0") << false << true << false << true << false << false; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 0") << true << true << false << true << false << false; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 0") << false << false << true << true << false << false; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 0") << true << false << true << true << false << false; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 0") << false << true << true << true << false << false; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 0") << true << true << true << true << false << false; + QTest::newRow("window 1 sub1 1 sub2 1 subsub 1 windowMinimized") << false << false << false << false << true << false; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 1 windowMinimized") << true << false << false << false << true << false; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 1 windowMinimized") << false << true << false << false << true << false; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 1 windowMinimized") << true << true << false << false << true << false; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 1 windowMinimized") << false << false << true << false << true << false; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 1 windowMinimized") << true << false << true << false << true << false; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 1 windowMinimized") << false << true << true << false << true << false; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 1 windowMinimized") << true << true << true << false << true << false; + QTest::newRow("window 1 sub1 1 sub2 1 subsub 0 windowMinimized") << false << false << false << true << true << false; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 0 windowMinimized") << true << false << false << true << true << false; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 0 windowMinimized") << false << true << false << true << true << false; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 0 windowMinimized") << true << true << false << true << true << false; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 0 windowMinimized") << false << false << true << true << true << false; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 0 windowMinimized") << true << false << true << true << true << false; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 0 windowMinimized") << false << true << true << true << true << false; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 0 windowMinimized") << true << true << true << true << true << false; + QTest::newRow("window 1 sub1 1 sub2 1 subsub 1 subWindow1Minimized") << false << false << false << false << false << true; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 1 subWindow1Minimized") << true << false << false << false << false << true; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 1 subWindow1Minimized") << false << true << false << false << false << true; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 1 subWindow1Minimized") << true << true << false << false << false << true; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 1 subWindow1Minimized") << false << false << true << false << false << true; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 1 subWindow1Minimized") << true << false << true << false << false << true; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 1 subWindow1Minimized") << false << true << true << false << false << true; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 1 subWindow1Minimized") << true << true << true << false << false << true; + QTest::newRow("window 1 sub1 1 sub2 1 subsub 0 subWindow1Minimized") << false << false << false << true << false << true; + QTest::newRow("window 0 sub1 1 sub2 1 subsub 0 subWindow1Minimized") << true << false << false << true << false << true; + QTest::newRow("window 1 sub1 0 sub2 1 subsub 0 subWindow1Minimized") << false << true << false << true << false << true; + QTest::newRow("window 0 sub1 0 sub2 1 subsub 0 subWindow1Minimized") << true << true << false << true << false << true; + QTest::newRow("window 1 sub1 1 sub2 0 subsub 0 subWindow1Minimized") << false << false << true << true << false << true; + QTest::newRow("window 0 sub1 1 sub2 0 subsub 0 subWindow1Minimized") << true << false << true << true << false << true; + QTest::newRow("window 1 sub1 0 sub2 0 subsub 0 subWindow1Minimized") << false << true << true << true << false << true; + QTest::newRow("window 0 sub1 0 sub2 0 subsub 0 subWindow1Minimized") << true << true << true << true << false << true; + + +} + +void tst_QWidget::mapFromAndTo() +{ + QFETCH(bool, windowHidden); + QFETCH(bool, subWindow1Hidden); + QFETCH(bool, subWindow2Hidden); + QFETCH(bool, subSubWindowHidden); + QFETCH(bool, windowMinimized); + QFETCH(bool, subWindow1Minimized); + + // create a toplevel and two overlapping siblings + QWidget window; + window.setWindowFlags(window.windowFlags() | Qt::X11BypassWindowManagerHint); + QWidget *subWindow1 = new QWidget(&window); + QWidget *subWindow2 = new QWidget(&window); + QWidget *subSubWindow = new QWidget(subWindow1); + + // set their geometries + window.setGeometry(100, 100, 100, 100); + subWindow1->setGeometry(50, 50, 100, 100); + subWindow2->setGeometry(75, 75, 100, 100); + subSubWindow->setGeometry(10, 10, 10, 10); + +#if !defined (Q_OS_WINCE) //still no proper minimizing + //update visibility + if (windowMinimized) { + if (!windowHidden) { + window.showMinimized(); + QVERIFY(window.isMinimized()); + } + } else { + window.setVisible(!windowHidden); + } + if (subWindow1Minimized) { + subWindow1->hide(); + subWindow1->showMinimized(); + QVERIFY(subWindow1->isMinimized()); + } else { + subWindow1->setVisible(!subWindow1Hidden); + } +#else + Q_UNUSED(windowHidden); + Q_UNUSED(subWindow1Hidden); + Q_UNUSED(windowMinimized); + Q_UNUSED(subWindow1Minimized); +#endif + + subWindow2->setVisible(!subWindow2Hidden); + subSubWindow->setVisible(!subSubWindowHidden); + + // window + QCOMPARE(window.mapToGlobal(QPoint(0, 0)), QPoint(100, 100)); + QCOMPARE(window.mapToGlobal(QPoint(10, 0)), QPoint(110, 100)); + QCOMPARE(window.mapToGlobal(QPoint(0, 10)), QPoint(100, 110)); + QCOMPARE(window.mapToGlobal(QPoint(-10, 0)), QPoint(90, 100)); + QCOMPARE(window.mapToGlobal(QPoint(0, -10)), QPoint(100, 90)); + QCOMPARE(window.mapToGlobal(QPoint(100, 100)), QPoint(200, 200)); + QCOMPARE(window.mapToGlobal(QPoint(110, 100)), QPoint(210, 200)); + QCOMPARE(window.mapToGlobal(QPoint(100, 110)), QPoint(200, 210)); + QCOMPARE(window.mapFromGlobal(QPoint(100, 100)), QPoint(0, 0)); + QCOMPARE(window.mapFromGlobal(QPoint(110, 100)), QPoint(10, 0)); + QCOMPARE(window.mapFromGlobal(QPoint(100, 110)), QPoint(0, 10)); + QCOMPARE(window.mapFromGlobal(QPoint(90, 100)), QPoint(-10, 0)); + QCOMPARE(window.mapFromGlobal(QPoint(100, 90)), QPoint(0, -10)); + QCOMPARE(window.mapFromGlobal(QPoint(200, 200)), QPoint(100, 100)); + QCOMPARE(window.mapFromGlobal(QPoint(210, 200)), QPoint(110, 100)); + QCOMPARE(window.mapFromGlobal(QPoint(200, 210)), QPoint(100, 110)); + QCOMPARE(window.mapToParent(QPoint(0, 0)), QPoint(100, 100)); + QCOMPARE(window.mapToParent(QPoint(10, 0)), QPoint(110, 100)); + QCOMPARE(window.mapToParent(QPoint(0, 10)), QPoint(100, 110)); + QCOMPARE(window.mapToParent(QPoint(-10, 0)), QPoint(90, 100)); + QCOMPARE(window.mapToParent(QPoint(0, -10)), QPoint(100, 90)); + QCOMPARE(window.mapToParent(QPoint(100, 100)), QPoint(200, 200)); + QCOMPARE(window.mapToParent(QPoint(110, 100)), QPoint(210, 200)); + QCOMPARE(window.mapToParent(QPoint(100, 110)), QPoint(200, 210)); + QCOMPARE(window.mapFromParent(QPoint(100, 100)), QPoint(0, 0)); + QCOMPARE(window.mapFromParent(QPoint(110, 100)), QPoint(10, 0)); + QCOMPARE(window.mapFromParent(QPoint(100, 110)), QPoint(0, 10)); + QCOMPARE(window.mapFromParent(QPoint(90, 100)), QPoint(-10, 0)); + QCOMPARE(window.mapFromParent(QPoint(100, 90)), QPoint(0, -10)); + QCOMPARE(window.mapFromParent(QPoint(200, 200)), QPoint(100, 100)); + QCOMPARE(window.mapFromParent(QPoint(210, 200)), QPoint(110, 100)); + QCOMPARE(window.mapFromParent(QPoint(200, 210)), QPoint(100, 110)); + + // first subwindow + QCOMPARE(subWindow1->mapToGlobal(QPoint(0, 0)), QPoint(150, 150)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(10, 0)), QPoint(160, 150)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(0, 10)), QPoint(150, 160)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(-10, 0)), QPoint(140, 150)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(0, -10)), QPoint(150, 140)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(100, 100)), QPoint(250, 250)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(110, 100)), QPoint(260, 250)); + QCOMPARE(subWindow1->mapToGlobal(QPoint(100, 110)), QPoint(250, 260)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 150)), QPoint(0, 0)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(160, 150)), QPoint(10, 0)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 160)), QPoint(0, 10)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(140, 150)), QPoint(-10, 0)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 140)), QPoint(0, -10)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(250, 250)), QPoint(100, 100)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(260, 250)), QPoint(110, 100)); + QCOMPARE(subWindow1->mapFromGlobal(QPoint(250, 260)), QPoint(100, 110)); + QCOMPARE(subWindow1->mapToParent(QPoint(0, 0)), QPoint(50, 50)); + QCOMPARE(subWindow1->mapToParent(QPoint(10, 0)), QPoint(60, 50)); + QCOMPARE(subWindow1->mapToParent(QPoint(0, 10)), QPoint(50, 60)); + QCOMPARE(subWindow1->mapToParent(QPoint(-10, 0)), QPoint(40, 50)); + QCOMPARE(subWindow1->mapToParent(QPoint(0, -10)), QPoint(50, 40)); + QCOMPARE(subWindow1->mapToParent(QPoint(100, 100)), QPoint(150, 150)); + QCOMPARE(subWindow1->mapToParent(QPoint(110, 100)), QPoint(160, 150)); + QCOMPARE(subWindow1->mapToParent(QPoint(100, 110)), QPoint(150, 160)); + QCOMPARE(subWindow1->mapFromParent(QPoint(50, 50)), QPoint(0, 0)); + QCOMPARE(subWindow1->mapFromParent(QPoint(60, 50)), QPoint(10, 0)); + QCOMPARE(subWindow1->mapFromParent(QPoint(50, 60)), QPoint(0, 10)); + QCOMPARE(subWindow1->mapFromParent(QPoint(40, 50)), QPoint(-10, 0)); + QCOMPARE(subWindow1->mapFromParent(QPoint(50, 40)), QPoint(0, -10)); + QCOMPARE(subWindow1->mapFromParent(QPoint(150, 150)), QPoint(100, 100)); + QCOMPARE(subWindow1->mapFromParent(QPoint(160, 150)), QPoint(110, 100)); + QCOMPARE(subWindow1->mapFromParent(QPoint(150, 160)), QPoint(100, 110)); + + // subsubwindow + QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, 0)), QPoint(160, 160)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(10, 0)), QPoint(170, 160)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, 10)), QPoint(160, 170)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(-10, 0)), QPoint(150, 160)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, -10)), QPoint(160, 150)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(100, 100)), QPoint(260, 260)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(110, 100)), QPoint(270, 260)); + QCOMPARE(subSubWindow->mapToGlobal(QPoint(100, 110)), QPoint(260, 270)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 160)), QPoint(0, 0)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(170, 160)), QPoint(10, 0)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 170)), QPoint(0, 10)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(150, 160)), QPoint(-10, 0)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 150)), QPoint(0, -10)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(260, 260)), QPoint(100, 100)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(270, 260)), QPoint(110, 100)); + QCOMPARE(subSubWindow->mapFromGlobal(QPoint(260, 270)), QPoint(100, 110)); + QCOMPARE(subSubWindow->mapToParent(QPoint(0, 0)), QPoint(10, 10)); + QCOMPARE(subSubWindow->mapToParent(QPoint(10, 0)), QPoint(20, 10)); + QCOMPARE(subSubWindow->mapToParent(QPoint(0, 10)), QPoint(10, 20)); + QCOMPARE(subSubWindow->mapToParent(QPoint(-10, 0)), QPoint(0, 10)); + QCOMPARE(subSubWindow->mapToParent(QPoint(0, -10)), QPoint(10, 0)); + QCOMPARE(subSubWindow->mapToParent(QPoint(100, 100)), QPoint(110, 110)); + QCOMPARE(subSubWindow->mapToParent(QPoint(110, 100)), QPoint(120, 110)); + QCOMPARE(subSubWindow->mapToParent(QPoint(100, 110)), QPoint(110, 120)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 10)), QPoint(0, 0)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(20, 10)), QPoint(10, 0)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 20)), QPoint(0, 10)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(0, 10)), QPoint(-10, 0)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 0)), QPoint(0, -10)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(110, 110)), QPoint(100, 100)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(120, 110)), QPoint(110, 100)); + QCOMPARE(subSubWindow->mapFromParent(QPoint(110, 120)), QPoint(100, 110)); +} + +void tst_QWidget::focusChainOnReparent() +{ + QWidget window; + QWidget *child1 = new QWidget(&window); + QWidget *child2 = new QWidget(&window); + QWidget *child3 = new QWidget(&window); + QWidget *child21 = new QWidget(child2); + QWidget *child22 = new QWidget(child2); + QWidget *child4 = new QWidget(&window); + + QWidget *expectedOriginalChain[8] = {&window, child1, child2, child3, child21, child22, child4, &window}; + QWidget *w = &window; + for (int i = 0; i <8; ++i) { + QCOMPARE(w, expectedOriginalChain[i]); + w = w->nextInFocusChain(); + } + for (int i = 7; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedOriginalChain[i]); + } + + QWidget window2; + child2->setParent(&window2); + + QWidget *expectedNewChain[5] = {&window2, child2, child21, child22, &window2}; + w = &window2; + for (int i = 0; i <5; ++i) { + QCOMPARE(w, expectedNewChain[i]); + w = w->nextInFocusChain(); + } + for (int i = 4; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedNewChain[i]); + } + + QWidget *expectedOldChain[5] = {&window, child1, child3, child4, &window}; + w = &window; + for (int i = 0; i <5; ++i) { + QCOMPARE(w, expectedOldChain[i]); + w = w->nextInFocusChain(); + } + for (int i = 4; i >= 0; --i) { + w = w->previousInFocusChain(); + QCOMPARE(w, expectedOldChain[i]); + } +} + + +void tst_QWidget::focusChainOnHide() +{ + testWidget->hide(); // We do not want to get disturbed by other widgets + // focus should move to the next widget in the focus chain when we hide it. + QWidget *parent = new QWidget(); + parent->setObjectName(QLatin1String("Parent")); + parent->setFocusPolicy(Qt::StrongFocus); + QWidget *child = new QWidget(parent); + child->setObjectName(QLatin1String("child")); + child->setFocusPolicy(Qt::StrongFocus); + QWidget::setTabOrder(child, parent); + + parent->show(); + qApp->setActiveWindow(parent->window()); + child->activateWindow(); + child->setFocus(); + qApp->processEvents(); + + QTRY_COMPARE(child->hasFocus(), true); + child->hide(); + qApp->processEvents(); + + QTRY_COMPARE(parent->hasFocus(), true); + QCOMPARE(parent, qApp->focusWidget()); + + delete parent; + testWidget->show(); //don't disturb later tests +} + +class Container : public QWidget +{ +public: + QVBoxLayout* box; + + Container() + { + box = new QVBoxLayout(this); + //(new QVBoxLayout(this))->setAutoAdd(true); + } + + void tab() + { + focusNextPrevChild(TRUE); + } + + void backTab() + { + focusNextPrevChild(FALSE); + } +}; + +class Composite : public QFrame +{ +public: + Composite(QWidget* parent = 0, const char* name = 0) + : QFrame(parent) + { + setObjectName(name); + //QHBoxLayout* hbox = new QHBoxLayout(this, 2, 0); + //hbox->setAutoAdd(true); + QHBoxLayout* hbox = new QHBoxLayout(this); + + lineEdit = new QLineEdit(this); + hbox->addWidget(lineEdit); + + button = new QPushButton(this); + hbox->addWidget(button); + button->setFocusPolicy( Qt::NoFocus ); + + setFocusProxy( lineEdit ); + setFocusPolicy( Qt::StrongFocus ); + + setTabOrder(lineEdit, button); + } + +private: + QLineEdit* lineEdit; + QPushButton* button; +}; + +#define NUM_WIDGETS 4 + +void tst_QWidget::setTabOrder() +{ + QTest::qWait(100); + + Container container; + + Composite* comp[NUM_WIDGETS]; + + QLineEdit *firstEdit = new QLineEdit(&container); + container.box->addWidget(firstEdit); + + int i = 0; + for(i = 0; i < NUM_WIDGETS; i++) { + comp[i] = new Composite(&container); + container.box->addWidget(comp[i]); + } + + QLineEdit *lastEdit = new QLineEdit(&container); + container.box->addWidget(lastEdit); + + container.setTabOrder(lastEdit, comp[NUM_WIDGETS-1]); + for(i = NUM_WIDGETS-1; i > 0; i--) { + container.setTabOrder(comp[i], comp[i-1]); + } + container.setTabOrder(comp[0], firstEdit); + + int current = NUM_WIDGETS-1; + lastEdit->setFocus(); + + container.show(); + container.activateWindow(); + qApp->setActiveWindow(&container); +#ifdef Q_WS_X11 + QTest::qWaitForWindowShown(&container); + QTest::qWait(50); +#endif + + QTest::qWait(100); + + QTRY_VERIFY(lastEdit->hasFocus()); + container.tab(); + do { + QVERIFY(comp[current]->focusProxy()->hasFocus()); + container.tab(); + current--; + } while (current >= 0); + + QVERIFY(firstEdit->hasFocus()); +} + +#ifdef Q_WS_WIN +void tst_QWidget::activation() +{ + Q_CHECK_PAINTEVENTS + +#if defined(Q_OS_WINCE) + int waitTime = 1000; +#else + int waitTime = 100; +#endif + +#ifdef Q_OS_WINCE + qApp->processEvents(); +#endif + QWidget widget1; + widget1.setWindowTitle("Widget1"); + + QWidget widget2; + widget2.setWindowTitle("Widget2"); + + widget1.show(); + widget2.show(); + + QTest::qWait(waitTime); + QVERIFY(qApp->activeWindow() == &widget2); + widget2.showMinimized(); + QTest::qWait(waitTime); + + QVERIFY(qApp->activeWindow() == &widget1); + widget2.showMaximized(); + QTest::qWait(waitTime); + QVERIFY(qApp->activeWindow() == &widget2); + widget2.showMinimized(); + QTest::qWait(waitTime); + QVERIFY(qApp->activeWindow() == &widget1); + widget2.showNormal(); + QTest::qWait(waitTime); +#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) + QEXPECT_FAIL("", "MS introduced new behavior after XP", Continue); +#endif + QTest::qWait(waitTime); + QVERIFY(qApp->activeWindow() == &widget2); + widget2.hide(); + QTest::qWait(waitTime); + QVERIFY(qApp->activeWindow() == &widget1); +} +#endif + +// Many window managers do not support window state properly, which causes this test to fail. +#ifndef Q_WS_X11 +void tst_QWidget::windowState() +{ +#ifdef Q_OS_WINCE_WM + QPoint pos(500, 500); + QSize size(200, 200); + if (qt_wince_is_smartphone()) { //small screen + pos = QPoint(10,10); + size = QSize(100,100); + } +#else + const QPoint pos(500, 500); + const QSize size(200, 200); +#endif + + QWidget widget1; + widget1.move(pos); + widget1.resize(size); + QCOMPARE(widget1.pos(), pos); + QCOMPARE(widget1.size(), size); + QTest::qWait(100); + widget1.setWindowTitle("Widget1"); + QCOMPARE(widget1.pos(), pos); + QCOMPARE(widget1.size(), size); + +#define VERIFY_STATE(s) QCOMPARE(int(widget1.windowState() & stateMask), int(s)) + + const int stateMask = Qt::WindowMaximized|Qt::WindowMinimized|Qt::WindowFullScreen; + + widget1.setWindowState(Qt::WindowMaximized); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowMaximized); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized); + + widget1.show(); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowMaximized); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); + QTest::qWait(100); + QVERIFY(!(widget1.windowState() & Qt::WindowMaximized)); + QTRY_COMPARE(widget1.pos(), pos); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); + + widget1.setWindowState(Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowMinimized); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized); + + widget1.setWindowState(widget1.windowState() | Qt::WindowMaximized); + QTest::qWait(100); + VERIFY_STATE((Qt::WindowMinimized|Qt::WindowMaximized)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowMaximized); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); + QTest::qWait(100); + QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized))); + QTRY_COMPARE(widget1.pos(), pos); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); + + widget1.setWindowState(Qt::WindowFullScreen); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowFullScreen); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE((Qt::WindowFullScreen|Qt::WindowMinimized)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowFullScreen); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen); + + widget1.setWindowState(Qt::WindowNoState); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowNoState); + QTRY_COMPARE(widget1.pos(), pos); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); + + widget1.setWindowState(Qt::WindowFullScreen); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowFullScreen); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); + QTest::qWait(100); + VERIFY_STATE((Qt::WindowFullScreen|Qt::WindowMaximized)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE((Qt::WindowFullScreen|Qt::WindowMaximized|Qt::WindowMinimized)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized); + QTest::qWait(100); + VERIFY_STATE((Qt::WindowFullScreen|Qt::WindowMaximized)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowFullScreen); + QTest::qWait(100); + VERIFY_STATE(Qt::WindowMaximized); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized); + + widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized); + QTest::qWait(100); + QVERIFY(!(widget1.windowState() & stateMask)); + QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState); + + QTRY_COMPARE(widget1.pos(), pos); + QTRY_COMPARE(widget1.size(), size); +} +#endif + +void tst_QWidget::showMaximized() +{ + QWidget plain; + QHBoxLayout *layout; + layout = new QHBoxLayout; + QWidget layouted; + QLineEdit le; + QLineEdit le2; + QLineEdit le3; + + layout->addWidget(&le); + layout->addWidget(&le2); + layout->addWidget(&le3); + + layouted.setLayout(layout); + + plain.showMaximized(); + QVERIFY(plain.windowState() & Qt::WindowMaximized); + + plain.showNormal(); + QVERIFY(!(plain.windowState() & Qt::WindowMaximized)); + + layouted.showMaximized(); + QVERIFY(layouted.windowState() & Qt::WindowMaximized); + + layouted.showNormal(); + QVERIFY(!(layouted.windowState() & Qt::WindowMaximized)); + +#if !defined(Q_WS_QWS) && !defined(Q_OS_WINCE) && !defined(Q_WS_QPA) +//embedded may choose a different size to fit on the screen. + QCOMPARE(layouted.size(), layouted.sizeHint()); +#endif + layouted.showMaximized(); + QVERIFY(layouted.isMaximized()); + QVERIFY(layouted.isVisible()); + + layouted.hide(); + QVERIFY(layouted.isMaximized()); + QVERIFY(!layouted.isVisible()); + + layouted.showMaximized(); + QVERIFY(layouted.isMaximized()); + QVERIFY(layouted.isVisible()); + + layouted.showMinimized(); + QVERIFY(layouted.isMinimized()); + QVERIFY(layouted.isMaximized()); + + layouted.showMaximized(); + QVERIFY(!layouted.isMinimized()); + QVERIFY(layouted.isMaximized()); + QVERIFY(layouted.isVisible()); + + layouted.showMinimized(); + QVERIFY(layouted.isMinimized()); + QVERIFY(layouted.isMaximized()); + + layouted.showMaximized(); + QVERIFY(!layouted.isMinimized()); + QVERIFY(layouted.isMaximized()); + QVERIFY(layouted.isVisible()); + + { + QWidget frame; + QWidget widget(&frame); + widget.showMaximized(); + QVERIFY(widget.isMaximized()); + } + + { + QWidget widget; + widget.setGeometry(0, 0, 10, 10); + widget.showMaximized(); + QTRY_VERIFY(widget.size().width() > 20 && widget.size().height() > 20); + } +} + +void tst_QWidget::showFullScreen() +{ + QWidget plain; + QHBoxLayout *layout; + QWidget layouted; + QLineEdit le; + QLineEdit le2; + QLineEdit le3; + layout = new QHBoxLayout; + + layout->addWidget(&le); + layout->addWidget(&le2); + layout->addWidget(&le3); + + layouted.setLayout(layout); + + plain.showFullScreen(); + QVERIFY(plain.windowState() & Qt::WindowFullScreen); + + plain.showNormal(); + QVERIFY(!(plain.windowState() & Qt::WindowFullScreen)); + + layouted.showFullScreen(); + QVERIFY(layouted.windowState() & Qt::WindowFullScreen); + + layouted.showNormal(); + QVERIFY(!(layouted.windowState() & Qt::WindowFullScreen)); + +#if !defined(Q_WS_QWS) && !defined(Q_OS_WINCE) && !defined(Q_WS_QPA) +//embedded may choose a different size to fit on the screen. + QCOMPARE(layouted.size(), layouted.sizeHint()); +#endif + + layouted.showFullScreen(); + QVERIFY(layouted.isFullScreen()); + QVERIFY(layouted.isVisible()); + + layouted.hide(); + QVERIFY(layouted.isFullScreen()); + QVERIFY(!layouted.isVisible()); + + layouted.showFullScreen(); + QVERIFY(layouted.isFullScreen()); + QVERIFY(layouted.isVisible()); + + layouted.showMinimized(); + QVERIFY(layouted.isMinimized()); + QVERIFY(layouted.isFullScreen()); + + layouted.showFullScreen(); + QVERIFY(!layouted.isMinimized()); + QVERIFY(layouted.isFullScreen()); + QVERIFY(layouted.isVisible()); + + layouted.showMinimized(); + QVERIFY(layouted.isMinimized()); + QVERIFY(layouted.isFullScreen()); + + layouted.showFullScreen(); + QVERIFY(!layouted.isMinimized()); + QVERIFY(layouted.isFullScreen()); + QVERIFY(layouted.isVisible()); + + { + QWidget frame; + QWidget widget(&frame); + widget.showFullScreen(); + QVERIFY(widget.isFullScreen()); + } +} + +class ResizeWidget : public QWidget { +public: + ResizeWidget(QWidget *p = 0) : QWidget(p) + { + m_resizeEventCount = 0; + } +protected: + void resizeEvent(QResizeEvent *e){ + QCOMPARE(size(), e->size()); + ++m_resizeEventCount; + } + +public: + int m_resizeEventCount; +}; + +void tst_QWidget::resizeEvent() +{ + { + QWidget wParent; + ResizeWidget wChild(&wParent); + wParent.show(); + QCOMPARE (wChild.m_resizeEventCount, 1); // initial resize event before paint + wParent.hide(); + QSize safeSize(640,480); + if (wChild.size() == safeSize) + safeSize.setWidth(639); + wChild.resize(safeSize); + QCOMPARE (wChild.m_resizeEventCount, 1); + wParent.show(); + QCOMPARE (wChild.m_resizeEventCount, 2); + } + + { + ResizeWidget wTopLevel; + wTopLevel.show(); + QCOMPARE (wTopLevel.m_resizeEventCount, 1); // initial resize event before paint for toplevels + wTopLevel.hide(); + QSize safeSize(640,480); + if (wTopLevel.size() == safeSize) + safeSize.setWidth(639); + wTopLevel.resize(safeSize); + QCOMPARE (wTopLevel.m_resizeEventCount, 1); + wTopLevel.show(); + QCOMPARE (wTopLevel.m_resizeEventCount, 2); + } +} + +void tst_QWidget::showMinimized() +{ + QWidget plain; + plain.move(100, 100); + plain.resize(200, 200); + QPoint pos = plain.pos(); + + plain.showMinimized(); + QVERIFY(plain.isMinimized()); + QVERIFY(plain.isVisible()); + QCOMPARE(plain.pos(), pos); + + plain.showNormal(); + QVERIFY(!plain.isMinimized()); + QVERIFY(plain.isVisible()); + QCOMPARE(plain.pos(), pos); + + plain.showMinimized(); + QVERIFY(plain.isMinimized()); + QVERIFY(plain.isVisible()); + QCOMPARE(plain.pos(), pos); + + plain.hide(); + QVERIFY(plain.isMinimized()); + QVERIFY(!plain.isVisible()); + + plain.showMinimized(); + QVERIFY(plain.isMinimized()); + QVERIFY(plain.isVisible()); + + plain.setGeometry(200, 200, 300, 300); + plain.showNormal(); + QCOMPARE(plain.geometry(), QRect(200, 200, 300, 300)); + + { + QWidget frame; + QWidget widget(&frame); + widget.showMinimized(); + QVERIFY(widget.isMinimized()); + } +} + +void tst_QWidget::showMinimizedKeepsFocus() +{ + //here we test that minimizing a widget and restoring it doesn't change the focus inside of it + { + QWidget window; + QWidget child1(&window), child2(&window); + child1.setFocusPolicy(Qt::StrongFocus); + child2.setFocusPolicy(Qt::StrongFocus); + window.show(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + child2.setFocus(); + QTest::qWait(50); + + QTRY_COMPARE(window.focusWidget(), &child2); + QTRY_COMPARE(qApp->focusWidget(), &child2); + + window.showMinimized(); + QTest::qWait(10); + QTRY_VERIFY(window.isMinimized()); + QTRY_COMPARE(window.focusWidget(), &child2); + + window.showNormal(); + QTest::qWait(10); + QTRY_COMPARE(window.focusWidget(), &child2); + } + + //testing deletion of the focusWidget + { + QWidget window; + QWidget *child = new QWidget(&window); + child->setFocusPolicy(Qt::StrongFocus); + window.show(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + child->setFocus(); + QTest::qWait(50); + QTRY_COMPARE(window.focusWidget(), child); + QTRY_COMPARE(qApp->focusWidget(), child); + + delete child; + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(qApp->focusWidget(), static_cast(0)); + } + + //testing reparenting the focus widget + { + QWidget window; + QWidget *child = new QWidget(&window); + child->setFocusPolicy(Qt::StrongFocus); + window.show(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + child->setFocus(); + QTest::qWait(50); + QTRY_COMPARE(window.focusWidget(), child); + QTRY_COMPARE(qApp->focusWidget(), child); + + child->setParent(0); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(qApp->focusWidget(), static_cast(0)); + } + + //testing setEnabled(false) + { + QWidget window; + QWidget *child = new QWidget(&window); + child->setFocusPolicy(Qt::StrongFocus); + window.show(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + child->setFocus(); + QTest::qWait(10); + QTRY_COMPARE(window.focusWidget(), child); + QTRY_COMPARE(qApp->focusWidget(), child); + + child->setEnabled(false); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(qApp->focusWidget(), static_cast(0)); + } + + //testing clearFocus + { + QWidget window; + QWidget *firstchild = new QWidget(&window); + firstchild->setFocusPolicy(Qt::StrongFocus); + QWidget *child = new QWidget(&window); + child->setFocusPolicy(Qt::StrongFocus); + window.show(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + child->setFocus(); + QTest::qWait(10); + QTRY_COMPARE(window.focusWidget(), child); + QTRY_COMPARE(qApp->focusWidget(), child); + + child->clearFocus(); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(qApp->focusWidget(), static_cast(0)); + + window.showMinimized(); + QTest::qWait(30); + QTRY_VERIFY(window.isMinimized()); +#ifdef Q_WS_QWS + QEXPECT_FAIL("", "QWS does not implement showMinimized()", Continue); +#endif + QCOMPARE(window.focusWidget(), static_cast(0)); +#ifdef Q_WS_QWS + QEXPECT_FAIL("", "QWS does not implement showMinimized()", Continue); +#endif + QTRY_COMPARE(qApp->focusWidget(), static_cast(0)); + + window.showNormal(); + qApp->setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + QTest::qWait(30); +#ifdef Q_WS_MAC + if (!macHasAccessToWindowsServer()) + QEXPECT_FAIL("", "When not having WindowServer access, we lose focus.", Continue); +#endif + QTRY_COMPARE(window.focusWidget(), firstchild); +#ifdef Q_WS_MAC + if (!macHasAccessToWindowsServer()) + QEXPECT_FAIL("", "When not having WindowServer access, we lose focus.", Continue); +#endif + QTRY_COMPARE(qApp->focusWidget(), firstchild); + } +} + + +void tst_QWidget::reparent() +{ + QWidget parent; + parent.setWindowTitle("Toplevel"); + parent.setGeometry(300, 300, 200, 150); + + QWidget child(0); + child.setObjectName("child"); + child.setGeometry(10, 10, 180, 130); + QPalette pal1; + pal1.setColor(child.backgroundRole(), Qt::white); + child.setPalette(pal1); + + QWidget childTLW(&child, Qt::Window); + childTLW.setObjectName("childTLW"); + childTLW.setGeometry(100, 100, 50, 50); + QPalette pal2; + pal2.setColor(childTLW.backgroundRole(), Qt::yellow); + childTLW.setPalette(pal2); + + parent.show(); + childTLW.show(); + QTest::qWaitForWindowShown(&parent); + +#ifdef Q_OS_WINCE + parent.move(50, 50); +#else + parent.move(300, 300); +#endif + + QPoint childPos = parent.mapToGlobal(child.pos()); + QPoint tlwPos = childTLW.pos(); + + child.setParent(0, child.windowFlags() & ~Qt::WindowType_Mask); + child.setGeometry(childPos.x(), childPos.y(), child.width(), child.height()); + child.show(); + +#ifdef Q_WS_X11 + // On X11, the window manager will apply NorthWestGravity rules to 'child', which + // means the top-left corner of the window frame will be placed at 'childPos', + // causing this test to fail +#else + QCOMPARE(child.geometry().topLeft(), childPos); +#endif + QTRY_COMPARE(childTLW.pos(), tlwPos); + + // This following part of the test only makes sense on Windows. +#ifdef Q_WS_WIN + QWidget childTLWChild(&childTLW); + childTLWChild.setObjectName("childTLWChild"); + + QWidget grandChild(&child); + grandChild.setObjectName("grandChild"); + grandChild.setGeometry(10, 10, 160, 110); + QPalette pal3; + pal3.setColor(grandChild.backgroundRole(), Qt::red); + grandChild.setPalette(pal3); + //grandChild.setPaletteBackgroundColor(Qt::red); + + QWidget grandChildTLW(&grandChild, Qt::Window); + grandChildTLW.setObjectName("grandChildTLW"); + grandChildTLW.setGeometry(200, 200, 50, 50); + QPalette pal4; + pal4.setColor(grandChildTLW.backgroundRole(), Qt::yellow); + grandChildTLW.setPalette(pal4); + //grandChildTLW.setPaletteBackgroundColor(Qt::yellow); + + QWidget grandChildTLWChild(&grandChildTLW); + grandChildTLWChild.setObjectName("grandChildTLWChild"); + + QVERIFY(IsWindow(childTLW.winId())); + QVERIFY(IsWindow(childTLWChild.winId())); + QVERIFY(IsWindow(grandChildTLW.winId())); + QVERIFY(IsWindow(grandChildTLWChild.winId())); + + parent.show(); + + QVERIFY(IsWindow(childTLW.winId())); + QVERIFY(IsWindow(childTLWChild.winId())); + QVERIFY(IsWindow(grandChildTLW.winId())); + QVERIFY(IsWindow(grandChildTLWChild.winId())); + + child.setParent(&parent); + child.move(10,10); + child.show(); + + // this appears to stabelize results + qApp->processEvents(); + + QVERIFY(IsWindow(childTLW.winId())); + QVERIFY(IsWindow(childTLWChild.winId())); + + QVERIFY(IsWindow(grandChildTLW.winId())); + QVERIFY(IsWindow(grandChildTLWChild.winId())); +#endif +} + +// Qt/Embedded does it differently. +#ifndef Q_WS_QWS +void tst_QWidget::icon() +{ + QPixmap p(20,20); + p.fill(Qt::red); + testWidget->setWindowIcon(p); + + QVERIFY(!testWidget->windowIcon().isNull()); + testWidget->show(); + QVERIFY(!testWidget->windowIcon().isNull()); + testWidget->showFullScreen(); + QVERIFY(!testWidget->windowIcon().isNull()); + testWidget->showNormal(); + QVERIFY(!testWidget->windowIcon().isNull()); +} +#endif + +void tst_QWidget::hideWhenFocusWidgetIsChild() +{ + testWidget->activateWindow(); + QWidget *parentWidget = new QWidget(testWidget); + parentWidget->setObjectName("parentWidget"); + parentWidget->setGeometry(0, 0, 100, 100); + QLineEdit *edit = new QLineEdit(parentWidget); + edit->setObjectName("edit1"); + QLineEdit *edit3 = new QLineEdit(parentWidget); + edit3->setObjectName("edit3"); + edit3->move(0,50); + parentWidget->show(); + QLineEdit *edit2 = new QLineEdit(testWidget); + edit2->setObjectName("edit2"); + edit2->show(); + edit2->move(110, 100); + edit->setFocus(); + qApp->processEvents(); + QString actualFocusWidget, expectedFocusWidget; +#ifdef Q_WS_X11 + if (!qApp->focusWidget()) + QSKIP("Your window manager is too broken for this test", SkipAll); +#endif + QVERIFY(qApp->focusWidget()); + actualFocusWidget.sprintf("%p %s %s", qApp->focusWidget(), qApp->focusWidget()->objectName().toLatin1().constData(), qApp->focusWidget()->metaObject()->className()); + expectedFocusWidget.sprintf("%p %s %s", edit, edit->objectName().toLatin1().constData(), edit->metaObject()->className()); + QCOMPARE(actualFocusWidget, expectedFocusWidget); + + parentWidget->hide(); + qApp->processEvents(); + actualFocusWidget.sprintf("%p %s %s", qApp->focusWidget(), qApp->focusWidget()->objectName().toLatin1().constData(), qApp->focusWidget()->metaObject()->className()); + expectedFocusWidget.sprintf("%p %s %s", edit2, edit2->objectName().toLatin1().constData(), edit2->metaObject()->className()); + QCOMPARE(actualFocusWidget, expectedFocusWidget); + + delete edit2; + delete parentWidget; +} + +// 4DWM issues on IRIX makes this test fail. +#ifndef Q_OS_IRIX +void tst_QWidget::normalGeometry() +{ + QWidget parent; + parent.setWindowTitle("NormalGeometry parent"); + QWidget *child = new QWidget(&parent); + + QCOMPARE(parent.normalGeometry(), parent.geometry()); + QCOMPARE(child->normalGeometry(), QRect()); + + parent.setGeometry(100, 100, 200, 200); + parent.show(); + QTest::qWaitForWindowShown(&parent); + QApplication::processEvents(); + + QRect geom = parent.geometry(); + // ### the window manager places the top-left corner at + // ### 100,100... making geom something like 102,124 (offset by + // ### the frame/frame)... this indicates a rather large different + // ### between how X11 and Windows works + // QCOMPARE(geom, QRect(100, 100, 200, 200)); + QCOMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); + QTest::qWait(10); + QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); + QTRY_VERIFY(parent.geometry() != geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); + QTest::qWait(10); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); + QTRY_COMPARE(parent.geometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.showMaximized(); + QTest::qWait(10); + QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); + QTRY_VERIFY(parent.geometry() != geom); + QCOMPARE(parent.normalGeometry(), geom); + + parent.showNormal(); + QTest::qWait(10); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); + QTRY_COMPARE(parent.geometry(), geom); + QCOMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized); + QTest::qWait(10); + parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); + QTest::qWait(10); + QTRY_VERIFY(parent.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized)); + // ### when minimized and maximized at the same time, the geometry + // ### does *NOT* have to be the normal geometry, it could be the + // ### maximized geometry. + // QCOMPARE(parent.geometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized); + QTest::qWait(10); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowMinimized)); + QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); + QTRY_VERIFY(parent.geometry() != geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); + QTest::qWait(10); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); + QTRY_COMPARE(parent.geometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen); + QTest::qWait(10); + QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen); + QTRY_VERIFY(parent.geometry() != geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen); + QTest::qWait(10); + QVERIFY(!(parent.windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(parent.geometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.showFullScreen(); + QTest::qWait(10); + QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen); + QTRY_VERIFY(parent.geometry() != geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.showNormal(); + QTest::qWait(10); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(parent.geometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), geom); + + parent.showNormal(); + parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized); + parent.setWindowState(Qt::WindowMinimized | Qt:: WindowFullScreen | Qt::WindowMaximized); + parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized); + QTest::qWait(10); + QTRY_COMPARE(parent.normalGeometry(), geom); +} +#endif + +void tst_QWidget::setGeometry() +{ + QWidget tlw; + QWidget child(&tlw); + + QRect tr(100,100,200,200); + QRect cr(50,50,50,50); + tlw.setGeometry(tr); + child.setGeometry(cr); + tlw.show(); + QTest::qWait(50); + QCOMPARE(tlw.geometry().size(), tr.size()); + QCOMPARE(child.geometry(), cr); + + tlw.setParent(0, Qt::Window|Qt::FramelessWindowHint); + tr = QRect(0,0,100,100); + tr.moveTopLeft(QApplication::desktop()->availableGeometry().topLeft()); + tlw.setGeometry(tr); + QCOMPARE(tlw.geometry(), tr); + tlw.show(); + QTest::qWait(50); + if (tlw.frameGeometry() != tlw.geometry()) + QSKIP("Your window manager is too broken for this test", SkipAll); + QCOMPARE(tlw.geometry(), tr); + +} + +// Windows CE does not support windowOpacity. +#ifndef Q_OS_WINCE +void tst_QWidget::windowOpacity() +{ + QWidget widget; + QWidget child(&widget); + + // Initial value should be 1.0 + QCOMPARE(widget.windowOpacity(), 1.0); + // children should always return 1.0 + QCOMPARE(child.windowOpacity(), 1.0); + + widget.setWindowOpacity(0.0); + QCOMPARE(widget.windowOpacity(), 0.0); + child.setWindowOpacity(0.0); + QCOMPARE(child.windowOpacity(), 1.0); + + widget.setWindowOpacity(1.0); + QCOMPARE(widget.windowOpacity(), 1.0); + child.setWindowOpacity(1.0); + QCOMPARE(child.windowOpacity(), 1.0); + + widget.setWindowOpacity(2.0); + QCOMPARE(widget.windowOpacity(), 1.0); + child.setWindowOpacity(2.0); + QCOMPARE(child.windowOpacity(), 1.0); + + widget.setWindowOpacity(-1.0); + QCOMPARE(widget.windowOpacity(), 0.0); + child.setWindowOpacity(-1.0); + QCOMPARE(child.windowOpacity(), 1.0); +} +#endif + +class UpdateWidget : public QWidget +{ +public: + UpdateWidget(QWidget *parent = 0) : QWidget(parent) { + reset(); + } + + void paintEvent(QPaintEvent *e) { + paintedRegion += e->region(); + ++numPaintEvents; + if (resizeInPaintEvent) { + resizeInPaintEvent = false; + resize(size() + QSize(2, 2)); + } + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::ZOrderChange: + ++numZOrderChangeEvents; + break; + case QEvent::UpdateRequest: + ++numUpdateRequestEvents; + break; + case QEvent::ActivationChange: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::WindowActivate: + case QEvent::WindowDeactivate: + if (!updateOnActivationChangeAndFocusIn) + return true; // Filter out to avoid update() calls in QWidget. + break; + default: + break; + } + return QWidget::event(event); + } + + void reset() { + numPaintEvents = 0; + numZOrderChangeEvents = 0; + numUpdateRequestEvents = 0; + updateOnActivationChangeAndFocusIn = false; + resizeInPaintEvent = false; + paintedRegion = QRegion(); + } + + int numPaintEvents; + int numZOrderChangeEvents; + int numUpdateRequestEvents; + bool updateOnActivationChangeAndFocusIn; + bool resizeInPaintEvent; + QRegion paintedRegion; +}; + +void tst_QWidget::lostUpdatesOnHide() +{ +#ifndef Q_WS_MAC + UpdateWidget widget; + widget.setAttribute(Qt::WA_DontShowOnScreen); + widget.show(); + widget.hide(); + QTest::qWait(50); + widget.show(); + QTest::qWait(50); + + QCOMPARE(widget.numPaintEvents, 1); +#endif +} + +void tst_QWidget::raise() +{ + QTest::qWait(10); + QWidget *parent = new QWidget(0); + QList allChildren; + + UpdateWidget *child1 = new UpdateWidget(parent); + child1->setAutoFillBackground(true); + allChildren.append(child1); + + UpdateWidget *child2 = new UpdateWidget(parent); + child2->setAutoFillBackground(true); + allChildren.append(child2); + + UpdateWidget *child3 = new UpdateWidget(parent); + child3->setAutoFillBackground(true); + allChildren.append(child3); + + UpdateWidget *child4 = new UpdateWidget(parent); + child4->setAutoFillBackground(true); + allChildren.append(child4); + + parent->show(); + QTest::qWaitForWindowShown(parent); + QTest::qWait(10); + +#ifdef Q_OS_MAC + if (child1->internalWinId()) { + QSKIP("Cocoa has no Z-Order for views, we hack it, but it results in paint events.", SkipAll); + } +#endif + + QList list1; + list1 << child1 << child2 << child3 << child4; + QVERIFY(parent->children() == list1); + QCOMPARE(allChildren.count(), list1.count()); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child4 ? 1 : 0; + if (expectedPaintEvents == 0) { + QVERIFY(child->numPaintEvents == 0); + } else { + // show() issues multiple paint events on some window managers + QTRY_VERIFY(child->numPaintEvents >= expectedPaintEvents); + } + QCOMPARE(child->numZOrderChangeEvents, 0); + child->reset(); + } + + for (int i = 0; i < 5; ++i) + child2->raise(); + QTest::qWait(50); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child2 ? 1 : 0; + int expectedZOrderChangeEvents = child == child2 ? 1 : 0; +#ifdef Q_OS_MAC + QSKIP("Not yet sure why this fails.", SkipSingle); +#endif + QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents); + QCOMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents); + child->reset(); + } + + QList list2; + list2 << child1 << child3 << child4 << child2; + QVERIFY(parent->children() == list2); + + // Creates a widget on top of all the children and checks that raising one of + // the children underneath doesn't trigger a repaint on the covering widget. + QWidget topLevel; + parent->setParent(&topLevel); + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); + QTest::qWait(50); + + UpdateWidget *onTop = new UpdateWidget(&topLevel); + onTop->reset(); + onTop->resize(topLevel.size()); + onTop->setAutoFillBackground(true); + onTop->show(); + QTest::qWait(50); + QTRY_VERIFY(onTop->numPaintEvents > 0); + onTop->reset(); + + // Reset all the children. + foreach (UpdateWidget *child, allChildren) + child->reset(); + + for (int i = 0; i < 5; ++i) + child3->raise(); + QTest::qWait(50); + + QCOMPARE(onTop->numPaintEvents, 0); + QCOMPARE(onTop->numZOrderChangeEvents, 0); + + QList list3; + list3 << child1 << child4 << child2 << child3; + QVERIFY(parent->children() == list3); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = 0; + int expectedZOrderChangeEvents = child == child3 ? 1 : 0; + QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents); + QCOMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents); + child->reset(); + } +} + +// Cocoa has no Z-Order for views, we hack it, but it results in paint events. +#ifndef QT_OS_MAC +void tst_QWidget::lower() +{ + QWidget *parent = new QWidget(0); + QList allChildren; + + UpdateWidget *child1 = new UpdateWidget(parent); + child1->setAutoFillBackground(true); + allChildren.append(child1); + + UpdateWidget *child2 = new UpdateWidget(parent); + child2->setAutoFillBackground(true); + allChildren.append(child2); + + UpdateWidget *child3 = new UpdateWidget(parent); + child3->setAutoFillBackground(true); + allChildren.append(child3); + + UpdateWidget *child4 = new UpdateWidget(parent); + child4->setAutoFillBackground(true); + allChildren.append(child4); + + parent->show(); + QTest::qWaitForWindowShown(parent); + QTest::qWait(100); + + QList list1; + list1 << child1 << child2 << child3 << child4; + QVERIFY(parent->children() == list1); + QCOMPARE(allChildren.count(), list1.count()); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child4 ? 1 : 0; + if (expectedPaintEvents == 0) { + QVERIFY(child->numPaintEvents == 0); + } else { + // show() issues multiple paint events on some window managers + QTRY_VERIFY(child->numPaintEvents >= expectedPaintEvents); + } + QCOMPARE(child->numZOrderChangeEvents, 0); + child->reset(); + } + + for (int i = 0; i < 5; ++i) + child4->lower(); + + QTest::qWait(100); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child3 ? 1 : 0; + int expectedZOrderChangeEvents = child == child4 ? 1 : 0; + QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents); + QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents); + child->reset(); + } + + QList list2; + list2 << child4 << child1 << child2 << child3; + QVERIFY(parent->children() == list2); + + delete parent; +} +#endif + +// Cocoa has no Z-Order for views, we hack it, but it results in paint events. +#ifndef QT_OS_MAC +void tst_QWidget::stackUnder() +{ + QTest::qWait(10); + QWidget *parent = new QWidget(0); + QList allChildren; + + UpdateWidget *child1 = new UpdateWidget(parent); + child1->setAutoFillBackground(true); + allChildren.append(child1); + + UpdateWidget *child2 = new UpdateWidget(parent); + child2->setAutoFillBackground(true); + allChildren.append(child2); + + UpdateWidget *child3 = new UpdateWidget(parent); + child3->setAutoFillBackground(true); + allChildren.append(child3); + + UpdateWidget *child4 = new UpdateWidget(parent); + child4->setAutoFillBackground(true); + allChildren.append(child4); + + parent->show(); + QTest::qWaitForWindowShown(parent); + QTest::qWait(10); +#ifdef Q_WS_QWS + QApplication::sendPostedEvents(); //glib workaround +#endif + + QList list1; + list1 << child1 << child2 << child3 << child4; + QVERIFY(parent->children() == list1); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child4 ? 1 : 0; +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) + if (expectedPaintEvents == 1 && child->numPaintEvents == 2) + QEXPECT_FAIL(0, "Mac and Windows issues double repaints for Z-Order change", Continue); +#endif + QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents); + QCOMPARE(child->numZOrderChangeEvents, 0); + child->reset(); + } + + for (int i = 0; i < 5; ++i) + child4->stackUnder(child2); + QTest::qWait(10); + + QList list2; + list2 << child1 << child4 << child2 << child3; + QVERIFY(parent->children() == list2); + + foreach (UpdateWidget *child, allChildren) { + int expectedPaintEvents = child == child3 ? 1 : 0; + int expectedZOrderChangeEvents = child == child4 ? 1 : 0; + QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents); + QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents); + child->reset(); + } + + for (int i = 0; i < 5; ++i) + child1->stackUnder(child3); + QTest::qWait(10); + + QList list3; + list3 << child4 << child2 << child1 << child3; + QVERIFY(parent->children() == list3); + + foreach (UpdateWidget *child, allChildren) { + int expectedZOrderChangeEvents = child == child1 ? 1 : 0; + if (child == child3) { +#ifdef Q_OS_WINCE + qApp->processEvents(); +#endif +#ifndef Q_WS_MAC + QEXPECT_FAIL(0, "See QTBUG-493", Continue); +#endif + QCOMPARE(child->numPaintEvents, 0); + } else { + QCOMPARE(child->numPaintEvents, 0); + } + QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents); + child->reset(); + } + + delete parent; +} +#endif + +void drawPolygon(QPaintDevice *dev, int w, int h) +{ + QPainter p(dev); + p.fillRect(0, 0, w, h, Qt::white); + + QPolygon a; + a << QPoint(0, 0) << QPoint(w/2, h/2) << QPoint(w, 0) + << QPoint(w/2, h) << QPoint(0, 0); + + p.setPen(QPen(Qt::black, 1)); + p.setBrush(Qt::DiagCrossPattern); + p.drawPolygon(a); +} + +class ContentsPropagationWidget : public QWidget +{ + Q_OBJECT +public: + ContentsPropagationWidget(QWidget *parent = 0) : QWidget(parent) + { + QWidget *child = this; + for (int i=0; i<32; ++i) { + child = new QWidget(child); + child->setGeometry(i, i, 400 - i*2, 400 - i*2); + } + } + + void setContentsPropagation(bool enable) { + foreach (QObject *child, children()) + qobject_cast(child)->setAutoFillBackground(!enable); + } + +protected: + void paintEvent(QPaintEvent *) + { + int w = width(), h = height(); + drawPolygon(this, w, h); + } + + QSize sizeHint() const { return QSize(500, 500); } +}; + +void tst_QWidget::testContentsPropagation() +{ + ContentsPropagationWidget widget; +#ifdef Q_WS_QWS + widget.resize(500,500); +#else + widget.setFixedSize(500, 500); +#endif + widget.setContentsPropagation(false); + QPixmap widgetSnapshot = QPixmap::grabWidget(&widget); + + QPixmap correct(500, 500); + drawPolygon(&correct, 500, 500); + //correct.save("correct.png", "PNG"); + + //widgetSnapshot.save("snap1.png", "PNG"); + QVERIFY(widgetSnapshot.toImage() != correct.toImage()); + + widget.setContentsPropagation(true); + widgetSnapshot = QPixmap::grabWidget(&widget); + //widgetSnapshot.save("snap2.png", "PNG"); + + QCOMPARE(widgetSnapshot, correct); +} + +/* + Test that saving and restoring window geometry with + saveGeometry() and restoreGeometry() works. +*/ +// 4DWM issues on IRIX makes this test fail. +#ifndef Q_OS_IRIX +void tst_QWidget::saveRestoreGeometry() +{ + const QPoint position(100, 100); + const QSize size(200, 200); + + QByteArray savedGeometry; + + { + QWidget widget; + widget.move(position); + widget.resize(size); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QApplication::processEvents(); + + QTRY_COMPARE(widget.pos(), position); + QCOMPARE(widget.size(), size); + savedGeometry = widget.saveGeometry(); + } + + { + QWidget widget; + + const QByteArray empty; + const QByteArray one("a"); + const QByteArray two("ab"); + const QByteArray three("abc"); + const QByteArray four("abca"); + const QByteArray garbage("abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"); + + QVERIFY(widget.restoreGeometry(empty) == false); + QVERIFY(widget.restoreGeometry(one) == false); + QVERIFY(widget.restoreGeometry(two) == false); + QVERIFY(widget.restoreGeometry(three) == false); + QVERIFY(widget.restoreGeometry(four) == false); + QVERIFY(widget.restoreGeometry(garbage) == false); + + QVERIFY(widget.restoreGeometry(savedGeometry)); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QApplication::processEvents(); + + QTRY_COMPARE(widget.pos(), position); + QCOMPARE(widget.size(), size); + widget.show(); + QCOMPARE(widget.pos(), position); + QCOMPARE(widget.size(), size); + } + + { + QWidget widget; + widget.move(position); + widget.resize(size); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(500); + QTRY_COMPARE(widget.geometry().size(), size); + + QRect geom; + + //Restore from Full screen + savedGeometry = widget.saveGeometry(); + geom = widget.geometry(); + widget.setWindowState(widget.windowState() | Qt::WindowFullScreen); + QTRY_VERIFY((widget.windowState() & Qt::WindowFullScreen)); + QTest::qWait(500); + QVERIFY(widget.restoreGeometry(savedGeometry)); + QTest::qWait(120); + QTRY_VERIFY(!(widget.windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(widget.geometry(), geom); + + //Restore to full screen + widget.setWindowState(widget.windowState() | Qt::WindowFullScreen); + QTest::qWait(120); + QTRY_VERIFY((widget.windowState() & Qt::WindowFullScreen)); + QTest::qWait(500); + savedGeometry = widget.saveGeometry(); + geom = widget.geometry(); + widget.setWindowState(widget.windowState() ^ Qt::WindowFullScreen); + QTest::qWait(120); + QTRY_VERIFY(!(widget.windowState() & Qt::WindowFullScreen)); + QTest::qWait(400); + QVERIFY(widget.restoreGeometry(savedGeometry)); + QTest::qWait(120); + QTRY_VERIFY((widget.windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(widget.geometry(), geom); + QVERIFY((widget.windowState() & Qt::WindowFullScreen)); + widget.setWindowState(widget.windowState() ^ Qt::WindowFullScreen); + QTest::qWait(120); + QTRY_VERIFY(!(widget.windowState() & Qt::WindowFullScreen)); + QTest::qWait(120); + + //Restore from Maximised + widget.move(position); + widget.resize(size); + QTest::qWait(10); + QTRY_COMPARE(widget.size(), size); + QTest::qWait(500); + savedGeometry = widget.saveGeometry(); + geom = widget.geometry(); + widget.setWindowState(widget.windowState() | Qt::WindowMaximized); + QTest::qWait(120); + QTRY_VERIFY((widget.windowState() & Qt::WindowMaximized)); + QTRY_VERIFY(widget.geometry() != geom); + QTest::qWait(500); + QVERIFY(widget.restoreGeometry(savedGeometry)); + QTest::qWait(120); + QTRY_COMPARE(widget.geometry(), geom); + + QVERIFY(!(widget.windowState() & Qt::WindowMaximized)); + + //Restore to maximised + widget.setWindowState(widget.windowState() | Qt::WindowMaximized); + QTest::qWait(120); + QTRY_VERIFY((widget.windowState() & Qt::WindowMaximized)); + QTest::qWait(500); + geom = widget.geometry(); + savedGeometry = widget.saveGeometry(); + widget.setWindowState(widget.windowState() ^ Qt::WindowMaximized); + QTest::qWait(120); + QTRY_VERIFY(!(widget.windowState() & Qt::WindowMaximized)); + QTest::qWait(500); + QVERIFY(widget.restoreGeometry(savedGeometry)); + QTest::qWait(120); + QTRY_VERIFY((widget.windowState() & Qt::WindowMaximized)); + QTRY_COMPARE(widget.geometry(), geom); + } +} +#endif + +// 4DWM issues on IRIX makes this test fail. +#ifndef Q_OS_IRIX +void tst_QWidget::restoreVersion1Geometry_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("expectedWindowState"); + QTest::addColumn("expectedPosition"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedNormalGeometry"); + const QPoint position(100, 100); + const QSize size(200, 200); + const QRect normalGeometry(102, 124, 200, 200); + + QTest::newRow("geometry.dat") << ":geometry.dat" << uint(Qt::WindowNoState) << position << size << normalGeometry; + QTest::newRow("geometry-maximized.dat") << ":geometry-maximized.dat" << uint(Qt::WindowMaximized) << position << size << normalGeometry; + QTest::newRow("geometry-fullscreen.dat") << ":geometry-fullscreen.dat" << uint(Qt::WindowFullScreen) << position << size << normalGeometry; +} + +/* + Test that the current version of restoreGeometry() can restore geometry + saved width saveGeometry() version 1.0. +*/ +void tst_QWidget::restoreVersion1Geometry() +{ + QFETCH(QString, fileName); + QFETCH(uint, expectedWindowState); + QFETCH(QPoint, expectedPosition); + QFETCH(QSize, expectedSize); + QFETCH(QRect, expectedNormalGeometry); + + // WindowActive is uninteresting for this test + const uint WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized; + + QFile f(fileName); + QVERIFY(f.exists()); + f.open(QIODevice::ReadOnly); + const QByteArray savedGeometry = f.readAll(); + QCOMPARE(savedGeometry.count(), 46); + f.close(); + + QWidget widget; + + QVERIFY(widget.restoreGeometry(savedGeometry)); + + QCOMPARE(uint(widget.windowState() & WindowStateMask), expectedWindowState); + if (expectedWindowState == Qt::WindowNoState) { + QCOMPARE(widget.pos(), expectedPosition); + QCOMPARE(widget.size(), expectedSize); + } + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(100); + + if (expectedWindowState == Qt::WindowNoState) { + QTRY_COMPARE(widget.pos(), expectedPosition); + QTRY_COMPARE(widget.size(), expectedSize); + } + + widget.showNormal(); + QTest::qWait(10); + + if (expectedWindowState != Qt::WindowNoState) { + // restoring from maximized or fullscreen, we can only restore to the normal geometry + QTRY_COMPARE(widget.geometry(), expectedNormalGeometry); + } else { + QTRY_COMPARE(widget.pos(), expectedPosition); + QTRY_COMPARE(widget.size(), expectedSize); + } + +#if 0 + // Code for saving a new geometry*.dat files + { + QWidget widgetToSave; + widgetToSave.move(expectedPosition); + widgetToSave.resize(expectedSize); + widgetToSave.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); +#endif + QTest::qWait(500); // stabilize + widgetToSave.setWindowState(Qt::WindowStates(expectedWindowState)); + QTest::qWait(500); // stabilize + + QByteArray geometryToSave = widgetToSave.saveGeometry(); + + // Code for saving a new geometry.dat file. + f.setFileName(fileName.mid(1)); + QVERIFY(f.open(QIODevice::WriteOnly)); // did you forget to 'p4 edit *.dat'? :) + f.write(geometryToSave); + f.close(); + } +#endif +} +#endif + +void tst_QWidget::widgetAt() +{ + Q_CHECK_PAINTEVENTS + + QWidget *w1 = new QWidget(0, Qt::X11BypassWindowManagerHint); + w1->setGeometry(0,0,150,150); + w1->setObjectName("w1"); + + QWidget *w2 = new QWidget(0, Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint); + w2->setGeometry(50,50,100,100); + w2->setObjectName("w2"); + w1->show(); + QTest::qWaitForWindowShown(w1); + qApp->processEvents(); + QWidget *wr; + QTRY_VERIFY((wr = QApplication::widgetAt(100, 100))); + QCOMPARE(wr->objectName(), QString("w1")); + + w2->show(); + QTest::qWaitForWindowShown(w2); + qApp->processEvents(); + qApp->processEvents(); + qApp->processEvents(); + QTRY_VERIFY((wr = QApplication::widgetAt(100, 100))); + QCOMPARE(wr->objectName(), QString("w2")); + + w2->lower(); + qApp->processEvents(); + QTRY_VERIFY((wr = QApplication::widgetAt(100, 100)) && wr->objectName() == QString("w1")); + w2->raise(); + + qApp->processEvents(); + QTRY_VERIFY((wr = QApplication::widgetAt(100, 100)) && wr->objectName() == QString("w2")); + + QWidget *w3 = new QWidget(w2); + w3->setGeometry(10,10,50,50); + w3->setObjectName("w3"); + w3->show(); + qApp->processEvents(); + QTRY_VERIFY((wr = QApplication::widgetAt(100,100)) && wr->objectName() == QString("w3")); + + w3->setAttribute(Qt::WA_TransparentForMouseEvents); + qApp->processEvents(); + QTRY_VERIFY((wr = QApplication::widgetAt(100, 100)) && wr->objectName() == QString("w2")); + + QRegion rgn = QRect(QPoint(0,0), w2->size()); + QPoint point = w2->mapFromGlobal(QPoint(100,100)); + rgn -= QRect(point, QSize(1,1)); + w2->setMask(rgn); + qApp->processEvents(); + QTest::qWait(10); +#if defined(Q_OS_WINCE) + QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 +#endif +#if defined(Q_WS_QPA) + QEXPECT_FAIL("", "Window mask not implemented on Lighthouse", Continue); +#endif + + QTRY_COMPARE(QApplication::widgetAt(100,100)->objectName(), w1->objectName()); + QTRY_COMPARE(QApplication::widgetAt(101,101)->objectName(), w2->objectName()); + + QBitmap bitmap(w2->size()); + QPainter p(&bitmap); + p.fillRect(bitmap.rect(), Qt::color1); + p.setPen(Qt::color0); + p.drawPoint(w2->mapFromGlobal(QPoint(100,100))); + p.end(); + w2->setMask(bitmap); + qApp->processEvents(); + QTest::qWait(10); +#if defined(Q_OS_WINCE) + QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 +#endif +#if defined(Q_WS_QPA) + QEXPECT_FAIL("", "Window mask not implemented on Lighthouse", Continue); +#endif + QTRY_VERIFY(QApplication::widgetAt(100,100) == w1); + QTRY_VERIFY(QApplication::widgetAt(101,101) == w2); + + delete w2; + delete w1; +} + +#if defined(Q_WS_X11) +bool getProperty(Display *display, Window target, Atom type, Atom property, + unsigned char** data, unsigned long* count) +{ + Atom atom_return; + int size; + unsigned long nitems, bytes_left; + + int ret = XGetWindowProperty(display, target, property, + 0l, 1l, false, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success || nitems < 1) + return false; + + if (bytes_left != 0) { + XFree(*data); + unsigned long remain = ((size / 8) * nitems) + bytes_left; + ret = XGetWindowProperty(display, target, + property, 0l, remain, false, + type, &atom_return, &size, + &nitems, &bytes_left, data); + if (ret != Success) + return false; + } + + *count = nitems; + return true; +} + +QString textPropertyToString(Display *display, XTextProperty& text_prop) +{ + QString ret; + if (text_prop.value && text_prop.nitems > 0) { + if (text_prop.encoding == XA_STRING) { + ret = reinterpret_cast(text_prop.value); + } else { + text_prop.nitems = strlen(reinterpret_cast(text_prop.value)); + char **list; + int num; + if (XmbTextPropertyToTextList(display, &text_prop, &list, &num) == Success + && num > 0 && *list) { + ret = QString::fromLocal8Bit(*list); + XFreeStringList(list); + } + } + } + return ret; +} +#endif + +void tst_QWidget::task110173() +{ + QWidget w; + + QPushButton *pb1 = new QPushButton("click", &w); + pb1->setFocusPolicy(Qt::ClickFocus); + pb1->move(100, 100); + + QPushButton *pb2 = new QPushButton("push", &w); + pb2->setFocusPolicy(Qt::ClickFocus); + pb2->move(300, 300); + + QTest::keyClick( &w, Qt::Key_Tab ); + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(200); +} + +class Widget : public QWidget +{ +public: + Widget() : deleteThis(false) { setFocusPolicy(Qt::StrongFocus); } + void actionEvent(QActionEvent *) { if (deleteThis) delete this; } + void changeEvent(QEvent *) { if (deleteThis) delete this; } + void closeEvent(QCloseEvent *) { if (deleteThis) delete this; } + void hideEvent(QHideEvent *) { if (deleteThis) delete this; } + void focusOutEvent(QFocusEvent *) { if (deleteThis) delete this; } + void keyPressEvent(QKeyEvent *) { if (deleteThis) delete this; } + void keyReleaseEvent(QKeyEvent *) { if (deleteThis) delete this; } + void mouseDoubleClickEvent(QMouseEvent *) { if (deleteThis) delete this; } + void mousePressEvent(QMouseEvent *) { if (deleteThis) delete this; } + void mouseReleaseEvent(QMouseEvent *) { if (deleteThis) delete this; } + void mouseMoveEvent(QMouseEvent *) { if (deleteThis) delete this; } + + bool deleteThis; +}; + +void tst_QWidget::testDeletionInEventHandlers() +{ + // closeEvent + QPointer w = new Widget; + w->deleteThis = true; + w->close(); + QVERIFY(w == 0); + delete w; + + // focusOut (crashes) + //w = new Widget; + //w->show(); + //w->setFocus(); + //QVERIFY(qApp->focusWidget() == w); + //w->deleteThis = true; + //w->clearFocus(); + //QVERIFY(w == 0); + + // key press + w = new Widget; + w->show(); + w->deleteThis = true; + QTest::keyPress(w, Qt::Key_A); + QVERIFY(w == 0); + delete w; + + // key release + w = new Widget; + w->show(); + w->deleteThis = true; + QTest::keyRelease(w, Qt::Key_A); + QVERIFY(w == 0); + delete w; + + // mouse press + w = new Widget; + w->show(); + w->deleteThis = true; + QTest::mousePress(w, Qt::LeftButton); + QVERIFY(w == 0); + delete w; + + // mouse release + w = new Widget; + w->show(); + w->deleteThis = true; + QTest::mouseRelease(w, Qt::LeftButton); + QVERIFY(w == 0); + delete w; + + // mouse double click + w = new Widget; + w->show(); + w->deleteThis = true; + QTest::mouseDClick(w, Qt::LeftButton); + QVERIFY(w == 0); + delete w; + + // hide event (crashes) + //w = new Widget; + //w->show(); + //w->deleteThis = true; + //w->hide(); + //QVERIFY(w == 0); + + // action event + w = new Widget; + w->deleteThis = true; + w->addAction(new QAction(w)); + QVERIFY(w == 0); + delete w; + + // change event + w = new Widget; + w->show(); + w->deleteThis = true; + w->setMouseTracking(true); + QVERIFY(w == 0); + delete w; + + w = new Widget; + w->setMouseTracking(true); + w->show(); + w->deleteThis = true; + QMouseEvent me(QEvent::MouseMove, QPoint(0, 0), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + QApplication::sendEvent(w, &me); + QVERIFY(w == 0); + delete w; +} + +#ifdef Q_WS_MAC + +/* + Test that retaining and releasing the HIView returned by QWidget::winId() + works even if the widget itself is deleted. +*/ +void tst_QWidget::retainHIView() +{ + // Single window + { + const WidgetViewPair window = createAndRetain(); + delete window.first; + QVERIFY(testAndRelease(window.second)); + } + + // Child widget + { + const WidgetViewPair parent = createAndRetain(); + const WidgetViewPair child = createAndRetain(parent.first); + + delete parent.first; + QVERIFY(testAndRelease(parent.second)); + QVERIFY(testAndRelease(child.second)); + } + + // Multiple children + { + const WidgetViewPair parent = createAndRetain(); + const WidgetViewPair child1 = createAndRetain(parent.first); + const WidgetViewPair child2 = createAndRetain(parent.first); + + delete parent.first; + QVERIFY(testAndRelease(parent.second)); + QVERIFY(testAndRelease(child1.second)); + QVERIFY(testAndRelease(child2.second)); + } + + // Grandchild widget + { + const WidgetViewPair parent = createAndRetain(); + const WidgetViewPair child = createAndRetain(parent.first); + const WidgetViewPair grandchild = createAndRetain(child.first); + + delete parent.first; + QVERIFY(testAndRelease(parent.second)); + QVERIFY(testAndRelease(child.second)); + QVERIFY(testAndRelease(grandchild.second)); + } + + // Reparent child widget + { + const WidgetViewPair parent1 = createAndRetain(); + const WidgetViewPair parent2 = createAndRetain(); + const WidgetViewPair child = createAndRetain(parent1.first); + + child.first->setParent(parent2.first); + + delete parent1.first; + QVERIFY(testAndRelease(parent1.second)); + delete parent2.first; + QVERIFY(testAndRelease(parent2.second)); + QVERIFY(testAndRelease(child.second)); + } + + // Reparent window + { + const WidgetViewPair window1 = createAndRetain(); + const WidgetViewPair window2 = createAndRetain(); + const WidgetViewPair child1 = createAndRetain(window1.first); + const WidgetViewPair child2 = createAndRetain(window2.first); + + window2.first->setParent(window1.first); + + delete window2.first; + QVERIFY(testAndRelease(window2.second)); + QVERIFY(testAndRelease(child2.second)); + delete window1.first; + QVERIFY(testAndRelease(window1.second)); + QVERIFY(testAndRelease(child1.second)); + } + + // Delete child widget + { + const WidgetViewPair parent = createAndRetain(); + const WidgetViewPair child = createAndRetain(parent.first); + + delete child.first; + QVERIFY(testAndRelease(child.second)); + delete parent.first; + QVERIFY(testAndRelease(parent.second)); + } +} + +void tst_QWidget::sheetOpacity() +{ + QWidget tmpWindow; + QWidget sheet(&tmpWindow, Qt::Sheet); + tmpWindow.show(); + sheet.show(); + QCOMPARE(int(sheet.windowOpacity() * 255), 242); // 95% + sheet.setParent(0, Qt::Dialog); + QCOMPARE(int(sheet.windowOpacity() * 255), 255); +} + +class MaskedPainter : public QWidget +{ +public: + QRect mask; + + MaskedPainter() + : mask(20, 20, 50, 50) + { + setMask(mask); + } + + void paintEvent(QPaintEvent *) + { + QPainter p(this); + p.fillRect(mask, QColor(Qt::red)); + } +}; + +/* + Verifies that the entire area inside the mask is painted red. +*/ +bool verifyWidgetMask(QWidget *widget, QRect mask) +{ + const QImage image = QPixmap::grabWindow(widget->winId()).toImage(); + + const QImage masked = image.copy(mask); + QImage red(masked); + red.fill(QColor(Qt::red).rgb()); + + return (masked == red); +} + +void tst_QWidget::setMask() +{ + testWidget->hide(); // get this out of the way. + + { + MaskedPainter w; + w.resize(200, 200); + w.show(); + QTest::qWait(100); + QVERIFY(verifyWidgetMask(&w, w.mask)); + } + { + MaskedPainter w; + w.resize(200, 200); + w.setWindowFlags(w.windowFlags() | Qt::FramelessWindowHint); + w.show(); + QTest::qWait(100); + QRect mask = w.mask; + + QVERIFY(verifyWidgetMask(&w, mask)); + } +} +#endif + +class StaticWidget : public QWidget +{ +Q_OBJECT +public: + bool partial; + bool gotPaintEvent; + QRegion paintedRegion; + + StaticWidget(QWidget *parent = 0) + :QWidget(parent) + { + setAttribute(Qt::WA_StaticContents); + setAttribute(Qt::WA_OpaquePaintEvent); + setPalette(Qt::red); // Make sure we have an opaque palette. + setAutoFillBackground(true); + gotPaintEvent = false; + } + + void paintEvent(QPaintEvent *e) + { + paintedRegion += e->region(); + gotPaintEvent = true; +// qDebug() << "paint" << e->region(); + // Look for a full update, set partial to false if found. + foreach(QRect r, e->region().rects()) { + partial = (r != rect()); + if (partial == false) + break; + } + } +}; + +/* + Test that widget resizes and moves can be done with minimal repaints when WA_StaticContents + and WA_OpaquePaintEvent is set. Test is mac-only for now. +*/ +void tst_QWidget::optimizedResizeMove() +{ + QWidget parent; + parent.resize(400, 400); + + StaticWidget staticWidget(&parent); + staticWidget.gotPaintEvent = false; + staticWidget.move(150, 150); + staticWidget.resize(150, 150); + parent.show(); + QTest::qWaitForWindowShown(&parent); + QTest::qWait(20); + QTRY_COMPARE(staticWidget.gotPaintEvent, true); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(10, 10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(-10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(-10, 10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.gotPaintEvent = false; + staticWidget.resize(staticWidget.size() + QSize(10, 10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, true); + QCOMPARE(staticWidget.partial, true); + + staticWidget.gotPaintEvent = false; + staticWidget.resize(staticWidget.size() + QSize(-10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.gotPaintEvent = false; + staticWidget.resize(staticWidget.size() + QSize(10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, true); + QCOMPARE(staticWidget.partial, true); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(10, 10)); + staticWidget.resize(staticWidget.size() + QSize(-10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(10, 10)); + staticWidget.resize(staticWidget.size() + QSize(10, 10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, true); + QCOMPARE(staticWidget.partial, true); + + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(-10, -10)); + staticWidget.resize(staticWidget.size() + QSize(-10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + + staticWidget.setAttribute(Qt::WA_StaticContents, false); + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(-10, -10)); + staticWidget.resize(staticWidget.size() + QSize(-10, -10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, true); + QCOMPARE(staticWidget.partial, false); + staticWidget.setAttribute(Qt::WA_StaticContents, true); + + staticWidget.setAttribute(Qt::WA_StaticContents, false); + staticWidget.gotPaintEvent = false; + staticWidget.move(staticWidget.pos() + QPoint(10, 10)); + QTest::qWait(20); + QCOMPARE(staticWidget.gotPaintEvent, false); + staticWidget.setAttribute(Qt::WA_StaticContents, true); +} + +void tst_QWidget::optimizedResize_topLevel() +{ +#if defined(Q_WS_MAC) || defined(Q_WS_QWS) + QSKIP("We do not yet have static contents support for *top-levels* on this platform", SkipAll); +#endif + + StaticWidget topLevel; + topLevel.gotPaintEvent = false; + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); + QTest::qWait(10); + QTRY_COMPARE(topLevel.gotPaintEvent, true); + + topLevel.gotPaintEvent = false; + topLevel.partial = false; + topLevel.paintedRegion = QRegion(); + +#ifndef Q_WS_WIN + topLevel.resize(topLevel.size() + QSize(10, 10)); +#else + // Static contents does not work when programmatically resizing + // top-levels with QWidget::resize. We do some funky stuff in + // setGeometry_sys. However, resizing it with the mouse or with + // a native function call works (it basically has to go through + // WM_RESIZE in QApplication). This is a corner case, though. + // See task 243708 + const QRect frame = topLevel.frameGeometry(); + MoveWindow(topLevel.winId(), frame.x(), frame.y(), + frame.width() + 10, frame.height() + 10, + true); +#endif + + QTest::qWait(100); + + // Expected update region: New rect - old rect. + QRegion expectedUpdateRegion(topLevel.rect()); + expectedUpdateRegion -= QRect(QPoint(), topLevel.size() - QSize(10, 10)); + + QTRY_COMPARE(topLevel.gotPaintEvent, true); + QCOMPARE(topLevel.partial, true); + QCOMPARE(topLevel.paintedRegion, expectedUpdateRegion); +} + +class SiblingDeleter : public QWidget +{ +public: + inline SiblingDeleter(QWidget *sibling, QWidget *parent) + : QWidget(parent), sibling(sibling) {} + inline virtual ~SiblingDeleter() { delete sibling; } + +private: + QPointer sibling; +}; + + +void tst_QWidget::childDeletesItsSibling() +{ + QWidget *commonParent = new QWidget(0); + QPointer child = new QWidget(0); + QPointer siblingDeleter = new SiblingDeleter(child, commonParent); + child->setParent(commonParent); + delete commonParent; // don't crash + QVERIFY(!child); + QVERIFY(!siblingDeleter); + +} + +#ifdef Q_WS_QWS +# define SET_SAFE_SIZE(w) \ + do { \ + QSize safeSize(qt_screen->width() - 250, qt_screen->height() - 250); \ + if (!safeSize.isValid()) \ + QSKIP("Screen size too small", SkipAll); \ + if (defaultSize.width() > safeSize.width() || defaultSize.height() > safeSize.height()) { \ + defaultSize = safeSize; \ + w.resize(defaultSize); \ + w.setAttribute(Qt::WA_Resized, false); \ + } \ + } while (false) +#else +# define SET_SAFE_SIZE(w) +#endif + + +void tst_QWidget::setMinimumSize() +{ + QWidget w; + QSize defaultSize = w.size(); + SET_SAFE_SIZE(w); + + w.setMinimumSize(defaultSize + QSize(100, 100)); + QCOMPARE(w.size(), defaultSize + QSize(100, 100)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setMinimumSize(defaultSize + QSize(50, 50)); + QCOMPARE(w.size(), defaultSize + QSize(100, 100)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setMinimumSize(defaultSize + QSize(200, 200)); + QCOMPARE(w.size(), defaultSize + QSize(200, 200)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + // Setting a minimum size larger than the desktop does not work on WinCE, + // so skip this part of the test. +#ifndef Q_OS_WINCE + QSize nonDefaultSize = defaultSize + QSize(5,5); + w.setMinimumSize(nonDefaultSize); + w.show(); + QTest::qWait(50); + QVERIFY(w.height() >= nonDefaultSize.height()); + QVERIFY(w.width() >= nonDefaultSize.width()); +#endif +} + +void tst_QWidget::setMaximumSize() +{ + QWidget w; + QSize defaultSize = w.size(); + SET_SAFE_SIZE(w); + + w.setMinimumSize(defaultSize + QSize(100, 100)); + QCOMPARE(w.size(), defaultSize + QSize(100, 100)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + w.setMinimumSize(defaultSize); + + w.setMaximumSize(defaultSize + QSize(200, 200)); + QCOMPARE(w.size(), defaultSize + QSize(100, 100)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setMaximumSize(defaultSize + QSize(50, 50)); + QCOMPARE(w.size(), defaultSize + QSize(50, 50)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + +#if 0 + //we don't enforce maximum size on show, apparently + QSize nonDefaultSize = defaultSize - QSize(5,5); + w.setMaximumSize(nonDefaultSize); + w.show(); + QTest::qWait(50); + qDebug() << nonDefaultSize << w.size(); + QVERIFY(w.height() <= nonDefaultSize.height()); + QVERIFY(w.width() <= nonDefaultSize.width()); +#endif +} + +void tst_QWidget::setFixedSize() +{ + QWidget w; + QSize defaultSize = w.size(); + SET_SAFE_SIZE(w); + + w.setFixedSize(defaultSize + QSize(100, 100)); + QCOMPARE(w.size(), defaultSize + QSize(100, 100)); + QVERIFY(w.testAttribute(Qt::WA_Resized)); + + w.setFixedSize(defaultSize + QSize(200, 200)); + + QCOMPARE(w.minimumSize(), defaultSize + QSize(200,200)); + QCOMPARE(w.maximumSize(), defaultSize + QSize(200,200)); + QCOMPARE(w.size(), defaultSize + QSize(200, 200)); + QVERIFY(w.testAttribute(Qt::WA_Resized)); + + w.setFixedSize(defaultSize + QSize(50, 50)); + QCOMPARE(w.size(), defaultSize + QSize(50, 50)); + QVERIFY(w.testAttribute(Qt::WA_Resized)); + + w.setAttribute(Qt::WA_Resized, false); + w.setFixedSize(defaultSize + QSize(50, 50)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setFixedSize(defaultSize + QSize(150, 150)); + w.show(); + QTest::qWait(50); + QVERIFY(w.size() == defaultSize + QSize(150,150)); +} + +void tst_QWidget::ensureCreated() +{ + { + QWidget widget; + WId widgetWinId = widget.winId(); + Q_UNUSED(widgetWinId); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + } + + { + QWidget window; + + QDialog dialog(&window); + dialog.setWindowModality(Qt::NonModal); + + WId dialogWinId = dialog.winId(); + Q_UNUSED(dialogWinId); + QVERIFY(dialog.testAttribute(Qt::WA_WState_Created)); + QVERIFY(window.testAttribute(Qt::WA_WState_Created)); + } + + { + QWidget window; + + QDialog dialog(&window); + dialog.setWindowModality(Qt::WindowModal); + + WId dialogWinId = dialog.winId(); + Q_UNUSED(dialogWinId); + QVERIFY(dialog.testAttribute(Qt::WA_WState_Created)); + QVERIFY(window.testAttribute(Qt::WA_WState_Created)); + } + + { + QWidget window; + + QDialog dialog(&window); + dialog.setWindowModality(Qt::ApplicationModal); + + WId dialogWinId = dialog.winId(); + Q_UNUSED(dialogWinId); + QVERIFY(dialog.testAttribute(Qt::WA_WState_Created)); + QVERIFY(window.testAttribute(Qt::WA_WState_Created)); + } +} + +class WinIdChangeWidget : public QWidget { +public: + WinIdChangeWidget(QWidget *p = 0) + : QWidget(p) + { + + } +protected: + bool event(QEvent *e) + { + if (e->type() == QEvent::WinIdChange) { + m_winIdList.append(internalWinId()); + return true; + } + return QWidget::event(e); + } +public: + QList m_winIdList; + int winIdChangeEventCount() const { return m_winIdList.count(); } +}; + +void tst_QWidget::winIdChangeEvent() +{ + { + // Transforming an alien widget into a native widget + WinIdChangeWidget widget; + const WId winIdBefore = widget.internalWinId(); + const WId winIdAfter = widget.winId(); + QVERIFY(winIdBefore != winIdAfter); + QCOMPARE(widget.winIdChangeEventCount(), 1); + } + + { + // Changing parent of a native widget + // Should cause winId of child to change, on all platforms + QWidget parent1, parent2; + WinIdChangeWidget child(&parent1); + const WId winIdBefore = child.winId(); + QCOMPARE(child.winIdChangeEventCount(), 1); + child.setParent(&parent2); + const WId winIdAfter = child.internalWinId(); + QVERIFY(winIdBefore != winIdAfter); + QCOMPARE(child.winIdChangeEventCount(), 3); + // winId is set to zero during reparenting + QVERIFY(0 == child.m_winIdList[1]); + } + + { + // Changing grandparent of a native widget + QWidget grandparent1, grandparent2; + QWidget parent(&grandparent1); + WinIdChangeWidget child(&parent); + const WId winIdBefore = child.winId(); + QCOMPARE(child.winIdChangeEventCount(), 1); + parent.setParent(&grandparent2); + const WId winIdAfter = child.internalWinId(); + QCOMPARE(winIdBefore, winIdAfter); + QCOMPARE(child.winIdChangeEventCount(), 1); + } + + { + // Changing parent of an alien widget + QWidget parent1, parent2; + WinIdChangeWidget child(&parent1); + const WId winIdBefore = child.internalWinId(); + child.setParent(&parent2); + const WId winIdAfter = child.internalWinId(); + QCOMPARE(winIdBefore, winIdAfter); + QCOMPARE(child.winIdChangeEventCount(), 0); + } + + { + // Making native child widget into a top-level window + QWidget parent; + WinIdChangeWidget child(&parent); + child.winId(); + const WId winIdBefore = child.internalWinId(); + QCOMPARE(child.winIdChangeEventCount(), 1); + const Qt::WindowFlags flags = child.windowFlags(); + child.setWindowFlags(flags | Qt::Window); + const WId winIdAfter = child.internalWinId(); + QVERIFY(winIdBefore != winIdAfter); + QCOMPARE(child.winIdChangeEventCount(), 3); + // winId is set to zero during reparenting + QVERIFY(0 == child.m_winIdList[1]); + } +} + +void tst_QWidget::persistentWinId() +{ + QWidget *parent = new QWidget; + QWidget *w1 = new QWidget; + QWidget *w2 = new QWidget; + QWidget *w3 = new QWidget; + w1->setParent(parent); + w2->setParent(w1); + w3->setParent(w2); + + WId winId1 = w1->winId(); + WId winId2 = w2->winId(); + WId winId3 = w3->winId(); + + // reparenting should change the winId of the widget being reparented, but not of its children + w1->setParent(0); + QVERIFY(w1->winId() != winId1); + winId1 = w1->winId(); + QCOMPARE(w2->winId(), winId2); + QCOMPARE(w3->winId(), winId3); + + w1->setParent(parent); + QVERIFY(w1->winId() != winId1); + winId1 = w1->winId(); + QCOMPARE(w2->winId(), winId2); + QCOMPARE(w3->winId(), winId3); + + w2->setParent(0); + QVERIFY(w2->winId() != winId2); + winId2 = w2->winId(); + QCOMPARE(w3->winId(), winId3); + + w2->setParent(parent); + QVERIFY(w2->winId() != winId2); + winId2 = w2->winId(); + QCOMPARE(w3->winId(), winId3); + + w2->setParent(w1); + QVERIFY(w2->winId() != winId2); + winId2 = w2->winId(); + QCOMPARE(w3->winId(), winId3); + + w3->setParent(0); + QVERIFY(w3->winId() != winId3); + winId3 = w3->winId(); + + w3->setParent(w1); + QVERIFY(w3->winId() != winId3); + winId3 = w3->winId(); + + w3->setParent(w2); + QVERIFY(w3->winId() != winId3); + winId3 = w3->winId(); + + delete parent; +} + +void tst_QWidget::showNativeChild() +{ + QWidget topLevel; + topLevel.setGeometry(0, 0, 100, 100); + QWidget child(&topLevel); + child.winId(); + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); +} + +class ShowHideEventWidget : public QWidget +{ +public: + int numberOfShowEvents, numberOfHideEvents; + + ShowHideEventWidget(QWidget *parent = 0) + : QWidget(parent), numberOfShowEvents(0), numberOfHideEvents(0) + { } + + void create() + { QWidget::create(); } + + void showEvent(QShowEvent *) + { ++numberOfShowEvents; } + + void hideEvent(QHideEvent *) + { ++numberOfHideEvents; } +}; + +void tst_QWidget::showHideEvent_data() +{ + QTest::addColumn("show"); + QTest::addColumn("hide"); + QTest::addColumn("create"); + QTest::addColumn("expectedShowEvents"); + QTest::addColumn("expectedHideEvents"); + + QTest::newRow("window: only show") + << true + << false + << false + << 1 + << 0; + QTest::newRow("window: show/hide") + << true + << true + << false + << 1 + << 1; + QTest::newRow("window: show/hide/create") + << true + << true + << true + << 1 + << 1; + QTest::newRow("window: hide/create") + << false + << true + << true + << 0 + << 0; + QTest::newRow("window: only hide") + << false + << true + << false + << 0 + << 0; + QTest::newRow("window: nothing") + << false + << false + << false + << 0 + << 0; +} + +void tst_QWidget::showHideEvent() +{ + QFETCH(bool, show); + QFETCH(bool, hide); + QFETCH(bool, create); + QFETCH(int, expectedShowEvents); + QFETCH(int, expectedHideEvents); + + ShowHideEventWidget widget; + if (show) + widget.show(); + if (hide) + widget.hide(); + if (create && !widget.testAttribute(Qt::WA_WState_Created)) + widget.create(); + + QCOMPARE(widget.numberOfShowEvents, expectedShowEvents); + QCOMPARE(widget.numberOfHideEvents, expectedHideEvents); +} + +void tst_QWidget::update() +{ + QTest::qWait(10); // Wait for the initStuff to do it's stuff. + Q_CHECK_PAINTEVENTS + + UpdateWidget w; + w.setGeometry(50, 50, 100, 100); + w.show(); + QTest::qWaitForWindowShown(&w); + + QApplication::processEvents(); + QApplication::processEvents(); + +#ifdef Q_OS_MAC + QEXPECT_FAIL(0, "Cocoa compositor says to paint this twice.", Continue); +#endif + QTRY_COMPARE(w.numPaintEvents, 1); + + QCOMPARE(w.visibleRegion(), QRegion(w.rect())); + QCOMPARE(w.paintedRegion, w.visibleRegion()); + w.reset(); + + UpdateWidget child(&w); + child.setGeometry(10, 10, 80, 80); + child.show(); + + QPoint childOffset = child.mapToParent(QPoint()); + + // widgets are transparent by default, so both should get repaints + { + QApplication::processEvents(); + QApplication::processEvents(); + QCOMPARE(child.numPaintEvents, 1); + QCOMPARE(child.visibleRegion(), QRegion(child.rect())); + QCOMPARE(child.paintedRegion, child.visibleRegion()); + QCOMPARE(w.numPaintEvents, 1); + QCOMPARE(w.visibleRegion(), QRegion(w.rect())); + QCOMPARE(w.paintedRegion, child.visibleRegion().translated(childOffset)); + + w.reset(); + child.reset(); + + w.update(); + QApplication::processEvents(); + QApplication::processEvents(); + QCOMPARE(child.numPaintEvents, 1); + QCOMPARE(child.visibleRegion(), QRegion(child.rect())); + QCOMPARE(child.paintedRegion, child.visibleRegion()); + QCOMPARE(w.numPaintEvents, 1); + QCOMPARE(w.visibleRegion(), QRegion(w.rect())); + QCOMPARE(w.paintedRegion, w.visibleRegion()); + } + + QPalette opaquePalette = child.palette(); + opaquePalette.setColor(child.backgroundRole(), QColor(Qt::red)); + + // setting an opaque background on the child should prevent paint-events + // for the parent in the child area + { + child.setPalette(opaquePalette); + child.setAutoFillBackground(true); + QApplication::processEvents(); + + w.reset(); + child.reset(); + + w.update(); + QApplication::processEvents(); + QApplication::processEvents(); + + QCOMPARE(w.numPaintEvents, 1); + QRegion expectedVisible = QRegion(w.rect()) + - child.visibleRegion().translated(childOffset); + QCOMPARE(w.visibleRegion(), expectedVisible); + QCOMPARE(w.paintedRegion, expectedVisible); + QCOMPARE(child.numPaintEvents, 0); + + w.reset(); + child.reset(); + + child.update(); + QApplication::processEvents(); + QApplication::processEvents(); + + QCOMPARE(w.numPaintEvents, 0); + QCOMPARE(child.numPaintEvents, 1); + QCOMPARE(child.paintedRegion, child.visibleRegion()); + + w.reset(); + child.reset(); + } + + // overlapping sibling + UpdateWidget sibling(&w); + child.setGeometry(10, 10, 20, 20); + sibling.setGeometry(15, 15, 20, 20); + sibling.show(); + + QApplication::processEvents(); + w.reset(); + child.reset(); + sibling.reset(); + + const QPoint siblingOffset = sibling.mapToParent(QPoint()); + + sibling.update(); + QApplication::processEvents(); + QApplication::processEvents(); + + // child is opaque, sibling transparent + { + QCOMPARE(sibling.numPaintEvents, 1); + QCOMPARE(sibling.paintedRegion, sibling.visibleRegion()); + + QCOMPARE(child.numPaintEvents, 1); + QCOMPARE(child.paintedRegion.translated(childOffset), + child.visibleRegion().translated(childOffset) + & sibling.visibleRegion().translated(siblingOffset)); + + QCOMPARE(w.numPaintEvents, 1); + QCOMPARE(w.paintedRegion, + w.visibleRegion() & sibling.visibleRegion().translated(siblingOffset)); + QCOMPARE(w.paintedRegion, + (w.visibleRegion() - child.visibleRegion().translated(childOffset)) + & sibling.visibleRegion().translated(siblingOffset)); + + } + w.reset(); + child.reset(); + sibling.reset(); + + sibling.setPalette(opaquePalette); + sibling.setAutoFillBackground(true); + + sibling.update(); + QApplication::processEvents(); + QApplication::processEvents(); + + // child opaque, sibling opaque + { + QCOMPARE(sibling.numPaintEvents, 1); + QCOMPARE(sibling.paintedRegion, sibling.visibleRegion()); + +#ifdef Q_OS_MAC + if (child.internalWinId()) // child is native + QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue); +#endif + QCOMPARE(child.numPaintEvents, 0); + QCOMPARE(child.visibleRegion(), + QRegion(child.rect()) + - sibling.visibleRegion().translated(siblingOffset - childOffset)); + + QCOMPARE(w.numPaintEvents, 0); + QCOMPARE(w.visibleRegion(), + QRegion(w.rect()) + - child.visibleRegion().translated(childOffset) + - sibling.visibleRegion().translated(siblingOffset)); + } +} + +static inline bool isOpaque(QWidget *widget) +{ + if (!widget) + return false; + return qt_widget_private(widget)->isOpaque; +} + +void tst_QWidget::isOpaque() +{ +#ifndef Q_WS_MAC + QWidget w; + QVERIFY(::isOpaque(&w)); + + QWidget child(&w); + QVERIFY(!::isOpaque(&child)); + + child.setAutoFillBackground(true); + QVERIFY(::isOpaque(&child)); + + QPalette palette; + + // background color + + palette = child.palette(); + palette.setColor(child.backgroundRole(), QColor(255, 0, 0, 127)); + child.setPalette(palette); + QVERIFY(!::isOpaque(&child)); + + palette.setColor(child.backgroundRole(), QColor(255, 0, 0, 255)); + child.setPalette(palette); + QVERIFY(::isOpaque(&child)); + + palette.setColor(QPalette::Window, QColor(0, 0, 255, 127)); + w.setPalette(palette); + + QVERIFY(!::isOpaque(&w)); + + child.setAutoFillBackground(false); + QVERIFY(!::isOpaque(&child)); + + // Qt::WA_OpaquePaintEvent + + child.setAttribute(Qt::WA_OpaquePaintEvent); + QVERIFY(::isOpaque(&child)); + + child.setAttribute(Qt::WA_OpaquePaintEvent, false); + QVERIFY(!::isOpaque(&child)); + + // Qt::WA_NoSystemBackground + + child.setAttribute(Qt::WA_NoSystemBackground); + QVERIFY(!::isOpaque(&child)); + + child.setAttribute(Qt::WA_NoSystemBackground, false); + QVERIFY(!::isOpaque(&child)); + + palette.setColor(QPalette::Window, QColor(0, 0, 255, 255)); + w.setPalette(palette); + QVERIFY(::isOpaque(&w)); + + w.setAttribute(Qt::WA_NoSystemBackground); + QVERIFY(!::isOpaque(&w)); + + w.setAttribute(Qt::WA_NoSystemBackground, false); + QVERIFY(::isOpaque(&w)); + + { + QPalette palette = QApplication::palette(); + QPalette old = palette; + palette.setColor(QPalette::Window, Qt::transparent); + QApplication::setPalette(palette); + + QWidget widget; + QVERIFY(!::isOpaque(&widget)); + + QApplication::setPalette(old); + QCOMPARE(::isOpaque(&widget), old.color(QPalette::Window).alpha() == 255); + } +#endif +} + +#ifndef Q_WS_MAC +/* + Test that scrolling of a widget invalidates the correct regions +*/ +void tst_QWidget::scroll() +{ + UpdateWidget updateWidget; + updateWidget.resize(500, 500); + updateWidget.reset(); + updateWidget.show(); + QTest::qWaitForWindowShown(&updateWidget); + QTest::qWait(50); + qApp->processEvents(); + QTRY_VERIFY(updateWidget.numPaintEvents > 0); + + { + updateWidget.reset(); + updateWidget.scroll(10, 10); + qApp->processEvents(); + QRegion dirty(QRect(0, 0, 500, 10)); + dirty += QRegion(QRect(0, 10, 10, 490)); + QCOMPARE(updateWidget.paintedRegion, dirty); + } + + { + updateWidget.reset(); + updateWidget.update(0, 0, 10, 10); + updateWidget.scroll(0, 10); + qApp->processEvents(); + QRegion dirty(QRect(0, 0, 500, 10)); + dirty += QRegion(QRect(0, 10, 10, 10)); + QCOMPARE(updateWidget.paintedRegion, dirty); + } + + { + updateWidget.reset(); + updateWidget.update(0, 0, 100, 100); + updateWidget.scroll(10, 10, QRect(50, 50, 100, 100)); + qApp->processEvents(); + QRegion dirty(QRect(0, 0, 100, 50)); + dirty += QRegion(QRect(0, 50, 150, 10)); + dirty += QRegion(QRect(0, 60, 110, 40)); + dirty += QRegion(QRect(50, 100, 60, 10)); + dirty += QRegion(QRect(50, 110, 10, 40)); + QCOMPARE(updateWidget.paintedRegion, dirty); + } + + { + updateWidget.reset(); + updateWidget.update(0, 0, 100, 100); + updateWidget.scroll(10, 10, QRect(100, 100, 100, 100)); + qApp->processEvents(); + QRegion dirty(QRect(0, 0, 100, 100)); + dirty += QRegion(QRect(100, 100, 100, 10)); + dirty += QRegion(QRect(100, 110, 10, 90)); + QCOMPARE(updateWidget.paintedRegion, dirty); + } +} +#endif + +class DestroyedSlotChecker : public QObject +{ + Q_OBJECT + +public: + bool wasQWidget; + + DestroyedSlotChecker() + : wasQWidget(false) + { + } + +public slots: + void destroyedSlot(QObject *object) + { + wasQWidget = (qobject_cast(object) != 0 || object->isWidgetType()); + } +}; + +/* + Test that qobject_cast returns 0 in a slot + connected to QObject::destroyed. +*/ +void tst_QWidget::qobject_castInDestroyedSlot() +{ + DestroyedSlotChecker checker; + QWidget *widget = new QWidget(); + + QObject::connect(widget, SIGNAL(destroyed(QObject *)), &checker, SLOT(destroyedSlot(QObject *))); + delete widget; + + QVERIFY(checker.wasQWidget == true); +} + +Q_DECLARE_METATYPE(QList) + +// Since X11 WindowManager operations are all async, and we have no way to know if the window +// manager has finished playing with the window geometry, this test can't be reliable on X11. +#ifndef Q_WS_X11 +void tst_QWidget::setWindowGeometry_data() +{ + QTest::addColumn >("rects"); + QTest::addColumn("windowFlags"); + + QList > rects; + rects << (QList() + << QRect(100, 100, 200, 200) + << QApplication::desktop()->availableGeometry().adjusted(100, 100, -100, -100) + << QRect(130, 100, 0, 200) + << QRect(100, 50, 200, 0) + << QRect(130, 50, 0, 0)) + << (QList() + << QApplication::desktop()->availableGeometry().adjusted(100, 100, -100, -100) + << QRect(130, 100, 0, 200) + << QRect(100, 50, 200, 0) + << QRect(130, 50, 0, 0) + << QRect(100, 100, 200, 200)) + << (QList() + << QRect(130, 100, 0, 200) + << QRect(100, 50, 200, 0) + << QRect(130, 50, 0, 0) + << QRect(100, 100, 200, 200) + << QApplication::desktop()->availableGeometry().adjusted(100, 100, -100, -100)) + << (QList() + << QRect(100, 50, 200, 0) + << QRect(130, 50, 0, 0) + << QRect(100, 100, 200, 200) + << QApplication::desktop()->availableGeometry().adjusted(100, 100, -100, -100) + << QRect(130, 100, 0, 200)) + << (QList() + << QRect(130, 50, 0, 0) + << QRect(100, 100, 200, 200) + << QApplication::desktop()->availableGeometry().adjusted(100, 100, -100, -100) + << QRect(130, 100, 0, 200) + << QRect(100, 50, 200, 0)); + + QList windowFlags; + windowFlags << 0 << Qt::FramelessWindowHint; + + foreach (QList l, rects) { + QRect rect = l.first(); + foreach (int windowFlag, windowFlags) { + QTest::newRow(QString("%1,%2 %3x%4, flags %5") + .arg(rect.x()) + .arg(rect.y()) + .arg(rect.width()) + .arg(rect.height()) + .arg(windowFlag, 0, 16).toAscii()) + << l + << windowFlag; + } + } +} + +void tst_QWidget::setWindowGeometry() +{ + QFETCH(QList, rects); + QFETCH(int, windowFlags); + QRect rect = rects.takeFirst(); + + { + // test setGeometry() without actually showing the window + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.setGeometry(rect); + QTest::qWait(100); + QCOMPARE(widget.geometry(), rect); + + // setGeometry() without showing + foreach (QRect r, rects) { + widget.setGeometry(r); + QTest::qWait(100); + QCOMPARE(widget.geometry(), r); + } + } + + { + // setGeometry() first, then show() + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.setGeometry(rect); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(20); + QTRY_COMPARE(widget.geometry(), rect); + + // setGeometry() while shown + foreach (QRect r, rects) { + widget.setGeometry(r); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), r); + } + widget.setGeometry(rect); + QTest::qWait(20); + QTRY_COMPARE(widget.geometry(), rect); + + // now hide + widget.hide(); + QTest::qWait(20); + QTRY_COMPARE(widget.geometry(), rect); + + // setGeometry() after hide() + foreach (QRect r, rects) { + widget.setGeometry(r); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), r); + } + widget.setGeometry(rect); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // show() again, geometry() should still be the same + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // final hide(), again geometry() should be unchanged + widget.hide(); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + } + + { + // show() first, then setGeometry() + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + widget.setGeometry(rect); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // setGeometry() while shown + foreach (QRect r, rects) { + widget.setGeometry(r); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), r); + } + widget.setGeometry(rect); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // now hide + widget.hide(); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // setGeometry() after hide() + foreach (QRect r, rects) { + widget.setGeometry(r); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), r); + } + widget.setGeometry(rect); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // show() again, geometry() should still be the same + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + + // final hide(), again geometry() should be unchanged + widget.hide(); + QTest::qWait(10); + QTRY_COMPARE(widget.geometry(), rect); + } +} +#endif + +#if defined (Q_WS_WIN) && !defined(Q_OS_WINCE) +void tst_QWidget::setGeometry_win() +{ + QWidget widget; + widget.setGeometry(0, 600, 100,100); + widget.show(); + widget.setWindowState(widget.windowState() | Qt::WindowMaximized); + QRect geom = widget.normalGeometry(); + widget.close(); + widget.setGeometry(geom); + widget.setWindowState(widget.windowState() | Qt::WindowMaximized); + widget.show(); + RECT rt; + ::GetWindowRect(widget.internalWinId(), &rt); + QVERIFY(rt.left <= 0); + QVERIFY(rt.top <= 0); +} +#endif + +// Since X11 WindowManager operation are all async, and we have no way to know if the window +// manager has finished playing with the window geometry, this test can't be reliable on X11. +// 4DWM issues on IRIX also makes this test fail. +#if !defined(Q_WS_X11) && !defined(Q_OS_IRIX) +void tst_QWidget::windowMoveResize_data() +{ + setWindowGeometry_data(); +} + +void tst_QWidget::windowMoveResize() +{ + QFETCH(QList, rects); + QFETCH(int, windowFlags); + + QRect rect = rects.takeFirst(); + + { + // test setGeometry() without actually showing the window + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // move() without showing + foreach (QRect r, rects) { + widget.move(r.topLeft()); + widget.resize(r.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), r.topLeft()); + QTRY_COMPARE(widget.size(), r.size()); + } + } + + { + // move() first, then show() + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.move(rect.topLeft()); + widget.resize(rect.size()); + widget.show(); + + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // move() while shown + foreach (QRect r, rects) { +#ifdef Q_WS_X11 + if ((widget.width() == 0 || widget.height() == 0) && r.width() != 0 && r.height() != 0) { + QEXPECT_FAIL("130,100 0x200, flags 0", + "First resize after show of zero-sized gets wrong win_gravity.", + Continue); + QEXPECT_FAIL("100,50 200x0, flags 0", + "First resize after show of zero-sized gets wrong win_gravity.", + Continue); + QEXPECT_FAIL("130,50 0x0, flags 0", + "First resize after show of zero-sized gets wrong win_gravity.", + Continue); + } +#endif + widget.move(r.topLeft()); + widget.resize(r.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), r.topLeft()); + QTRY_COMPARE(widget.size(), r.size()); + } + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // now hide + widget.hide(); + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // move() after hide() + foreach (QRect r, rects) { + widget.move(r.topLeft()); + widget.resize(r.size()); + QApplication::processEvents(); +#if defined(Q_WS_MAC) + if (r.width() == 0 && r.height() > 0) { + widget.move(r.topLeft()); + widget.resize(r.size()); + } +#endif + QTRY_COMPARE(widget.pos(), r.topLeft()); + QTRY_COMPARE(widget.size(), r.size()); + } + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // show() again, pos() should be the same + widget.show(); + QTest::qWaitForWindowShown(&widget); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // final hide(), again pos() should be unchanged + widget.hide(); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + } + + { + // show() first, then move() + QWidget widget; + if (windowFlags != 0) + widget.setWindowFlags(Qt::WindowFlags(windowFlags)); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QApplication::processEvents(); + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // move() while shown + foreach (QRect r, rects) { + widget.move(r.topLeft()); + widget.resize(r.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), r.topLeft()); + QTRY_COMPARE(widget.size(), r.size()); + } + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // now hide + widget.hide(); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // move() after hide() + foreach (QRect r, rects) { + widget.move(r.topLeft()); + widget.resize(r.size()); + QApplication::processEvents(); +#if defined(Q_WS_MAC) + if (r.width() == 0 && r.height() > 0) { + widget.move(r.topLeft()); + widget.resize(r.size()); + } +#endif + QTRY_COMPARE(widget.pos(), r.topLeft()); + QTRY_COMPARE(widget.size(), r.size()); + } + widget.move(rect.topLeft()); + widget.resize(rect.size()); + QApplication::processEvents(); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // show() again, pos() should be the same + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + + // final hide(), again pos() should be unchanged + widget.hide(); + QTest::qWait(10); + QTRY_COMPARE(widget.pos(), rect.topLeft()); + QTRY_COMPARE(widget.size(), rect.size()); + } +} +#endif + +class ColorWidget : public QWidget +{ +public: + ColorWidget(QWidget *parent = 0, const QColor &c = QColor(Qt::red)) + : QWidget(parent, Qt::FramelessWindowHint), color(c) + { + QPalette opaquePalette = palette(); + opaquePalette.setColor(backgroundRole(), color); + setPalette(opaquePalette); + setAutoFillBackground(true); + } + + void paintEvent(QPaintEvent *e) { + r += e->region(); + } + + void reset() { + r = QRegion(); + } + + QColor color; + QRegion r; +}; + +#define VERIFY_COLOR(region, color) { \ + const QRegion r = QRegion(region); \ + for (int i = 0; i < r.rects().size(); ++i) { \ + const QRect rect = r.rects().at(i); \ + for (int t = 0; t < 5; t++) { \ + const QPixmap pixmap = QPixmap::grabWindow(QDesktopWidget().winId(), \ + rect.left(), rect.top(), \ + rect.width(), rect.height()); \ + QCOMPARE(pixmap.size(), rect.size()); \ + QPixmap expectedPixmap(pixmap); /* ensure equal formats */ \ + expectedPixmap.detach(); \ + expectedPixmap.fill(color); \ + QImage image = pixmap.toImage(); \ + uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; \ + uint firstPixel = image.pixel(0,0) | alphaCorrection; \ + if ( firstPixel != QColor(color).rgb() && t < 4 ) \ + { QTest::qWait(200); continue; } \ + QCOMPARE(firstPixel, QColor(color).rgb()); \ + QCOMPARE(pixmap, expectedPixmap); \ + break; \ + } \ + } \ +} + +void tst_QWidget::moveChild_data() +{ + QTest::addColumn("offset"); + + QTest::newRow("right") << QPoint(20, 0); + QTest::newRow("down") << QPoint(0, 20); + QTest::newRow("left") << QPoint(-20, 0); + QTest::newRow("up") << QPoint(0, -20); +} + +void tst_QWidget::moveChild() +{ + QFETCH(QPoint, offset); + + ColorWidget parent; + // prevent custom styles + parent.setStyle(new QWindowsStyle); + ColorWidget child(&parent, Qt::blue); + +#ifndef Q_OS_WINCE + parent.setGeometry(QRect(QPoint(QApplication::desktop()->availableGeometry(&parent).topLeft()), + QSize(100, 100))); +#else + parent.setGeometry(60, 60, 150, 150); +#endif + child.setGeometry(25, 25, 50, 50); + QPoint childOffset = child.mapToGlobal(QPoint()); + + parent.show(); + QTest::qWaitForWindowShown(&parent); + QTest::qWait(30); + const QPoint tlwOffset = parent.geometry().topLeft(); + + QTRY_COMPARE(parent.r, QRegion(parent.rect()) - child.geometry()); + QTRY_COMPARE(child.r, QRegion(child.rect())); + VERIFY_COLOR(child.geometry().translated(tlwOffset), + child.color); + VERIFY_COLOR(QRegion(parent.geometry()) - child.geometry().translated(tlwOffset), + parent.color); + parent.reset(); + child.reset(); + + // move + + const QRect oldGeometry = child.geometry(); + + QPoint pos = child.pos() + offset; + child.move(pos); + QTest::qWait(100); + QTRY_COMPARE(pos, child.pos()); + + QCOMPARE(parent.r, QRegion(oldGeometry) - child.geometry()); +#if !defined(Q_WS_MAC) + // should be scrolled in backingstore + QCOMPARE(child.r, QRegion()); +#endif + VERIFY_COLOR(child.geometry().translated(tlwOffset), + child.color); + VERIFY_COLOR(QRegion(parent.geometry()) - child.geometry().translated(tlwOffset), + parent.color); +} + +void tst_QWidget::showAndMoveChild() +{ + QWidget parent(0, Qt::FramelessWindowHint); + // prevent custom styles + parent.setStyle(new QWindowsStyle); + + QDesktopWidget desktop; + QRect desktopDimensions = desktop.availableGeometry(&parent); + desktopDimensions = desktopDimensions.adjusted(64, 64, -64, -64); + + parent.setGeometry(desktopDimensions); + parent.setPalette(Qt::red); + parent.show(); + QTest::qWaitForWindowShown(&parent); + QTest::qWait(10); + + const QPoint tlwOffset = parent.geometry().topLeft(); + QWidget child(&parent); + child.resize(desktopDimensions.width()/2, desktopDimensions.height()/2); + child.setPalette(Qt::blue); + child.setAutoFillBackground(true); + + // Ensure that the child is repainted correctly when moved right after show. + // NB! Do NOT processEvents() (or qWait()) in between show() and move(). + child.show(); + child.move(desktopDimensions.width()/2, desktopDimensions.height()/2); + qApp->processEvents(); + + VERIFY_COLOR(child.geometry().translated(tlwOffset), Qt::blue); + VERIFY_COLOR(QRegion(parent.geometry()) - child.geometry().translated(tlwOffset), Qt::red); +} + +// Cocoa only has rect granularity. +#ifndef QT_OS_MAC +void tst_QWidget::subtractOpaqueSiblings() +{ + QWidget w; + w.setGeometry(50, 50, 300, 300); + + ColorWidget *large = new ColorWidget(&w, Qt::red); + large->setGeometry(50, 50, 200, 200); + + ColorWidget *medium = new ColorWidget(large, Qt::gray); + medium->setGeometry(50, 50, 100, 100); + + ColorWidget *tall = new ColorWidget(&w, Qt::blue); + tall->setGeometry(100, 30, 50, 100); + + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(10); + + large->reset(); + medium->reset(); + tall->reset(); + + medium->update(); + QTest::qWait(10); + + // QWidgetPrivate::subtractOpaqueSiblings() should prevent parts of medium + // to be repainted and tall from be repainted at all. + + QTRY_COMPARE(large->r, QRegion()); + QTRY_COMPARE(tall->r, QRegion()); + QTRY_COMPARE(medium->r.translated(medium->mapTo(&w, QPoint())), + QRegion(medium->geometry().translated(large->pos())) + - tall->geometry()); +} +#endif + +void tst_QWidget::deleteStyle() +{ + QWidget widget; + widget.setStyle(new QWindowsStyle); + widget.show(); + delete widget.style(); + qApp->processEvents(); +} + +#ifdef Q_WS_WIN +void tst_QWidget::getDC() +{ + QWidget widget; + widget.setGeometry(0, 0, 2, 4); + + HDC dc = widget.getDC(); + QVERIFY(dc != 0); + + widget.releaseDC(dc); +} +#endif + +class TopLevelFocusCheck: public QWidget +{ + Q_OBJECT +public: + QLineEdit* edit; + TopLevelFocusCheck(QWidget* parent = 0) : QWidget(parent) + { + edit = new QLineEdit(this); + edit->hide(); + edit->installEventFilter(this); + } + +public slots: + void mouseDoubleClickEvent ( QMouseEvent * /*event*/ ) + { + edit->show(); + edit->setFocus(Qt::OtherFocusReason); + qApp->processEvents(); + } + bool eventFilter(QObject *obj, QEvent *event) + { + if (obj == edit && event->type()== QEvent::FocusOut) { + edit->hide(); + return true; + } + return false; + } +}; + +void tst_QWidget::multipleToplevelFocusCheck() +{ + TopLevelFocusCheck w1; + TopLevelFocusCheck w2; + + w1.resize(200, 200); + w1.show(); + QTest::qWaitForWindowShown(&w1); + w2.resize(200,200); + w2.show(); + QTest::qWaitForWindowShown(&w2); + + QTest::qWait(100); + + QApplication::setActiveWindow(&w1); + w1.activateWindow(); + QApplication::processEvents(); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&w1)); + QTest::qWait(50); + QTest::mouseDClick(&w1, Qt::LeftButton); + QTRY_COMPARE(QApplication::focusWidget(), static_cast(w1.edit)); + + w2.activateWindow(); + QApplication::setActiveWindow(&w2); + QApplication::processEvents(); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&w2)); + QTest::mouseClick(&w2, Qt::LeftButton); +#ifdef Q_WS_QWS + QEXPECT_FAIL("", "embedded toplevels take focus anyway", Continue); +#endif + QTRY_COMPARE(QApplication::focusWidget(), (QWidget *)0); + + QTest::mouseDClick(&w2, Qt::LeftButton); + QTRY_COMPARE(QApplication::focusWidget(), static_cast(w2.edit)); + + w1.activateWindow(); + QApplication::setActiveWindow(&w1); + QApplication::processEvents(); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&w1)); + QTest::mouseDClick(&w1, Qt::LeftButton); + QTRY_COMPARE(QApplication::focusWidget(), static_cast(w1.edit)); + + w2.activateWindow(); + QApplication::setActiveWindow(&w2); + QApplication::processEvents(); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&w2)); + QTest::mouseClick(&w2, Qt::LeftButton); + QTRY_COMPARE(QApplication::focusWidget(), (QWidget *)0); +} + +void tst_QWidget::setFocus() +{ + { + // move focus to another window + testWidget->activateWindow(); + QApplication::setActiveWindow(testWidget); + if (testWidget->focusWidget()) + testWidget->focusWidget()->clearFocus(); + else + testWidget->clearFocus(); + + // window and children never shown, nobody gets focus + QWidget window; + + QWidget child1(&window); + child1.setFocusPolicy(Qt::StrongFocus); + + QWidget child2(&window); + child2.setFocusPolicy(Qt::StrongFocus); + + child1.setFocus(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), &child1); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child2.setFocus(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), &child2); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + } + + { + // window and children show, but window not active, nobody gets focus + QWidget window; + + QWidget child1(&window); + child1.setFocusPolicy(Qt::StrongFocus); + + QWidget child2(&window); + child2.setFocusPolicy(Qt::StrongFocus); + + window.show(); + + // note: window may be active, but we don't want it to be + testWidget->activateWindow(); + QApplication::setActiveWindow(testWidget); + if (testWidget->focusWidget()) + testWidget->focusWidget()->clearFocus(); + else + testWidget->clearFocus(); + + child1.setFocus(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), &child1); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child2.setFocus(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), &child2); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + } + + { + // window and children show, but window *is* active, children get focus + QWidget window; + + QWidget child1(&window); + child1.setFocusPolicy(Qt::StrongFocus); + + QWidget child2(&window); + child2.setFocusPolicy(Qt::StrongFocus); + + window.show(); +#ifdef Q_WS_X11 + QApplication::setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); +#else + window.activateWindow(); + QApplication::processEvents(); +#endif + + child1.setFocus(); + QTRY_VERIFY(child1.hasFocus()); + QCOMPARE(window.focusWidget(), &child1); + QCOMPARE(QApplication::focusWidget(), &child1); + + child2.setFocus(); + QVERIFY(child2.hasFocus()); + QCOMPARE(window.focusWidget(), &child2); + QCOMPARE(QApplication::focusWidget(), &child2); + } + + { + // window shown and active, children created, don't get focus, but get focus when shown + QWidget window; + + window.show(); +#ifdef Q_WS_X11 + QApplication::setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); +#else + window.activateWindow(); +#endif + + QWidget child1(&window); + child1.setFocusPolicy(Qt::StrongFocus); + + QWidget child2(&window); + child2.setFocusPolicy(Qt::StrongFocus); + + child1.setFocus(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child1.show(); +#ifdef Q_WS_X11 + QApplication::setActiveWindow(&child1); + child1.activateWindow(); +#endif + QApplication::processEvents(); + QTRY_VERIFY(child1.hasFocus()); + QCOMPARE(window.focusWidget(), &child1); + QCOMPARE(QApplication::focusWidget(), &child1); + + child2.setFocus(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), &child1); + QCOMPARE(QApplication::focusWidget(), &child1); + + child2.show(); + QVERIFY(child2.hasFocus()); + QCOMPARE(window.focusWidget(), &child2); + QCOMPARE(QApplication::focusWidget(), &child2); + } + + { + // window shown and active, children created, don't get focus, + // even after setFocus(), hide(), then show() + QWidget window; + + window.show(); +#ifdef Q_WS_X11 + QApplication::setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); +#else + window.activateWindow(); +#endif + + QWidget child1(&window); + child1.setFocusPolicy(Qt::StrongFocus); + + QWidget child2(&window); + child2.setFocusPolicy(Qt::StrongFocus); + + child1.setFocus(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child1.hide(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child1.show(); + QVERIFY(!child1.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child2.setFocus(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child2.hide(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + + child2.show(); + QVERIFY(!child2.hasFocus()); + QCOMPARE(window.focusWidget(), static_cast(0)); + QCOMPARE(QApplication::focusWidget(), static_cast(0)); + } +} + +class EventSpy : public QObject +{ +public: + EventSpy(QWidget *widget, QEvent::Type event) + : m_widget(widget), eventToSpy(event), m_count(0) + { + if (m_widget) + m_widget->installEventFilter(this); + } + + QWidget *widget() const { return m_widget; } + int count() const { return m_count; } + void clear() { m_count = 0; } + +protected: + bool eventFilter(QObject *object, QEvent *event) + { + if (event->type() == eventToSpy) + ++m_count; + return QObject::eventFilter(object, event); + } + +private: + QWidget *m_widget; + QEvent::Type eventToSpy; + int m_count; +}; + +void tst_QWidget::setCursor() +{ +#ifndef QT_NO_CURSOR + { + QWidget window; + QWidget child(&window); + + QVERIFY(!window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + + window.setCursor(window.cursor()); + QVERIFY(window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window.cursor().shape()); + } + + // do it again, but with window show()n + { + QWidget window; + QWidget child(&window); + window.show(); + + QVERIFY(!window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + + window.setCursor(window.cursor()); + QVERIFY(window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window.cursor().shape()); + } + + + { + QWidget window; + QWidget child(&window); + + window.setCursor(Qt::WaitCursor); + QVERIFY(window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window.cursor().shape()); + } + + // same thing again, just with window show()n + { + QWidget window; + QWidget child(&window); + + window.show(); + window.setCursor(Qt::WaitCursor); + QVERIFY(window.testAttribute(Qt::WA_SetCursor)); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window.cursor().shape()); + } + + // reparenting child should not cause the WA_SetCursor to become set + { + QWidget window; + QWidget window2; + QWidget child(&window); + + window.setCursor(Qt::WaitCursor); + + child.setParent(0); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), QCursor().shape()); + + child.setParent(&window2); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window2.cursor().shape()); + + window2.setCursor(Qt::WaitCursor); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window2.cursor().shape()); + } + + // again, with windows show()n + { + QWidget window; + QWidget window2; + QWidget child(&window); + + window.setCursor(Qt::WaitCursor); + window.show(); + + child.setParent(0); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), QCursor().shape()); + + child.setParent(&window2); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window2.cursor().shape()); + + window2.show(); + window2.setCursor(Qt::WaitCursor); + QVERIFY(!child.testAttribute(Qt::WA_SetCursor)); + QCOMPARE(child.cursor().shape(), window2.cursor().shape()); + } + + // test if CursorChange is sent + { + QWidget widget; + EventSpy spy(&widget, QEvent::CursorChange); + QCOMPARE(spy.count(), 0); + widget.setCursor(QCursor(Qt::WaitCursor)); + QCOMPARE(spy.count(), 1); + widget.unsetCursor(); + QCOMPARE(spy.count(), 2); + } +#endif +} + +void tst_QWidget::setToolTip() +{ + QWidget widget; + EventSpy spy(&widget, QEvent::ToolTipChange); + QCOMPARE(spy.count(), 0); + + QCOMPARE(widget.toolTip(), QString()); + widget.setToolTip(QString("Hello")); + QCOMPARE(widget.toolTip(), QString("Hello")); + QCOMPARE(spy.count(), 1); + widget.setToolTip(QString()); + QCOMPARE(widget.toolTip(), QString()); + QCOMPARE(spy.count(), 2); + + // Mouse over doesn't work on Windows mobile, so skip the rest of the test for that platform. +#ifndef Q_OS_WINCE_WM + for (int pass = 0; pass < 2; ++pass) { + QWidget *popup = new QWidget(0, Qt::Popup); + popup->resize(150, 50); + QFrame *frame = new QFrame(popup); + frame->setGeometry(0, 0, 50, 50); + frame->setFrameStyle(QFrame::Box | QFrame::Plain); + EventSpy spy1(frame, QEvent::ToolTip); + EventSpy spy2(popup, QEvent::ToolTip); + frame->setMouseTracking(pass == 0 ? false : true); + frame->setToolTip(QLatin1String("TOOLTIP FRAME")); + popup->setToolTip(QLatin1String("TOOLTIP POPUP")); + popup->show(); + QTest::qWaitForWindowShown(popup); + QTest::qWait(10); + QTest::mouseMove(frame); + QTest::qWait(900); // delay is 700 + + QCOMPARE(spy1.count(), 1); + QCOMPARE(spy2.count(), 0); + if (pass == 0) + QTest::qWait(2200); // delay is 2000 + QTest::mouseMove(popup); + delete popup; + } +#endif +} + +void tst_QWidget::testWindowIconChangeEventPropagation() +{ + // Create widget hierarchy. + QWidget topLevelWidget; + QWidget topLevelChild(&topLevelWidget); + + QDialog dialog(&topLevelWidget); + QWidget dialogChild(&dialog); + + QWidgetList widgets; + widgets << &topLevelWidget << &topLevelChild + << &dialog << &dialogChild; + QCOMPARE(widgets.count(), 4); + + // Create spy lists. + QList applicationEventSpies; + QList widgetEventSpies; + foreach (QWidget *widget, widgets) { + applicationEventSpies.append(new EventSpy(widget, QEvent::ApplicationWindowIconChange)); + widgetEventSpies.append(new EventSpy(widget, QEvent::WindowIconChange)); + } + + // QApplication::setWindowIcon + const QIcon windowIcon = qApp->style()->standardIcon(QStyle::SP_TitleBarMenuButton); + qApp->setWindowIcon(windowIcon); + + for (int i = 0; i < widgets.count(); ++i) { + // Check QEvent::ApplicationWindowIconChange + EventSpy *spy = applicationEventSpies.at(i); + QWidget *widget = spy->widget(); + if (widget->isWindow()) { + QCOMPARE(spy->count(), 1); + QCOMPARE(widget->windowIcon(), windowIcon); + } else { + QCOMPARE(spy->count(), 0); + } + spy->clear(); + + // Check QEvent::WindowIconChange + spy = widgetEventSpies.at(i); + QCOMPARE(spy->count(), 1); + spy->clear(); + } + + // Set icon on a top-level widget. + topLevelWidget.setWindowIcon(*new QIcon); + + for (int i = 0; i < widgets.count(); ++i) { + // Check QEvent::ApplicationWindowIconChange + EventSpy *spy = applicationEventSpies.at(i); + QCOMPARE(spy->count(), 0); + spy->clear(); + + // Check QEvent::WindowIconChange + spy = widgetEventSpies.at(i); + QWidget *widget = spy->widget(); + if (widget == &topLevelWidget) { + QCOMPARE(widget->windowIcon(), QIcon()); + QCOMPARE(spy->count(), 1); + } else if (topLevelWidget.isAncestorOf(widget)) { + QCOMPARE(spy->count(), 1); + } else { + QCOMPARE(spy->count(), 0); + } + spy->clear(); + } + + // Cleanup. + for (int i = 0; i < widgets.count(); ++i) { + delete applicationEventSpies.at(i); + delete widgetEventSpies.at(i); + } + qApp->setWindowIcon(QIcon()); +} + +#ifdef Q_WS_X11 +void tst_QWidget::minAndMaxSizeWithX11BypassWindowManagerHint() +{ + // Same size as in QWidget::create_sys(). + const QSize desktopSize = QApplication::desktop()->size(); + const QSize originalSize(desktopSize.width() / 2, desktopSize.height() * 4 / 10); + + { // Maximum size. + QWidget widget(0, Qt::X11BypassWindowManagerHint); + + const QSize newMaximumSize = widget.size().boundedTo(originalSize) - QSize(10, 10); + widget.setMaximumSize(newMaximumSize); + QCOMPARE(widget.size(), newMaximumSize); + + widget.show(); + qt_x11_wait_for_window_manager(&widget); + QCOMPARE(widget.size(), newMaximumSize); + } + + { // Minimum size. + QWidget widget(0, Qt::X11BypassWindowManagerHint); + + const QSize newMinimumSize = widget.size().expandedTo(originalSize) + QSize(10, 10); + widget.setMinimumSize(newMinimumSize); + QCOMPARE(widget.size(), newMinimumSize); + + widget.show(); + qt_x11_wait_for_window_manager(&widget); + QCOMPARE(widget.size(), newMinimumSize); + } +} + +class ShowHideShowWidget : public QWidget +{ + Q_OBJECT + + int state; +public: + bool gotExpectedMapNotify; + + ShowHideShowWidget() + : state(0), gotExpectedMapNotify(false) + { + startTimer(1000); + } + + void timerEvent(QTimerEvent *) + { + switch (state++) { + case 0: + show(); + break; + case 1: + emit done(); + break; + } + } + + bool x11Event(XEvent *event) + { + if (state == 1 && event->type == MapNotify) + gotExpectedMapNotify = true; + return false; + } + +signals: + void done(); +}; + +void tst_QWidget::showHideShow() +{ + ShowHideShowWidget w; + w.show(); + w.hide(); + + QEventLoop eventLoop; + connect(&w, SIGNAL(done()), &eventLoop, SLOT(quit())); + eventLoop.exec(); + + QVERIFY(w.gotExpectedMapNotify); +} + +void tst_QWidget::clean_qt_x11_enforce_cursor() +{ + { + QWidget window; + QWidget *w = new QWidget(&window); + QWidget *child = new QWidget(w); + child->setAttribute(Qt::WA_SetCursor, true); + + window.show(); + QApplication::setActiveWindow(&window); + QTest::qWaitForWindowShown(&window); + QTest::qWait(100); + QCursor::setPos(window.geometry().center()); + QTest::qWait(100); + + child->setFocus(); + QApplication::processEvents(); + QTest::qWait(100); + + delete w; + } + + QGraphicsScene scene; + QLineEdit *edit = new QLineEdit; + scene.addWidget(edit); + + // If the test didn't crash, then it passed. +} +#endif + +class EventRecorder : public QObject +{ + Q_OBJECT + +public: + typedef QList > EventList; + + EventRecorder(QObject *parent = 0) + : QObject(parent) + { } + + EventList eventList() + { + return events; + } + + void clear() + { + events.clear(); + } + + bool eventFilter(QObject *object, QEvent *event) + { + QWidget *widget = qobject_cast(object); + if (widget && !event->spontaneous()) + events.append(qMakePair(widget, event->type())); + return false; + } + +private: + EventList events; +}; + +void tst_QWidget::compatibilityChildInsertedEvents() +{ + EventRecorder::EventList expected; + bool accessibilityEnabled = false; + + // Move away the cursor; otherwise it might result in an enter event if it's + // inside the widget when the widget is shown. + QCursor::setPos(qApp->desktop()->availableGeometry().bottomRight()); + QTest::qWait(100); + + { + // no children created, not shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + QCoreApplication::sendPostedEvents(); + + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)); + QCOMPARE(spy.eventList(), expected); + } + + { + // no children, shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + widget.show(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::WinIdChange) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::Move) + << qMakePair(&widget, QEvent::Resize) + << qMakePair(&widget, QEvent::Show); + + if (accessibilityEnabled) + expected << qMakePair(&widget, QEvent::AccessibilityPrepare); + expected << qMakePair(&widget, QEvent::ShowToParent); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::sendPostedEvents(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)); + +#ifdef Q_OS_MAC + expected << qMakePair(&widget, QEvent::UpdateLater); +#endif + expected << qMakePair(&widget, QEvent::UpdateRequest); + + QCOMPARE(spy.eventList(), expected); + } + + { + // 2 children, not shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + QWidget child1(&widget); + QWidget child2; + child2.setParent(&widget); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildAdded); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::sendPostedEvents(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)) + << qMakePair(&widget, QEvent::Type(QEvent::User + 2)); + QCOMPARE(spy.eventList(), expected); + } + + { + // 2 children, widget shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + QWidget child1(&widget); + QWidget child2; + child2.setParent(&widget); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildAdded); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + widget.show(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::WinIdChange) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::Move) + << qMakePair(&widget, QEvent::Resize) + << qMakePair(&widget, QEvent::Show); + + if (accessibilityEnabled) + expected << qMakePair(&widget, QEvent::AccessibilityPrepare); + expected << qMakePair(&widget, QEvent::ShowToParent); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::sendPostedEvents(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)) + << qMakePair(&widget, QEvent::Type(QEvent::User + 2)); + +#ifdef Q_OS_MAC + expected << qMakePair(&widget, QEvent::UpdateLater); +#endif + expected << qMakePair(&widget, QEvent::UpdateRequest); + + QCOMPARE(spy.eventList(), expected); + } + + { + // 2 children, but one is reparented away, not shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + QWidget child1(&widget); + QWidget child2; + child2.setParent(&widget); + child2.setParent(0); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildRemoved); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::sendPostedEvents(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)) + << qMakePair(&widget, QEvent::Type(QEvent::User + 2)); + QCOMPARE(spy.eventList(), expected); + } + + { + // 2 children, but one is reparented away, then widget is shown + QWidget widget; + EventRecorder spy; + widget.installEventFilter(&spy); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 1))); + + QWidget child1(&widget); + QWidget child2; + child2.setParent(&widget); + child2.setParent(0); + + QCoreApplication::postEvent(&widget, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildAdded) + << qMakePair(&widget, QEvent::ChildRemoved); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + widget.show(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::WinIdChange) + << qMakePair(&widget, QEvent::Polish) + << qMakePair(&widget, QEvent::ChildPolished) + << qMakePair(&widget, QEvent::Move) + << qMakePair(&widget, QEvent::Resize) + << qMakePair(&widget, QEvent::Show); + + if (accessibilityEnabled) + expected << qMakePair(&widget, QEvent::AccessibilityPrepare); + expected << qMakePair(&widget, QEvent::ShowToParent); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::sendPostedEvents(); + expected = + EventRecorder::EventList() + << qMakePair(&widget, QEvent::PolishRequest) + << qMakePair(&widget, QEvent::Type(QEvent::User + 1)) + << qMakePair(&widget, QEvent::Type(QEvent::User + 2)); + +#ifdef Q_OS_MAC + expected << qMakePair(&widget, QEvent::UpdateLater); +#endif + expected << qMakePair(&widget, QEvent::UpdateRequest); + + QCOMPARE(spy.eventList(), expected); + } +} + +class RenderWidget : public QWidget +{ +public: + RenderWidget(QWidget *source) + : source(source), ellipse(false) {} + + void setEllipseEnabled(bool enable = true) + { + ellipse = enable; + update(); + } + +protected: + void paintEvent(QPaintEvent *) + { + if (ellipse) { + QPainter painter(this); + painter.fillRect(rect(), Qt::red); + painter.end(); + QRegion regionToRender = QRegion(0, 0, source->width(), source->height() / 2, + QRegion::Ellipse); + source->render(this, QPoint(0, 30), regionToRender); + } else { + source->render(this); + } + } + +private: + QWidget *source; + bool ellipse; +}; + +void tst_QWidget::render() +{ + return; + QCalendarWidget source; + // disable anti-aliasing to eliminate potential differences when subpixel antialiasing + // is enabled on the screen + QFont f; + f.setStyleStrategy(QFont::NoAntialias); + source.setFont(f); + source.show(); + QTest::qWaitForWindowShown(&source); + + // Render the entire source into target. + RenderWidget target(&source); + target.resize(source.size()); + target.show(); + + qApp->processEvents(); + qApp->sendPostedEvents(); + QTest::qWait(250); + + QImage sourceImage = QPixmap::grabWidget(&source).toImage(); + qApp->processEvents(); + QImage targetImage = QPixmap::grabWidget(&target).toImage(); + qApp->processEvents(); + QCOMPARE(sourceImage, targetImage); + + // Fill target.rect() will Qt::red and render + // QRegion(0, 0, source->width(), source->height() / 2, QRegion::Ellipse) + // of source into target with offset (0, 30). + target.setEllipseEnabled(); + qApp->processEvents(); + qApp->sendPostedEvents(); + + targetImage = QPixmap::grabWidget(&target).toImage(); + QVERIFY(sourceImage != targetImage); + + QCOMPARE(targetImage.pixel(target.width() / 2, 29), QColor(Qt::red).rgb()); + QCOMPARE(targetImage.pixel(target.width() / 2, 30), sourceImage.pixel(source.width() / 2, 0)); + + // Test that a child widget properly fills its background + { + QWidget window; + window.resize(100, 100); + // prevent custom styles + window.setStyle(new QWindowsStyle); + window.show(); + QTest::qWaitForWindowShown(&window); + QWidget child(&window); + child.resize(window.size()); + child.show(); + + qApp->processEvents(); + QCOMPARE(QPixmap::grabWidget(&child), QPixmap::grabWidget(&window)); + } + + { // Check that the target offset is correct. + QWidget widget; + widget.resize(200, 200); + widget.setAutoFillBackground(true); + widget.setPalette(Qt::red); + // prevent custom styles + widget.setStyle(new QWindowsStyle); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QImage image(widget.size(), QImage::Format_RGB32); + image.fill(QColor(Qt::blue).rgb()); + + // Target offset (0, 0) + widget.render(&image, QPoint(), QRect(20, 20, 100, 100)); + QCOMPARE(image.pixel(0, 0), QColor(Qt::red).rgb()); + QCOMPARE(image.pixel(99, 99), QColor(Qt::red).rgb()); + QCOMPARE(image.pixel(100, 100), QColor(Qt::blue).rgb()); + + // Target offset (20, 20). + image.fill(QColor(Qt::blue).rgb()); + widget.render(&image, QPoint(20, 20), QRect(20, 20, 100, 100)); + QCOMPARE(image.pixel(0, 0), QColor(Qt::blue).rgb()); + QCOMPARE(image.pixel(19, 19), QColor(Qt::blue).rgb()); + QCOMPARE(image.pixel(20, 20), QColor(Qt::red).rgb()); + QCOMPARE(image.pixel(119, 119), QColor(Qt::red).rgb()); + QCOMPARE(image.pixel(120, 120), QColor(Qt::blue).rgb()); + } +} + +// On Windows the active palette is used instead of the inactive palette even +// though the widget is invisible. This is probably related to task 178507/168682, +// but for the renderInvisible test it doesn't matter, we're mostly interested +// in testing the geometry so just workaround the palette issue for now. +static void workaroundPaletteIssue(QWidget *widget) +{ +#ifndef Q_WS_WIN + return; +#endif + if (!widget) + return; + + QWidget *navigationBar = qFindChild(widget, QLatin1String("qt_calendar_navigationbar")); + QVERIFY(navigationBar); + + QPalette palette = navigationBar->palette(); + const QColor background = palette.color(QPalette::Inactive, navigationBar->backgroundRole()); + const QColor highlightedText = palette.color(QPalette::Inactive, QPalette::HighlightedText); + palette.setColor(QPalette::Active, navigationBar->backgroundRole(), background); + palette.setColor(QPalette::Active, QPalette::HighlightedText, highlightedText); + navigationBar->setPalette(palette); +} + +//#define RENDER_DEBUG +void tst_QWidget::renderInvisible() +{ + QCalendarWidget *calendar = new QCalendarWidget; + // disable anti-aliasing to eliminate potential differences when subpixel antialiasing + // is enabled on the screen + QFont f; + f.setStyleStrategy(QFont::NoAntialias); + calendar->setFont(f); + calendar->show(); + QTest::qWaitForWindowShown(calendar); + + // Create a dummy focus widget to get rid of focus rect in reference image. + QLineEdit dummyFocusWidget; + dummyFocusWidget.show(); + QTest::qWaitForWindowShown(&dummyFocusWidget); + qApp->processEvents(); + QTest::qWait(120); + + // Create normal reference image. + const QSize calendarSize = calendar->size(); + QImage referenceImage(calendarSize, QImage::Format_ARGB32); + calendar->render(&referenceImage); +#ifdef RENDER_DEBUG + referenceImage.save("referenceImage.png"); +#endif + QVERIFY(!referenceImage.isNull()); + + // Create resized reference image. + const QSize calendarSizeResized = calendar->size() + QSize(50, 50); + calendar->resize(calendarSizeResized); + qApp->processEvents(); + QTest::qWait(30); + QImage referenceImageResized(calendarSizeResized, QImage::Format_ARGB32); + calendar->render(&referenceImageResized); +#ifdef RENDER_DEBUG + referenceImageResized.save("referenceImageResized.png"); +#endif + QVERIFY(!referenceImageResized.isNull()); + + // Explicitly hide the calendar. + calendar->hide(); + qApp->processEvents(); + QTest::qWait(30); + workaroundPaletteIssue(calendar); + + { // Make sure we get the same image when the calendar is explicitly hidden. + QImage testImage(calendarSizeResized, QImage::Format_ARGB32); + calendar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("explicitlyHiddenCalendarResized.png"); +#endif + QCOMPARE(testImage, referenceImageResized); + } + + // Now that we have reference images we can delete the source and re-create + // the calendar and check that we get the same images from a calendar which has never + // been visible, laid out or created (Qt::WA_WState_Created). + delete calendar; + calendar = new QCalendarWidget; + calendar->setFont(f); + workaroundPaletteIssue(calendar); + + { // Never been visible, created or laid out. + QImage testImage(calendarSize, QImage::Format_ARGB32); + calendar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("neverBeenVisibleCreatedOrLaidOut.png"); +#endif + QCOMPARE(testImage, referenceImage); + } + + calendar->hide(); + qApp->processEvents(); + QTest::qWait(30); + + { // Calendar explicitly hidden. + QImage testImage(calendarSize, QImage::Format_ARGB32); + calendar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("explicitlyHiddenCalendar.png"); +#endif + QCOMPARE(testImage, referenceImage); + } + + // Get navigation bar and explicitly hide it. + QWidget *navigationBar = qFindChild(calendar, QLatin1String("qt_calendar_navigationbar")); + QVERIFY(navigationBar); + navigationBar->hide(); + + { // Check that the navigation bar isn't drawn when rendering the entire calendar. + QImage testImage(calendarSize, QImage::Format_ARGB32); + calendar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("calendarWithoutNavigationBar.png"); +#endif + QVERIFY(testImage != referenceImage); + } + + { // Make sure the navigation bar renders correctly even though it's hidden. + QImage testImage(navigationBar->size(), QImage::Format_ARGB32); + navigationBar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("explicitlyHiddenNavigationBar.png"); +#endif + QCOMPARE(testImage, referenceImage.copy(navigationBar->rect())); + } + + // Get next month button. + QWidget *nextMonthButton = qFindChild(navigationBar, QLatin1String("qt_calendar_nextmonth")); + QVERIFY(nextMonthButton); + + { // Render next month button. + // Fill test image with correct background color. + QImage testImage(nextMonthButton->size(), QImage::Format_ARGB32); + navigationBar->render(&testImage, QPoint(), QRegion(), QWidget::RenderFlags()); +#ifdef RENDER_DEBUG + testImage.save("nextMonthButtonBackground.png"); +#endif + + // Set the button's background color to Qt::transparent; otherwise it will fill the + // background with QPalette::Window. + const QPalette originalPalette = nextMonthButton->palette(); + QPalette palette = originalPalette; + palette.setColor(QPalette::Window, Qt::transparent); + nextMonthButton->setPalette(palette); + + // Render the button on top of the background. + nextMonthButton->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("nextMonthButton.png"); +#endif + const QRect buttonRect(nextMonthButton->mapTo(calendar, QPoint()), nextMonthButton->size()); + QCOMPARE(testImage, referenceImage.copy(buttonRect)); + + // Restore palette. + nextMonthButton->setPalette(originalPalette); + } + + // Navigation bar isn't explicitly hidden anymore. + navigationBar->show(); + qApp->processEvents(); + QTest::qWait(30); + QVERIFY(!calendar->isVisible()); + + // Now, completely mess up the layout. This will trigger an update on the layout + // when the calendar is visible or shown, but it's not. QWidget::render must therefore + // make sure the layout is activated before rendering. + QVERIFY(!calendar->isVisible()); + calendar->resize(calendarSizeResized); + qApp->processEvents(); + + { // Make sure we get an image equal to the resized reference image. + QImage testImage(calendarSizeResized, QImage::Format_ARGB32); + calendar->render(&testImage); +#ifdef RENDER_DEBUG + testImage.save("calendarResized.png"); +#endif + QCOMPARE(testImage, referenceImageResized); + } + + { // Make sure we lay out the widget correctly the first time it's rendered. + QCalendarWidget calendar; + const QSize calendarSize = calendar.sizeHint(); + + QImage image(2 * calendarSize, QImage::Format_ARGB32); + image.fill(QColor(Qt::red).rgb()); + calendar.render(&image); + + for (int i = calendarSize.height(); i < 2 * calendarSize.height(); ++i) + for (int j = calendarSize.width(); j < 2 * calendarSize.width(); ++j) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + + { // Ensure that we don't call adjustSize() on invisible top-levels if render() is called + // right after widgets have been added/removed to/from its layout. + QWidget topLevel; + topLevel.setLayout(new QVBoxLayout); + + QWidget *widget = new QLineEdit; + topLevel.layout()->addWidget(widget); + + const QSize initialSize = topLevel.size(); + QPixmap pixmap(topLevel.sizeHint()); + topLevel.render(&pixmap); // triggers adjustSize() + const QSize finalSize = topLevel.size(); + QVERIFY(finalSize != initialSize); + + topLevel.layout()->removeWidget(widget); + QCOMPARE(topLevel.size(), finalSize); + topLevel.render(&pixmap); + QCOMPARE(topLevel.size(), finalSize); + + topLevel.layout()->addWidget(widget); + QCOMPARE(topLevel.size(), finalSize); + topLevel.render(&pixmap); + QCOMPARE(topLevel.size(), finalSize); + } +} + +void tst_QWidget::renderWithPainter() +{ + QWidget widget; + // prevent custom styles + widget.setStyle(new QWindowsStyle); + widget.show(); + widget.resize(70, 50); + widget.setAutoFillBackground(true); + widget.setPalette(Qt::black); + + // Render the entire widget onto the image. + QImage image(QSize(70, 50), QImage::Format_ARGB32); + image.fill(QColor(Qt::red).rgb()); + QPainter painter(&image); + widget.render(&painter); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) + QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb()); + } + + // Translate painter (10, 10). + painter.save(); + image.fill(QColor(Qt::red).rgb()); + painter.translate(10, 10); + widget.render(&painter); + painter.restore(); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (i < 10 || j < 10) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb()); + } + } + + // Pass target offset (10, 10) (the same as QPainter::translate). + image.fill(QColor(Qt::red).rgb()); + widget.render(&painter, QPoint(10, 10)); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (i < 10 || j < 10) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb()); + } + } + + // Translate (10, 10) and pass target offset (10, 10). + painter.save(); + image.fill(QColor(Qt::red).rgb()); + painter.translate(10, 10); + widget.render(&painter, QPoint(10, 10)); + painter.restore(); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (i < 20 || j < 20) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb()); + } + } + + // Rotate painter 90 degrees. + painter.save(); + image.fill(QColor(Qt::red).rgb()); + painter.rotate(90); + widget.render(&painter); + painter.restore(); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + + // Translate and rotate. + image.fill(QColor(Qt::red).rgb()); + widget.resize(40, 10); + painter.translate(10, 10); + painter.rotate(90); + widget.render(&painter); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (i >= 10 && j >= 0 && j < 10) + QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + } + + // Make sure QWidget::render does not modify the render hints set on the painter. + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform + | QPainter::NonCosmeticDefaultPen | QPainter::TextAntialiasing); + QPainter::RenderHints oldRenderHints = painter.renderHints(); + widget.render(&painter); + QCOMPARE(painter.renderHints(), oldRenderHints); +} + +void tst_QWidget::render_task188133() +{ + QMainWindow mainWindow; + + // Make sure QWidget::render does not trigger QWidget::repaint/update + // and asserts for Qt::WA_WState_Created. + QPixmap pixmap = QPixmap::grabWidget(&mainWindow); +} + +void tst_QWidget::render_task211796() +{ + class MyWidget : public QWidget + { + void resizeEvent(QResizeEvent *) + { + QPixmap pixmap(size()); + render(&pixmap); + } + }; + + { // Please don't die in a resize recursion. + MyWidget widget; + widget.resize(200, 200); + widget.show(); + } + + { // Same check with a deeper hierarchy. + QWidget widget; + widget.show(); + QWidget child(&widget); + MyWidget grandChild; + grandChild.setParent(&child); + grandChild.resize(100, 100); + child.show(); + } +} + +void tst_QWidget::render_task217815() +{ + // Make sure we don't change the size of the widget when calling + // render() and the widget has an explicit size set. + // This was a problem on Windows because we called createWinId(), + // which in turn enforced the size to be bigger than the smallest + // possible native window size (which is (115,something) on WinXP). + QWidget widget; + const QSize explicitSize(80, 20); + widget.resize(explicitSize); + QCOMPARE(widget.size(), explicitSize); + + QPixmap pixmap(explicitSize); + widget.render(&pixmap); + + QCOMPARE(widget.size(), explicitSize); +} + +// Window Opacity is not supported on Windows CE. +#ifndef Q_OS_WINCE +void tst_QWidget::render_windowOpacity() +{ + const qreal opacity = 0.5; + + { // Check that the painter opacity effects the widget drawing. + QWidget topLevel; + QWidget child(&topLevel); + child.resize(50, 50); + child.setPalette(Qt::red); + child.setAutoFillBackground(true); + + QPixmap expected(child.size()); +#ifdef Q_WS_X11 + if (expected.depth() < 24) { + QSKIP("This test won't give correct results with dithered pixmaps", SkipAll); + } +#endif + expected.fill(Qt::green); + QPainter painter(&expected); + painter.setOpacity(opacity); + painter.fillRect(QRect(QPoint(0, 0), child.size()), Qt::red); + painter.end(); + + QPixmap result(child.size()); + result.fill(Qt::green); + painter.begin(&result); + painter.setOpacity(opacity); + child.render(&painter); + painter.end(); + QCOMPARE(result, expected); + } + + { // Combine the opacity set on the painter with the widget opacity. + class MyWidget : public QWidget + { + public: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.setOpacity(opacity); + QCOMPARE(painter.opacity(), opacity); + painter.fillRect(rect(), Qt::red); + } + qreal opacity; + }; + + MyWidget widget; + widget.resize(50, 50); + widget.opacity = opacity; + widget.setPalette(Qt::blue); + widget.setAutoFillBackground(true); + + QPixmap expected(widget.size()); + expected.fill(Qt::green); + QPainter painter(&expected); + painter.setOpacity(opacity); + QPixmap pixmap(widget.size()); + pixmap.fill(Qt::blue); + QPainter pixmapPainter(&pixmap); + pixmapPainter.setOpacity(opacity); + pixmapPainter.fillRect(QRect(QPoint(), widget.size()), Qt::red); + painter.drawPixmap(QPoint(), pixmap); + painter.end(); + + QPixmap result(widget.size()); + result.fill(Qt::green); + painter.begin(&result); + painter.setOpacity(opacity); + widget.render(&painter); + painter.end(); + QCOMPARE(result, expected); + } +} +#endif + +void tst_QWidget::render_systemClip() +{ + QWidget widget; + widget.setPalette(Qt::blue); + widget.resize(100, 100); + + QImage image(widget.size(), QImage::Format_RGB32); + image.fill(QColor(Qt::red).rgb()); + + QPaintEngine *paintEngine = image.paintEngine(); + QVERIFY(paintEngine); + paintEngine->setSystemClip(QRegion(0, 0, 50, 50)); + + QPainter painter(&image); + // Make sure we're using the same paint engine and has the right clip set. + QCOMPARE(painter.paintEngine(), paintEngine); + QCOMPARE(paintEngine->systemClip(), QRegion(0, 0, 50, 50)); + + // Translate painter outside system clip. + painter.translate(50, 0); + widget.render(&painter); + +#ifdef RENDER_DEBUG + image.save("outside_systemclip.png"); +#endif + + // All pixels should be red. + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + + // Restore painter and refill image with red. + image.fill(QColor(Qt::red).rgb()); + painter.translate(-50, 0); + + // Set transform on the painter. + QTransform transform; + transform.shear(0, 1); + painter.setTransform(transform); + widget.render(&painter); + +#ifdef RENDER_DEBUG + image.save("blue_triangle.png"); +#endif + + // We should now have a blue triangle starting at scan line 1, and the rest should be red. + // rrrrrrrrrr + // brrrrrrrrr + // bbrrrrrrrr + // bbbrrrrrrr + // bbbbrrrrrr + // rrrrrrrrrr + // ... + +#ifndef Q_WS_MAC + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (i < 50 && j < i) + QCOMPARE(image.pixel(j, i), QColor(Qt::blue).rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + } +#else + // We don't paint directly on the image on the Mac, so we cannot do the pixel comparison + // as above due to QPainter::SmoothPixmapTransform. We therefore need to generate an + // expected image by first painting on a pixmap, and then draw the pixmap onto + // the image using QPainter::SmoothPixmapTransform. Then we can compare pixels :) + // The check is basically the same, except that it takes the smoothening into account. + QPixmap pixmap(50, 50); + const QRegion sysClip(0, 0, 50, 50); + widget.render(&pixmap, QPoint(), sysClip); + + QImage expectedImage(widget.size(), QImage::Format_RGB32); + expectedImage.fill(QColor(Qt::red).rgb()); + expectedImage.paintEngine()->setSystemClip(sysClip); + + QPainter expectedImagePainter(&expectedImage); + expectedImagePainter.setTransform(QTransform().shear(0, 1)); + // NB! This is the important part (SmoothPixmapTransform). + expectedImagePainter.setRenderHints(QPainter::SmoothPixmapTransform); + expectedImagePainter.drawPixmap(QPoint(0, 0), pixmap); + expectedImagePainter.end(); + + QCOMPARE(image, expectedImage); +#endif +} + +void tst_QWidget::render_systemClip2_data() +{ + QTest::addColumn("autoFillBackground"); + QTest::addColumn("usePaintEvent"); + QTest::addColumn("expectedColor"); + + QTest::newRow("Only auto-fill background") << true << false << QColor(Qt::blue); + QTest::newRow("Only draw in paintEvent") << false << true << QColor(Qt::green); + QTest::newRow("Auto-fill background and draw in paintEvent") << true << true << QColor(Qt::green); +} + +void tst_QWidget::render_systemClip2() +{ + QFETCH(bool, autoFillBackground); + QFETCH(bool, usePaintEvent); + QFETCH(QColor, expectedColor); + + QVERIFY2(expectedColor != QColor(Qt::red), "Qt::red is the reference color for the image, pick another color"); + + class MyWidget : public QWidget + { + public: + bool usePaintEvent; + void paintEvent(QPaintEvent *) + { + if (usePaintEvent) + QPainter(this).fillRect(rect(), Qt::green); + } + }; + + MyWidget widget; + widget.usePaintEvent = usePaintEvent; + widget.setPalette(Qt::blue); + // NB! widget.setAutoFillBackground(autoFillBackground) won't do the + // trick here since the widget is a top-level. The background is filled + // regardless, unless Qt::WA_OpaquePaintEvent or Qt::WA_NoSystemBackground + // is set. We therefore use the opaque attribute to turn off auto-fill. + if (!autoFillBackground) + widget.setAttribute(Qt::WA_OpaquePaintEvent); + widget.resize(100, 100); + + QImage image(widget.size(), QImage::Format_RGB32); + image.fill(QColor(Qt::red).rgb()); + + QPaintEngine *paintEngine = image.paintEngine(); + QVERIFY(paintEngine); + + QRegion systemClip(QRegion(50, 0, 50, 10)); + systemClip += QRegion(90, 10, 10, 40); + paintEngine->setSystemClip(systemClip); + + // Render entire widget directly onto device. + widget.render(&image); + +#ifdef RENDER_DEBUG + image.save("systemclip_with_device.png"); +#endif + // All pixels within the system clip should now be + // the expectedColor, and the rest should be red. + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (systemClip.contains(QPoint(j, i))) + QCOMPARE(image.pixel(j, i), expectedColor.rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + } + + // Refill image with red. + image.fill(QColor(Qt::red).rgb()); + paintEngine->setSystemClip(systemClip); + + // Do the same with an untransformed painter. + QPainter painter(&image); + //Make sure we're using the same paint engine and has the right clip set. + QCOMPARE(painter.paintEngine(), paintEngine); + QCOMPARE(paintEngine->systemClip(), systemClip); + + widget.render(&painter); + +#ifdef RENDER_DEBUG + image.save("systemclip_with_untransformed_painter.png"); +#endif + // All pixels within the system clip should now be + // the expectedColor, and the rest should be red. + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (systemClip.contains(QPoint(j, i))) + QCOMPARE(image.pixel(j, i), expectedColor.rgb()); + else + QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb()); + } + } +} + +void tst_QWidget::render_systemClip3_data() +{ + QTest::addColumn("size"); + QTest::addColumn("useSystemClip"); + + // Reference: http://en.wikipedia.org/wiki/Flag_of_Norway + QTest::newRow("Norwegian Civil Flag") << QSize(220, 160) << false; + QTest::newRow("Norwegian War Flag") << QSize(270, 160) << true; +} + +// This test ensures that the current engine clip (systemClip + painter clip) +// is preserved after QPainter::setClipRegion(..., Qt::ReplaceClip); +void tst_QWidget::render_systemClip3() +{ + QFETCH(QSize, size); + QFETCH(bool, useSystemClip); + + // Calculate the inner/outer cross of the flag. + QRegion outerCross(0, 0, size.width(), size.height()); + outerCross -= QRect(0, 0, 60, 60); + outerCross -= QRect(100, 0, size.width() - 100, 60); + outerCross -= QRect(0, 100, 60, 60); + outerCross -= QRect(100, 100, size.width() - 100, 60); + + QRegion innerCross(0, 0, size.width(), size.height()); + innerCross -= QRect(0, 0, 70, 70); + innerCross -= QRect(90, 0, size.width() - 90, 70); + innerCross -= QRect(0, 90, 70, 70); + innerCross -= QRect(90, 90, size.width() - 90, 70); + + const QRegion redArea(QRegion(0, 0, size.width(), size.height()) - outerCross); + const QRegion whiteArea(outerCross - innerCross); + const QRegion blueArea(innerCross); + QRegion systemClip; + + // Okay, here's the image that should look like a Norwegian civil/war flag in the end. + QImage flag(size, QImage::Format_ARGB32); + flag.fill(QColor(Qt::transparent).rgba()); + + if (useSystemClip) { + QPainterPath warClip(QPoint(size.width(), 0)); + warClip.lineTo(size.width() - 110, 60); + warClip.lineTo(size.width(), 80); + warClip.lineTo(size.width() - 110, 100); + warClip.lineTo(size.width(), 160); + warClip.closeSubpath(); + systemClip = QRegion(0, 0, size.width(), size.height()) - QRegion(warClip.toFillPolygon().toPolygon()); + flag.paintEngine()->setSystemClip(systemClip); + } + + QPainter painter(&flag); + painter.fillRect(QRect(QPoint(), size), Qt::red); // Fill image background with red. + painter.setClipRegion(outerCross); // Limit widget painting to inside the outer cross. + + // Here's the widget that's supposed to draw the inner/outer cross of the flag. + // The outer cross (white) should be drawn when the background is auto-filled, and + // the inner cross (blue) should be drawn in the paintEvent. + class MyWidget : public QWidget + { public: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + // Be evil and try to paint outside the outer cross. This should not be + // possible since the shared painter is clipped to the outer cross. + painter.setClipRect(0, 0, 60, 60, Qt::ReplaceClip); + painter.fillRect(rect(), Qt::green); + painter.setClipRegion(clip, Qt::ReplaceClip); + painter.fillRect(rect(), Qt::blue); + } + QRegion clip; + }; + + MyWidget widget; + widget.clip = innerCross; + widget.setFixedSize(size); + widget.setPalette(Qt::white); + widget.setAutoFillBackground(true); + widget.render(&painter); + +#ifdef RENDER_DEBUG + flag.save("flag.png"); +#endif + + // Let's make sure we got a Norwegian flag. + for (int i = 0; i < flag.height(); ++i) { + for (int j = 0; j < flag.width(); ++j) { + const QPoint pixel(j, i); + const QRgb pixelValue = flag.pixel(pixel); + if (useSystemClip && !systemClip.contains(pixel)) + QCOMPARE(pixelValue, QColor(Qt::transparent).rgba()); + else if (redArea.contains(pixel)) + QCOMPARE(pixelValue, QColor(Qt::red).rgba()); + else if (whiteArea.contains(pixel)) + QCOMPARE(pixelValue, QColor(Qt::white).rgba()); + else + QCOMPARE(pixelValue, QColor(Qt::blue).rgba()); + } + } +} + +void tst_QWidget::render_task252837() +{ + QWidget widget; + widget.resize(200, 200); + + QPixmap pixmap(widget.size()); + QPainter painter(&pixmap); + // Please do not crash. + widget.render(&painter); +} + +void tst_QWidget::render_worldTransform() +{ + class MyWidget : public QWidget + { public: + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + // Make sure world transform is identity. + QCOMPARE(painter.worldTransform(), QTransform()); + + // Make sure device transform is correct. + const QPoint widgetOffset = geometry().topLeft(); + QTransform expectedDeviceTransform = QTransform::fromTranslate(105, 5); + expectedDeviceTransform.rotate(90); + expectedDeviceTransform.translate(widgetOffset.x(), widgetOffset.y()); + QCOMPARE(painter.deviceTransform(), expectedDeviceTransform); + + // Set new world transform. + QTransform newWorldTransform = QTransform::fromTranslate(10, 10); + newWorldTransform.rotate(90); + painter.setWorldTransform(newWorldTransform); + QCOMPARE(painter.worldTransform(), newWorldTransform); + + // Again, check device transform. + expectedDeviceTransform.translate(10, 10); + expectedDeviceTransform.rotate(90); + QCOMPARE(painter.deviceTransform(), expectedDeviceTransform); + + painter.fillRect(QRect(0, 0, 20, 10), Qt::green); + } + }; + + MyWidget widget; + widget.setFixedSize(100, 100); + widget.setPalette(Qt::red); + widget.setAutoFillBackground(true); + + MyWidget child; + child.setParent(&widget); + child.move(50, 50); + child.setFixedSize(50, 50); + child.setPalette(Qt::blue); + child.setAutoFillBackground(true); + + QImage image(QSize(110, 110), QImage::Format_RGB32); + image.fill(QColor(Qt::black).rgb()); + + QPainter painter(&image); + painter.translate(105, 5); + painter.rotate(90); + + const QTransform worldTransform = painter.worldTransform(); + const QTransform deviceTransform = painter.deviceTransform(); + + // Render widgets onto image. + widget.render(&painter); +#ifdef RENDER_DEBUG + image.save("render_worldTransform_image.png"); +#endif + + // Ensure the transforms are unchanged after render. + QCOMPARE(painter.worldTransform(), painter.worldTransform()); + QCOMPARE(painter.deviceTransform(), painter.deviceTransform()); + painter.end(); + + // Paint expected image. + QImage expected(QSize(110, 110), QImage::Format_RGB32); + expected.fill(QColor(Qt::black).rgb()); + + QPainter expectedPainter(&expected); + expectedPainter.translate(105, 5); + expectedPainter.rotate(90); + expectedPainter.save(); + expectedPainter.fillRect(widget.rect(),Qt::red); + expectedPainter.translate(10, 10); + expectedPainter.rotate(90); + expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green); + expectedPainter.restore(); + expectedPainter.translate(50, 50); + expectedPainter.fillRect(child.rect(),Qt::blue); + expectedPainter.translate(10, 10); + expectedPainter.rotate(90); + expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green); + expectedPainter.end(); + +#ifdef RENDER_DEBUG + expected.save("render_worldTransform_expected.png"); +#endif + + QCOMPARE(image, expected); +} + +void tst_QWidget::setContentsMargins() +{ + QLabel label("why does it always rain on me?"); + QSize oldSize = label.sizeHint(); + label.setFrameStyle(QFrame::Sunken | QFrame::Box); + QSize newSize = label.sizeHint(); + QVERIFY(oldSize != newSize); + + QLabel label2("why does it always rain on me?"); + label2.show(); + label2.setFrameStyle(QFrame::Sunken | QFrame::Box); + QCOMPARE(newSize, label2.sizeHint()); + + QLabel label3("why does it always rain on me?"); + label3.setFrameStyle(QFrame::Sunken | QFrame::Box); + QCOMPARE(newSize, label3.sizeHint()); +} + +// 4DWM issues on IRIX makes this test fail. +#ifndef Q_OS_IRIX +void tst_QWidget::moveWindowInShowEvent_data() +{ + QTest::addColumn("initial"); + QTest::addColumn("position"); + + QPoint p = QApplication::desktop()->availableGeometry().topLeft(); + + QTest::newRow("1") << p << (p + QPoint(10, 10)); + QTest::newRow("2") << (p + QPoint(10,10)) << p; +} + +void tst_QWidget::moveWindowInShowEvent() +{ + QFETCH(QPoint, initial); + QFETCH(QPoint, position); + + class MoveWindowInShowEventWidget : public QWidget + { + public: + QPoint position; + void showEvent(QShowEvent *) + { + move(position); + } + }; + + MoveWindowInShowEventWidget widget; + widget.resize(QSize(qApp->desktop()->availableGeometry().size() / 3).expandedTo(QSize(1, 1))); + // move to this position in showEvent() + widget.position = position; + + // put the widget in it's starting position + widget.move(initial); + QCOMPARE(widget.pos(), initial); + + // show it + widget.show(); + #ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); + #endif + QTest::qWait(100); + // it should have moved + QCOMPARE(widget.pos(), position); +} +#endif + +void tst_QWidget::repaintWhenChildDeleted() +{ +#ifdef Q_WS_WIN + if (QSysInfo::WindowsVersion & QSysInfo::WV_VISTA) { + QTest::qWait(1000); + } +#endif + ColorWidget w(0, Qt::red); +#if !defined(Q_OS_WINCE) + QPoint startPoint = QApplication::desktop()->availableGeometry(&w).topLeft(); + startPoint.rx() += 50; + startPoint.ry() += 50; + w.setGeometry(QRect(startPoint, QSize(100, 100))); +#else + w.setGeometry(60, 60, 110, 110); +#endif + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(10); + QTRY_COMPARE(w.r, QRegion(w.rect())); + w.r = QRegion(); + + { + const QPoint tlwOffset = w.geometry().topLeft(); + ColorWidget child(&w, Qt::blue); + child.setGeometry(10, 10, 10, 10); + child.show(); + QTest::qWait(10); + QTRY_COMPARE(child.r, QRegion(child.rect())); + w.r = QRegion(); + } + + QTest::qWait(10); + QTRY_COMPARE(w.r, QRegion(10, 10, 10, 10)); +} + +// task 175114 +void tst_QWidget::hideOpaqueChildWhileHidden() +{ + ColorWidget w(0, Qt::red); +#if !defined(Q_OS_WINCE) + QPoint startPoint = QApplication::desktop()->availableGeometry(&w).topLeft(); + startPoint.rx() += 50; + startPoint.ry() += 50; + w.setGeometry(QRect(startPoint, QSize(100, 100))); +#else + w.setGeometry(60, 60, 110, 110); +#endif + + ColorWidget child(&w, Qt::blue); + child.setGeometry(10, 10, 80, 80); + + ColorWidget child2(&child, Qt::white); + child2.setGeometry(10, 10, 60, 60); + + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(10); + QTRY_COMPARE(child2.r, QRegion(child2.rect())); + child.r = QRegion(); + child2.r = QRegion(); + w.r = QRegion(); + + child.hide(); + child2.hide(); + QTest::qWait(100); + + QCOMPARE(w.r, QRegion(child.geometry())); + + child.show(); + QTest::qWait(100); + QCOMPARE(child.r, QRegion(child.rect())); + QCOMPARE(child2.r, QRegion()); +} + +// This test doesn't make sense without support for showMinimized(). +#if !defined(Q_OS_WINCE) && !defined(Q_WS_QWS) +void tst_QWidget::updateWhileMinimized() +{ + UpdateWidget widget; + // Filter out activation change and focus events to avoid update() calls in QWidget. + widget.updateOnActivationChangeAndFocusIn = false; + widget.reset(); + widget.show(); + QTest::qWaitForWindowShown(&widget); + QApplication::processEvents(); + QTRY_VERIFY(widget.numPaintEvents > 0); + QTest::qWait(150); + + // Minimize window. + widget.showMinimized(); + QTest::qWait(110); + + widget.reset(); + + // The widget is not visible on the screen (but isVisible() still returns true). + // Make sure update requests are discarded until the widget is shown again. + widget.update(0, 0, 50, 50); + QTest::qWait(10); + QCOMPARE(widget.numPaintEvents, 0); + + // Restore window. + widget.showNormal(); + QTest::qWait(30); + QTRY_COMPARE(widget.numPaintEvents, 1); + QCOMPARE(widget.paintedRegion, QRegion(0, 0, 50, 50)); +} +#endif + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) +class PaintOnScreenWidget: public QWidget +{ +public: + PaintOnScreenWidget(QWidget *parent = 0, Qt::WindowFlags f = 0) + :QWidget(parent, f) + { + } +#if defined(Q_WS_WIN) + // This is the only way to enable PaintOnScreen on Windows. + QPaintEngine * paintEngine () const {return 0;} +#endif +}; + +void tst_QWidget::alienWidgets() +{ + qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + QWidget parent; + QWidget child(&parent); + QWidget grandChild(&child); + QWidget greatGrandChild(&grandChild); + parent.show(); + +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&parent); +#endif + + // Verify that the WA_WState_Created attribute is set + // and the top-level is the only native window. + QVERIFY(parent.testAttribute(Qt::WA_WState_Created)); + QVERIFY(parent.internalWinId()); + + QVERIFY(child.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!child.internalWinId()); + + QVERIFY(grandChild.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!grandChild.internalWinId()); + + QVERIFY(greatGrandChild.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!greatGrandChild.internalWinId()); + + // Enforce native windows all the way up in the parent hierarchy + // if not WA_DontCreateNativeAncestors is set. + grandChild.setAttribute(Qt::WA_DontCreateNativeAncestors); + greatGrandChild.setAttribute(Qt::WA_NativeWindow); + QVERIFY(greatGrandChild.internalWinId()); + QVERIFY(grandChild.internalWinId()); + QVERIFY(!child.internalWinId()); + + { + // Ensure that hide() on an ancestor of a widget with + // Qt::WA_DontCreateNativeAncestors still gets unmapped + QWidget window; + QWidget widget(&window); + QWidget child(&widget); + child.setAttribute(Qt::WA_NativeWindow); + child.setAttribute(Qt::WA_DontCreateNativeAncestors); + window.show(); + QVERIFY(child.testAttribute(Qt::WA_Mapped)); + widget.hide(); + QVERIFY(!child.testAttribute(Qt::WA_Mapped)); + } + + // Enforce a native window when calling QWidget::winId. + QVERIFY(child.winId()); + QVERIFY(child.internalWinId()); + + // Check that paint on screen widgets (incl. children) are native. + PaintOnScreenWidget paintOnScreen(&parent); + QWidget paintOnScreenChild(&paintOnScreen); + paintOnScreen.show(); + QVERIFY(paintOnScreen.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!paintOnScreen.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(!paintOnScreen.internalWinId()); + QVERIFY(!paintOnScreenChild.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(!paintOnScreenChild.internalWinId()); + + paintOnScreen.setAttribute(Qt::WA_PaintOnScreen); + QVERIFY(paintOnScreen.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(paintOnScreen.internalWinId()); + QVERIFY(paintOnScreenChild.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(paintOnScreenChild.internalWinId()); + + // Check that widgets with the Qt::MSWindowsOwnDC attribute set + // are native. + QWidget msWindowsOwnDC(&parent, Qt::MSWindowsOwnDC); + msWindowsOwnDC.show(); + QVERIFY(msWindowsOwnDC.testAttribute(Qt::WA_WState_Created)); + QVERIFY(msWindowsOwnDC.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(msWindowsOwnDC.internalWinId()); + + { // Enforce a native window when calling QWidget::handle() (on X11) or QWidget::getDC() (on Windows). + QWidget widget(&parent); + widget.show(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!widget.internalWinId()); +#ifdef Q_WS_X11 + widget.handle(); +#else + widget.getDC(); +#endif + QVERIFY(widget.internalWinId()); + } + +#ifdef Q_WS_X11 +#ifndef QT_NO_XRENDER + { // Enforce a native window when calling QWidget::x11PictureHandle(). + QWidget widget(&parent); + widget.show(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QVERIFY(!widget.internalWinId()); + widget.x11PictureHandle(); + QVERIFY(widget.internalWinId()); + } +#endif + + { // Make sure we don't create native windows when setting Qt::WA_X11NetWmWindowType attributes + // on alien widgets (see task 194231). + QWidget dummy; + QVERIFY(dummy.winId()); + QWidget widget(&dummy); + widget.setAttribute(Qt::WA_X11NetWmWindowTypeToolBar); + QVERIFY(!widget.internalWinId()); + } +#endif + + + { // Make sure we create native ancestors when setting Qt::WA_PaintOnScreen before show(). + QWidget topLevel; + QWidget child(&topLevel); + QWidget grandChild(&child); + PaintOnScreenWidget greatGrandChild(&grandChild); + + greatGrandChild.setAttribute(Qt::WA_PaintOnScreen); + QVERIFY(!child.internalWinId()); + QVERIFY(!grandChild.internalWinId()); + QVERIFY(!greatGrandChild.internalWinId()); + + topLevel.show(); + QVERIFY(child.internalWinId()); + QVERIFY(grandChild.internalWinId()); + QVERIFY(greatGrandChild.internalWinId()); + } + + { // Ensure that widgets reparented into Qt::WA_PaintOnScreen widgets become native. + QWidget topLevel; + QWidget *widget = new PaintOnScreenWidget(&topLevel); + widget->setAttribute(Qt::WA_PaintOnScreen); + QWidget *child = new QWidget; + QWidget *dummy = new QWidget(child); + QWidget *grandChild = new QWidget(child); + QWidget *dummy2 = new QWidget(grandChild); + + child->setParent(widget); + + QVERIFY(!topLevel.internalWinId()); + QVERIFY(!child->internalWinId()); + QVERIFY(!dummy->internalWinId()); + QVERIFY(!grandChild->internalWinId()); + QVERIFY(!dummy2->internalWinId()); + + topLevel.show(); + QVERIFY(topLevel.internalWinId()); + QVERIFY(widget->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(child->internalWinId()); + QVERIFY(child->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(!child->testAttribute(Qt::WA_PaintOnScreen)); + QVERIFY(!dummy->internalWinId()); + QVERIFY(!dummy->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(!grandChild->internalWinId()); + QVERIFY(!grandChild->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(!dummy2->internalWinId()); + QVERIFY(!dummy2->testAttribute(Qt::WA_NativeWindow)); + } + + { // Ensure that ancestors of a Qt::WA_PaintOnScreen widget stay native + // if they are re-created (typically in QWidgetPrivate::setParent_sys) (task 210822). + QWidget window; + QWidget child(&window); + + QWidget grandChild; + grandChild.setWindowTitle("This causes the widget to be created"); + + PaintOnScreenWidget paintOnScreenWidget; + paintOnScreenWidget.setAttribute(Qt::WA_PaintOnScreen); + paintOnScreenWidget.setParent(&grandChild); + + grandChild.setParent(&child); + + window.show(); + + QVERIFY(window.internalWinId()); + QVERIFY(child.internalWinId()); + QVERIFY(child.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(grandChild.internalWinId()); + QVERIFY(grandChild.testAttribute(Qt::WA_NativeWindow)); + QVERIFY(paintOnScreenWidget.internalWinId()); + QVERIFY(paintOnScreenWidget.testAttribute(Qt::WA_NativeWindow)); + } + + { // Ensure that all siblings are native unless Qt::AA_DontCreateNativeWidgetSiblings is set. + qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, false); + QWidget mainWindow; + QWidget *toolBar = new QWidget(&mainWindow); + QWidget *dockWidget = new QWidget(&mainWindow); + QWidget *centralWidget = new QWidget(&mainWindow); + + QWidget *button = new QWidget(centralWidget); + QWidget *mdiArea = new QWidget(centralWidget); + + QWidget *horizontalScroll = new QWidget(mdiArea); + QWidget *verticalScroll = new QWidget(mdiArea); + QWidget *viewport = new QWidget(mdiArea); + + viewport->setAttribute(Qt::WA_NativeWindow); + mainWindow.show(); + + // Ensure that the viewport and its siblings are native: + QVERIFY(verticalScroll->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(verticalScroll->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(horizontalScroll->testAttribute(Qt::WA_NativeWindow)); + + // Ensure that the mdi area and its siblings are native: + QVERIFY(mdiArea->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(button->testAttribute(Qt::WA_NativeWindow)); + + // Ensure that the central widget and its siblings are native: + QVERIFY(centralWidget->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(dockWidget->testAttribute(Qt::WA_NativeWindow)); + QVERIFY(toolBar->testAttribute(Qt::WA_NativeWindow)); + } +} +#endif // Q_WS_WIN / Q_WS_X11 + +class ASWidget : public QWidget +{ +public: + ASWidget(QSize sizeHint, QSizePolicy sizePolicy, bool layout, bool hfwLayout, QWidget *parent = 0) + : QWidget(parent), mySizeHint(sizeHint) + { + setSizePolicy(sizePolicy); + if (layout) { + QSizePolicy sp = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sp.setHeightForWidth(hfwLayout); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->setMargin(0); + vbox->addWidget(new ASWidget(sizeHint + QSize(30, 20), sp, false, false)); + setLayout(vbox); + } + } + + QSize sizeHint() const { + if (layout()) + return layout()->totalSizeHint(); + return mySizeHint; + } + int heightForWidth(int width) const { + if (sizePolicy().hasHeightForWidth()) { + return width * 2; + } else { + return -1; + } + } + + QSize mySizeHint; +}; + +void tst_QWidget::adjustSize_data() +{ + const int MagicW = 200; + const int MagicH = 100; + + QTest::addColumn("sizeHint"); + QTest::addColumn("hPolicy"); + QTest::addColumn("vPolicy"); + QTest::addColumn("hfwSP"); + QTest::addColumn("layout"); + QTest::addColumn("hfwLayout"); + QTest::addColumn("haveParent"); + QTest::addColumn("expectedSize"); + + QTest::newRow("1") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << false << false << false << QSize(5, qMax(6, MagicH)); + QTest::newRow("2") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << true << false << false << false << QSize(5, qMax(10, MagicH)); + QTest::newRow("3") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << false << false << QSize(35, 26); + QTest::newRow("4") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << true << false << QSize(35, 70); + QTest::newRow("5") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << false << false << false << QSize(100000, 100000); + QTest::newRow("6") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << true << false << false << false << QSize(100000, 100000); + QTest::newRow("7") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << false << false << QSize(100000, 100000); + QTest::newRow("8") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << true << false << QSize(100000, 100000); + QTest::newRow("9") << QSize(5, 6) << int(QSizePolicy::Expanding) << int(QSizePolicy::Minimum) + << true << false << false << false << QSize(qMax(5, MagicW), 10); + + QTest::newRow("1c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << false << false << true << QSize(5, 6); + QTest::newRow("2c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << true << false << false << true << QSize(5, 6 /* or 10 would be OK too, since hfw contradicts sizeHint() */); + QTest::newRow("3c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << false << true << QSize(35, 26); + QTest::newRow("4c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << true << true << QSize(35, 70); + QTest::newRow("5c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << false << false << true << QSize(40001, 30001); + QTest::newRow("6c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << true << false << false << true << QSize(40001, 30001 /* or 80002 would be OK too, since hfw contradicts sizeHint() */); + QTest::newRow("7c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << false << true << QSize(40001 + 30, 30001 + 20); + QTest::newRow("8c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding) + << false << true << true << true << QSize(40001 + 30, 80002 + 60); + QTest::newRow("9c") << QSize(5, 6) << int(QSizePolicy::Expanding) << int(QSizePolicy::Minimum) + << true << false << false << true << QSize(5, 6); +} + +void tst_QWidget::adjustSize() +{ + QFETCH(QSize, sizeHint); + QFETCH(int, hPolicy); + QFETCH(int, vPolicy); + QFETCH(bool, hfwSP); + QFETCH(bool, layout); + QFETCH(bool, hfwLayout); + QFETCH(bool, haveParent); + QFETCH(QSize, expectedSize); + + QWidget *parent = new QWidget; + + QSizePolicy sp = QSizePolicy(QSizePolicy::Policy(hPolicy), QSizePolicy::Policy(vPolicy)); + sp.setHeightForWidth(hfwSP); + + QWidget *child = new ASWidget(sizeHint, sp, layout, hfwLayout, haveParent ? parent : 0); + child->resize(123, 456); + child->adjustSize(); + if (expectedSize == QSize(100000, 100000)) { + QVERIFY(child->size().width() < sizeHint.width()); + QVERIFY(child->size().height() < sizeHint.height()); + } else { +#if defined (Q_OS_WINCE) + if (!haveParent) { + const QRect& desktopRect = qApp->desktop()->availableGeometry(); + expectedSize.setWidth(qMin(expectedSize.width(), desktopRect.width())); + expectedSize.setHeight(qMin(expectedSize.height(), desktopRect.height())); + } +#endif + QCOMPARE(child->size(), expectedSize); + } + + delete parent; +} + +class TestLayout : public QVBoxLayout +{ + Q_OBJECT +public: + TestLayout(QWidget *w = 0) : QVBoxLayout(w) + { + invalidated = false; + } + + void invalidate() + { + invalidated = true; + } + + bool invalidated; +}; + +void tst_QWidget::updateGeometry_data() +{ + QTest::addColumn("minSize"); + QTest::addColumn("shouldInvalidate"); + QTest::addColumn("maxSize"); + QTest::addColumn("shouldInvalidate2"); + QTest::addColumn("verticalSizePolicy"); + QTest::addColumn("shouldInvalidate3"); + QTest::addColumn("setVisible"); + QTest::addColumn("shouldInvalidate4"); + + QTest::newRow("setMinimumSize") + << QSize(100, 100) << true + << QSize() << false + << int(QSizePolicy::Preferred) << false + << true << false; + QTest::newRow("setMaximumSize") + << QSize() << false + << QSize(100, 100) << true + << int(QSizePolicy::Preferred) << false + << true << false; + QTest::newRow("setMinimumSize, then maximumSize to a different size") + << QSize(100, 100) << true + << QSize(300, 300) << true + << int(QSizePolicy::Preferred) << false + << true << false; + QTest::newRow("setMinimumSize, then maximumSize to the same size") + << QSize(100, 100) << true + << QSize(100, 100) << true + << int(QSizePolicy::Preferred) << false + << true << false; + QTest::newRow("setMinimumSize, then maximumSize to the same size and then hide it") + << QSize(100, 100) << true + << QSize(100, 100) << true + << int(QSizePolicy::Preferred) << false + << false << true; + QTest::newRow("Change sizePolicy") + << QSize() << false + << QSize() << false + << int(QSizePolicy::Minimum) << true + << true << false; + +} + +void tst_QWidget::updateGeometry() +{ + QFETCH(QSize, minSize); + QFETCH(bool, shouldInvalidate); + QFETCH(QSize, maxSize); + QFETCH(bool, shouldInvalidate2); + QFETCH(int, verticalSizePolicy); + QFETCH(bool, shouldInvalidate3); + QFETCH(bool, setVisible); + QFETCH(bool, shouldInvalidate4); + QWidget parent; + parent.resize(200, 200); + TestLayout *lout = new TestLayout(); + parent.setLayout(lout); + QWidget *child = new QWidget(&parent); + lout->addWidget(child); + parent.show(); + QApplication::processEvents(); + + lout->invalidated = false; + if (minSize.isValid()) + child->setMinimumSize(minSize); + QCOMPARE(lout->invalidated, shouldInvalidate); + + lout->invalidated = false; + if (maxSize.isValid()) + child->setMaximumSize(maxSize); + QCOMPARE(lout->invalidated, shouldInvalidate2); + + lout->invalidated = false; + child->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, (QSizePolicy::Policy)verticalSizePolicy)); + if (shouldInvalidate3) + QCOMPARE(lout->invalidated, true); + + lout->invalidated = false; + if (!setVisible) + child->setVisible(false); + QCOMPARE(lout->invalidated, shouldInvalidate4); +} + +void tst_QWidget::sendUpdateRequestImmediately() +{ +#ifdef Q_WS_MAC + if (!QApplicationPrivate::graphicsSystem()) + QSKIP("We only send update requests on the Mac when passing -graphicssystem", SkipAll); +#endif + + UpdateWidget updateWidget; + updateWidget.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&updateWidget); +#endif + + qApp->processEvents(); +#ifdef Q_WS_QWS + QApplication::sendPostedEvents(); //glib workaround +#endif + updateWidget.reset(); + + QCOMPARE(updateWidget.numUpdateRequestEvents, 0); + updateWidget.repaint(); + QCOMPARE(updateWidget.numUpdateRequestEvents, 1); +} + +// 4DWM issues on IRIX makes this test fail. +#ifndef Q_OS_IRIX +void tst_QWidget::doubleRepaint() +{ +#if defined(Q_WS_MAC) + if (!macHasAccessToWindowsServer()) + QSKIP("Not having window server access causes the wrong number of repaints to be issues", SkipAll); +#endif + UpdateWidget widget; + widget.setFocusPolicy(Qt::StrongFocus); + // Filter out activation change and focus events to avoid update() calls in QWidget. + widget.updateOnActivationChangeAndFocusIn = false; + + // Show: 1 repaint + int expectedRepaints = 1; + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(10); + QTRY_COMPARE(widget.numPaintEvents, expectedRepaints); + widget.numPaintEvents = 0; + + // Minmize: Should not trigger a repaint. + widget.showMinimized(); + QTest::qWait(10); + QCOMPARE(widget.numPaintEvents, 0); + widget.numPaintEvents = 0; + + // Restore: Should not trigger a repaint. + widget.showNormal(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(10); + QCOMPARE(widget.numPaintEvents, 0); +} +#endif + +#ifndef Q_WS_MAC +// This test only makes sense on the Mac when passing -graphicssystem. +void tst_QWidget::resizeInPaintEvent() +{ + QWidget window; + UpdateWidget widget(&window); + window.show(); + QTest::qWaitForWindowShown(&window); + QTRY_VERIFY(widget.numPaintEvents > 0); + + widget.reset(); + QCOMPARE(widget.numPaintEvents, 0); + + widget.resizeInPaintEvent = true; + // This will call resize in the paintEvent, which in turn will call + // invalidateBuffer() and a new update request should be posted. + widget.repaint(); + QCOMPARE(widget.numPaintEvents, 1); + widget.numPaintEvents = 0; + + QTest::qWait(10); + // Make sure the resize triggers another update. + QTRY_COMPARE(widget.numPaintEvents, 1); +} + +void tst_QWidget::opaqueChildren() +{ + QWidget widget; + widget.resize(200, 200); + + QWidget child(&widget); + child.setGeometry(-700, -700, 200, 200); + + QWidget grandChild(&child); + grandChild.resize(200, 200); + + QWidget greatGrandChild(&grandChild); + greatGrandChild.setGeometry(50, 50, 200, 200); + greatGrandChild.setPalette(Qt::red); + greatGrandChild.setAutoFillBackground(true); // Opaque child widget. + + widget.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); +#endif + QTest::qWait(100); + + // Child, grandChild and greatGrandChild are outside the ancestor clip. + QRegion expectedOpaqueRegion(50, 50, 150, 150); + QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion); + + // Now they are all inside the ancestor clip. + child.setGeometry(50, 50, 150, 150); + QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion); + + // Set mask on greatGrandChild. + const QRegion mask(10, 10, 50, 50); + greatGrandChild.setMask(mask); + expectedOpaqueRegion &= mask.translated(50, 50); + QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion); + + // Make greatGrandChild "transparent". + greatGrandChild.setAutoFillBackground(false); + QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), QRegion()); +} +#endif + + +class MaskSetWidget : public QWidget +{ + Q_OBJECT +public: + MaskSetWidget(QWidget* p =0) + : QWidget(p) {} + + void paintEvent(QPaintEvent* event) { + QPainter p(this); + + paintedRegion += event->region(); + foreach(QRect r, event->region().rects()) + p.fillRect(r, Qt::red); + } + + void resizeEvent(QResizeEvent*) { + setMask(QRegion(QRect(0, 0, width(), 10).normalized())); + } + + QRegion paintedRegion; + +public slots: + void resizeDown() { + setGeometry(QRect(0, 50, 50, 50)); + } + + void resizeUp() { + setGeometry(QRect(0, 50, 150, 50)); + } + +}; + +void tst_QWidget::setMaskInResizeEvent() +{ + UpdateWidget w; + w.reset(); + w.resize(200, 200); + w.setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + w.raise(); + + MaskSetWidget testWidget(&w); + testWidget.setGeometry(0, 0, 100, 100); + testWidget.setMask(QRegion(QRect(0,0,100,10))); + testWidget.show(); + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(30); + QTRY_VERIFY(w.numPaintEvents > 0); + + w.reset(); + testWidget.paintedRegion = QRegion(); + QTimer::singleShot(0, &testWidget, SLOT(resizeDown())); + QTest::qWait(100); + + QRegion expectedParentUpdate(0, 0, 100, 10); // Old testWidget area. + expectedParentUpdate += testWidget.geometry(); // New testWidget area. + QCOMPARE(w.paintedRegion, expectedParentUpdate); + QCOMPARE(testWidget.paintedRegion, testWidget.mask()); + + testWidget.paintedRegion = QRegion(); + // Now resize the widget again, but in the oposite direction + QTimer::singleShot(0, &testWidget, SLOT(resizeUp())); + QTest::qWait(100); + + QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask()); +} + +class MoveInResizeWidget : public QWidget +{ + Q_OBJECT +public: + MoveInResizeWidget(QWidget* p = 0) + : QWidget(p) + { + setWindowFlags(Qt::FramelessWindowHint); + } + + void resizeEvent(QResizeEvent*) { + + move(QPoint(100,100)); + + static bool firstTime = true; + if (firstTime) + QTimer::singleShot(250, this, SLOT(resizeMe())); + + firstTime = false; + } + +public slots: + void resizeMe() { + resize(100, 100); + } +}; + +void tst_QWidget::moveInResizeEvent() +{ + MoveInResizeWidget testWidget; + testWidget.setGeometry(50, 50, 200, 200); + testWidget.show(); + QTest::qWaitForWindowShown(&testWidget); + QTest::qWait(300); + + QRect expectedGeometry(100,100, 100, 100); + QTRY_COMPARE(testWidget.geometry(), expectedGeometry); +} + + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) +void tst_QWidget::immediateRepaintAfterShow() +{ + UpdateWidget widget; + widget.show(); + qApp->processEvents(); + // On X11 in particular, we are now waiting for a MapNotify event before + // syncing the backing store. However, if someone request a repaint() + // we must repaint immediately regardless of the current state. + widget.numPaintEvents = 0; + widget.repaint(); + QCOMPARE(widget.numPaintEvents, 1); +} + +void tst_QWidget::immediateRepaintAfterInvalidateBuffer() +{ + QWidget *widget = new UpdateWidget; + widget->show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(widget); +#endif + QTest::qWait(200); + + static_cast(widget)->numPaintEvents = 0; + + // Marks the area covered by the widget as dirty in the backing store and + // posts an UpdateRequest event. + qt_widget_private(widget)->invalidateBuffer(widget->rect()); + QCOMPARE(static_cast(widget)->numPaintEvents, 0); + + // The entire widget is already dirty, but this time we want to update immediately + // by calling repaint(), and thus we have to repaint the widget and not wait for + // the UpdateRequest to be sent when we get back to the event loop. + widget->repaint(); + QCOMPARE(static_cast(widget)->numPaintEvents, 1); + + delete widget; +} +#endif + +void tst_QWidget::effectiveWinId() +{ + QWidget parent; + QWidget child(&parent); + + // Shouldn't crash. + QVERIFY(!parent.effectiveWinId()); + QVERIFY(!child.effectiveWinId()); + + parent.show(); + + QVERIFY(parent.effectiveWinId()); + QVERIFY(child.effectiveWinId()); +} + +void tst_QWidget::effectiveWinId2() +{ + QWidget parent; + + class MyWidget : public QWidget { + bool event(QEvent *e) + { + if (e->type() == QEvent::WinIdChange) { + // Shouldn't crash. + effectiveWinId(); + } + + return QWidget::event(e); + } + }; + + MyWidget child; + child.setParent(&parent); + parent.show(); + + child.setParent(0); + child.setParent(&parent); +} + +class CustomWidget : public QWidget +{ +public: + mutable int metricCallCount; + + CustomWidget(QWidget *parent = 0) : QWidget(parent), metricCallCount(0) {} + + virtual int metric(PaintDeviceMetric metric) const { + ++metricCallCount; + return QWidget::metric(metric); + } +}; + +void tst_QWidget::customDpi() +{ + QWidget *topLevel = new QWidget; + CustomWidget *custom = new CustomWidget(topLevel); + QWidget *child = new QWidget(custom); + + custom->metricCallCount = 0; + topLevel->logicalDpiX(); + QCOMPARE(custom->metricCallCount, 0); + custom->logicalDpiX(); + QCOMPARE(custom->metricCallCount, 1); + child->logicalDpiX(); + QCOMPARE(custom->metricCallCount, 2); + + delete topLevel; +} + +void tst_QWidget::customDpiProperty() +{ + QWidget *topLevel = new QWidget; + QWidget *middle = new CustomWidget(topLevel); + QWidget *child = new QWidget(middle); + + const int initialDpiX = topLevel->logicalDpiX(); + const int initialDpiY = topLevel->logicalDpiY(); + + middle->setProperty("_q_customDpiX", 300); + middle->setProperty("_q_customDpiY", 400); + + QCOMPARE(topLevel->logicalDpiX(), initialDpiX); + QCOMPARE(topLevel->logicalDpiY(), initialDpiY); + + QCOMPARE(middle->logicalDpiX(), 300); + QCOMPARE(middle->logicalDpiY(), 400); + + QCOMPARE(child->logicalDpiX(), 300); + QCOMPARE(child->logicalDpiY(), 400); + + middle->setProperty("_q_customDpiX", QVariant()); + middle->setProperty("_q_customDpiY", QVariant()); + + QCOMPARE(topLevel->logicalDpiX(), initialDpiX); + QCOMPARE(topLevel->logicalDpiY(), initialDpiY); + + QCOMPARE(middle->logicalDpiX(), initialDpiX); + QCOMPARE(middle->logicalDpiY(), initialDpiY); + + QCOMPARE(child->logicalDpiX(), initialDpiX); + QCOMPARE(child->logicalDpiY(), initialDpiY); + + delete topLevel; +} + +void tst_QWidget::quitOnCloseAttribute() +{ + QWidget w; + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true); + w.setAttribute(Qt::WA_QuitOnClose, false); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::Tool); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::Popup); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::ToolTip); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::SplashScreen); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::SubWindow); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); + + w.setAttribute(Qt::WA_QuitOnClose); + w.setWindowFlags(Qt::Dialog); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true); + w.show(); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true); + w.setWindowFlags(Qt::Tool); + QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false); +} + +void tst_QWidget::moveRect() +{ + QWidget widget; + widget.setUpdatesEnabled(false); + QWidget child(&widget); + child.setUpdatesEnabled(false); + child.setAttribute(Qt::WA_OpaquePaintEvent); + widget.show(); + QTest::qWait(200); + child.move(10, 10); // Don't crash. +} + +#ifdef Q_WS_WIN +class GDIWidget : public QDialog +{ +public: + GDIWidget() { setAttribute(Qt::WA_PaintOnScreen); } + QPaintEngine *paintEngine() const { return 0; } + + + void paintEvent(QPaintEvent *) { + HDC hdc = getDC(); + SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0))); + Rectangle(hdc, 0, 0, 10, 10); + + releaseDC(hdc); + + QImage im = QPixmap::grabWindow(winId(), 0, 0, width(), height()).toImage(); + color = im.pixel(1, 1); + + accept(); + } + + QSize sizeHint() const { + return QSize(400, 300); + } + + QColor color; +}; + +void tst_QWidget::gdiPainting() +{ + GDIWidget w; + w.exec(); + + QCOMPARE(w.color, QColor(255, 0, 0)); + +} + +void tst_QWidget::paintOnScreenPossible() +{ + QWidget w1; + w1.setAttribute(Qt::WA_PaintOnScreen); + QVERIFY(!w1.testAttribute(Qt::WA_PaintOnScreen)); + + GDIWidget w2; + w2.setAttribute(Qt::WA_PaintOnScreen); + QVERIFY(w2.testAttribute(Qt::WA_PaintOnScreen)); +} +#endif + +void tst_QWidget::reparentStaticWidget() +{ + QWidget window1; + + QWidget *child = new QWidget(&window1); + child->setPalette(Qt::red); + child->setAutoFillBackground(true); + child->setAttribute(Qt::WA_StaticContents); + child->resize(100, 100); + + QWidget *grandChild = new QWidget(child); + grandChild->setPalette(Qt::blue); + grandChild->setAutoFillBackground(true); + grandChild->resize(50, 50); + grandChild->setAttribute(Qt::WA_StaticContents); + window1.show(); + QTest::qWaitForWindowShown(&window1); + + QWidget window2; + window2.show(); + QTest::qWaitForWindowShown(&window2); + QTest::qWait(20); + + // Reparent into another top-level. + child->setParent(&window2); + child->show(); + + // Please don't crash. + window1.resize(window1.size() + QSize(2, 2)); + QTest::qWait(20); + + // Make sure we move all static children even though + // the reparented widget itself is non-static. + child->setAttribute(Qt::WA_StaticContents, false); + child->setParent(&window1); + child->show(); + + // Please don't crash. + window2.resize(window2.size() + QSize(2, 2)); + QTest::qWait(20); + + child->setParent(0); + child->show(); + QTest::qWait(20); + + // Please don't crash. + child->resize(child->size() + QSize(2, 2)); + window2.resize(window2.size() + QSize(2, 2)); + QTest::qWait(20); + + QWidget *siblingOfGrandChild = new QWidget(child); + siblingOfGrandChild->show(); + QTest::qWait(20); + + // Nothing should happen when reparenting within the same top-level. + grandChild->setParent(siblingOfGrandChild); + grandChild->show(); + QTest::qWait(20); + + QWidget paintOnScreen; + paintOnScreen.setAttribute(Qt::WA_PaintOnScreen); + paintOnScreen.show(); + QTest::qWaitForWindowShown(&paintOnScreen); + QTest::qWait(20); + + child->setParent(&paintOnScreen); + child->show(); + QTest::qWait(20); + + // Please don't crash. + paintOnScreen.resize(paintOnScreen.size() + QSize(2, 2)); + QTest::qWait(20); + +} + +void tst_QWidget::QTBUG6883_reparentStaticWidget2() +{ + QMainWindow mw; + QDockWidget *one = new QDockWidget("one", &mw); + mw.addDockWidget(Qt::LeftDockWidgetArea, one , Qt::Vertical); + + QWidget *child = new QWidget(); + child->setPalette(Qt::red); + child->setAutoFillBackground(true); + child->setAttribute(Qt::WA_StaticContents); + child->resize(100, 100); + one->setWidget(child); + + QToolBar *mainTools = mw.addToolBar("Main Tools"); + mainTools->addWidget(new QLineEdit); + + mw.show(); + QTest::qWaitForWindowShown(&mw); + + one->setFloating(true); + QTest::qWait(20); + //do not crash +} + +#ifdef Q_WS_QWS +void tst_QWidget::updateOutsideSurfaceClip() +{ + UpdateWidget widget; + widget.setWindowFlags(Qt::FramelessWindowHint); + widget.resize(100, 100); + widget.raise(); + widget.show(); + QTest::qWait(200); + widget.reset(); + + // Move widget partially outside buffer and change the surface clip. + widget.move(-50, 0); + QTest::qWait(100); + + // Update region is outside the surface clip and should not trigger a repaint. + widget.update(0, 0, 20, 20); + QTest::qWait(100); + QCOMPARE(widget.numPaintEvents, 0); + + // Now, move the widget back so that the update region is inside the clip + // and make sure we get a repaint of the dirty area. + widget.move(0, 0); + QTest::qWait(100); + QCOMPARE(widget.numPaintEvents, 1); + QCOMPARE(widget.paintedRegion, QRegion(0, 0, 20, 20)); +} +#endif +class ColorRedWidget : public QWidget +{ +public: + ColorRedWidget(QWidget *parent = 0) + : QWidget(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::ToolTip) + { + } + + void paintEvent(QPaintEvent *) { + QPainter p(this); + p.fillRect(rect(),Qt::red); + } +}; + +void tst_QWidget::translucentWidget() +{ + QPixmap pm(16,16); + pm.fill(Qt::red); + ColorRedWidget label; + label.setFixedSize(16,16); + label.setAttribute(Qt::WA_TranslucentBackground); + label.move(qApp->desktop()->availableGeometry().topLeft()); + label.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&label); +#endif + QTest::qWait(200); + + QPixmap widgetSnapshot; + +#ifdef Q_WS_WIN + QWidget *desktopWidget = QApplication::desktop()->screen(0); + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) + widgetSnapshot = QPixmap::grabWindow(desktopWidget->winId(), 0,0, label.width(), label.height()); + else +#endif + widgetSnapshot = QPixmap::grabWindow(label.winId()); + QImage actual = widgetSnapshot.toImage().convertToFormat(QImage::Format_RGB32); + QImage expected = pm.toImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(actual.size(),expected.size()); + QCOMPARE(actual,expected); +} + +class MaskResizeTestWidget : public QWidget +{ + Q_OBJECT +public: + MaskResizeTestWidget(QWidget* p =0) + : QWidget(p) { + setMask(QRegion(QRect(0, 0, 100, 100).normalized())); + } + + void paintEvent(QPaintEvent* event) { + QPainter p(this); + + paintedRegion += event->region(); + foreach(QRect r, event->region().rects()) + p.fillRect(r, Qt::red); + } + + QRegion paintedRegion; + +public slots: + void enlargeMask() { + QRegion newMask(QRect(0, 0, 150, 150).normalized()); + setMask(newMask); + } + + void shrinkMask() { + QRegion newMask(QRect(0, 0, 50, 50).normalized()); + setMask(newMask); + } + +}; + +void tst_QWidget::setClearAndResizeMask() +{ + UpdateWidget topLevel; + topLevel.resize(150, 150); + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); + QTRY_VERIFY(topLevel.numPaintEvents > 0); + topLevel.reset(); + + // Mask top-level widget + const QRegion topLevelMask(0, 0, 100, 100, QRegion::Ellipse); + topLevel.setMask(topLevelMask); + QCOMPARE(topLevel.mask(), topLevelMask); +#if defined(Q_WS_WIN) || defined(Q_WS_X11) // We don't control what's happening on other platforms. + // and ensure that the top-level doesn't get any update. + QCOMPARE(topLevel.numPaintEvents, 0); +#endif + + topLevel.reset(); + + // Clear top-level mask + topLevel.clearMask(); + QCOMPARE(topLevel.mask(), QRegion()); + QTest::qWait(10); + QRegion outsideOldMask(topLevel.rect()); + outsideOldMask -= topLevelMask; +#if defined(Q_WS_WIN) || defined(Q_WS_X11) // We don't control what's happening on other platforms. + // and ensure that the top-level gets an update for the area outside the old mask. + QTRY_VERIFY(topLevel.numPaintEvents > 0); + QTRY_COMPARE(topLevel.paintedRegion, outsideOldMask); +#endif + + UpdateWidget child(&topLevel); + child.setAutoFillBackground(true); // NB! Opaque child. + child.setPalette(Qt::red); + child.resize(100, 100); + child.show(); + QTest::qWait(10); + + child.reset(); + topLevel.reset(); + + // Mask child widget with a mask that is smaller than the rect + const QRegion childMask(0, 0, 50, 50); + child.setMask(childMask); + QTRY_COMPARE(child.mask(), childMask); + QTest::qWait(50); + // and ensure that the child widget doesn't get any update. +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (child.internalWinId()) + QCOMPARE(child.numPaintEvents, 1); + else +#endif + QCOMPARE(child.numPaintEvents, 0); + // and the parent widget gets an update for the newly exposed area. + QTRY_COMPARE(topLevel.numPaintEvents, 1); + QRegion expectedParentExpose(child.rect()); + expectedParentExpose -= childMask; + QCOMPARE(topLevel.paintedRegion, expectedParentExpose); + + child.reset(); + topLevel.reset(); + + // Clear child widget mask + child.clearMask(); + QTRY_COMPARE(child.mask(), QRegion()); + QTest::qWait(10); + // and ensure that that the child widget gets an update for the area outside the old mask. + QTRY_COMPARE(child.numPaintEvents, 1); + outsideOldMask = child.rect(); +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (!child.internalWinId()) +#endif + outsideOldMask -= childMask; + QCOMPARE(child.paintedRegion, outsideOldMask); + // and the parent widget doesn't get any update. + QCOMPARE(topLevel.numPaintEvents, 0); + + child.reset(); + topLevel.reset(); + + // Mask child widget with a mask that is bigger than the rect + child.setMask(QRegion(0, 0, 1000, 1000)); + QTest::qWait(100); +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (child.internalWinId()) + QTRY_COMPARE(child.numPaintEvents, 1); + else +#endif + // and ensure that we don't get any updates at all. + QTRY_COMPARE(child.numPaintEvents, 0); + QCOMPARE(topLevel.numPaintEvents, 0); + + // ...and the same applies when clearing the mask. + child.clearMask(); + QTest::qWait(100); +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (child.internalWinId()) + QTRY_VERIFY(child.numPaintEvents > 0); + else +#endif + QCOMPARE(child.numPaintEvents, 0); + QCOMPARE(topLevel.numPaintEvents, 0); + + QWidget resizeParent; + MaskResizeTestWidget resizeChild(&resizeParent); + + resizeParent.resize(300,300); + resizeParent.raise(); + resizeParent.setWindowFlags(Qt::WindowStaysOnTopHint); + resizeChild.setGeometry(50,50,200,200); + QPalette pal = resizeParent.palette(); + pal.setColor(QPalette::Window, QColor(Qt::white)); + resizeParent.setPalette(pal); + + resizeParent.show(); + QTest::qWaitForWindowShown(&resizeParent); + // Disable the size grip on the Mac; otherwise it'll be included when grabbing the window. + resizeParent.setFixedSize(resizeParent.size()); + resizeChild.show(); + QTest::qWait(100); + resizeChild.paintedRegion = QRegion(); + + QTimer::singleShot(100, &resizeChild, SLOT(shrinkMask())); + QTest::qWait(200); +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (child.internalWinId()) + QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask()); + else +#endif + QTRY_COMPARE(resizeChild.paintedRegion, QRegion()); + + resizeChild.paintedRegion = QRegion(); + const QRegion oldMask = resizeChild.mask(); + QTimer::singleShot(0, &resizeChild, SLOT(enlargeMask())); + QTest::qWait(100); +#ifdef Q_WS_MAC + // Mac always issues a full update when calling setMask, and we cannot force it to not do so. + if (child.internalWinId()) + QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask()); + else +#endif + QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask() - oldMask); +} + +void tst_QWidget::maskedUpdate() +{ + UpdateWidget topLevel; + topLevel.resize(200, 200); + const QRegion topLevelMask(50, 50, 70, 70); + topLevel.setMask(topLevelMask); + + UpdateWidget child(&topLevel); + child.setGeometry(20, 20, 180, 180); + const QRegion childMask(60, 60, 30, 30); + child.setMask(childMask); + + UpdateWidget grandChild(&child); + grandChild.setGeometry(50, 50, 100, 100); + const QRegion grandChildMask(20, 20, 10, 10); + grandChild.setMask(grandChildMask); + + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); + QTRY_VERIFY(topLevel.numPaintEvents > 0); + + +#define RESET_WIDGETS \ + topLevel.reset(); \ + child.reset(); \ + grandChild.reset(); + +#define CLEAR_MASK(widget) \ + widget.clearMask(); \ + QTest::qWait(100); \ + RESET_WIDGETS; + + // All widgets are transparent at this point, so any call to update() will result + // in composition, i.e. the update propagates to ancestors and children. + + // TopLevel update. + RESET_WIDGETS; + topLevel.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, topLevelMask); + QTRY_COMPARE(child.paintedRegion, childMask); + QTRY_COMPARE(grandChild.paintedRegion, grandChildMask); + + // Child update. + RESET_WIDGETS; + child.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, childMask.translated(child.pos())); + QTRY_COMPARE(child.paintedRegion, childMask); + QTRY_COMPARE(grandChild.paintedRegion, grandChildMask); + + // GrandChild update. + RESET_WIDGETS; + grandChild.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, grandChildMask.translated(grandChild.mapTo(&topLevel, QPoint()))); + QTRY_COMPARE(child.paintedRegion, grandChildMask.translated(grandChild.pos())); + QTRY_COMPARE(grandChild.paintedRegion, grandChildMask); + + topLevel.setAttribute(Qt::WA_OpaquePaintEvent); + child.setAttribute(Qt::WA_OpaquePaintEvent); + grandChild.setAttribute(Qt::WA_OpaquePaintEvent); + + // All widgets are now opaque, which means no composition, i.e. + // the update does not propate to ancestors and children. + + // TopLevel update. + RESET_WIDGETS; + topLevel.update(); + QTest::qWait(10); + + QRegion expectedTopLevelUpdate = topLevelMask; + expectedTopLevelUpdate -= childMask.translated(child.pos()); // Subtract opaque children. + QTRY_COMPARE(topLevel.paintedRegion, expectedTopLevelUpdate); + QTRY_COMPARE(child.paintedRegion, QRegion()); + QTRY_COMPARE(grandChild.paintedRegion, QRegion()); + + // Child update. + RESET_WIDGETS; + child.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + QRegion expectedChildUpdate = childMask; + expectedChildUpdate -= grandChildMask.translated(grandChild.pos()); // Subtract oapque children. + QTRY_COMPARE(child.paintedRegion, expectedChildUpdate); + QTRY_COMPARE(grandChild.paintedRegion, QRegion()); + + // GrandChild update. + RESET_WIDGETS; + grandChild.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + QTRY_COMPARE(child.paintedRegion, QRegion()); + QTRY_COMPARE(grandChild.paintedRegion, grandChildMask); + + // GrandChild update. + CLEAR_MASK(grandChild); + grandChild.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + QTRY_COMPARE(child.paintedRegion, QRegion()); + QRegion expectedGrandChildUpdate = grandChild.rect(); + // Clip with parent's mask. + expectedGrandChildUpdate &= childMask.translated(-grandChild.pos()); + QCOMPARE(grandChild.paintedRegion, expectedGrandChildUpdate); + + // GrandChild update. + CLEAR_MASK(child); + grandChild.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + QTRY_COMPARE(child.paintedRegion, QRegion()); + expectedGrandChildUpdate = grandChild.rect(); + // Clip with parent's mask. + expectedGrandChildUpdate &= topLevelMask.translated(-grandChild.mapTo(&topLevel, QPoint())); + QTRY_COMPARE(grandChild.paintedRegion, expectedGrandChildUpdate); + + // Child update. + RESET_WIDGETS; + child.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + expectedChildUpdate = child.rect(); + // Clip with parent's mask. + expectedChildUpdate &= topLevelMask.translated(-child.pos()); + expectedChildUpdate -= grandChild.geometry(); // Subtract opaque children. + QTRY_COMPARE(child.paintedRegion, expectedChildUpdate); + QTRY_COMPARE(grandChild.paintedRegion, QRegion()); + + // GrandChild update. + CLEAR_MASK(topLevel); + grandChild.update(); + QTest::qWait(10); + + QTRY_COMPARE(topLevel.paintedRegion, QRegion()); + QTRY_COMPARE(child.paintedRegion, QRegion()); + QTRY_COMPARE(grandChild.paintedRegion, QRegion(grandChild.rect())); // Full update. +} + +// Windows Mobile has no proper cursor support, so skip this test on that platform. +#if defined(Q_WS_X11) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE_WM)) || defined(Q_WS_QWS) || defined(Q_WS_QPA) +void tst_QWidget::syntheticEnterLeave() +{ + class MyWidget : public QWidget + { + public: + MyWidget(QWidget *parent = 0) : QWidget(parent), numEnterEvents(0), numLeaveEvents(0) {} + void enterEvent(QEvent *) { ++numEnterEvents; } + void leaveEvent(QEvent *) { ++numLeaveEvents; } + int numEnterEvents; + int numLeaveEvents; + }; + + QCursor::setPos(QPoint(0,0)); + + MyWidget window; + window.setWindowFlags(Qt::WindowStaysOnTopHint); + window.resize(200, 200); + + MyWidget *child1 = new MyWidget(&window); + child1->setPalette(Qt::blue); + child1->setAutoFillBackground(true); + child1->resize(200, 200); + child1->setCursor(Qt::OpenHandCursor); + + MyWidget *child2 = new MyWidget(&window); + child2->resize(200, 200); + + MyWidget *grandChild = new MyWidget(child2); + grandChild->setPalette(Qt::red); + grandChild->setAutoFillBackground(true); + grandChild->resize(200, 200); + grandChild->setCursor(Qt::WaitCursor); + + window.show(); + window.raise(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&window); +#endif + QTest::qWait(300); + +#define RESET_EVENT_COUNTS \ + window.numEnterEvents = 0; \ + window.numLeaveEvents = 0; \ + child1->numEnterEvents = 0; \ + child1->numLeaveEvents = 0; \ + child2->numEnterEvents = 0; \ + child2->numLeaveEvents = 0; \ + grandChild->numEnterEvents = 0; \ + grandChild->numLeaveEvents = 0; + + // Position the cursor in the middle of the window. + const QPoint globalPos = window.mapToGlobal(QPoint(100, 100)); + QCursor::setPos(globalPos); // Enter child2 and grandChild. + QTest::qWait(300); + + QCOMPARE(window.numLeaveEvents, 0); + QCOMPARE(child2->numLeaveEvents, 0); + QCOMPARE(grandChild->numLeaveEvents, 0); + QCOMPARE(child1->numLeaveEvents, 0); + + // This event arrives asynchronously + QTRY_COMPARE(window.numEnterEvents, 1); + QCOMPARE(child2->numEnterEvents, 1); + QCOMPARE(grandChild->numEnterEvents, 1); + QCOMPARE(child1->numEnterEvents, 0); + + RESET_EVENT_COUNTS; + child2->hide(); // Leave child2 and grandChild, enter child1. + + QCOMPARE(window.numLeaveEvents, 0); + QCOMPARE(child2->numLeaveEvents, 1); + QCOMPARE(grandChild->numLeaveEvents, 1); + QCOMPARE(child1->numLeaveEvents, 0); + + QCOMPARE(window.numEnterEvents, 0); + QCOMPARE(child2->numEnterEvents, 0); + QCOMPARE(grandChild->numEnterEvents, 0); + QCOMPARE(child1->numEnterEvents, 1); + + RESET_EVENT_COUNTS; + child2->show(); // Leave child1, enter child2 and grandChild. + + QCOMPARE(window.numLeaveEvents, 0); + QCOMPARE(child2->numLeaveEvents, 0); + QCOMPARE(grandChild->numLeaveEvents, 0); + QCOMPARE(child1->numLeaveEvents, 1); + + QCOMPARE(window.numEnterEvents, 0); + QCOMPARE(child2->numEnterEvents, 1); + QCOMPARE(grandChild->numEnterEvents, 1); + QCOMPARE(child1->numEnterEvents, 0); + + RESET_EVENT_COUNTS; + delete child2; // Enter child1 (and do not send leave events to child2 and grandChild). + + QCOMPARE(window.numLeaveEvents, 0); + QCOMPARE(child1->numLeaveEvents, 0); + + QCOMPARE(window.numEnterEvents, 0); + QCOMPARE(child1->numEnterEvents, 1); +} +#endif + +// Windows Mobile has no proper cursor support, so skip this test on that platform. +#if defined(Q_WS_X11) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE_WM)) || defined(Q_WS_QWS) || defined(Q_WS_QPA) +void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave() +{ + class SELParent : public QWidget + { + public: + SELParent(QWidget *parent = 0): QWidget(parent) { } + + void mousePressEvent(QMouseEvent *) { child->show(); } + QWidget *child; + }; + + class SELChild : public QWidget + { + public: + SELChild(QWidget *parent = 0) : QWidget(parent), numEnterEvents(0), numMouseMoveEvents(0) {} + void enterEvent(QEvent *) { ++numEnterEvents; } + void mouseMoveEvent(QMouseEvent *event) + { + QCOMPARE(event->button(), Qt::NoButton); + QCOMPARE(event->buttons(), Qt::MouseButtons(Qt::NoButton)); + ++numMouseMoveEvents; + } + void reset() { numEnterEvents = numMouseMoveEvents = 0; } + int numEnterEvents, numMouseMoveEvents; + }; + + QCursor::setPos(QPoint(0,0)); + + SELParent parent; + parent.resize(200, 200); + SELChild child(&parent); + child.resize(200, 200); + parent.show(); + #ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&parent); + #endif + QTest::qWait(150); + + QCursor::setPos(child.mapToGlobal(QPoint(100, 100))); + // Make sure the cursor has entered the child. + QTRY_VERIFY(child.numEnterEvents > 0); + + child.hide(); + child.reset(); + child.show(); + + // Make sure the child gets enter event and no mouse move event. + QTRY_COMPARE(child.numEnterEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 0); + + child.hide(); + child.reset(); + child.setMouseTracking(true); + child.show(); + + // Make sure the child gets enter event and mouse move event. + // Note that we verify event->button() and event->buttons() + // in SELChild::mouseMoveEvent(). + QTRY_COMPARE(child.numEnterEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 1); + + // Sending synthetic enter/leave trough the parent's mousePressEvent handler. + parent.child = &child; + + child.hide(); + child.reset(); + QTest::mouseClick(&parent, Qt::LeftButton); + + // Make sure the child gets enter event and one mouse move event. + QTRY_COMPARE(child.numEnterEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 1); + + child.hide(); + child.reset(); + child.setMouseTracking(false); + QTest::mouseClick(&parent, Qt::LeftButton); + + // Make sure the child gets enter event and no mouse move event. + QTRY_COMPARE(child.numEnterEvents, 1); + QCOMPARE(child.numMouseMoveEvents, 0); + } +#endif + +void tst_QWidget::windowFlags() +{ + QWidget w; + w.setWindowFlags(w.windowFlags() | Qt::FramelessWindowHint); + QVERIFY(w.windowFlags() & Qt::FramelessWindowHint); +} + +void tst_QWidget::initialPosForDontShowOnScreenWidgets() +{ + { // Check default position. + const QPoint expectedPos(0, 0); + QWidget widget; + widget.setAttribute(Qt::WA_DontShowOnScreen); + widget.winId(); // Make sure create_sys is called. + QCOMPARE(widget.pos(), expectedPos); + QCOMPARE(widget.geometry().topLeft(), expectedPos); + } + + { // Explicitly move to a position. + const QPoint expectedPos(100, 100); + QWidget widget; + widget.setAttribute(Qt::WA_DontShowOnScreen); + widget.move(expectedPos); + widget.winId(); // Make sure create_sys is called. + QCOMPARE(widget.pos(), expectedPos); + QCOMPARE(widget.geometry().topLeft(), expectedPos); + } +} + +#ifdef Q_WS_X11 +void tst_QWidget::paintOutsidePaintEvent() +{ + QWidget widget; + widget.resize(200, 200); + + QWidget child1(&widget); + child1.resize(100, 100); + child1.setPalette(Qt::red); + child1.setAutoFillBackground(true); + + QWidget child2(&widget); + child2.setGeometry(50, 50, 100, 100); + child2.setPalette(Qt::blue); + child2.setAutoFillBackground(true); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + QTest::qWait(60); + + const QPixmap before = QPixmap::grabWindow(widget.winId()); + + // Child 1 should be clipped by child 2, so nothing should change. + child1.setAttribute(Qt::WA_PaintOutsidePaintEvent); + QPainter painter(&child1); + painter.fillRect(child1.rect(), Qt::red); + painter.end(); + XSync(QX11Info::display(), false); // Flush output buffer. + QTest::qWait(60); + + const QPixmap after = QPixmap::grabWindow(widget.winId()); + + QCOMPARE(before, after); +} +#endif + +class MyEvilObject : public QObject +{ + Q_OBJECT +public: + MyEvilObject(QWidget *widgetToCrash) : QObject(), widget(widgetToCrash) + { + connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(beEvil(QObject *))); + delete widget; + } + QWidget *widget; + +private slots: + void beEvil(QObject *) { widget->update(0, 0, 150, 150); } +}; + +void tst_QWidget::updateOnDestroyedSignal() +{ + QWidget widget; + + QWidget *child = new QWidget(&widget); + child->resize(100, 100); + child->setAutoFillBackground(true); + child->setPalette(Qt::red); + + widget.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&widget); +#endif + QTest::qWait(200); + + // Please do not crash. + MyEvilObject evil(child); + QTest::qWait(200); +} + +void tst_QWidget::toplevelLineEditFocus() +{ + testWidget->hide(); + + QLineEdit w; + w.show(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(20); + + QTRY_COMPARE(QApplication::activeWindow(), (QWidget*)&w); + QTRY_COMPARE(QApplication::focusWidget(), (QWidget*)&w); +} + +void tst_QWidget::focusWidget_task254563() +{ + //having different visibility for widget is important + QWidget top; + top.show(); + QWidget container(&top); + QWidget *widget = new QWidget(&container); + widget->show(); + + widget->setFocus(); //set focus (will set the focus widget up to the toplevel to be 'widget') + container.setFocus(); + delete widget; // will call clearFocus but that doesn't help + QVERIFY(top.focusWidget() != widget); //dangling pointer +} + +// This test case relies on developer build (AUTOTEST_EXPORT). +#ifdef QT_BUILD_INTERNAL +void tst_QWidget::destroyBackingStore() +{ + UpdateWidget w; + w.reset(); + w.show(); + + QTest::qWaitForWindowShown(&w); + QApplication::processEvents(); + QTRY_VERIFY(w.numPaintEvents > 0); + w.reset(); + w.update(); + qt_widget_private(&w)->topData()->backingStoreTracker.create(&w); + + w.update(); + QApplication::processEvents(); +#ifdef Q_WS_QWS + QApplication::processEvents(); +#endif + QCOMPARE(w.numPaintEvents, 1); + + // Check one more time, because the second time around does more caching. + w.update(); + QApplication::processEvents(); + QCOMPARE(w.numPaintEvents, 2); +} +#endif + +// Helper function +QWidgetBackingStore* backingStore(QWidget &widget) +{ + QWidgetBackingStore *backingStore = 0; +#ifdef QT_BUILD_INTERNAL + if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData()) + backingStore = topExtra->backingStoreTracker.data(); +#endif + return backingStore; +} + +// Tables of 5000 elements do not make sense on Windows Mobile. +#ifndef Q_OS_WINCE_WM +void tst_QWidget::rectOutsideCoordinatesLimit_task144779() +{ + QApplication::setOverrideCursor(Qt::BlankCursor); //keep the cursor out of screen grabs + QWidget main(0,Qt::FramelessWindowHint); //don't get confused by the size of the window frame + QPalette palette; + palette.setColor(QPalette::Window, Qt::red); + main.setPalette(palette); + + QDesktopWidget desktop; + QRect desktopDimensions = desktop.availableGeometry(&main); + QSize mainSize(400, 400); + mainSize = mainSize.boundedTo(desktopDimensions.size()); + main.resize(mainSize); + + QWidget *offsetWidget = new QWidget(&main); + offsetWidget->setGeometry(0, -(15000 - mainSize.height()), mainSize.width(), 15000); + + // big widget is too big for the coordinates, it must be limited by wrect + // if wrect is not at the right position because of offsetWidget, bigwidget + // is not painted correctly + QWidget *bigWidget = new QWidget(offsetWidget); + bigWidget->setGeometry(0, 0, mainSize.width(), 50000); + palette.setColor(QPalette::Window, Qt::green); + bigWidget->setPalette(palette); + bigWidget->setAutoFillBackground(true); + + main.show(); + QTest::qWaitForWindowShown(&main); + + QPixmap correct(main.size()); + correct.fill(Qt::green); + + QTRY_COMPARE(QPixmap::grabWindow(main.winId()).toImage().convertToFormat(QImage::Format_RGB32), + correct.toImage().convertToFormat(QImage::Format_RGB32)); + QApplication::restoreOverrideCursor(); +} +#endif + +void tst_QWidget::inputFocus_task257832() +{ + QLineEdit *widget = new QLineEdit; + QInputContext *context = widget->inputContext(); + if (!context) + QSKIP("No input context", SkipSingle); + widget->setFocus(); + widget->winId(); // make sure, widget has been created + context->setFocusWidget(widget); + QCOMPARE(context->focusWidget(), static_cast(widget)); + widget->setReadOnly(true); + QVERIFY(!context->focusWidget()); + delete widget; +} + +void tst_QWidget::setGraphicsEffect() +{ + // Check that we don't have any effect by default. + QWidget *widget = new QWidget; + QVERIFY(!widget->graphicsEffect()); + + // SetGet check. + QPointer blurEffect = new QGraphicsBlurEffect; + widget->setGraphicsEffect(blurEffect); + QCOMPARE(widget->graphicsEffect(), static_cast(blurEffect)); + + // Ensure the existing effect is deleted when setting a new one. + QPointer shadowEffect = new QGraphicsDropShadowEffect; + widget->setGraphicsEffect(shadowEffect); + QVERIFY(!blurEffect); + QCOMPARE(widget->graphicsEffect(), static_cast(shadowEffect)); + blurEffect = new QGraphicsBlurEffect; + + // Ensure the effect is uninstalled when setting it on a new target. + QWidget *anotherWidget = new QWidget; + anotherWidget->setGraphicsEffect(blurEffect); + widget->setGraphicsEffect(blurEffect); + QVERIFY(!anotherWidget->graphicsEffect()); + QVERIFY(!shadowEffect); + + // Ensure the existing effect is deleted when deleting the widget. + delete widget; + QVERIFY(!blurEffect); + delete anotherWidget; + + // Ensure the effect is uninstalled when deleting it + widget = new QWidget; + blurEffect = new QGraphicsBlurEffect; + widget->setGraphicsEffect(blurEffect); + delete blurEffect; + QVERIFY(!widget->graphicsEffect()); + + // Ensure the existing effect is uninstalled and deleted when setting a null effect + blurEffect = new QGraphicsBlurEffect; + widget->setGraphicsEffect(blurEffect); + widget->setGraphicsEffect(0); + QVERIFY(!widget->graphicsEffect()); + QVERIFY(!blurEffect); + + delete widget; +} + +void tst_QWidget::activateWindow() +{ + // Test case for task 260685 + + // Create first mainwindow and set it active + QMainWindow* mainwindow = new QMainWindow(); + QLabel* label = new QLabel(mainwindow); + mainwindow->setCentralWidget(label); + mainwindow->setVisible(true); + mainwindow->activateWindow(); + QTest::qWaitForWindowShown(mainwindow); + qApp->processEvents(); + + QTRY_VERIFY(mainwindow->isActiveWindow()); + + // Create second mainwindow and set it active + QMainWindow* mainwindow2 = new QMainWindow(); + QLabel* label2 = new QLabel(mainwindow2); + mainwindow2->setCentralWidget(label2); + mainwindow2->setVisible(true); + mainwindow2->activateWindow(); + qApp->processEvents(); + + QTRY_VERIFY(!mainwindow->isActiveWindow()); + QTRY_VERIFY(mainwindow2->isActiveWindow()); + + // Revert first mainwindow back to visible active + mainwindow->setVisible(true); + mainwindow->activateWindow(); + qApp->processEvents(); + + QTRY_VERIFY(mainwindow->isActiveWindow()); + QTRY_VERIFY(!mainwindow2->isActiveWindow()); +} + +void tst_QWidget::openModal_taskQTBUG_5804() +{ + class Widget : public QWidget + { + public: + Widget(QWidget *parent) : QWidget(parent) + { + } + ~Widget() + { + QMessageBox msgbox; + QTimer::singleShot(10, &msgbox, SLOT(accept())); + msgbox.exec(); //open a modal dialog + } + }; + + QWidget *win = new QWidget; + new Widget(win); + win->show(); + QTest::qWaitForWindowShown(win); + delete win; +} + +class InputContextTester : public QInputContext +{ + Q_OBJECT +public: + QString identifierName() { return QString(); } + bool isComposing() const { return false; } + QString language() { return QString(); } + void reset() { ++resets; } + int resets; +}; + +void tst_QWidget::focusProxyAndInputMethods() +{ + InputContextTester *inputContext = new InputContextTester; + QWidget *toplevel = new QWidget(0, Qt::X11BypassWindowManagerHint); + toplevel->setAttribute(Qt::WA_InputMethodEnabled, true); + qApp->setInputContext(inputContext); // ownership is transferred + + QWidget *child = new QWidget(toplevel); + child->setFocusProxy(toplevel); + child->setAttribute(Qt::WA_InputMethodEnabled, true); + + toplevel->setFocusPolicy(Qt::WheelFocus); + child->setFocusPolicy(Qt::WheelFocus); + + QVERIFY(!child->hasFocus()); + QVERIFY(!toplevel->hasFocus()); + + toplevel->show(); + QTest::qWaitForWindowShown(toplevel); + QApplication::setActiveWindow(toplevel); + QVERIFY(toplevel->hasFocus()); + QVERIFY(child->hasFocus()); + + // verify that toggling input methods on the child widget + // correctly propagate to the focus proxy's input method + // and that the input method gets the focus proxy passed + // as the focus widget instead of the child widget. + // otherwise input method queries go to the wrong widget + + QCOMPARE(inputContext->focusWidget(), toplevel); + + child->setAttribute(Qt::WA_InputMethodEnabled, false); + QVERIFY(!inputContext->focusWidget()); + + child->setAttribute(Qt::WA_InputMethodEnabled, true); + QCOMPARE(inputContext->focusWidget(), toplevel); + + child->setEnabled(false); + QVERIFY(!inputContext->focusWidget()); + + child->setEnabled(true); + QCOMPARE(inputContext->focusWidget(), toplevel); + + delete toplevel; +} + +#ifdef QT_BUILD_INTERNAL +class scrollWidgetWBS : public QWidget +{ +public: + void deleteBackingStore() + { + static_cast(d_ptr.data())->topData()->backingStoreTracker.destroy(); + } + void enableBackingStore() + { + if (!static_cast(d_ptr.data())->maybeBackingStore()) { + static_cast(d_ptr.data())->topData()->backingStoreTracker.create(this); + static_cast(d_ptr.data())->invalidateBuffer(this->rect()); + repaint(); + } + } +}; +#endif + +// Test case relies on developer build (AUTOTEST_EXPORT). +#ifdef QT_BUILD_INTERNAL +void tst_QWidget::scrollWithoutBackingStore() +{ + scrollWidgetWBS scrollable; + scrollable.resize(100,100); + QLabel child(QString("@"),&scrollable); + child.resize(50,50); + scrollable.show(); + QTest::qWaitForWindowShown(&scrollable); + scrollable.scroll(50,50); + QCOMPARE(child.pos(),QPoint(50,50)); + scrollable.deleteBackingStore(); + scrollable.scroll(-25,-25); + QCOMPARE(child.pos(),QPoint(25,25)); + scrollable.enableBackingStore(); + QCOMPARE(child.pos(),QPoint(25,25)); +} +#endif + +void tst_QWidget::taskQTBUG_7532_tabOrderWithFocusProxy() +{ + QWidget w; + w.setFocusPolicy(Qt::TabFocus); + QWidget *fp = new QWidget(&w); + fp->setFocusPolicy(Qt::TabFocus); + w.setFocusProxy(fp); + QWidget::setTabOrder(&w, fp); + + // In debug mode, no assertion failure means it's alright. +} + +void tst_QWidget::movedAndResizedAttributes() +{ +#if defined (Q_OS_MAC) || defined(Q_WS_QWS) + QEXPECT_FAIL("", "FixMe, QTBUG-8941 and QTBUG-8977", Abort); + QVERIFY(false); +#else + QWidget w; + w.show(); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setWindowState(Qt::WindowFullScreen); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setWindowState(Qt::WindowMaximized); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.setWindowState(Qt::WindowMinimized); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.showNormal(); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.showMaximized(); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.showFullScreen(); + + QVERIFY(!w.testAttribute(Qt::WA_Moved)); + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.showNormal(); + w.move(10,10); + QVERIFY(w.testAttribute(Qt::WA_Moved)); +#if defined(Q_OS_WIN) + QEXPECT_FAIL("", "FixMe, QTBUG-8911", Abort); +#endif + QVERIFY(!w.testAttribute(Qt::WA_Resized)); + + w.resize(100, 100); + QVERIFY(w.testAttribute(Qt::WA_Moved)); + QVERIFY(w.testAttribute(Qt::WA_Resized)); +#endif +} + +void tst_QWidget::childAt() +{ + QWidget parent(0, Qt::FramelessWindowHint); + parent.resize(200, 200); + + QWidget *child = new QWidget(&parent); + child->setPalette(Qt::red); + child->setAutoFillBackground(true); + child->setGeometry(20, 20, 160, 160); + + QWidget *grandChild = new QWidget(child); + grandChild->setPalette(Qt::blue); + grandChild->setAutoFillBackground(true); + grandChild->setGeometry(-20, -20, 220, 220); + + QVERIFY(!parent.childAt(19, 19)); + QVERIFY(!parent.childAt(180, 180)); + QCOMPARE(parent.childAt(20, 20), grandChild); + QCOMPARE(parent.childAt(179, 179), grandChild); + + grandChild->setAttribute(Qt::WA_TransparentForMouseEvents); + QCOMPARE(parent.childAt(20, 20), child); + QCOMPARE(parent.childAt(179, 179), child); + grandChild->setAttribute(Qt::WA_TransparentForMouseEvents, false); + + child->setMask(QRect(50, 50, 60, 60)); + + QVERIFY(!parent.childAt(69, 69)); + QVERIFY(!parent.childAt(130, 130)); + QCOMPARE(parent.childAt(70, 70), grandChild); + QCOMPARE(parent.childAt(129, 129), grandChild); + + child->setAttribute(Qt::WA_MouseNoMask); + QCOMPARE(parent.childAt(69, 69), grandChild); + QCOMPARE(parent.childAt(130, 130), grandChild); + child->setAttribute(Qt::WA_MouseNoMask, false); + + grandChild->setAttribute(Qt::WA_TransparentForMouseEvents); + QCOMPARE(parent.childAt(70, 70), child); + QCOMPARE(parent.childAt(129, 129), child); + grandChild->setAttribute(Qt::WA_TransparentForMouseEvents, false); + + grandChild->setMask(QRect(80, 80, 40, 40)); + + QCOMPARE(parent.childAt(79, 79), child); + QCOMPARE(parent.childAt(120, 120), child); + QCOMPARE(parent.childAt(80, 80), grandChild); + QCOMPARE(parent.childAt(119, 119), grandChild); + + grandChild->setAttribute(Qt::WA_MouseNoMask); + + QCOMPARE(parent.childAt(79, 79), grandChild); + QCOMPARE(parent.childAt(120, 120), grandChild); +} + +#ifdef Q_WS_MAC +void tst_QWidget::childAt_unifiedToolBar() +{ + QLabel *label = new QLabel(QLatin1String("foo")); + QToolBar *toolBar = new QToolBar; + toolBar->addWidget(new QLabel("dummy")); + toolBar->addWidget(label); + + QMainWindow mainWindow; + mainWindow.addToolBar(toolBar); + mainWindow.show(); + + // Calculate the top-left corner of the tool bar and the label (in mainWindow's coordinates). + QPoint labelTopLeft = label->mapTo(&mainWindow, QPoint()); + QPoint toolBarTopLeft = toolBar->mapTo(&mainWindow, QPoint()); + + QCOMPARE(mainWindow.childAt(toolBarTopLeft), static_cast(toolBar)); + QCOMPARE(mainWindow.childAt(labelTopLeft), static_cast(label)); + + // Enable unified tool bars. + mainWindow.setUnifiedTitleAndToolBarOnMac(true); + QTest::qWait(50); + + // The tool bar is now in the "non-client" area of QMainWindow, i.e. + // outside the mainWindow's rect(), and since mapTo et al. doesn't work + // in that case (see commit 35667fd45ada49269a5987c235fdedfc43e92bb8), + // we use mapToGlobal/mapFromGlobal to re-calculate the corners. + QPoint oldToolBarTopLeft = toolBarTopLeft; + toolBarTopLeft = mainWindow.mapFromGlobal(toolBar->mapToGlobal(QPoint())); + QVERIFY(toolBarTopLeft != oldToolBarTopLeft); + QVERIFY(toolBarTopLeft.y() < 0); + labelTopLeft = mainWindow.mapFromGlobal(label->mapToGlobal(QPoint())); + + QCOMPARE(mainWindow.childAt(toolBarTopLeft), static_cast(toolBar)); + QCOMPARE(mainWindow.childAt(labelTopLeft), static_cast(label)); +} + +void tst_QWidget::taskQTBUG_11373() +{ + QMainWindow * myWindow = new QMainWindow(); + QWidget * center = new QWidget(); + myWindow -> setCentralWidget(center); + QWidget * drawer = new QWidget(myWindow, Qt::Drawer); + drawer -> hide(); + QCOMPARE(drawer->isVisible(), false); + myWindow -> show(); + myWindow -> raise(); + // The drawer shouldn't be visible now. + QCOMPARE(drawer->isVisible(), false); + myWindow -> setWindowState(Qt::WindowFullScreen); + myWindow -> setWindowState(Qt::WindowNoState); + // The drawer should still not be visible, since we haven't shown it. + QCOMPARE(drawer->isVisible(), false); +} +#endif + +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. +} + +void tst_QWidget::nativeChildFocus() +{ + QWidget w; + QLayout *layout = new QVBoxLayout; + w.setLayout(layout); + QLineEdit *p1 = new QLineEdit; + QLineEdit *p2 = new QLineEdit; + layout->addWidget(p1); + layout->addWidget(p2); +#if 1 + p1->setObjectName("p1"); + p2->setObjectName("p2"); +#endif + w.show(); +#if 1 + w.activateWindow(); + p1->setFocus(); + p1->setAttribute(Qt::WA_NativeWindow); + p2->setAttribute(Qt::WA_NativeWindow); + QApplication::processEvents(); + QTest::qWaitForWindowShown(&w); + QTest::qWait(10); + + qDebug() << "checking active window:" << QApplication::activeWindow(); + QCOMPARE(QApplication::activeWindow(), &w); + QCOMPARE(QApplication::focusWidget(), static_cast(p1)); +#endif + + QTest::qWait(1000); +} + +QTEST_MAIN(tst_QWidget) +#include "tst_qwidget.moc" diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h new file mode 100644 index 0000000000..d7bc3f33c7 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include + +#pragma once // Yeah, it's deprecated in general, but it's standard practive for Mac OS X. + +QString nativeWindowTitle(QWidget *widget, Qt::WindowState state); +bool nativeWindowModified(QWidget *widget); + +typedef QPair WidgetViewPair; +bool testAndRelease(const WId); +WidgetViewPair createAndRetain(QWidget * const parent = 0); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm new file mode 100644 index 0000000000..10e137c06c --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget_mac_helpers.mm @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_qwidget_mac_helpers.h" +#include +#include + + +QString nativeWindowTitle(QWidget *window, Qt::WindowState state) +{ + OSWindowRef windowRef = qt_mac_window_for(window); + QCFString macTitle; + if (state == Qt::WindowMinimized) { + macTitle = reinterpret_cast([[windowRef miniwindowTitle] retain]); + } else { + macTitle = reinterpret_cast([[windowRef title] retain]); + } + return macTitle; +} + +bool nativeWindowModified(QWidget *widget) +{ + return [qt_mac_window_for(widget) isDocumentEdited]; +} + +bool testAndRelease(const WId view) +{ + if ([id(view) retainCount] != 2) + return false; + [id(view) release]; + [id(view) release]; + return true; +} + +WidgetViewPair createAndRetain(QWidget * const parent) +{ + QWidget * const widget = new QWidget(parent); + const WId view = widget->winId(); + // Retain twice so we can safely call retainCount even if the retain count + // is off by one because of a double release. + [id(view) retain]; + [id(view) retain]; + return qMakePair(widget, view); +} + diff --git a/tests/auto/widgets/kernel/qwidget_window/.gitignore b/tests/auto/widgets/kernel/qwidget_window/.gitignore new file mode 100644 index 0000000000..7f0bd8d631 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget_window/.gitignore @@ -0,0 +1 @@ +tst_qwidget_window diff --git a/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro new file mode 100644 index 0000000000..dd5837012c --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qwidget_window.cpp + +x11 { + LIBS += $$QMAKE_LIBS_X11 +} + diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp new file mode 100644 index 0000000000..eb8b555bd6 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include + +#include + +#ifdef Q_WS_X11 +#include +#include +#endif // Q_WS_X11 + +class tst_QWidget_window : public QWidget +{ + Q_OBJECT + +public: + tst_QWidget_window(){}; + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void tst_move_show(); + void tst_show_move(); + void tst_show_move_hide_show(); + + void tst_resize_show(); + void tst_show_resize(); + void tst_show_resize_hide_show(); + + void tst_windowFilePathAndwindowTitle_data(); + void tst_windowFilePathAndwindowTitle(); + void tst_windowFilePath_data(); + void tst_windowFilePath(); + +#ifdef Q_WS_X11 + void tst_showWithoutActivating(); +#endif + void tst_paintEventOnSecondShow(); +}; + +void tst_QWidget_window::initTestCase() +{ +} + +void tst_QWidget_window::cleanupTestCase() +{ +} + +void tst_QWidget_window::tst_move_show() +{ + QWidget w; + w.move(100, 100); + w.show(); + QCOMPARE(w.pos(), QPoint(100, 100)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 3000); +} + +void tst_QWidget_window::tst_show_move() +{ + QWidget w; + w.show(); + w.move(100, 100); + QCOMPARE(w.pos(), QPoint(100, 100)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); +} + +void tst_QWidget_window::tst_show_move_hide_show() +{ + QWidget w; + w.show(); + w.move(100, 100); + w.hide(); + w.show(); + QCOMPARE(w.pos(), QPoint(100, 100)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); +} + +void tst_QWidget_window::tst_resize_show() +{ + QWidget w; + w.resize(200, 200); + w.show(); + QCOMPARE(w.size(), QSize(200, 200)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); +} + +void tst_QWidget_window::tst_show_resize() +{ + QWidget w; + w.show(); + w.resize(200, 200); + QCOMPARE(w.size(), QSize(200, 200)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); +} + +void tst_QWidget_window::tst_show_resize_hide_show() +{ + QWidget w; + w.show(); + w.resize(200, 200); + w.hide(); + w.show(); + QCOMPARE(w.size(), QSize(200, 200)); +// QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); +} + +class TestWidget : public QWidget +{ +public: + int m_first, m_next; + bool paintEventReceived; + + void reset(){ m_first = m_next = 0; paintEventReceived = false; } + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::WindowActivate: + case QEvent::WindowDeactivate: + case QEvent::Hide: + case QEvent::Show: + if (m_first) + m_next = event->type(); + else + m_first = event->type(); + break; + case QEvent::Paint: + paintEventReceived = true; + break; + default: + break; + } + return QWidget::event(event); + } +}; + +void tst_QWidget_window::tst_windowFilePathAndwindowTitle_data() +{ + QTest::addColumn("setWindowTitleBefore"); + QTest::addColumn("setWindowTitleAfter"); + QTest::addColumn("filePath"); + QTest::addColumn("applicationName"); + QTest::addColumn("indyWindowTitle"); + QTest::addColumn("finalTitleBefore"); + QTest::addColumn("finalTitleAfter"); + + QString validPath = QApplication::applicationFilePath(); + QString appName = QLatin1String("Killer App"); + QString fileNameOnly = QFileInfo(validPath).fileName() + QLatin1String("[*]"); + QString fileAndApp = fileNameOnly + QLatin1String(" ") + QChar(0x2014) + QLatin1String(" ") + appName; + QString windowTitle = QLatin1String("Here is a Window Title"); + + QTest::newRow("never Set Title nor AppName") << false << false << validPath << QString() << windowTitle << fileNameOnly << fileNameOnly; + QTest::newRow("set title after only, but no AppName") << false << true << validPath << QString() << windowTitle << fileNameOnly << windowTitle; + QTest::newRow("set title before only, not AppName") << true << false << validPath << QString() << windowTitle << windowTitle << windowTitle; + QTest::newRow("always set title, not appName") << true << true << validPath << QString() << windowTitle << windowTitle << windowTitle; + + QString platString = +#ifdef Q_WS_MAC + fileNameOnly; +#else + fileAndApp; +#endif + + QTest::newRow("never Set Title, yes AppName") << false << false << validPath << appName << windowTitle << platString << platString; + QTest::newRow("set title after only, yes AppName") << false << true << validPath << appName << windowTitle << platString << windowTitle; + QTest::newRow("set title before only, yes AppName") << true << false << validPath << appName << windowTitle << windowTitle << windowTitle; + QTest::newRow("always set title, yes appName") << true << true << validPath << appName << windowTitle << windowTitle << windowTitle; +} + +void tst_QWidget_window::tst_windowFilePathAndwindowTitle() +{ + QFETCH(bool, setWindowTitleBefore); + QFETCH(bool, setWindowTitleAfter); + QFETCH(QString, filePath); + QFETCH(QString, applicationName); + QFETCH(QString, indyWindowTitle); + QFETCH(QString, finalTitleBefore); + QFETCH(QString, finalTitleAfter); + + + QWidget widget; + QCOMPARE(widget.windowFilePath(), QString()); + + if (!applicationName.isEmpty()) + qApp->setApplicationName(applicationName); + else + qApp->setApplicationName(QString()); + + if (setWindowTitleBefore) { + widget.setWindowTitle(indyWindowTitle); + } + widget.setWindowFilePath(filePath); + QCOMPARE(finalTitleBefore, widget.windowTitle()); + QCOMPARE(widget.windowFilePath(), filePath); + + if (setWindowTitleAfter) { + widget.setWindowTitle(indyWindowTitle); + } + QCOMPARE(finalTitleAfter, widget.windowTitle()); + QCOMPARE(widget.windowFilePath(), filePath); +} + +void tst_QWidget_window::tst_windowFilePath_data() +{ + QTest::addColumn("filePath"); + QTest::addColumn("result"); + QTest::addColumn("again"); + QTest::addColumn("filePath2"); + QTest::addColumn("result2"); + + QString validPath = QApplication::applicationFilePath(); + QString invalidPath = QLatin1String("::**Never a Real Path**::"); + + QTest::newRow("never Set Path") << QString() << QString() << false << QString() << QString(); + QTest::newRow("never EVER Set Path") << QString() << QString() << true << QString() << QString(); + QTest::newRow("Valid Path") << validPath << validPath << false << QString() << QString(); + QTest::newRow("invalid Path") << invalidPath << invalidPath << false << QString() << QString(); + QTest::newRow("Valid Path then empty") << validPath << validPath << true << QString() << QString(); + QTest::newRow("invalid Path then empty") << invalidPath << invalidPath << true << QString() << QString(); + QTest::newRow("invalid Path then valid") << invalidPath << invalidPath << true << validPath << validPath; + QTest::newRow("valid Path then invalid") << validPath << validPath << true << invalidPath << invalidPath; +} + +void tst_QWidget_window::tst_windowFilePath() +{ + QFETCH(QString, filePath); + QFETCH(QString, result); + QFETCH(bool, again); + QFETCH(QString, filePath2); + QFETCH(QString, result2); + + QWidget widget; + QCOMPARE(widget.windowFilePath(), QString()); + widget.setWindowFilePath(filePath); + QCOMPARE(widget.windowFilePath(), result); + if (again) { + widget.setWindowFilePath(filePath2); + QCOMPARE(widget.windowFilePath(), result2); + } +} + +#ifdef Q_WS_X11 +void tst_QWidget_window::tst_showWithoutActivating() +{ + QWidget w; + w.show(); + QTest::qWaitForWindowShown(&w); + QApplication::processEvents(); + + QApplication::clipboard(); + QLineEdit *lineEdit = new QLineEdit; + lineEdit->setAttribute(Qt::WA_ShowWithoutActivating, true); + lineEdit->show(); + lineEdit->setAttribute(Qt::WA_ShowWithoutActivating, false); + lineEdit->raise(); + lineEdit->activateWindow(); + + Window window; + int revertto; + QTRY_COMPARE(lineEdit->winId(), + (XGetInputFocus(QX11Info::display(), &window, &revertto), window) ); + // Note the use of the , before window because we want the XGetInputFocus to be re-executed + // in each iteration of the inside loop of the QTRY_COMPARE macro +} +#endif + +void tst_QWidget_window::tst_paintEventOnSecondShow() +{ + TestWidget w; + w.show(); + w.hide(); + + w.reset(); + w.show(); + QTest::qWaitForWindowShown(&w); + QApplication::processEvents(); + QTRY_VERIFY(w.paintEventReceived); +} + +QTEST_MAIN(tst_QWidget_window) +#include "tst_qwidget_window.moc" diff --git a/tests/auto/widgets/kernel/qwidgetaction/.gitignore b/tests/auto/widgets/kernel/qwidgetaction/.gitignore new file mode 100644 index 0000000000..56d519d851 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidgetaction/.gitignore @@ -0,0 +1 @@ +tst_qwidgetaction diff --git a/tests/auto/widgets/kernel/qwidgetaction/qwidgetaction.pro b/tests/auto/widgets/kernel/qwidgetaction/qwidgetaction.pro new file mode 100644 index 0000000000..3e037c2efb --- /dev/null +++ b/tests/auto/widgets/kernel/qwidgetaction/qwidgetaction.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qwidgetaction.cpp + + diff --git a/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp b/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp new file mode 100644 index 0000000000..5f51f6d316 --- /dev/null +++ b/tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QWidgetAction : public QObject +{ + Q_OBJECT +private slots: + void defaultWidget(); + void visibilityUpdate(); + void customWidget(); + void keepOwnership(); + void visibility(); + void setEnabled(); + void popup(); + void releaseWidgetCrash(); +}; + +void tst_QWidgetAction::defaultWidget() +{ + { + QToolBar tb1; + + QPointer combo = new QComboBox(&tb1); + + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + QVERIFY(!combo->isVisible()); + QVERIFY(!combo->parent()); + QVERIFY(action->isVisible()); + + delete action; + QVERIFY(!combo); + } + { + QToolBar tb1; + + QPointer combo = new QComboBox(&tb1); + combo->hide(); + + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + // explicitly hidden widgets should also set the action invisible + QVERIFY(!action->isVisible()); + + delete action; + } + { + QPointer combo = new QComboBox(0); + combo->show(); + + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + QVERIFY(action->isVisible()); + QVERIFY(!combo->isVisible()); + + delete action; + } + { + QToolBar tb1; + tb1.show(); + QToolBar tb2; + tb2.show(); + + QPointer combo = new QComboBox(0); + + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + tb1.addAction(action); + QVERIFY(combo->parent() == &tb1); + qApp->processEvents(); + qApp->processEvents(); + QVERIFY(combo->isVisible()); + + // not supported, not supposed to work, hence the parent() check + tb2.addAction(action); + QVERIFY(combo->parent() == &tb1); + + tb2.removeAction(action); + tb1.removeAction(action); + + qApp->processEvents(); //the call to hide is delayd by the toolbar layout + QVERIFY(!combo->isVisible()); + + tb2.addAction(action); + qApp->processEvents(); //the call to hide is delayd by the toolbar layout + qApp->processEvents(); + QVERIFY(combo->parent() == &tb2); + QVERIFY(combo->isVisible()); + + tb1.addAction(action); + QVERIFY(combo->parent() == &tb2); + + delete action; + QVERIFY(!combo); + } + { + QWidgetAction *a = new QWidgetAction(0); + QVERIFY(!a->defaultWidget()); + + QPointer combo1 = new QComboBox; + a->setDefaultWidget(combo1); + QVERIFY(a->defaultWidget() == combo1); + a->setDefaultWidget(combo1); + QVERIFY(combo1); + QVERIFY(a->defaultWidget() == combo1); + + QPointer combo2 = new QComboBox; + QVERIFY(combo1 != combo2); + + a->setDefaultWidget(combo2); + QVERIFY(!combo1); + QVERIFY(a->defaultWidget() == combo2); + + delete a; + QVERIFY(!combo2); + } +} + +void tst_QWidgetAction::visibilityUpdate() +{ + // actually keeping the widget's state in sync with the + // action in terms of visibility is QToolBar's responsibility. + QToolBar tb; + tb.show(); + + QComboBox *combo = new QComboBox(0); + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + tb.addAction(action); + //the call to show is delayed by the toolbar layout + QTRY_VERIFY(combo->isVisible()); + QVERIFY(action->isVisible()); + + action->setVisible(false); + //the call to hide is delayed by the toolbar layout + QTRY_VERIFY(!combo->isVisible()); + + delete action; + // action also deletes combo +} + +class ComboAction : public QWidgetAction +{ +public: + inline ComboAction(QObject *parent) : QWidgetAction(parent) {} + + QList createdWidgets() const { return QWidgetAction::createdWidgets(); } + +protected: + virtual QWidget *createWidget(QWidget *parent); +}; + +QWidget *ComboAction::createWidget(QWidget *parent) +{ + return new QComboBox(parent); +} + +void tst_QWidgetAction::customWidget() +{ + QToolBar tb1; + tb1.show(); + QToolBar tb2; + tb2.show(); + + ComboAction *action = new ComboAction(0); + + tb1.addAction(action); + + QList combos = action->createdWidgets(); + QCOMPARE(combos.count(), 1); + + QPointer combo1 = qobject_cast(combos.at(0)); + QVERIFY(combo1); + + tb2.addAction(action); + + combos = action->createdWidgets(); + QCOMPARE(combos.count(), 2); + + QVERIFY(combos.at(0) == combo1); + QPointer combo2 = qobject_cast(combos.at(1)); + QVERIFY(combo2); + + tb2.removeAction(action); + QVERIFY(combo2); + // widget is deleted using deleteLater(), so process that posted event + QCoreApplication::sendPostedEvents(combo2, QEvent::DeferredDelete); + QVERIFY(!combo2); + + delete action; + QVERIFY(!combo1); + QVERIFY(!combo2); +} + +void tst_QWidgetAction::keepOwnership() +{ + QPointer combo = new QComboBox; + QWidgetAction *action = new QWidgetAction(0); + action->setDefaultWidget(combo); + + { + QToolBar *tb = new QToolBar; + tb->addAction(action); + QVERIFY(combo->parent() == tb); + delete tb; + } + + QVERIFY(combo); + delete action; + QVERIFY(!combo); +} + +void tst_QWidgetAction::visibility() +{ + { + QWidgetAction *a = new QWidgetAction(0); + QComboBox *combo = new QComboBox; + a->setDefaultWidget(combo); + + QToolBar *tb = new QToolBar; + tb->addAction(a); + QVERIFY(!combo->isVisible()); + tb->show(); + QVERIFY(combo->isVisible()); + + delete tb; + + delete a; + } + { + QWidgetAction *a = new QWidgetAction(0); + QComboBox *combo = new QComboBox; + a->setDefaultWidget(combo); + + QToolBar *tb = new QToolBar; + tb->addAction(a); + QVERIFY(!combo->isVisible()); + + QToolBar *tb2 = new QToolBar; + tb->removeAction(a); + tb2->addAction(a); + QVERIFY(!combo->isVisible()); + tb2->show(); + QVERIFY(combo->isVisible()); + + delete tb; + delete tb2; + + delete a; + } +} + +void tst_QWidgetAction::setEnabled() +{ + QToolBar toolbar; + QComboBox *combobox = new QComboBox; + QAction *action = toolbar.addWidget(combobox); + toolbar.show(); + + QVERIFY(action->isEnabled()); + QVERIFY(combobox->isEnabled()); + + action->setEnabled(false); + QVERIFY(!action->isEnabled()); + QVERIFY(!combobox->isEnabled()); + + action->setEnabled(true); + QVERIFY(action->isEnabled()); + QVERIFY(combobox->isEnabled()); + + combobox->setEnabled(false); + QVERIFY(!combobox->isEnabled()); + + combobox->setEnabled(true); + QVERIFY(action->isEnabled()); + QVERIFY(combobox->isEnabled()); + + + QWidgetAction aw(0); + aw.setEnabled(false); + QVERIFY(!aw.isEnabled()); + + combobox = new QComboBox; + aw.setDefaultWidget(combobox); + QVERIFY(!aw.isEnabled()); + QVERIFY(!combobox->isEnabled()); + + // Make sure we don't change the default widget's Qt::WA_ForceDisabled attribute + // during a normal disable/enable operation (task 207433). + { + QToolBar toolBar; + QWidget widget; + toolBar.addWidget(&widget); // creates a QWidgetAction and sets 'widget' as the default widget. + QVERIFY(!widget.testAttribute(Qt::WA_ForceDisabled)); + + toolBar.setEnabled(false); + QVERIFY(toolBar.testAttribute(Qt::WA_ForceDisabled)); + QVERIFY(!widget.isEnabled()); + QVERIFY(!widget.testAttribute(Qt::WA_ForceDisabled)); + + toolBar.setEnabled(true); + QVERIFY(widget.isEnabled()); + QVERIFY(!widget.testAttribute(Qt::WA_ForceDisabled)); + } +} + +void tst_QWidgetAction::popup() +{ + QPointer l = new QLabel("test"); + QWidgetAction action(0); + action.setDefaultWidget(l); + + { + QMenu menu; + menu.addAction(&action); + QTimer::singleShot(0, &menu, SLOT(close())); + menu.exec(); + } + + QVERIFY(!l.isNull()); + delete l; +} + +class CrashedAction : public QWidgetAction +{ +public: + inline CrashedAction(QObject *parent) : QWidgetAction(parent) { } + + virtual QWidget *createWidget(QWidget *parent) { + return new QWidget(parent); + } +}; + +void tst_QWidgetAction::releaseWidgetCrash() +{ + // this should not crash! + QMainWindow *w = new QMainWindow; + QAction *a = new CrashedAction(w); + QMenu *menu = w->menuBar()->addMenu("Test"); + menu->addAction("foo"); + menu->addAction(a); + menu->addAction("bar"); + delete w; +} + +QTEST_MAIN(tst_QWidgetAction) +#include "tst_qwidgetaction.moc" -- cgit v1.2.3