qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,28 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qapplication)
add_subdirectory(qboxlayout)
add_subdirectory(qformlayout)
add_subdirectory(qgridlayout)
add_subdirectory(qlayout)
add_subdirectory(qstackedlayout)
add_subdirectory(qtooltip)
add_subdirectory(qwidget_window)
add_subdirectory(qwidgetmetatype)
add_subdirectory(qwidgetrepaintmanager)
add_subdirectory(qwidgetsvariant)
add_subdirectory(qwindowcontainer)
add_subdirectory(qsizepolicy)
if(NOT APPLE)
add_subdirectory(qgesturerecognizer)
endif()
add_subdirectory(qwidget)
if(QT_FEATURE_shortcut)
add_subdirectory(qshortcut)
endif()
if(QT_FEATURE_action)
add_subdirectory(qaction)
add_subdirectory(qactiongroup)
add_subdirectory(qwidgetaction)
endif()

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qaction Test:
#####################################################################
qt_internal_add_test(tst_qaction
SOURCES
tst_qaction.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,478 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QDialog>
#include <QMainWindow>
#include <QTest>
#include <QSignalSpy>
#include <qapplication.h>
#include <qevent.h>
#include <qaction.h>
#include <qactiongroup.h>
#include <qmenu.h>
#include <qmenubar.h>
#include <qtoolbar.h>
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
#include <QtWidgets/private/qapplication_p.h>
class tst_QAction : public QObject
{
Q_OBJECT
public:
tst_QAction();
void updateState(QActionEvent *e);
private slots:
void init();
void cleanup();
void setUnknownFont();
void actionEvent();
#if QT_CONFIG(shortcut)
void alternateShortcuts();
void enabledVisibleInteraction();
#endif
void task229128TriggeredSignalWhenInActiongroup();
#if QT_CONFIG(shortcut)
void repeat();
void keysequence(); // QTBUG-53381
void disableShortcutsWithBlockedWidgets_data();
void disableShortcutsWithBlockedWidgets();
void shortcutFromKeyEvent(); // QTBUG-48325
void disableShortcutInMenuAction_data();
void disableShortcutInMenuAction();
#endif
private:
QEvent::Type m_lastEventType;
const int m_keyboardScheme;
QAction *m_lastAction;
};
tst_QAction::tst_QAction()
: m_keyboardScheme(QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::KeyboardScheme).toInt())
{
}
void tst_QAction::init()
{
m_lastEventType = QEvent::None;
m_lastAction = nullptr;
}
void tst_QAction::cleanup()
{
QVERIFY(QApplication::topLevelWidgets().isEmpty());
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(tst_QAction *tst, QWidget *parent = nullptr) : QWidget(parent), m_test(tst)
{ setWindowTitle(QTest::currentTestFunction()); }
protected:
void actionEvent(QActionEvent *e) override { m_test->updateState(e); }
private:
tst_QAction *m_test;
};
void tst_QAction::setUnknownFont() // QTBUG-42728
{
QAction action(nullptr);
QFont font("DoesNotExist", 11);
action.setFont(font);
QMenu menu;
menu.addAction(&action); // should not crash
}
void tst_QAction::updateState(QActionEvent *e)
{
if (!e) {
m_lastEventType = QEvent::None;
m_lastAction = nullptr;
} else {
m_lastEventType = e->type();
m_lastAction = e->action();
}
}
void tst_QAction::actionEvent()
{
QAction a(nullptr);
a.setText("action text");
// add action
MyWidget testWidget(this);
testWidget.show();
QApplicationPrivate::setActiveWindow(&testWidget);
testWidget.addAction(&a);
qApp->processEvents();
QCOMPARE(m_lastEventType, QEvent::ActionAdded);
QCOMPARE(m_lastAction, &a);
// change action
a.setText("new action text");
qApp->processEvents();
QCOMPARE(m_lastEventType, QEvent::ActionChanged);
QCOMPARE(m_lastAction, &a);
// remove action
testWidget.removeAction(&a);
qApp->processEvents();
QCOMPARE(m_lastEventType, QEvent::ActionRemoved);
QCOMPARE(m_lastAction, &a);
}
#if QT_CONFIG(shortcut)
void tst_QAction::alternateShortcuts()
{
//test the alternate shortcuts (by adding more than 1 shortcut)
MyWidget testWidget(this);
testWidget.show();
QApplicationPrivate::setActiveWindow(&testWidget);
{
QAction act(&testWidget);
testWidget.addAction(&act);
QList<QKeySequence> shlist = QList<QKeySequence>() << QKeySequence("CTRL+P") << QKeySequence("CTRL+A");
act.setShortcuts(shlist);
QSignalSpy spy(&act, &QAction::triggered);
act.setAutoRepeat(true);
QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier);
QCOMPARE(spy.size(), 1); //act should have been triggered
act.setAutoRepeat(false);
QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier);
QCOMPARE(spy.size(), 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(&testWidget, Qt::Key_A, Qt::ControlModifier);
}
void tst_QAction::keysequence()
{
MyWidget testWidget(this);
testWidget.show();
QApplicationPrivate::setActiveWindow(&testWidget);
{
QAction act(&testWidget);
testWidget.addAction(&act);
QKeySequence ks(QKeySequence::SelectAll);
act.setShortcut(ks);
QSignalSpy spy(&act, &QAction::triggered);
act.setAutoRepeat(true);
QTest::keySequence(&testWidget, ks);
QCoreApplication::processEvents();
QCOMPARE(spy.size(), 1); // act should have been triggered
act.setAutoRepeat(false);
QTest::keySequence(&testWidget, ks);
QCoreApplication::processEvents();
QCOMPARE(spy.size(), 2); //act should have been triggered a 2nd time
// end of the scope of the action, it will be destroyed and removed from widget
// This action should also unregister its shortcuts
}
// this tests a crash (if the action did not unregister its alternate shortcuts)
QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier);
}
void tst_QAction::enabledVisibleInteraction()
{
MyWidget testWidget(this);
testWidget.show();
QApplicationPrivate::setActiveWindow(&testWidget);
QAction act(nullptr);
// 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
testWidget.addAction(&act);
act.setShortcut(QKeySequence("Ctrl+T"));
QSignalSpy spy(&act, SIGNAL(triggered()));
act.setEnabled(true);
act.setVisible(false);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
QCOMPARE(spy.size(), 0); //act is not visible, so don't trigger
act.setVisible(false);
act.setEnabled(true);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
QCOMPARE(spy.size(), 0); //act is not visible, so don't trigger
act.setVisible(true);
act.setEnabled(true);
QTest::keyClick(&testWidget, Qt::Key_T, Qt::ControlModifier);
QCOMPARE(spy.size(), 1); //act is visible and enabled, so trigger
}
#endif // QT_CONFIG(shortcut)
void tst_QAction::task229128TriggeredSignalWhenInActiongroup()
{
QActionGroup ag(nullptr);
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, QOverload<bool>::of(&QAction::triggered));
QSignalSpy actionGroupSpy(&ag, QOverload<QAction*>::of(&QActionGroup::triggered));
QCOMPARE(actionGroupSpy.size(), 0);
QCOMPARE(actionSpy.size(), 0);
checkedAction->trigger();
// check that both the group and the action have emitted the signal
QCOMPARE(actionGroupSpy.size(), 1);
QCOMPARE(actionSpy.size(), 1);
}
#if QT_CONFIG(shortcut)
void tst_QAction::repeat()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
MyWidget testWidget(this);
testWidget.show();
QApplicationPrivate::setActiveWindow(&testWidget);
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
QAction act(&testWidget);
testWidget.addAction(&act);
act.setShortcut(QKeySequence(Qt::Key_F));
QSignalSpy spy(&act, SIGNAL(triggered()));
act.setAutoRepeat(true);
QTest::keyPress(&testWidget, Qt::Key_F);
QTest::keyRelease(&testWidget, Qt::Key_F);
QCOMPARE(spy.size(), 1);
spy.clear();
QTest::keyPress(&testWidget, Qt::Key_F);
// repeat event
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
QCOMPARE(spy.size(), 3);
spy.clear();
act.setAutoRepeat(false);
QTest::keyPress(&testWidget, Qt::Key_F);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
QCOMPARE(spy.size(), 1);
spy.clear();
act.setAutoRepeat(true);
QTest::keyPress(&testWidget, Qt::Key_F);
QTest::simulateEvent(&testWidget, true, Qt::Key_F, Qt::NoModifier, QString("f"), true);
QTest::keyRelease(&testWidget, Qt::Key_F);
QCOMPARE(spy.size(), 2);
}
void tst_QAction::disableShortcutsWithBlockedWidgets_data()
{
QTest::addColumn<Qt::ShortcutContext>("shortcutContext");
QTest::addColumn<Qt::WindowModality>("windowModality");
QTest::newRow("application modal dialog should block window shortcut.")
<< Qt::WindowShortcut << Qt::ApplicationModal;
QTest::newRow("application modal dialog should block application shortcut.")
<< Qt::ApplicationShortcut << Qt::ApplicationModal;
QTest::newRow("window modal dialog should block application shortcut.")
<< Qt::ApplicationShortcut << Qt::WindowModal;
QTest::newRow("window modal dialog should block window shortcut.")
<< Qt::WindowShortcut << Qt::WindowModal;
}
void tst_QAction::disableShortcutsWithBlockedWidgets()
{
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
QSKIP("Window activation is not supported");
QMainWindow window;
QFETCH(Qt::ShortcutContext, shortcutContext);
QAction action(&window);
window.addAction(&action);
action.setShortcut(QKeySequence(Qt::Key_1));
action.setShortcutContext(shortcutContext);
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QDialog dialog(&window);
QFETCH(Qt::WindowModality, windowModality);
dialog.setWindowModality(windowModality);
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
QApplicationPrivate::setActiveWindow(&window);
QVERIFY(QTest::qWaitForWindowActive(&window));
QSignalSpy spy(&action, &QAction::triggered);
QTest::keyPress(&window, Qt::Key_1);
QCOMPARE(spy.size(), 0);
}
class ShortcutOverrideWidget : public QWidget
{
public:
using QWidget::QWidget;
int shortcutOverrideCount = 0;
protected:
bool event(QEvent *e) override
{
if (e->type() == QEvent::ShortcutOverride)
++shortcutOverrideCount;
return QWidget::event(e);
}
};
// Test that a key press event sent with sendEvent() still gets handled as a possible
// ShortcutOverride event first before passing it on as a normal KeyEvent.
void tst_QAction::shortcutFromKeyEvent()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
ShortcutOverrideWidget testWidget;
QAction action;
action.setShortcut(Qt::Key_1);
testWidget.addAction(&action);
testWidget.show();
QSignalSpy spy(&action, &QAction::triggered);
QVERIFY(spy.isValid());
QVERIFY(QTest::qWaitForWindowActive(&testWidget));
QCOMPARE(testWidget.shortcutOverrideCount, 0);
// Don't use the QTest::keyPress approach as this will take the
// shortcut route for us
QKeyEvent e(QEvent::KeyPress, Qt::Key_1, Qt::NoModifier);
QApplication::sendEvent(&testWidget, &e);
QCOMPARE(spy.size(), 1);
QCOMPARE(testWidget.shortcutOverrideCount, 1);
}
/*
Ignore actions in menus whose menu action has been hidden or disabled.
The menu entry will not be in the menu bar or parent menu, so the action
is not reachable through interactive means. QTBUG-25743
*/
void tst_QAction::disableShortcutInMenuAction_data()
{
QTest::addColumn<QByteArray>("property");
QTest::addRow("visible") << QByteArray("visible");
QTest::addRow("enabled") << QByteArray("enabled");
}
void tst_QAction::disableShortcutInMenuAction()
{
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
QSKIP("QWindow::requestActivate() is not supported.");
QFETCH(QByteArray, property);
QMainWindow mw;
QMenu *testMenu = mw.menuBar()->addMenu("Test");
QAction *testAction = testMenu->addAction("Test Action");
testAction->setShortcut(Qt::ControlModifier | Qt::Key_A);
QToolBar *toolBar = new QToolBar;
mw.addToolBar(toolBar);
mw.show();
QVERIFY(QTest::qWaitForWindowActive(&mw));
int expectedTriggerCount = 0;
QSignalSpy spy(testAction, &QAction::triggered);
QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), ++expectedTriggerCount);
testMenu->menuAction()->setProperty(property, false);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), expectedTriggerCount);
testMenu->menuAction()->setProperty(property, true);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), ++expectedTriggerCount);
// If the action lives somewhere else, then keep firing even
// if the menu has been hidden or disabled.
toolBar->addAction(testAction);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), ++expectedTriggerCount);
testMenu->menuAction()->setProperty(property, false);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), ++expectedTriggerCount);
// unless all other widgets in which the action lives have
// been hidden...
toolBar->hide();
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), expectedTriggerCount);
// ... or disabled
toolBar->show();
toolBar->setEnabled(false);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), expectedTriggerCount);
// back to normal
toolBar->setEnabled(true);
QApplication::sendEvent(&mw, &event);
QCOMPARE(spy.size(), ++expectedTriggerCount);
}
#endif // QT_CONFIG(shortcut)
QTEST_MAIN(tst_QAction)
#include "tst_qaction.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qactiongroup Test:
#####################################################################
qt_internal_add_test(tst_qactiongroup
SOURCES
tst_qactiongroup.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,56 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qmainwindow.h>
#include <qmenu.h>
#include <qaction.h>
#include <qactiongroup.h>
class tst_QActionGroup : public QObject
{
Q_OBJECT
private slots:
void cleanup() { QVERIFY(QApplication::topLevelWidgets().isEmpty()); }
void separators();
};
void tst_QActionGroup::separators()
{
QMainWindow mw;
QMenu menu(&mw);
QActionGroup actGroup(&mw);
mw.show();
QAction *action = new QAction(&actGroup);
action->setText("test one");
QAction *separator = new QAction(&actGroup);
separator->setSeparator(true);
actGroup.addAction(separator);
menu.addActions(actGroup.actions());
QCOMPARE(menu.actions().size(), 2);
const auto removeActions = [&menu](const QList<QAction *> &actions) {
for (QAction *action : actions)
menu.removeAction(action);
};
removeActions(actGroup.actions());
QCOMPARE(menu.actions().size(), 0);
action = new QAction(&actGroup);
action->setText("test two");
menu.addActions(actGroup.actions());
QCOMPARE(menu.actions().size(), 3);
}
QTEST_MAIN(tst_QActionGroup)
#include "tst_qactiongroup.moc"

View File

@ -0,0 +1,7 @@
[sendEventsOnProcessEvents]
ubuntu-20.04
ubuntu-22.04
rhel-9.0
[touchEventPropagation]
# QTBUG-66745
opensuse-leap

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(desktopsettingsaware)
add_subdirectory(modal)
add_subdirectory(test)
add_dependencies(tst_qapplication
desktopsettingsaware_helper
modal_helper
)

View File

@ -0,0 +1,3 @@
{
"Keys": [ "customstyle" ]
}

View File

@ -0,0 +1,19 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## desktopsettingsaware Binary:
#####################################################################
qt_internal_add_executable(desktopsettingsaware_helper
SOURCES
main.cpp
OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/..
LIBRARIES
Qt::Gui
Qt::Widgets
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QApplication>
#include <QComboBox>
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;
}

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="841.88976pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
<metadata>
<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<cc:Work rdf:about="">
<dc:title>Heart Left-Highlight</dc:title>
<dc:description>This is a normal valentines day heart.</dc:description>
<dc:subject>
<rdf:Bag>
<rdf:li>holiday</rdf:li>
<rdf:li>valentines</rdf:li>
<rdf:li></rdf:li>
<rdf:li>valentine</rdf:li>
<rdf:li>hash(0x8a091c0)</rdf:li>
<rdf:li>hash(0x8a0916c)</rdf:li>
<rdf:li>signs_and_symbols</rdf:li>
<rdf:li>hash(0x8a091f0)</rdf:li>
<rdf:li>day</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:publisher>
<cc:Agent rdf:about="http://www.openclipart.org">
<dc:title>Jon Phillips</dc:title>
</cc:Agent>
</dc:publisher>
<dc:creator>
<cc:Agent>
<dc:title>Jon Phillips</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Jon Phillips</dc:title>
</cc:Agent>
</dc:rights>
<dc:date></dc:date>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/>
<dc:language>en</dc:language>
</cc:Work>
<cc:License rdf:about="http://web.resource.org/cc/PublicDomain">
<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/>
<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
<defs id="defs3"/>
<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/>
<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1">
<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,20 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## modal Binary:
#####################################################################
qt_internal_add_executable(modal_helper
SOURCES
base.cpp base.h
main.cpp
OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/..
LIBRARIES
Qt::Gui
Qt::Widgets
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,24 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "base.h"
base::base(QWidget *parent) :
QWidget(parent)
{
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
connect(m_timer, &QTimer::timeout, this, &base::periodicTimer);
m_timer->start(5000);
}
void base::periodicTimer()
{
if(m_modalStarted)
exit(0);
m_modalDialog = new QDialog(this);
m_modalDialog->setWindowTitle(QLatin1String("modal"));
m_modalDialog->setModal(true);
m_modalDialog->show();
m_modalStarted = true;
}

View File

@ -0,0 +1,24 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef BASE_H
#define BASE_H
#include <QWidget>
#include <QTimer>
#include <QDialog>
class base : public QWidget
{
Q_OBJECT
QTimer *m_timer;
bool m_modalStarted = false;
QDialog *m_modalDialog = nullptr;
public:
explicit base(QWidget *parent = nullptr);
public slots:
void periodicTimer();
};
#endif // BASE_H

View File

@ -0,0 +1,13 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QApplication>
#include "base.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QApplication::setAttribute(Qt::AA_NativeWindows); //QTBUG-15774
base b;
return app.exec();
}

View File

@ -0,0 +1,21 @@
# This file is mainly used for Android tests since Android
# packages "test" instead of "qapplication" folder
# QTBUG-87025
[libraryPaths]
android
[setFont]
android
[closeAllWindows]
android
[libraryPaths_qt_plugin_path_2]
android
[desktopSettingsAware]
android
[applicationPalettePolish]
android
[touchEventPropagation]
android
[wheelEventPropagation]
android
[qtbug_12673]
android

View File

@ -0,0 +1,31 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## test Test:
#####################################################################
# Collect test data
list(APPEND test_data "../tmp/README")
list(APPEND test_data "../modal")
qt_internal_add_test(tst_qapplication
SOURCES
../tst_qapplication.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
TESTDATA ${test_data}
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.."
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qapplication CONDITION builtin_testdata
DEFINES
BUILTIN_TESTDATA
)

View File

@ -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...

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qboxlayout Test:
#####################################################################
qt_internal_add_test(tst_qboxlayout
SOURCES
tst_qboxlayout.cpp
LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
)

View File

@ -0,0 +1,579 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtGui>
#include <QtWidgets>
#include <QtTest/private/qtesthelpers_p.h>
using namespace QTestPrivate;
class tst_QBoxLayout : public QObject
{
Q_OBJECT
private slots:
void cleanup();
void insertSpacerItem();
void insertLayout();
void sizeHint();
void sizeConstraints();
void setGeometry();
void setStyleShouldChangeSpacing();
void widgetSurplus();
void testLayoutEngine_data();
void testLayoutEngine();
void taskQTBUG_7103_minMaxWidthNotRespected();
void taskQTBUG_27420_takeAtShouldUnparentLayout();
void taskQTBUG_40609_addingWidgetToItsOwnLayout();
void taskQTBUG_40609_addingLayoutToItself();
void replaceWidget();
void indexOf();
};
class CustomLayoutStyle : public QProxyStyle
{
Q_OBJECT
public:
CustomLayoutStyle() : QProxyStyle(QStyleFactory::create("windows"))
{
hspacing = 5;
vspacing = 10;
}
virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = nullptr,
const QWidget * widget = nullptr ) const override;
int hspacing;
int vspacing;
};
int CustomLayoutStyle::pixelMetric(PixelMetric metric, const QStyleOption * option /*= nullptr*/,
const QWidget * widget /*= nullptr*/ ) 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 QProxyStyle::pixelMetric(metric, option, widget);
}
void tst_QBoxLayout::cleanup()
{
QVERIFY(QApplication::topLevelWidgets().isEmpty());
}
void tst_QBoxLayout::insertSpacerItem()
{
QWidget window;
window.setWindowTitle(QTest::currentTestFunction());
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);
QCOMPARE(layout->itemAt(0), spacer2);
QCOMPARE(layout->itemAt(2), spacer1);
window.show();
}
void tst_QBoxLayout::insertLayout()
{
QWidget window;
QVBoxLayout *vbox = new QVBoxLayout(&window);
QScopedPointer<QVBoxLayout> dummyParentLayout(new QVBoxLayout);
QHBoxLayout *subLayout = new QHBoxLayout;
dummyParentLayout->addLayout(subLayout);
QCOMPARE(subLayout->parent(), dummyParentLayout.data());
QCOMPARE(dummyParentLayout->count(), 1);
// add subLayout to another layout
QTest::ignoreMessage(QtWarningMsg, "QLayout::addChildLayout: layout QHBoxLayout \"\" already has a parent");
vbox->addLayout(subLayout);
QCOMPARE((subLayout->parent() == vbox), (vbox->count() == 1));
}
void tst_QBoxLayout::sizeHint()
{
QWidget window;
window.setWindowTitle(QTest::currentTestFunction());
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();
QVERIFY(QTest::qWaitForWindowExposed(&window));
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;
window.setWindowTitle(QTest::currentTestFunction());
QHBoxLayout *lay = new QHBoxLayout;
lay->addWidget(new QLabel("foooooooooooooooooooooooooooooooooooo"));
lay->addWidget(new QLabel("baaaaaaaaaaaaaaaaaaaaaaaaaaaaaar"));
lay->setSizeConstraint(QLayout::SetFixedSize);
window.setLayout(lay);
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QSize sh = window.sizeHint();
delete lay->takeAt(1);
QVERIFY(sh.width() >= window.sizeHint().width() &&
sh.height() >= window.sizeHint().height());
}
void tst_QBoxLayout::setGeometry()
{
QWidget toplevel;
toplevel.setWindowTitle(QTest::currentTestFunction());
setFrameless(&toplevel);
QWidget w(&toplevel);
QVBoxLayout *lay = new QVBoxLayout;
lay->setContentsMargins(0, 0, 0, 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;
window.setWindowTitle(QTest::currentTestFunction());
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);
QScopedPointer<CustomLayoutStyle> style1(new CustomLayoutStyle);
style1->hspacing = 6;
window.setStyle(style1.data());
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
auto spacing = [&]() { return pb2->geometry().left() - pb1->geometry().right() - 1; };
QCOMPARE(spacing(), 6);
QScopedPointer<CustomLayoutStyle> style2(new CustomLayoutStyle());
style2->hspacing = 10;
window.setStyle(style2.data());
QTRY_COMPARE(spacing(), 10);
}
class MarginEatingStyle : public QProxyStyle
{
public:
MarginEatingStyle() : QProxyStyle(QStyleFactory::create("windows"))
{
}
virtual QRect subElementRect(SubElement sr, const QStyleOption *opt,
const QWidget *widget) const override
{
QRect rect = opt->rect;
switch (sr) {
case SE_GroupBoxLayoutItem:
// this is a simplifed version of what the macOS style does
rect.setTop(rect.top() + 20);
rect.setLeft(rect.left() + 20);
rect.setRight(rect.right() - 20);
rect.setBottom(rect.bottom() - 20);
break;
default:
return QProxyStyle::subElementRect(sr, opt, widget);
}
return rect;
}
};
void tst_QBoxLayout::widgetSurplus()
{
// Test case for QTBUG-67608 - a style requests space in the margin
QDialog window;
QScopedPointer<MarginEatingStyle> marginEater(new MarginEatingStyle);
QVBoxLayout *vbox = new QVBoxLayout(&window);
vbox->setContentsMargins(0, 0, 0, 0);
vbox->setSpacing(0);
QLabel *hiddenLabel = new QLabel(tr("Invisible label"));
hiddenLabel->setVisible(false);
QGroupBox *groupBox = new QGroupBox(tr("Groupbox Title"));
groupBox->setStyle(marginEater.data());
groupBox->setObjectName("Test group box");
QPushButton *button1 = new QPushButton(tr("Button 1"));
QPushButton *button2 = new QPushButton(tr("Button 2"));
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->addWidget(button1);
groupLayout->addWidget(button2);
groupBox->setLayout(groupLayout);
QLabel *label = new QLabel(tr("Visible label"));
vbox->addWidget(hiddenLabel);
vbox->addWidget(groupBox);
vbox->addWidget(label);
window.setLayout(vbox);
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QCOMPARE(groupBox->y(), 0);
QCOMPARE(groupBox->x(), 0);
}
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.setWindowTitle(QTest::currentTestFunction());
widget.setLayout(layout);
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
int height = label->height();
QRect g = widget.geometry();
g.setWidth(600);
widget.setGeometry(g);
QTest::qWait(50);
QCOMPARE(label->height(), height);
}
void tst_QBoxLayout::taskQTBUG_27420_takeAtShouldUnparentLayout()
{
QSharedPointer<QHBoxLayout> outer(new QHBoxLayout);
QPointer<QVBoxLayout> inner = new QVBoxLayout;
outer->addLayout(inner);
QCOMPARE(outer->count(), 1);
QCOMPARE(inner->parent(), outer.data());
QLayoutItem *item = outer->takeAt(0);
QCOMPARE(item->layout(), inner.data());
QVERIFY(!item->layout()->parent());
outer.reset();
if (inner)
delete item; // success: a taken item/layout should not be deleted when the old parent is deleted
else
QVERIFY(!inner.isNull());
}
void tst_QBoxLayout::taskQTBUG_40609_addingWidgetToItsOwnLayout(){
QWidget widget;
widget.setWindowTitle(QTest::currentTestFunction());
widget.setObjectName("347b469225a24a0ef05150a");
QVBoxLayout layout(&widget);
layout.setObjectName("ef9e2b42298e0e6420105bb");
QTest::ignoreMessage(QtWarningMsg, "QLayout: Cannot add a null widget to QVBoxLayout/ef9e2b42298e0e6420105bb");
layout.addWidget(nullptr);
QCOMPARE(layout.count(), 0);
QTest::ignoreMessage(QtWarningMsg, "QLayout: Cannot add parent widget QWidget/347b469225a24a0ef05150a to its child layout QVBoxLayout/ef9e2b42298e0e6420105bb");
layout.addWidget(&widget);
QCOMPARE(layout.count(), 0);
}
void tst_QBoxLayout::taskQTBUG_40609_addingLayoutToItself(){
QWidget widget;
widget.setWindowTitle(QTest::currentTestFunction());
widget.setObjectName("fe44e5cb6c08006597126a");
QVBoxLayout layout(&widget);
layout.setObjectName("cc751dd0f50f62b05a62da");
QTest::ignoreMessage(QtWarningMsg, "QLayout: Cannot add a null layout to QVBoxLayout/cc751dd0f50f62b05a62da");
layout.addLayout(nullptr);
QCOMPARE(layout.count(), 0);
QTest::ignoreMessage(QtWarningMsg, "QLayout: Cannot add layout QVBoxLayout/cc751dd0f50f62b05a62da to itself");
layout.addLayout(&layout);
QCOMPARE(layout.count(), 0);
}
struct Descr
{
Descr(int min, int sh, int max = -1, bool exp= false, int _stretch = 0, bool _empty = false)
:minimumSize(min), sizeHint(sh), maximumSize(max < 0 ? QLAYOUTSIZE_MAX : max),
expanding(exp), stretch(_stretch), empty(_empty)
{}
int minimumSize;
int sizeHint;
int maximumSize;
bool expanding;
int stretch;
bool empty;
};
typedef QList<Descr> DescrList;
Q_DECLARE_METATYPE(DescrList);
typedef QList<int> SizeList;
typedef QList<int> PosList;
class LayoutItem : public QLayoutItem
{
public:
LayoutItem(const Descr &descr) :m_descr(descr) {}
QSize sizeHint() const override { return QSize(m_descr.sizeHint, 100); }
QSize minimumSize() const override { return QSize(m_descr.minimumSize, 0); }
QSize maximumSize() const override { return QSize(m_descr.maximumSize, QLAYOUTSIZE_MAX); }
Qt::Orientations expandingDirections() const override
{ return m_descr.expanding ? Qt::Horizontal : Qt::Orientations{}; }
void setGeometry(const QRect &r) override { m_pos = r.x(); m_size = r.width();}
QRect geometry() const override { return QRect(m_pos, 0, m_size, 100); }
bool isEmpty() const override { return m_descr.empty; }
private:
Descr m_descr;
int m_pos;
int m_size;
};
void tst_QBoxLayout::testLayoutEngine_data()
{
// (int min, int sh, int max = -1, bool exp= false, int _stretch = 0, bool _empty = false)
QTest::addColumn<DescrList>("itemDescriptions");
QTest::addColumn<int>("size");
QTest::addColumn<int>("spacing");
QTest::addColumn<PosList>("expectedPositions");
QTest::addColumn<SizeList>("expectedSizes");
QTest::newRow("Just one")
<< (DescrList() << Descr(0, 100))
<< 200
<< 0
<< (PosList() << 0)
<< (SizeList() << 200);
QTest::newRow("Two non-exp")
<< (DescrList() << Descr(0, 100) << Descr(0,100))
<< 400
<< 0
<< (PosList() << 0 << 200)
<< (SizeList() << 200 << 200);
QTest::newRow("Exp + non-exp")
<< (DescrList() << Descr(0, 100, -1, true) << Descr(0,100))
<< 400
<< 0
<< (PosList() << 0 << 300)
<< (SizeList() << 300 << 100);
QTest::newRow("Stretch")
<< (DescrList() << Descr(0, 100, -1, false, 1) << Descr(0,100, -1, false, 2))
<< 300
<< 0
<< (PosList() << 0 << 100)
<< (SizeList() << 100 << 200);
QTest::newRow("Spacing")
<< (DescrList() << Descr(0, 100) << Descr(0,100))
<< 400
<< 10
<< (PosList() << 0 << 205)
<< (SizeList() << 195 << 195);
QTest::newRow("Less than minimum")
<< (DescrList() << Descr(100, 100, 100, false) << Descr(50, 100, 100, false))
<< 100
<< 0
<< (PosList() << 0 << 50)
<< (SizeList() << 50 << 50);
QTest::newRow("Less than sizehint")
<< (DescrList() << Descr(100, 200, 100, false) << Descr(50, 200, 100, false))
<< 200
<< 0
<< (PosList() << 0 << 100)
<< (SizeList() << 100 << 100);
QTest::newRow("Too much space")
<< (DescrList() << Descr(0, 100, 100, false) << Descr(0, 100, 100, false))
<< 500
<< 0
<< (PosList() << 100 << 300)
<< (SizeList() << 100 << 100);
QTest::newRow("Empty")
<< (DescrList() << Descr(0, 100, 100) << Descr(0,0,-1, false, 0, true) << Descr(0, 100, 100) )
<< 500
<< 0
<< (PosList() << 100 << 300 << 300)
<< (SizeList() << 100 << 0 << 100);
QTest::newRow("QTBUG-33104")
<< (DescrList() << Descr(11, 75, 75, true) << Descr(75, 75))
<< 200
<< 0
<< (PosList() << 0 << 75)
<< (SizeList() << 75 << 125);
QTest::newRow("Expanding with maximumSize")
<< (DescrList() << Descr(11, 75, 100, true) << Descr(75, 75))
<< 200
<< 0
<< (PosList() << 0 << 100)
<< (SizeList() << 100 << 100);
QTest::newRow("Stretch with maximumSize")
<< (DescrList() << Descr(11, 75, 100, false, 1) << Descr(75, 75))
<< 200
<< 0
<< (PosList() << 0 << 100)
<< (SizeList() << 100 << 100);
QTest::newRow("Stretch with maximumSize last")
<< (DescrList() << Descr(75, 75) << Descr(11, 75, 100, false, 1))
<< 200
<< 0
<< (PosList() << 0 << 100)
<< (SizeList() << 100 << 100);
}
void tst_QBoxLayout::testLayoutEngine()
{
QFETCH(DescrList, itemDescriptions);
QFETCH(int, size);
QFETCH(int, spacing);
QFETCH(PosList, expectedPositions);
QFETCH(SizeList, expectedSizes);
QHBoxLayout box;
box.setSpacing(spacing);
int i;
for (i = 0; i < itemDescriptions.size(); ++i) {
Descr descr = itemDescriptions.at(i);
LayoutItem *li = new LayoutItem(descr);
box.addItem(li);
box.setStretch(i, descr.stretch);
}
box.setGeometry(QRect(0,0,size,100));
for (i = 0; i < expectedSizes.size(); ++i) {
int xSize = expectedSizes.at(i);
int xPos = expectedPositions.at(i);
QLayoutItem *item = box.itemAt(i);
QCOMPARE(item->geometry().width(), xSize);
QCOMPARE(item->geometry().x(), xPos);
}
}
void tst_QBoxLayout::replaceWidget()
{
QWidget w;
QBoxLayout *boxLayout = new QVBoxLayout(&w);
QLineEdit *replaceFrom = new QLineEdit;
QLineEdit *replaceTo = new QLineEdit;
boxLayout->addWidget(new QLineEdit());
boxLayout->addWidget(replaceFrom);
boxLayout->addWidget(new QLineEdit());
QCOMPARE(boxLayout->indexOf(replaceFrom), 1);
QCOMPARE(boxLayout->indexOf(replaceTo), -1);
QCOMPARE(boxLayout->count(), 3);
boxLayout->replaceWidget(replaceFrom, replaceFrom);
QCOMPARE(boxLayout->count(), 3);
delete boxLayout->replaceWidget(replaceFrom, replaceTo);
QCOMPARE(boxLayout->indexOf(replaceFrom), -1);
QCOMPARE(boxLayout->indexOf(replaceTo), 1);
}
void tst_QBoxLayout::indexOf()
{
QWidget w;
auto outer = new QVBoxLayout(&w);
auto inner = new QHBoxLayout();
outer->addLayout(inner);
auto widget1 = new QWidget();
QWidget widget2;
inner->addWidget(widget1);
QCOMPARE(inner->indexOf(widget1), 0);
QCOMPARE(inner->indexOf(&widget2), -1);
QCOMPARE(outer->indexOf(widget1), -1);
QCOMPARE(outer->indexOf(&widget2), -1);
QCOMPARE(outer->indexOf(outer), -1);
QCOMPARE(outer->indexOf(inner), 0);
QCOMPARE(inner->indexOf(inner->itemAt(0)), 0);
}
QTEST_MAIN(tst_QBoxLayout)
#include "tst_qboxlayout.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qformlayout Test:
#####################################################################
qt_internal_add_test(tst_qformlayout
SOURCES
tst_qformlayout.cpp
LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qgesturerecognizer Test:
#####################################################################
qt_internal_add_test(tst_qgesturerecognizer
SOURCES
tst_qgesturerecognizer.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
)

View File

@ -0,0 +1,328 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QTest>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QGestureEvent>
#include <QtGui/QScreen>
#include <QtGui/QPointingDevice>
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QHash>
#include <QtCore/QDebug>
class tst_QGestureRecognizer : public QObject
{
Q_OBJECT
public:
tst_QGestureRecognizer();
private Q_SLOTS:
void initTestCase();
#ifndef QT_NO_GESTURES
void panGesture_data();
void panGesture();
void pinchGesture_data();
void pinchGesture();
void swipeGesture_data();
void swipeGesture();
void touchReplay();
#endif // !QT_NO_GESTURES
private:
const int m_fingerDistance;
QPointingDevice *m_touchDevice;
};
tst_QGestureRecognizer::tst_QGestureRecognizer()
: m_fingerDistance(qRound(QGuiApplication::primaryScreen()->physicalDotsPerInch() / 2.0))
, m_touchDevice(QTest::createTouchDevice())
{
qputenv("QT_PAN_TOUCHPOINTS", "2"); // Prevent device detection of pan touch point count.
}
void tst_QGestureRecognizer::initTestCase()
{
}
#ifndef QT_NO_GESTURES
typedef QList<Qt::GestureType> GestureTypeVector;
class TestWidget : public QWidget
{
public:
explicit TestWidget(const GestureTypeVector &gestureTypes);
bool gestureReceived(Qt::GestureType gestureType) const
{ return m_receivedGestures.value(gestureType); }
protected:
bool event(QEvent * event) override;
private:
typedef QHash<Qt::GestureType, bool> GestureTypeHash;
GestureTypeHash m_receivedGestures;
};
TestWidget::TestWidget(const GestureTypeVector &gestureTypes)
{
setAttribute(Qt::WA_AcceptTouchEvents);
foreach (Qt::GestureType gestureType, gestureTypes) {
grabGesture(gestureType);
m_receivedGestures.insert(gestureType, false);
}
const QRect geometry = QGuiApplication::primaryScreen()->availableGeometry();
const QSize size = geometry.size() / 2;
resize(size);
move(geometry.center() - QPoint(size.width() / 2, size.height() / 2));
}
bool TestWidget::event(QEvent * event)
{
switch (event->type()) {
case QEvent::Gesture: {
const QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event);
const GestureTypeHash::iterator hend = m_receivedGestures.end();
for (GestureTypeHash::iterator it = m_receivedGestures.begin(); it != hend; ++it) {
if (const QGesture *gesture = gestureEvent->gesture(it.key())) {
if (gesture->state() == Qt::GestureFinished)
it.value() = true;
}
}
}
break;
default:
break;
}
return QWidget::event(event);
}
static void pressSequence(QTest::QTouchEventWidgetSequence &sequence, QList<QPoint> &points,
QWidget *widget)
{
const int pointCount = points.size();
for (int p = 0; p < pointCount; ++p)
sequence.press(p, points.at(p), widget);
sequence.commit();
}
static void linearSequence(int n, const QPoint &delta, QTest::QTouchEventWidgetSequence &sequence,
QList<QPoint> &points, QWidget *widget)
{
const int pointCount = points.size();
for (int s = 0; s < n; ++s) {
for (int p = 0; p < pointCount; ++p) {
points[p] += delta;
sequence.move(p, points[p], widget);
}
sequence.commit();
}
}
static void releaseSequence(QTest::QTouchEventWidgetSequence &sequence, QList<QPoint> &points,
QWidget *widget)
{
const int pointCount = points.size();
for (int p = 0; p < pointCount; ++p)
sequence.release(p, points[p], widget);
sequence.commit();
}
// --- Pan
enum PanSubTest {
TwoFingerPanSubTest
};
void tst_QGestureRecognizer::panGesture_data()
{
QTest::addColumn<int>("panSubTest");
QTest::addColumn<bool>("gestureExpected");
QTest::newRow("Two finger") << int(TwoFingerPanSubTest) << true;
}
void tst_QGestureRecognizer::panGesture()
{
QFETCH(int, panSubTest);
QFETCH(bool, gestureExpected);
Q_UNUSED(panSubTest); // Single finger pan will be added later.
const int panPoints = 2;
const Qt::GestureType gestureType = Qt::PanGesture;
TestWidget widget(GestureTypeVector(1, gestureType));
widget.setWindowTitle(QTest::currentTestFunction());
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QList<QPoint> points;
for (int i = 0; i < panPoints; ++i)
points.append(QPoint(10 + i *20, 10 + i *20));
QTest::QTouchEventWidgetSequence panSequence = QTest::touchEvent(&widget, m_touchDevice);
pressSequence(panSequence, points, &widget);
linearSequence(5, QPoint(20, 20), panSequence, points, &widget);
releaseSequence(panSequence, points, &widget);
if (gestureExpected) {
QTRY_VERIFY(widget.gestureReceived(gestureType));
} else {
QCoreApplication::processEvents();
QVERIFY(!widget.gestureReceived(gestureType));
}
}
// --- Pinch
enum PinchSubTest {
StandardPinchSubTest
};
void tst_QGestureRecognizer::pinchGesture_data()
{
QTest::addColumn<int>("pinchSubTest");
QTest::addColumn<bool>("gestureExpected");
QTest::newRow("Standard") << int(StandardPinchSubTest) << true;
}
void tst_QGestureRecognizer::pinchGesture()
{
QFETCH(int, pinchSubTest);
QFETCH(bool, gestureExpected);
Q_UNUSED(pinchSubTest);
const Qt::GestureType gestureType = Qt::PinchGesture;
TestWidget widget(GestureTypeVector(1, gestureType));
widget.setWindowTitle(QTest::currentTestFunction());
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QList<QPoint> points;
points.append(widget.rect().center());
points.append(points.front() + QPoint(0, 20));
QTest::QTouchEventWidgetSequence pinchSequence = QTest::touchEvent(&widget, m_touchDevice);
pressSequence(pinchSequence, points, &widget);
for (int s = 0; s < 5; ++s) {
points[0] += QPoint(5, 30);
pinchSequence.move(0, points[0], &widget);
points[1] += QPoint(5, -30);
pinchSequence.move(1, points[1], &widget);
pinchSequence.commit();
}
releaseSequence(pinchSequence, points, &widget);
if (gestureExpected) {
QTRY_VERIFY(widget.gestureReceived(gestureType));
} else {
QCoreApplication::processEvents();
QVERIFY(!widget.gestureReceived(gestureType));
}
}
// --- Swipe
enum SwipeSubTest {
SwipeLineSubTest,
SwipeDirectionChangeSubTest,
SwipeSmallDirectionChangeSubTest
};
void tst_QGestureRecognizer::swipeGesture_data()
{
QTest::addColumn<int>("swipeSubTest");
QTest::addColumn<bool>("gestureExpected");
QTest::newRow("Line") << int(SwipeLineSubTest) << true;
QTest::newRow("DirectionChange") << int(SwipeDirectionChangeSubTest) << false;
QTest::newRow("SmallDirectionChange") << int(SwipeSmallDirectionChangeSubTest) << true;
}
void tst_QGestureRecognizer::swipeGesture()
{
enum { swipePoints = 3 };
QFETCH(int, swipeSubTest);
QFETCH(bool, gestureExpected);
const Qt::GestureType gestureType = Qt::SwipeGesture;
TestWidget widget(GestureTypeVector(1, gestureType));
widget.setWindowTitle(QTest::currentTestFunction());
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
// Start a swipe sequence with 2 points (QTBUG-15768)
const QPoint fingerDistance(m_fingerDistance, m_fingerDistance);
QList<QPoint> points;
for (int i = 0; i < swipePoints - 1; ++i)
points.append(fingerDistance + i * fingerDistance);
QTest::QTouchEventWidgetSequence swipeSequence = QTest::touchEvent(&widget, m_touchDevice);
pressSequence(swipeSequence, points, &widget);
// Press point #3
points.append(points.last() + fingerDistance);
swipeSequence.stationary(0).stationary(1).press(points.size() - 1, points.last(), &widget);
swipeSequence.commit();
Q_ASSERT(points.size() == swipePoints);
// Move.
const QPoint moveDelta(60, 20);
switch (swipeSubTest) {
case SwipeLineSubTest:
linearSequence(5, moveDelta, swipeSequence, points, &widget);
break;
case SwipeDirectionChangeSubTest:
linearSequence(5, moveDelta, swipeSequence, points, &widget);
linearSequence(3, QPoint(-moveDelta.x(), moveDelta.y()), swipeSequence, points, &widget);
break;
case SwipeSmallDirectionChangeSubTest: { // QTBUG-46195, small changes in direction should not cause the gesture to be canceled.
const QPoint smallChangeMoveDelta(50, 1);
linearSequence(5, smallChangeMoveDelta, swipeSequence, points, &widget);
linearSequence(1, QPoint(smallChangeMoveDelta.x(), -3), swipeSequence, points, &widget);
linearSequence(5, smallChangeMoveDelta, swipeSequence, points, &widget);
}
break;
}
releaseSequence(swipeSequence, points, &widget);
if (gestureExpected) {
QTRY_VERIFY(widget.gestureReceived(gestureType));
} else {
QCoreApplication::processEvents();
QVERIFY(!widget.gestureReceived(gestureType));
}
}
void tst_QGestureRecognizer::touchReplay()
{
const Qt::GestureType gestureType = Qt::TapGesture;
QWidget parent;
TestWidget widget(GestureTypeVector(1, gestureType));
widget.setParent(&parent);
widget.setGeometry(0, 0, 100, 100);
parent.adjustSize();
parent.show();
QVERIFY(QTest::qWaitForWindowActive(&parent));
QWindow* windowHandle = parent.window()->windowHandle();
const QPoint globalPos = QPoint(42, 16);
QTest::touchEvent(windowHandle, m_touchDevice).press(1, globalPos);
QTest::touchEvent(windowHandle, m_touchDevice).release(1, globalPos);
QVERIFY(widget.gestureReceived(gestureType));
}
#endif // !QT_NO_GESTURES
QTEST_MAIN(tst_QGestureRecognizer)
#include "tst_qgesturerecognizer.moc"

View File

@ -0,0 +1,3 @@
# QTBUG-87404
[minMaxSize]
android

View File

@ -0,0 +1,21 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qgridlayout Test:
#####################################################################
qt_internal_add_test(tst_qgridlayout
SOURCES
sortdialog.ui
tst_qgridlayout.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
ENABLE_AUTOGEN_TOOLS
uic
)

View File

@ -0,0 +1,135 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>SortDialog</class>
<widget class="QDialog" name="SortDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>370</height>
</rect>
</property>
<property name="windowTitle" >
<string>Sort</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>8</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item rowspan="2" row="0" column="1" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="okButton" >
<property name="text" >
<string>OK</string>
</property>
<property name="default" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="moreButton" >
<property name="text" >
<string>&amp;More</string>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" >
<widget class="QGroupBox" name="primaryGroupBox" >
<layout class="QHBoxLayout" >
<property name="margin" >
<number>8</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QComboBox" name="primaryColumnCombo" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<item>
<property name="text" >
<string>None</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<tabstops>
<tabstop>primaryColumnCombo</tabstop>
<tabstop>okButton</tabstop>
<tabstop>moreButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>okButton</sender>
<signal>clicked()</signal>
<receiver>SortDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>257</x>
<y>25</y>
</hint>
<hint type="destinationlabel" >
<x>283</x>
<y>268</y>
</hint>
</hints>
</connection>
</connections>
</ui>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qlayout Test:
#####################################################################
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
baseline/*)
list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qlayout
SOURCES
tst_qlayout.cpp
LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
TESTDATA ${test_data}
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,401 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qcoreapplication.h>
#include <qmetaobject.h>
#include <qdebug.h>
#include <qboxlayout.h>
#include <qmenubar.h>
#include <qdialog.h>
#include <qsizegrip.h>
#include <qlabel.h>
#include <QtWidgets/QFrame>
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QSizePolicy>
#include <QtWidgets/QComboBox>
#include <QPushButton>
#include <QRadioButton>
#include <private/qlayoutengine_p.h>
#include <QtTest/private/qtesthelpers_p.h>
using namespace QTestPrivate;
class tst_QLayout : public QObject
{
Q_OBJECT
public:
tst_QLayout();
virtual ~tst_QLayout();
private slots:
void cleanup() { QVERIFY(QApplication::topLevelWidgets().isEmpty()); }
void getSetCheck();
void geometry();
void smartMaxSize();
void setLayoutBugs();
void setContentsMargins();
void layoutItemRect();
void warnIfWrongParent();
void controlTypes();
void controlTypes2();
void adjustSizeShouldMakeSureLayoutIsActivated();
void testRetainSizeWhenHidden();
void removeWidget();
};
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<QWidget *>(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 override { return sh; }
QSize minimumSizeHint() const override { 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(QStyleFactory::create(QLatin1String("Windows")));
QWidget topLevel;
setFrameless(&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()
{
QList<int> expectedWidths;
QFile f(QFINDTESTDATA("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[] = { Qt::Alignment{},
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();
int expectedWidth = expectedWidths[expectedIndex];
if (width != expectedWidth) {
qDebug() << "error at index" << expectedIndex << ':' << sizePolicy.horizontalPolicy() << align << minSize << sizeHint << maxSize << width;
++regressionCount;
}
++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);
QCOMPARE(widget.layout(), hBoxLayout);
QWidget containerWidget(0);
containerWidget.setLayout(widget.layout());
QVERIFY(!widget.layout());
QCOMPARE(containerWidget.layout(), hBoxLayout);
}
class MyLayout : public QLayout
{
public:
MyLayout() : invalidated(false) {}
virtual void invalidate() override {invalidated = true;}
bool invalidated;
QSize sizeHint() const override {return QSize();}
void addItem(QLayoutItem*) override {}
QLayoutItem* itemAt(int) const override {return 0;}
QLayoutItem* takeAt(int) override {return 0;}
int count() const override {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);
MyLayout otherLayout; // with default contents margins
QVERIFY(layout.contentsMargins() != otherLayout.contentsMargins());
layout.unsetContentsMargins();
QCOMPARE(layout.contentsMargins(), otherLayout.contentsMargins());
layout.setContentsMargins(10, 20, 30, 40);
QVERIFY(layout.contentsMargins() != otherLayout.contentsMargins());
int contentsMarginsPropertyIndex = QLayout::staticMetaObject.indexOfProperty("contentsMargins");
QVERIFY(contentsMarginsPropertyIndex >= 0);
QMetaProperty contentsMarginsProperty = QLayout::staticMetaObject.property(contentsMarginsPropertyIndex);
QVERIFY(contentsMarginsProperty.isValid());
QVERIFY(contentsMarginsProperty.isResettable());
QVERIFY(contentsMarginsProperty.reset(&layout));
QCOMPARE(layout.contentsMargins(), otherLayout.contentsMargins());
}
class EventReceiver : public QObject
{
public:
bool eventFilter(QObject *watched, QEvent *event) override
{
if (event->type() == QEvent::Show) {
geom = static_cast<QWidget*>(watched)->geometry();
}
return false;
}
QRect geom;
};
void tst_QLayout::layoutItemRect()
{
#ifdef Q_OS_MAC
if (QApplication::style()->inherits("QMacStyle")) {
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(), nullptr);
}
void tst_QLayout::controlTypes()
{
QVBoxLayout layout;
QCOMPARE(layout.controlTypes(), QSizePolicy::DefaultType);
QSizePolicy p;
QCOMPARE(p.controlType(),QSizePolicy::DefaultType);
}
void tst_QLayout::controlTypes2()
{
QWidget main;
QVBoxLayout *const layout = new QVBoxLayout(&main);
layout->setContentsMargins(0, 0, 0, 0);
QComboBox *combo = new QComboBox(&main);
layout->addWidget(combo);
QCOMPARE(layout->controlTypes(), QSizePolicy::ComboBox);
}
void tst_QLayout::adjustSizeShouldMakeSureLayoutIsActivated()
{
QWidget main;
QVBoxLayout *const layout = new QVBoxLayout(&main);
layout->setContentsMargins(0, 0, 0, 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));
}
void tst_QLayout::testRetainSizeWhenHidden()
{
#ifdef Q_OS_ANDROID
QSKIP("Test does not work on platforms which default to showMaximized()");
#endif
QWidget widget;
QBoxLayout layout(QBoxLayout::TopToBottom, &widget);
QLabel *label1 = new QLabel("label1 text", &widget);
layout.addWidget(label1);
QLabel *label2 = new QLabel("label2 text", &widget);
layout.addWidget(label2);
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
int normalHeight = widget.height();
// a. Verify that a removed visible will mean lesser size after adjust
label1->hide();
widget.adjustSize();
int heightWithoutLabel1 = widget.height();
QVERIFY(heightWithoutLabel1 < normalHeight);
// b restore with verify that the size is the same
label1->show();
QCOMPARE(widget.sizeHint().height(), normalHeight);
// c verify that a policy with retainSizeWhenHidden is respected
QSizePolicy sp_remove = label1->sizePolicy();
QSizePolicy sp_retain = label1->sizePolicy();
sp_retain.setRetainSizeWhenHidden(true);
label1->setSizePolicy(sp_retain);
label1->hide();
QCOMPARE(widget.sizeHint().height(), normalHeight);
// d check that changing the policy to not wanting size will result in lesser size
label1->setSizePolicy(sp_remove);
QCOMPARE(widget.sizeHint().height(), heightWithoutLabel1);
// e verify that changing back the hidden widget to want the hidden size will ensure that it gets more size
label1->setSizePolicy(sp_retain);
QCOMPARE(widget.sizeHint().height(), normalHeight);
}
void tst_QLayout::removeWidget()
{
QHBoxLayout layout;
QCOMPARE(layout.count(), 0);
QWidget w;
layout.addWidget(&w);
QCOMPARE(layout.count(), 1);
layout.removeWidget(&w);
QCOMPARE(layout.count(), 0);
QPointer<QLayout> childLayout(new QHBoxLayout);
layout.addLayout(childLayout);
QCOMPARE(layout.count(), 1);
layout.removeWidget(nullptr);
QCOMPARE(layout.count(), 1);
layout.removeItem(childLayout);
QCOMPARE(layout.count(), 0);
QVERIFY(!childLayout.isNull());
}
QTEST_MAIN(tst_QLayout)
#include "tst_qlayout.moc"

View File

@ -0,0 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qshortcut Test:
#####################################################################
qt_internal_add_test(tst_qshortcut
SOURCES
tst_qshortcut.cpp
INCLUDE_DIRECTORIES
..
LIBRARIES
Qt::Gui
Qt::GuiPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qsizepolicy Test:
#####################################################################
qt_internal_add_test(tst_qsizepolicy
SOURCES
tst_qsizepolicy.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,355 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qsizepolicy.h>
Q_DECLARE_METATYPE(Qt::Orientations)
Q_DECLARE_METATYPE(QSizePolicy)
Q_DECLARE_METATYPE(QSizePolicy::Policy)
Q_DECLARE_METATYPE(QSizePolicy::ControlType)
#include <QTest>
class tst_QSizePolicy : public QObject
{
Q_OBJECT
private Q_SLOTS:
void cleanup() { QVERIFY(QApplication::topLevelWidgets().isEmpty()); }
void qtest();
void constExpr();
void defaultValues();
void getSetCheck_data() { data(); }
void getSetCheck();
void transposed_data() { data(); }
void transposed();
void dataStream();
void horizontalStretch();
void verticalStretch();
void qhash_data() { data(); }
void qhash();
private:
void data() const;
};
struct PrettyPrint {
const char *m_s;
template <typename T>
explicit PrettyPrint(const T &t) : m_s(nullptr)
{
using QT_PREPEND_NAMESPACE(QTest)::toString;
m_s = toString(t);
}
~PrettyPrint() { delete[] m_s; }
const char* s() const { return m_s ? m_s : "<null>" ; }
};
void tst_QSizePolicy::qtest()
{
#define CHECK(x) QCOMPARE(PrettyPrint(QSizePolicy::x).s(), #x)
// Policy:
CHECK(Fixed);
CHECK(Minimum);
CHECK(Ignored);
CHECK(MinimumExpanding);
CHECK(Expanding);
CHECK(Maximum);
CHECK(Preferred);
// ControlType:
CHECK(ButtonBox);
CHECK(CheckBox);
CHECK(ComboBox);
CHECK(Frame);
CHECK(GroupBox);
CHECK(Label);
CHECK(Line);
CHECK(LineEdit);
CHECK(PushButton);
CHECK(RadioButton);
CHECK(Slider);
CHECK(SpinBox);
CHECK(TabWidget);
CHECK(ToolButton);
#undef CHECK
#define CHECK2(x, y) QCOMPARE(PrettyPrint(QSizePolicy::x|QSizePolicy::y).s(), \
QSizePolicy::x < QSizePolicy::y ? #x "|" #y : #y "|" #x)
// ControlTypes (sample)
CHECK2(ButtonBox, CheckBox);
CHECK2(CheckBox, ButtonBox);
CHECK2(ToolButton, Slider);
#undef CHECK2
}
void tst_QSizePolicy::constExpr()
{
/* gcc < 4.8.0 has problems with init'ing variant members in constexpr ctors */
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54922 */
#if !defined(Q_CC_GNU) || defined(Q_CC_CLANG) || Q_CC_GNU >= 408
// check that certain ctors are constexpr (compile-only):
{ constexpr QSizePolicy sp; Q_UNUSED(sp); }
{ constexpr QSizePolicy sp = QSizePolicy(); Q_UNUSED(sp); }
{ constexpr QSizePolicy sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); Q_UNUSED(sp); }
{ constexpr QSizePolicy sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType);
constexpr QSizePolicy tp = sp.transposed(); Q_UNUSED(tp); }
{
// QTBUG-69983: For ControlType != QSizePolicy::DefaultType, qCountTrailingZeroBits()
// is used, which MSVC 15.8.1 does not consider constexpr due to built-ins
# if defined(QT_HAS_CONSTEXPR_BITOPS)
constexpr auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::CheckBox);
# else
constexpr auto sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding, QSizePolicy::DefaultType);
# endif
constexpr auto tp = sp.transposed(); Q_UNUSED(tp);
}
#else
QSKIP("QSizePolicy cannot be constexpr with this version of the compiler.");
#endif
}
void tst_QSizePolicy::defaultValues()
{
{
// check values of a default-constructed QSizePolicy
QSizePolicy sp;
QCOMPARE(sp.horizontalPolicy(), QSizePolicy::Fixed);
QCOMPARE(sp.verticalPolicy(), QSizePolicy::Fixed);
QCOMPARE(sp.horizontalStretch(), 0);
QCOMPARE(sp.verticalStretch(), 0);
QCOMPARE(sp.verticalStretch(), 0);
QCOMPARE(sp.controlType(), QSizePolicy::DefaultType);
QCOMPARE(sp.hasHeightForWidth(), false);
QCOMPARE(sp.hasWidthForHeight(), false);
}
}
#define FETCH_TEST_DATA \
QFETCH(QSizePolicy, sp); \
QFETCH(QSizePolicy::Policy, hp); \
QFETCH(QSizePolicy::Policy, vp); \
QFETCH(int, hst); \
QFETCH(int, vst); \
QFETCH(QSizePolicy::ControlType, ct); \
QFETCH(bool, hfw); \
QFETCH(bool, wfh); \
QFETCH(Qt::Orientations, ed)
// Testing get/set functions
void tst_QSizePolicy::getSetCheck()
{
FETCH_TEST_DATA;
QCOMPARE(QPixmap(), QPixmap());
QCOMPARE(sp.horizontalPolicy(), hp);
QCOMPARE(sp.verticalPolicy(), vp);
QCOMPARE(sp.horizontalStretch(), hst);
QCOMPARE(sp.verticalStretch(), vst);
QCOMPARE(sp.controlType(), ct);
QCOMPARE(sp.hasHeightForWidth(), hfw);
QCOMPARE(sp.hasWidthForHeight(), wfh);
QCOMPARE(sp.expandingDirections(), ed);
}
void tst_QSizePolicy::transposed()
{
FETCH_TEST_DATA;
const QSizePolicy tr = sp.transposed();
QCOMPARE(tr.horizontalPolicy(), vp); // swapped
QCOMPARE(tr.verticalPolicy(), hp); // swapped
QCOMPARE(tr.horizontalStretch(), vst); // swapped
QCOMPARE(tr.verticalStretch(), hst); // swapped
QCOMPARE(tr.controlType(), ct); // not swapped
QCOMPARE(tr.hasHeightForWidth(), hfw); // not swapped (historic behavior)
QCOMPARE(tr.hasWidthForHeight(), wfh); // not swapped (historic behavior)
QCOMPARE(tr.expandingDirections(), ed); // swapped
// destructive test - keep last:
sp.transpose();
QCOMPARE(sp, tr);
}
static void makeRow(QSizePolicy sp, QSizePolicy::Policy hp, QSizePolicy::Policy vp,
int hst, int vst, QSizePolicy::ControlType ct, bool hfw, bool wfh,
Qt::Orientations orients)
{
QTest::addRow("%s-%s-%d-%d-%s-%s-%s",
PrettyPrint(hp).s(), PrettyPrint(vp).s(), hst, vst,
PrettyPrint(ct).s(),
hfw ? "true" : "false", wfh ? "true" : "false")
<< sp << hp << vp << hst << vst << ct << hfw << wfh << orients;
}
void tst_QSizePolicy::data() const
{
QTest::addColumn<QSizePolicy>("sp");
QTest::addColumn<QSizePolicy::Policy>("hp");
QTest::addColumn<QSizePolicy::Policy>("vp");
QTest::addColumn<int>("hst");
QTest::addColumn<int>("vst");
QTest::addColumn<QSizePolicy::ControlType>("ct");
QTest::addColumn<bool>("hfw");
QTest::addColumn<bool>("wfh");
QTest::addColumn<Qt::Orientations>("ed");
{
static const QSizePolicy::Policy policies[3] = {
QSizePolicy::Fixed,
QSizePolicy::Minimum,
QSizePolicy::Ignored
};
static const QSizePolicy::ControlType controlTypes[4] = {
QSizePolicy::DefaultType,
QSizePolicy::ButtonBox,
QSizePolicy::CheckBox,
QSizePolicy::ToolButton
};
#define ITEMCOUNT(arr) int(sizeof(arr)/sizeof(arr[0]))
QSizePolicy sp, oldsp;
#ifdef GENERATE_BASELINE
QFile out(QString::fromAscii("qsizepolicy-Qt%1%2.txt").arg((QT_VERSION >> 16) & 0xff).arg((QT_VERSION) >> 8 & 0xff));
if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QDataStream stream(&out);
#endif
/* Loop for permutating over the values most likely to trigger a bug:
- mininumum, maximum values
- Some values with LSB set, others with MSB unset. (check if shifts are ok)
*/
// Look specifically for
for (int ihp = 0; ihp < ITEMCOUNT(policies); ++ihp) {
QSizePolicy::Policy hp = policies[ihp];
for (int ivp = 0; ivp < ITEMCOUNT(policies); ++ivp) {
QSizePolicy::Policy vp = policies[ivp];
for (int ict = 0; ict < ITEMCOUNT(controlTypes); ++ict) {
QSizePolicy::ControlType ct = controlTypes[ict];
for (int hst= 0; hst <= 255; hst+=85) { //[0,85,170,255]
for (int vst = 0; vst <= 255; vst+=85) {
for (int j = 0; j < 3; ++j) {
bool hfw = j & 1;
bool wfh = j & 2; // cannot set hfw and wfh at the same time
oldsp = sp;
for (int i = 0; i < 5; ++i) {
switch (i) {
case 0: sp.setHorizontalPolicy(hp); break;
case 1: sp.setVerticalPolicy(vp); break;
case 2: sp.setHorizontalStretch(hst); break;
case 3: sp.setVerticalStretch(vst); break;
case 4: sp.setControlType(ct); break;
case 5: sp.setHeightForWidth(hfw); sp.setWidthForHeight(wfh); break;
default: break;
}
Qt::Orientations orients;
if (sp.horizontalPolicy() & QSizePolicy::ExpandFlag)
orients |= Qt::Horizontal;
if (sp.verticalPolicy() & QSizePolicy::ExpandFlag)
orients |= Qt::Vertical;
makeRow(sp,
i >= 0 ? hp : oldsp.horizontalPolicy(),
i >= 1 ? vp : oldsp.verticalPolicy(),
i >= 2 ? hst : oldsp.horizontalStretch(),
i >= 3 ? vst : oldsp.verticalStretch(),
i >= 4 ? ct : oldsp.controlType(),
i >= 5 ? hfw : oldsp.hasHeightForWidth(),
i >= 5 ? wfh : oldsp.hasWidthForHeight(),
orients);
#ifdef GENERATE_BASELINE
stream << sp;
#endif
}
}
}
}
}
}
}
#ifdef GENERATE_BASELINE
out.close();
}
#endif
#undef ITEMCOUNT
}
}
void tst_QSizePolicy::dataStream()
{
QByteArray data;
QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Expanding);
{
QDataStream stream(&data, QIODevice::ReadWrite);
sp.setHorizontalStretch(42);
sp.setVerticalStretch(10);
sp.setControlType(QSizePolicy::CheckBox);
sp.setHeightForWidth(true);
stream << sp; // big endian
/*
| BYTE 0 | BYTE 1 |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| Horizontal stretch | Vertical stretch |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| BYTE 2 | BYTE 3 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| pad | wfh | Control Type | hfw | Vertical policy | Horizontal policy |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
*/
QCOMPARE((char)data[0], char(42)); // h stretch
QCOMPARE((char)data[1], char(10)); // v stretch
QCOMPARE((char)data[2], char(1 | (2 << 1))); // (hfw + CheckBox)
QCOMPARE((char)data[3], char(QSizePolicy::Minimum | (QSizePolicy::Expanding << 4)));
}
{
QSizePolicy readSP;
QDataStream stream(data);
stream >> readSP;
QCOMPARE(sp, readSP);
}
}
void tst_QSizePolicy::horizontalStretch()
{
QSizePolicy sp;
sp.setHorizontalStretch(257);
QCOMPARE(sp.horizontalStretch(), 255);
sp.setHorizontalStretch(-2);
QCOMPARE(sp.horizontalStretch(), 0);
}
void tst_QSizePolicy::verticalStretch()
{
QSizePolicy sp;
sp.setVerticalStretch(-2);
QCOMPARE(sp.verticalStretch(), 0);
sp.setVerticalStretch(257);
QCOMPARE(sp.verticalStretch(), 255);
}
void tst_QSizePolicy::qhash()
{
FETCH_TEST_DATA;
Q_UNUSED(ed);
QSizePolicy sp2(hp, vp, ct);
sp2.setVerticalStretch(vst);
sp2.setHorizontalStretch(hst);
if (hfw) sp2.setHeightForWidth(true);
if (wfh) sp2.setWidthForHeight(true);
QCOMPARE(sp, sp2);
QCOMPARE(qHash(sp), qHash(sp2));
}
#undef FETCH_TEST_DATA
QTEST_MAIN(tst_QSizePolicy)
#include "tst_qsizepolicy.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qstackedlayout Test:
#####################################################################
qt_internal_add_test(tst_qstackedlayout
SOURCES
tst_qstackedlayout.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,359 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QLineEdit>
#include <QLabel>
#include <QStackedLayout>
#include <qapplication.h>
#include <qwidget.h>
#include <QPushButton>
#include <QSignalSpy>
#include <QtWidgets/private/qapplication_p.h>
class tst_QStackedLayout : public QObject
{
Q_OBJECT
public:
tst_QStackedLayout();
private slots:
void init();
void cleanup();
void getSetCheck();
void testCase();
void deleteCurrent();
void removeWidget();
void keepFocusAfterSetCurrent();
void heigthForWidth();
void replaceWidget();
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)
{
}
void tst_QStackedLayout::init()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
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();
QVERIFY(QTest::qWaitForWindowActive(testWidget));
}
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(), nullptr);
QCOMPARE(testLayout->count(), 0);
// One widget added to layout
QWidget *w1 = new QWidget(testWidget);
testLayout->addWidget(w1);
QCOMPARE(spy.size(), 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.size(), 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.size(), 1);
QCOMPARE(spy.at(0).at(0).toInt(), -1);
spy.clear();
QCOMPARE(testLayout->currentIndex(), -1);
QCOMPARE(testLayout->currentWidget(), nullptr);
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(), nullptr);
}
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();
top->activateWindow();
QTRY_COMPARE(QApplication::focusWidget(), top);
// focus should stay at the 'top' widget
testLayout->removeWidget(w1);
QCOMPARE(QApplication::focusWidget(), 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<const QWidget*>(w->focusProxy()) != this
&& w->focusPolicy() & Qt::TabFocus) {
return false;
}
}
return true;
}
void focusInEvent(QFocusEvent *event) override
{
QLineEdit::focusInEvent(event);
hasFakeEditFocus = isSingleFocusWidget();
}
void focusOutEvent(QFocusEvent *event) override
{
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();
QApplicationPrivate::setActiveWindow(testWidget);
QVERIFY(QTest::qWaitForWindowActive(testWidget));
edit1->setFocus();
edit1->activateWindow();
QTRY_VERIFY(edit1->hasFocus());
stackLayout->setCurrentIndex(1);
QVERIFY(!edit1->hasFocus());
QVERIFY(edit2->hasFocus());
QVERIFY(edit2->hasFakeEditFocus);
}
void tst_QStackedLayout::heigthForWidth()
{
if (testWidget->layout()) delete testWidget->layout();
QStackedLayout *stackLayout = new QStackedLayout(testWidget);
QLabel *shortLabel = new QLabel("This is a short text.");
shortLabel->setWordWrap(true);
stackLayout->addWidget(shortLabel);
QLabel *longLabel = new QLabel("Write code once to target multiple platforms\n"
"Qt allows you to write advanced applications and UIs once, "
"and deploy them across desktop and embedded operating systems "
"without rewriting the source code saving time and development cost.\n\n"
"Create amazing user experiences\n"
"Whether you prefer C++ or JavaScript, Qt provides the building blocks - "
"a broad set of customizable widgets, graphics canvas, style engine "
"and more that you need to build modern user interfaces. "
"Incorporate 3D graphics, multimedia audio or video, visual effects, "
"and animations to set your application apart from the competition.");
longLabel->setWordWrap(true);
stackLayout->addWidget(longLabel);
stackLayout->setCurrentIndex(0);
int hfw_index0 = stackLayout->heightForWidth(200);
stackLayout->setCurrentIndex(1);
QCOMPARE(stackLayout->heightForWidth(200), hfw_index0);
}
void tst_QStackedLayout::replaceWidget()
{
QWidget w;
QStackedLayout *stackLayout = new QStackedLayout(&w);
QLineEdit *replaceFrom = new QLineEdit;
QLineEdit *replaceTo = new QLineEdit;
stackLayout->addWidget(new QLineEdit());
stackLayout->addWidget(replaceFrom);
stackLayout->addWidget(new QLineEdit());
stackLayout->setCurrentWidget(replaceFrom);
QCOMPARE(stackLayout->indexOf(replaceFrom), 1);
QCOMPARE(stackLayout->indexOf(replaceTo), -1);
delete stackLayout->replaceWidget(replaceFrom, replaceTo);
QCOMPARE(stackLayout->indexOf(replaceFrom), -1);
QCOMPARE(stackLayout->indexOf(replaceTo), 1);
QCOMPARE(stackLayout->currentWidget(), replaceTo);
}
QTEST_MAIN(tst_QStackedLayout)
#include "tst_qstackedlayout.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtooltip Test:
#####################################################################
qt_internal_add_test(tst_qtooltip
SOURCES
tst_qtooltip.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,217 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QTimer>
#include <qfont.h>
#include <qfontmetrics.h>
#include <qtooltip.h>
#include <qwhatsthis.h>
#include <qscreen.h>
#include <QtWidgets/private/qapplication_p.h>
class tst_QToolTip : public QObject
{
Q_OBJECT
private slots:
void init();
void cleanup();
void keyEvent_data();
void keyEvent();
void whatsThis();
void setPalette();
void qtbug64550_stylesheet();
void dontCrashOutsideScreenGeometry();
};
void tst_QToolTip::init()
{
QVERIFY(!QToolTip::isVisible());
}
void tst_QToolTip::cleanup()
{
QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty());
qApp->setStyleSheet(QString());
}
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr) : QWidget(parent) {}
void showDelayedToolTip(int msecs)
{
QTimer::singleShot(msecs, this, SLOT(showToolTip()));
}
static inline QString toolTipText() { return QStringLiteral("tool tip text"); }
private slots:
void showToolTip()
{
QToolTip::showText(mapToGlobal(QPoint(0, 0)), Widget::toolTipText(), this);
}
};
Q_DECLARE_METATYPE(Qt::Key)
void tst_QToolTip::keyEvent_data()
{
QTest::addColumn<Qt::Key>("key");
QTest::addColumn<bool>("visible");
QTest::newRow("non-modifier") << Qt::Key_A <<
#if defined(Q_OS_MACOS)
// macOS natively hides tooltips on non-modifier key events,
// so QTipLabel::eventFilter does the same. Match that here.
false;
#else
true;
#endif
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::keyEvent()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QFETCH(Qt::Key, key);
QFETCH(bool, visible);
Widget widget;
widget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(50, 50));
// Ensure cursor is not over tooltip, which causes it to hide
#ifndef QT_NO_CURSOR
QCursor::setPos(widget.geometry().topRight() + QPoint(-50, 50));
#endif
widget.setWindowTitle(QLatin1String(QTest::currentTestFunction())
+ QLatin1Char(' ') + QLatin1String(QTest::currentDataTag()));
widget.show();
QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
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);
if (visible)
QToolTip::hideText();
}
static QWidget *findWhatsThat()
{
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
if (widget->inherits("QWhatsThat"))
return widget;
}
return nullptr;
}
void tst_QToolTip::whatsThis()
{
qApp->setStyleSheet( "QWidget { font-size: 72px; }" );
QWhatsThis::showText(QPoint(0, 0), "This is text");
QWidget *whatsthis = nullptr;
QTRY_VERIFY( (whatsthis = findWhatsThat()) );
QVERIFY(whatsthis->isVisible());
const int whatsThisHeight = whatsthis->height();
qApp->setStyleSheet(QString());
QWhatsThis::hideText();
QVERIFY2(whatsThisHeight > 100, QByteArray::number(whatsThisHeight)); // Test QTBUG-2416
}
static QWidget *findToolTip()
{
const QWidgetList &topLevelWidgets = QApplication::topLevelWidgets();
for (QWidget *widget : topLevelWidgets) {
if (widget->windowType() == Qt::ToolTip && widget->objectName() == QLatin1String("qtooltip_label"))
return widget;
}
return nullptr;
}
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 = findToolTip();
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);
QToolTip::hideText();
}
static QByteArray msgSizeTooSmall(const QSize &actual, const QSize &expected)
{
return QByteArray::number(actual.width()) + 'x'
+ QByteArray::number(actual.height()) + " < "
+ QByteArray::number(expected.width()) + 'x'
+ QByteArray::number(expected.height());
}
// QTBUG-4550: When setting a style sheet specifying a font size on the tooltip's
// parent widget (as opposed to setting on QApplication), the tooltip should
// resize accordingly. This is an issue on Windows since the ToolTip widget is
// not directly parented on the widget itself.
// Set a large font size and verify that the tool tip is big enough.
void tst_QToolTip::qtbug64550_stylesheet()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
Widget widget;
widget.setStyleSheet(QStringLiteral("* { font-size: 48pt; }\n"));
widget.show();
QApplicationPrivate::setActiveWindow(&widget);
QVERIFY(QTest::qWaitForWindowActive(&widget));
widget.showDelayedToolTip(100);
QTRY_VERIFY(QToolTip::isVisible());
QWidget *toolTip = findToolTip();
QVERIFY(toolTip);
QTRY_VERIFY(toolTip->isVisible());
const QRect boundingRect = QFontMetrics(widget.font()).boundingRect(Widget::toolTipText());
const QSize toolTipSize = toolTip->size();
QVERIFY2(toolTipSize.width() >= boundingRect.width()
&& toolTipSize.height() >= boundingRect.height(),
msgSizeTooSmall(toolTipSize, boundingRect.size()).constData());
}
void tst_QToolTip::dontCrashOutsideScreenGeometry() {
QToolTip::showText(QPoint(-10000, -10000), "tip outside monitor", nullptr);
QTRY_VERIFY(QToolTip::isVisible());
QToolTip::hideText();
}
QTEST_MAIN(tst_QToolTip)
#include "tst_qtooltip.moc"

View File

@ -0,0 +1,47 @@
[raise]
opensuse-leap
[renderInvisible]
macos
[optimizedResizeMove]
osx
[optimizedResize_topLevel]
osx
[render_windowOpacity]
macos arm
[render_systemClip]
osx
[multipleToplevelFocusCheck]
centos
opensuse-leap
ubuntu
sles-15
# QTBUG-87668
[showMinimizedKeepsFocus]
android
macos-13 ci
[normalGeometry]
android
[saveRestoreGeometry]
android
[optimizedResizeMove]
android
[update]
android
[scroll]
android
[moveChild]
android
[multipleToplevelFocusCheck]
android
[renderInvisible]
android
[updateWhileMinimized]
android
[doubleRepaint]
android
[setMaskInResizeEvent]
android
[activateWindow]
android
[optimizedResize_topLevel]
android

View File

@ -0,0 +1,42 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidget Test:
#####################################################################
# Resources:
set(qwidget_resource_files
"geometry-fullscreen.dat"
"geometry-maximized.dat"
"geometry.dat"
"hellotr_la.qm"
)
qt_internal_add_test(tst_qwidget
SOURCES
tst_qwidget.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
TESTDATA ${qwidget_resource_files}
BUILTIN_TESTDATA
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qwidget CONDITION AIX
COMPILE_OPTIONS
-fpermissive
)
qt_internal_extend_target(tst_qwidget CONDITION WIN32
LIBRARIES
gdi32
user32
)

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
[tst_resize_count]
# QTBUG-66345
opensuse-42.3
ubuntu-16.04
# QTBUG-87412
[tst_move_show]
android
[tst_show_move_hide_show]
android
[tst_resize_show]
android
[tst_show_resize_hide_show]
android
[tst_resize_count]
android
[setWindowState]
android
[mouseMoveWithPopup]
android
# QTBUG-96270
[tst_paintEventOnSecondShow]
opensuse

View File

@ -0,0 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidget_window Test:
#####################################################################
qt_internal_add_test(tst_qwidget_window
SOURCES
tst_qwidget_window.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetaction Test:
#####################################################################
qt_internal_add_test(tst_qwidgetaction
SOURCES
tst_qwidgetaction.cpp
LIBRARIES
Qt::Gui
Qt::TestPrivate
Qt::Widgets
)

View File

@ -0,0 +1,405 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QTimer>
#include <qapplication.h>
#include <qtoolbar.h>
#include <qcombobox.h>
#include <qwidgetaction.h>
#include <qlabel.h>
#include <qmenu.h>
#include <qmainwindow.h>
#include <qmenubar.h>
#include <QtTest/private/qtesthelpers_p.h>
using namespace QTestPrivate;
class tst_QWidgetAction : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanup();
void defaultWidget();
void visibilityUpdate();
void customWidget();
void keepOwnership();
void visibility();
void setEnabled();
void popup();
void releaseWidgetCrash();
};
void tst_QWidgetAction::initTestCase()
{
// Disable menu/combo animations to prevent the alpha widgets from getting in the
// way in popup(), failing the top level leak check in cleanup().
QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false);
QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false);
}
void tst_QWidgetAction::cleanup()
{
QVERIFY(QApplication::topLevelWidgets().isEmpty());
}
void tst_QWidgetAction::defaultWidget()
{
// check that QWidgetAction deals with the widget being deleted before itself:
{
QToolBar tb1;
QComboBox combo(&tb1);
auto action = new QWidgetAction(&tb1);
action->setDefaultWidget(&combo);
tb1.addAction(action);
}
// check that QWidgetAction takes ownership of the widget:
{
QToolBar tb1;
QPointer<QComboBox> 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<QComboBox> 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<QComboBox> combo = new QComboBox(0);
setFrameless(combo.data());
combo->show();
QWidgetAction *action = new QWidgetAction(0);
action->setDefaultWidget(combo);
QVERIFY(action->isVisible());
QVERIFY(!combo->isVisible());
delete action;
}
{
QToolBar tb1;
setFrameless(&tb1);
tb1.show();
QToolBar tb2;
setFrameless(&tb2);
tb2.show();
QPointer<QComboBox> combo = new QComboBox(0);
QWidgetAction *action = new QWidgetAction(0);
action->setDefaultWidget(combo);
tb1.addAction(action);
QCOMPARE(combo->parent(), &tb1);
qApp->processEvents();
qApp->processEvents();
QVERIFY(combo->isVisible());
// not supported, not supposed to work, hence the parent() check
tb2.addAction(action);
QCOMPARE(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();
QCOMPARE(combo->parent(), &tb2);
QVERIFY(combo->isVisible());
tb1.addAction(action);
QCOMPARE(combo->parent(), &tb2);
delete action;
QVERIFY(!combo);
}
{
QWidgetAction *a = new QWidgetAction(0);
QVERIFY(!a->defaultWidget());
QPointer<QComboBox> combo1 = new QComboBox;
a->setDefaultWidget(combo1);
QCOMPARE(a->defaultWidget(), combo1.data());
a->setDefaultWidget(combo1);
QVERIFY(combo1);
QCOMPARE(a->defaultWidget(), combo1.data());
QPointer<QComboBox> combo2 = new QComboBox;
QVERIFY(combo1 != combo2);
a->setDefaultWidget(combo2);
QVERIFY(!combo1);
QCOMPARE(a->defaultWidget(), combo2.data());
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;
setFrameless(&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<QWidget *> createdWidgets() const { return QWidgetAction::createdWidgets(); }
protected:
virtual QWidget *createWidget(QWidget *parent) override;
};
QWidget *ComboAction::createWidget(QWidget *parent)
{
return new QComboBox(parent);
}
void tst_QWidgetAction::customWidget()
{
QToolBar tb1;
setFrameless(&tb1);
tb1.show();
QToolBar tb2;
setFrameless(&tb2);
tb2.show();
ComboAction *action = new ComboAction(0);
tb1.addAction(action);
QList<QWidget *> combos = action->createdWidgets();
QCOMPARE(combos.size(), 1);
QPointer<QComboBox> combo1 = qobject_cast<QComboBox *>(combos.at(0));
QVERIFY(combo1);
tb2.addAction(action);
combos = action->createdWidgets();
QCOMPARE(combos.size(), 2);
QCOMPARE(combos.at(0), combo1.data());
QPointer<QComboBox> combo2 = qobject_cast<QComboBox *>(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<QComboBox> combo = new QComboBox;
QWidgetAction *action = new QWidgetAction(0);
action->setDefaultWidget(combo);
{
QToolBar *tb = new QToolBar;
tb->addAction(action);
QCOMPARE(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;
setFrameless(tb);
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;
setFrameless(tb2);
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;
setFrameless(&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<QLabel> l = new QLabel("test");
QWidgetAction action(0);
action.setDefaultWidget(l);
{
QMenu menu;
menu.addAction(&action);
QTimer::singleShot(100, &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) override {
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"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetmetatype Test:
#####################################################################
qt_internal_add_test(tst_qwidgetmetatype
SOURCES
tst_qwidgetmetatype.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,94 @@
// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qwidget.h>
#include <qlabel.h>
class tst_QWidgetMetaType : public QObject
{
Q_OBJECT
public:
tst_QWidgetMetaType() {}
virtual ~tst_QWidgetMetaType() {}
private slots:
void metaObject();
void saveAndLoadBuiltin_data();
void saveAndLoadBuiltin();
};
class CustomWidget : public QWidget
{
Q_OBJECT
public:
CustomWidget(QWidget *parent = nullptr)
: QWidget(parent)
{
}
};
static_assert(( QMetaTypeId2<QSizePolicy>::IsBuiltIn));
static_assert((!QMetaTypeId2<QWidget*>::IsBuiltIn));
static_assert((!QMetaTypeId2<QList<QSizePolicy> >::IsBuiltIn));
static_assert((!QMetaTypeId2<QMap<QString,QSizePolicy> >::IsBuiltIn));
void tst_QWidgetMetaType::metaObject()
{
QCOMPARE(QMetaType::fromType<QWidget*>().metaObject(), &QWidget::staticMetaObject);
QCOMPARE(QMetaType::fromType<QLabel*>().metaObject(), &QLabel::staticMetaObject);
QCOMPARE(QMetaType::fromType<CustomWidget*>().metaObject(), &CustomWidget::staticMetaObject);
QCOMPARE(QMetaType::fromType<QSizePolicy>().metaObject(), &QSizePolicy::staticMetaObject);
}
template <typename T>
struct StreamingTraits
{
// Streamable by default, as currently all widgets built-in types are streamable
enum { isStreamable = 1 };
};
void tst_QWidgetMetaType::saveAndLoadBuiltin_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<bool>("isStreamable");
#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
QTest::newRow(#RealType) << MetaTypeId << bool(StreamingTraits<RealType>::isStreamable);
QT_FOR_EACH_STATIC_WIDGETS_CLASS(ADD_METATYPE_TEST_ROW)
#undef ADD_METATYPE_TEST_ROW
}
void tst_QWidgetMetaType::saveAndLoadBuiltin()
{
QFETCH(int, type);
QFETCH(bool, isStreamable);
void *value = QMetaType(type).create();
QByteArray ba;
QDataStream stream(&ba, QIODevice::ReadWrite);
QCOMPARE(QMetaType(type).save(stream, value), isStreamable);
QCOMPARE(stream.status(), QDataStream::Ok);
if (isStreamable)
QVERIFY(QMetaType(type).load(stream, value));
stream.device()->seek(0);
stream.resetStatus();
QCOMPARE(QMetaType(type).load(stream, value), isStreamable);
QCOMPARE(stream.status(), QDataStream::Ok);
if (isStreamable)
QVERIFY(QMetaType(type).load(stream, value));
QMetaType(type).destroy(value);
}
QTEST_MAIN(tst_QWidgetMetaType)
#include "tst_qwidgetmetatype.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qwidgetrepaintmanager
SOURCES
tst_qwidgetrepaintmanager.cpp
LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::TestPrivate
Qt::Widgets
Qt::WidgetsPrivate
)

View File

@ -0,0 +1,728 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QPainter>
#include <QScrollArea>
#include <QScrollBar>
#include <QApplication>
#include <private/qhighdpiscaling_p.h>
#include <private/qwidget_p.h>
#include <private/qwidgetrepaintmanager_p.h>
#include <qpa/qplatformbackingstore.h>
//#define MANUAL_DEBUG
class TestWidget : public QWidget
{
public:
TestWidget(QWidget *parent = nullptr)
: QWidget(parent)
{
}
QSize sizeHint() const override
{
const int screenWidth = QGuiApplication::primaryScreen()->geometry().width();
const int width = qMax(200, 100 * ((screenWidth + 500) / 1000));
return isWindow() ? QSize(width, width) : QSize(width - 40, width - 40);
}
void initialShow()
{
show();
if (isWindow()) {
QVERIFY(QTest::qWaitForWindowExposed(this));
QVERIFY(waitForPainted());
}
paintedRegions = {};
}
bool waitForPainted(int timeout = 5000)
{
int remaining = timeout;
QDeadlineTimer deadline(remaining, Qt::PreciseTimer);
if (!QTest::qWaitFor([this]{ return !paintedRegions.isEmpty(); }, timeout))
return false;
// In case of multiple paint events:
// Process events and wait until all have been consumed,
// i.e. paintedRegions no longer changes.
QRegion reg;
while (remaining > 0 && reg != paintedRegions) {
reg = paintedRegions;
QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
if (reg == paintedRegions)
return true;
remaining = int(deadline.remainingTime());
}
return false;
}
QRegion takePaintedRegions()
{
QRegion result = paintedRegions;
paintedRegions = {};
return result;
}
QRegion paintedRegions;
bool event(QEvent *event) override
{
const auto type = event->type();
if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
return true;
return QWidget::event(event);
}
protected:
void paintEvent(QPaintEvent *event) override
{
paintedRegions += event->region();
QPainter painter(this);
const QBrush patternBrush = isWindow() ? QBrush(Qt::blue, Qt::VerPattern)
: QBrush(Qt::red, Qt::HorPattern);
painter.fillRect(rect(), patternBrush);
}
};
class OpaqueWidget : public QWidget
{
public:
OpaqueWidget(const QColor &col, QWidget *parent = nullptr)
: QWidget(parent), fillColor(col)
{
setAttribute(Qt::WA_OpaquePaintEvent);
}
bool event(QEvent *event) override
{
const auto type = event->type();
if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
return true;
return QWidget::event(event);
}
protected:
void paintEvent(QPaintEvent *e) override
{
Q_UNUSED(e);
QPainter painter(this);
fillColor.setBlue(paintCount % 255);
painter.fillRect(e->rect(), fillColor);
#ifdef MANUAL_DEBUG
++paintCount;
painter.drawText(rect(), Qt::AlignCenter, QString::number(paintCount));
#endif
}
private:
QColor fillColor;
int paintCount = 0;
};
class Draggable : public OpaqueWidget
{
public:
Draggable(QWidget *parent = nullptr)
: OpaqueWidget(Qt::white, parent)
{
}
Draggable(const QColor &col, QWidget *parent = nullptr)
: OpaqueWidget(col, parent)
{
left = new OpaqueWidget(Qt::gray, this);
top = new OpaqueWidget(Qt::gray, this);
right = new OpaqueWidget(Qt::gray, this);
bottom = new OpaqueWidget(Qt::gray, this);
}
QSize sizeHint() const override {
return QSize(100, 100);
}
protected:
void resizeEvent(QResizeEvent *) override
{
if (!left)
return;
left->setGeometry(0, 0, 10, height());
top->setGeometry(10, 0, width() - 10, 10);
right->setGeometry(width() - 10, 10, 10, height() - 10);
bottom->setGeometry(10, height() - 10, width() - 10, 10);
}
void mousePressEvent(QMouseEvent *e) override
{
lastPos = e->position().toPoint();
}
void mouseMoveEvent(QMouseEvent *e) override
{
QPoint pos = geometry().topLeft();
pos += e->position().toPoint() - lastPos;
move(pos);
}
void mouseReleaseEvent(QMouseEvent *) override
{
lastPos = {};
}
private:
OpaqueWidget *left = nullptr;
OpaqueWidget *top = nullptr;
OpaqueWidget *right = nullptr;
OpaqueWidget *bottom = nullptr;
QPoint lastPos;
};
class TestScene : public QWidget
{
public:
TestScene()
{
setObjectName("scene");
// opaque because it has an opaque background color and autoFillBackground is set
area = new QWidget(this);
area->setObjectName("area");
area->setAutoFillBackground(true);
QPalette palette;
palette.setColor(QPalette::Window, QColor::fromRgb(0, 0, 0));
area->setPalette(palette);
// all these children set WA_OpaquePaintEvent
redChild = new Draggable(Qt::red, area);
redChild->setObjectName("redChild");
greenChild = new Draggable(Qt::green, area);
greenChild->setObjectName("greenChild");
yellowChild = new Draggable(Qt::yellow, this);
yellowChild->setObjectName("yellowChild");
nakedChild = new Draggable(this);
nakedChild->move(300, 0);
nakedChild->setObjectName("nakedChild");
bar = new OpaqueWidget(Qt::darkGray, this);
bar->setObjectName("bar");
}
QWidget *area;
QWidget *redChild;
QWidget *greenChild;
QWidget *yellowChild;
QWidget *nakedChild;
QWidget *bar;
QSize sizeHint() const override { return QSize(400, 400); }
bool event(QEvent *event) override
{
const auto type = event->type();
if (type == QEvent::WindowActivate || type == QEvent::WindowDeactivate)
return true;
return QWidget::event(event);
}
protected:
void resizeEvent(QResizeEvent *) override
{
area->setGeometry(50, 50, width() - 100, height() - 100);
bar->setGeometry(width() / 2 - 25, height() / 2, 50, height() / 2);
}
};
class tst_QWidgetRepaintManager : public QObject
{
Q_OBJECT
public:
tst_QWidgetRepaintManager();
public slots:
void initTestCase();
void cleanup();
private slots:
void basic();
void children();
void opaqueChildren();
void staticContents();
void scroll();
#if defined(QT_BUILD_INTERNAL)
void scrollWithOverlap();
void overlappedRegion();
void fastMove();
void moveAccross();
void moveInOutOverlapped();
protected:
/*
This helper compares the widget as rendered into the backingstore with the widget
as rendered via QWidget::grab. The latter always produces a fully rendered image,
so differences indicate bugs in QWidgetRepaintManager's or QWidget's painting code.
*/
bool compareWidget(QWidget *w)
{
QBackingStore *backingStore = w->window()->backingStore();
Q_ASSERT(backingStore && backingStore->handle());
QPlatformBackingStore *platformBackingStore = backingStore->handle();
if (!waitForFlush(w)) {
qWarning() << "Widget" << w << "failed to flush";
return false;
}
QImage backingstoreContent = platformBackingStore->toImage();
if (!w->isWindow()) {
const qreal dpr = w->devicePixelRatioF();
const QPointF offset = w->mapTo(w->window(), QPointF(0, 0)) * dpr;
backingstoreContent = backingstoreContent.copy(offset.x(), offset.y(), w->width() * dpr, w->height() * dpr);
}
const QImage widgetRender = w->grab().toImage().convertToFormat(backingstoreContent.format());
const bool result = backingstoreContent == widgetRender;
#ifdef MANUAL_DEBUG
if (!result) {
backingstoreContent.save(QString("/tmp/backingstore_%1_%2.png").arg(QTest::currentTestFunction(), QTest::currentDataTag()));
widgetRender.save(QString("/tmp/grab_%1_%2.png").arg(QTest::currentTestFunction(), QTest::currentDataTag()));
}
#endif
return result;
};
QRegion dirtyRegion(QWidget *widget) const
{
return QWidgetPrivate::get(widget)->dirty;
}
bool waitForFlush(QWidget *widget) const
{
if (!widget)
return true;
auto *repaintManager = QWidgetPrivate::get(widget->window())->maybeRepaintManager();
if (!repaintManager)
return true;
return QTest::qWaitFor([repaintManager]{ return !repaintManager->isDirty(); } );
};
#endif // QT_BUILD_INTERNAL
private:
const int m_fuzz;
bool m_implementsScroll = false;
};
tst_QWidgetRepaintManager::tst_QWidgetRepaintManager() :
m_fuzz(int(QHighDpiScaling::factor(QGuiApplication::primaryScreen())))
{
}
void tst_QWidgetRepaintManager::initTestCase()
{
QWidget widget;
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
m_implementsScroll = widget.backingStore()->handle()->scroll(QRegion(widget.rect()), 1, 1);
qInfo() << QGuiApplication::platformName() << "QPA backend implements scroll:" << m_implementsScroll;
}
void tst_QWidgetRepaintManager::cleanup()
{
QVERIFY(QApplication::topLevelWidgets().isEmpty());
}
void tst_QWidgetRepaintManager::basic()
{
TestWidget widget;
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
widget.update();
QVERIFY(widget.waitForPainted());
QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
widget.repaint();
QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, widget.width(), widget.height()));
}
/*!
Children cannot assumed to be fully opaque, so the parent will repaint when the
child repaints.
*/
void tst_QWidgetRepaintManager::children()
{
if (QStringList{"android"}.contains(QGuiApplication::platformName()))
QSKIP("This test fails on Android");
TestWidget widget;
widget.initialShow();
TestWidget *child1 = new TestWidget(&widget);
child1->move(20, 20);
child1->show();
QVERIFY(QTest::qWaitForWindowExposed(child1));
QVERIFY(child1->waitForPainted());
QCOMPARE(widget.takePaintedRegions(), QRegion(child1->geometry()));
QCOMPARE(child1->takePaintedRegions(), QRegion(child1->rect()));
child1->move(20, 30);
QVERIFY(widget.waitForPainted());
// both the old and the new area covered by child1 need to be repainted
QCOMPARE(widget.takePaintedRegions(), QRegion(20, 20, child1->width(), child1->height() + 10));
QCOMPARE(child1->takePaintedRegions(), QRegion(child1->rect()));
TestWidget *child2 = new TestWidget(&widget);
child2->move(30, 30);
child2->raise();
child2->show();
QVERIFY(child2->waitForPainted());
QCOMPARE(widget.takePaintedRegions(), QRegion(child2->geometry()));
QCOMPARE(child1->takePaintedRegions(), QRegion(10, 0, child2->width() - 10, child2->height()));
QCOMPARE(child2->takePaintedRegions(), QRegion(child2->rect()));
child1->hide();
QVERIFY(widget.waitForPainted());
QCOMPARE(widget.paintedRegions, QRegion(child1->geometry()));
}
void tst_QWidgetRepaintManager::opaqueChildren()
{
if (QStringList{"android"}.contains(QGuiApplication::platformName()))
QSKIP("This test fails on Android");
TestWidget widget;
widget.initialShow();
TestWidget *child1 = new TestWidget(&widget);
child1->move(20, 20);
child1->setAttribute(Qt::WA_OpaquePaintEvent);
child1->show();
QVERIFY(child1->waitForPainted());
QCOMPARE(widget.takePaintedRegions(), QRegion());
QCOMPARE(child1->takePaintedRegions(), child1->rect());
child1->move(20, 30);
QVERIFY(widget.waitForPainted());
QCOMPARE(widget.takePaintedRegions(), QRegion(20, 20, child1->width(), 10));
if (!m_implementsScroll)
QEXPECT_FAIL("", "child1 shouldn't get painted, we can just move the area of the backingstore", Continue);
QCOMPARE(child1->takePaintedRegions(), QRegion());
}
/*!
When resizing to be larger, a widget with Qt::WA_StaticContents set
should only repaint the newly revealed areas.
*/
void tst_QWidgetRepaintManager::staticContents()
{
TestWidget widget;
widget.setAttribute(Qt::WA_StaticContents);
widget.initialShow();
const QSize oldSize = widget.size();
widget.resize(widget.width() + 10, widget.height());
QVERIFY(widget.waitForPainted());
QEXPECT_FAIL("", "This should just repaint the newly exposed region", Continue);
QCOMPARE(widget.takePaintedRegions(), QRegion(oldSize.width(), 0, 10, widget.height()));
}
/*!
Scrolling a widget.
*/
void tst_QWidgetRepaintManager::scroll()
{
if (QStringList{"android"}.contains(QGuiApplication::platformName()))
QSKIP("This test fails on Android");
TestWidget widget;
widget.initialShow();
widget.scroll(10, 0);
QVERIFY(widget.waitForPainted());
if (!m_implementsScroll)
QEXPECT_FAIL("", "This should just repaint the newly exposed region", Continue);
QCOMPARE(widget.takePaintedRegions(), QRegion(0, 0, 10, widget.height()));
TestWidget *child = new TestWidget(&widget);
child->move(20, 20);
child->initialShow();
// a potentially semi-transparent child scrolling needs a full repaint
child->scroll(10, 0);
QVERIFY(child->waitForPainted());
QCOMPARE(child->takePaintedRegions(), child->rect());
QCOMPARE(widget.takePaintedRegions(), child->geometry());
// a explicitly opaque child scrolling only needs the child to repaint newly exposed regions
child->setAttribute(Qt::WA_OpaquePaintEvent);
child->scroll(10, 0);
QVERIFY(child->waitForPainted());
if (!m_implementsScroll)
QEXPECT_FAIL("", "This should just repaint the newly exposed region", Continue);
QCOMPARE(child->takePaintedRegions(), QRegion(0, 0, 10, child->height()));
QCOMPARE(widget.takePaintedRegions(), QRegion());
}
#if defined(QT_BUILD_INTERNAL)
/*!
Verify that overlapping children are repainted correctly when
a widget is moved (via a scroll area) for such a distance that
none of the old area is still visible. QTBUG-26269
*/
void tst_QWidgetRepaintManager::scrollWithOverlap()
{
if (QStringList{"android"}.contains(QGuiApplication::platformName()))
QSKIP("This test fails on Android");
class MainWindow : public QWidget
{
public:
MainWindow(QWidget *parent = 0)
: QWidget(parent, Qt::WindowStaysOnTopHint)
{
m_scrollArea = new QScrollArea(this);
QWidget *w = new QWidget;
w->setPalette(QPalette(Qt::gray));
w->setAutoFillBackground(true);
m_scrollArea->setWidget(w);
m_scrollArea->resize(500, 100);
w->resize(5000, 600);
m_topWidget = new QWidget(this);
m_topWidget->setPalette(QPalette(Qt::red));
m_topWidget->setAutoFillBackground(true);
m_topWidget->resize(300, 200);
resize(600, 300);
}
void resizeEvent(QResizeEvent *e) override
{
QWidget::resizeEvent(e);
// move scroll area and top widget to the center of the main window
scrollArea()->move((width() - scrollArea()->width()) / 2, (height() - scrollArea()->height()) / 2);
topWidget()->move((width() - topWidget()->width()) / 2, (height() - topWidget()->height()) / 2);
}
inline QScrollArea *scrollArea() const { return m_scrollArea; }
inline QWidget *topWidget() const { return m_topWidget; }
private:
QScrollArea *m_scrollArea;
QWidget *m_topWidget;
};
MainWindow w;
w.show();
QVERIFY(QTest::qWaitForWindowActive(&w));
bool result = compareWidget(w.topWidget());
// if this fails already, then the system we test on can't compare screenshots from grabbed widgets,
// and we have to skip this test. Possible reasons are differences in surface formats or DPI, or
// unrelated bugs in QPlatformBackingStore::toImage or QWidget::grab.
if (!result)
QSKIP("Cannot compare QWidget::grab with QScreen::grabWindow on this machine");
// scroll the horizontal slider to the right side
{
w.scrollArea()->horizontalScrollBar()->setValue(w.scrollArea()->horizontalScrollBar()->maximum());
QVERIFY(compareWidget(w.topWidget()));
}
// scroll the vertical slider down
{
w.scrollArea()->verticalScrollBar()->setValue(w.scrollArea()->verticalScrollBar()->maximum());
QVERIFY(compareWidget(w.topWidget()));
}
// hide the top widget
{
w.topWidget()->hide();
QVERIFY(compareWidget(w.scrollArea()->viewport()));
}
// scroll the horizontal slider to the left side
{
w.scrollArea()->horizontalScrollBar()->setValue(w.scrollArea()->horizontalScrollBar()->minimum());
QVERIFY(compareWidget(w.scrollArea()->viewport()));
}
// scroll the vertical slider up
{
w.scrollArea()->verticalScrollBar()->setValue(w.scrollArea()->verticalScrollBar()->minimum());
QVERIFY(compareWidget(w.scrollArea()->viewport()));
}
}
/*!
This tests QWidgetPrivate::overlappedRegion, which however is only used in the
QWidgetRepaintManager, so the test is here.
*/
void tst_QWidgetRepaintManager::overlappedRegion()
{
TestScene scene;
if (scene.screen()->availableSize().width() < scene.sizeHint().width()
|| scene.screen()->availableSize().height() < scene.sizeHint().height()) {
QSKIP("The screen on this system is too small for this test");
}
scene.show();
QVERIFY(QTest::qWaitForWindowExposed(&scene));
auto overlappedRegion = [](QWidget *widget, bool breakAfterFirst = false){
auto *priv = QWidgetPrivate::get(widget);
// overlappedRegion works on parent coordinates (crect, i.e. QWidget::geometry)
return priv->overlappedRegion(widget->geometry(), breakAfterFirst);
};
// the yellow child is not overlapped
QVERIFY(overlappedRegion(scene.yellowChild).isEmpty());
// the green child is partially overlapped by the yellow child, which
// is at position -50, -50 relative to the green child (and 100x100 large)
QRegion overlap = overlappedRegion(scene.greenChild);
QVERIFY(!overlap.isEmpty());
QCOMPARE(overlap, QRegion(QRect(-50, -50, 100, 100)));
// the red child is completely obscured by the green child, and partially
// obscured by the yellow child. How exactly this is divided into rects is
// irrelevant for the test.
overlap = overlappedRegion(scene.redChild);
QVERIFY(!overlap.isEmpty());
QCOMPARE(overlap.boundingRect(), QRect(-50, -50, 150, 150));
// moving the red child out of obscurity
scene.redChild->move(100, 0);
overlap = overlappedRegion(scene.redChild);
QTRY_VERIFY(overlap.isEmpty());
// moving the red child down so it's partially behind the bar
scene.redChild->move(100, 100);
overlap = overlappedRegion(scene.redChild);
QTRY_VERIFY(!overlap.isEmpty());
// moving the yellow child so it is partially overlapped by the bar
scene.yellowChild->move(200, 200);
overlap = overlappedRegion(scene.yellowChild);
QTRY_VERIFY(!overlap.isEmpty());
}
void tst_QWidgetRepaintManager::fastMove()
{
TestScene scene;
scene.show();
QVERIFY(QTest::qWaitForWindowExposed(&scene));
QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
QVERIFY(repaintManager->dirtyRegion().isEmpty());
// moving yellow; nothing obscured
scene.yellowChild->move(QPoint(25, 0));
QVERIFY(repaintManager->dirtyRegion().isEmpty()); // fast move
if (m_implementsScroll) {
QCOMPARE(repaintManager->dirtyWidgetList(), QList<QWidget *>() << &scene);
QVERIFY(dirtyRegion(scene.yellowChild).isEmpty());
} else {
QCOMPARE(repaintManager->dirtyWidgetList(), QList<QWidget *>() << scene.yellowChild << &scene);
QCOMPARE(dirtyRegion(scene.yellowChild), QRect(0, 0, 100, 100));
}
QCOMPARE(dirtyRegion(&scene), QRect(0, 0, 25, 100));
QTRY_VERIFY(dirtyRegion(&scene).isEmpty());
QVERIFY(compareWidget(&scene));
}
void tst_QWidgetRepaintManager::moveAccross()
{
TestScene scene;
scene.show();
QVERIFY(QTest::qWaitForWindowExposed(&scene));
QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
QVERIFY(repaintManager->dirtyRegion().isEmpty());
for (int i = 0; i < 4; ++i) {
scene.greenChild->move(scene.greenChild->pos() + QPoint(25, 0));
waitForFlush(&scene);
}
QVERIFY(compareWidget(&scene));
for (int i = 0; i < 16; ++i) {
scene.redChild->move(scene.redChild->pos() + QPoint(25, 0));
waitForFlush(&scene);
}
QVERIFY(compareWidget(&scene));
for (int i = 0; i < qMin(scene.area->width(), scene.area->height()); i += 25) {
scene.yellowChild->move(scene.yellowChild->pos() + QPoint(25, 25));
waitForFlush(&scene);
}
QVERIFY(compareWidget(&scene));
}
void tst_QWidgetRepaintManager::moveInOutOverlapped()
{
TestScene scene;
scene.show();
QVERIFY(QTest::qWaitForWindowExposed(&scene));
QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(&scene)->maybeRepaintManager();
QVERIFY(repaintManager->dirtyRegion().isEmpty());
// yellow out
scene.yellowChild->move(QPoint(-100, 0));
QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid dest rect
QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
QVERIFY(waitForFlush(&scene));
QVERIFY(compareWidget(&scene));
// yellow in, obscured by bar
scene.yellowChild->move(QPoint(scene.width() / 2, scene.height() / 2));
QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid source rect
QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
QVERIFY(waitForFlush(&scene));
QVERIFY(compareWidget(&scene));
// green out
scene.greenChild->move(QPoint(-100, 0));
QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid dest rect
QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
QVERIFY(waitForFlush(&scene));
QVERIFY(compareWidget(&scene));
// green back in, obscured by bar
scene.greenChild->move(QPoint(scene.area->width() / 2 - 50, scene.area->height() / 2 - 50));
QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // invalid source rect
QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
QVERIFY(waitForFlush(&scene));
QVERIFY(compareWidget(&scene));
// red back under green
scene.redChild->move(scene.greenChild->pos());
QVERIFY(!repaintManager->dirtyRegion().isEmpty()); // destination rect obscured
QVERIFY(repaintManager->dirtyWidgetList().isEmpty());
QVERIFY(waitForFlush(&scene));
QVERIFY(compareWidget(&scene));
}
#endif //# defined(QT_BUILD_INTERNAL)
QTEST_MAIN(tst_QWidgetRepaintManager)
#include "tst_qwidgetrepaintmanager.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwidgetsvariant Test:
#####################################################################
qt_internal_add_test(tst_qwidgetsvariant
SOURCES
tst_qwidgetsvariant.cpp
INCLUDE_DIRECTORIES
../../../other/qvariant_common
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>stream/qt4.9/</file>
<file>stream/qt5.0/</file>
</qresource>
</RCC>

View File

@ -0,0 +1,241 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qvariant.h>
#include "tst_qvariant_common.h"
class tst_QWidgetsVariant : public QObject
{
Q_OBJECT
private slots:
void constructor_invalid_data();
void constructor_invalid();
void canConvert_data();
void canConvert();
void writeToReadFromDataStream_data();
void writeToReadFromDataStream();
void qvariant_cast_QObject_data();
void qvariant_cast_QObject();
void qvariant_cast_QObject_derived();
void debugStream_data();
void debugStream();
void implicitConstruction();
void widgetsVariantAtExit();
};
void tst_QWidgetsVariant::constructor_invalid_data()
{
QTest::addColumn<uint>("typeId");
QTest::newRow("LastGuiType + 1") << uint(QMetaType::LastGuiType + 1);
QVERIFY(!QMetaType::isRegistered(QMetaType::LastGuiType + 1));
QTest::newRow("LastWidgetsType + 1") << uint(QMetaType::LastWidgetsType + 1);
QVERIFY(!QMetaType::isRegistered(QMetaType::LastWidgetsType + 1));
}
void tst_QWidgetsVariant::constructor_invalid()
{
QFETCH(uint, typeId);
{
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type, type id:"));
QVariant variant{QMetaType(typeId)};
QVERIFY(!variant.isValid());
QCOMPARE(variant.userType(), int(QMetaType::UnknownType));
}
{
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("^Trying to construct an instance of an invalid type, type id:"));
QVariant variant(QMetaType(typeId), nullptr);
QVERIFY(!variant.isValid());
QCOMPARE(variant.userType(), int(QMetaType::UnknownType));
}
}
void tst_QWidgetsVariant::canConvert_data()
{
TST_QVARIANT_CANCONVERT_DATATABLE_HEADERS
#ifdef Y
#undef Y
#endif
#ifdef N
#undef N
#endif
#define Y true
#define N false
QVariant var;
// bita bitm bool brsh byta col curs date dt dbl font img int inv kseq list ll map pal pen pix pnt rect reg size sp str strl time uint ull
var = QVariant::fromValue(QSizePolicy());
QTest::newRow("SizePolicy")
<< var << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << N << Y << N << N << N << N << N;
#undef N
#undef Y
}
void tst_QWidgetsVariant::canConvert()
{
TST_QVARIANT_CANCONVERT_FETCH_DATA
TST_QVARIANT_CANCONVERT_COMPARE_DATA
}
void tst_QWidgetsVariant::writeToReadFromDataStream_data()
{
QTest::addColumn<QVariant>("writeVariant");
QTest::addColumn<bool>("isNull");
QTest::newRow( "sizepolicy_valid" ) << QVariant::fromValue( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ) << false;
}
void tst_QWidgetsVariant::writeToReadFromDataStream()
{
QFETCH( QVariant, writeVariant );
QFETCH( bool, isNull );
QByteArray data;
QDataStream writeStream( &data, QIODevice::WriteOnly );
writeStream << writeVariant;
QVariant readVariant;
QDataStream readStream( &data, QIODevice::ReadOnly );
readStream >> readVariant;
QVERIFY( readVariant.isNull() == isNull );
}
class CustomQWidget : public QWidget {
Q_OBJECT
public:
CustomQWidget(QWidget *parent = nullptr) : QWidget(parent) {}
};
void tst_QWidgetsVariant::qvariant_cast_QObject_data()
{
QTest::addColumn<QVariant>("data");
QTest::addColumn<bool>("success");
QWidget *widget = new QWidget;
widget->setObjectName(QString::fromLatin1("Hello"));
QTest::newRow("from QWidget") << QVariant::fromValue(widget) << true;
CustomQWidget *customWidget = new CustomQWidget;
customWidget->setObjectName(QString::fromLatin1("Hello"));
QTest::newRow("from Derived QWidget") << QVariant::fromValue(customWidget) << true;
}
void tst_QWidgetsVariant::qvariant_cast_QObject()
{
QFETCH(QVariant, data);
QFETCH(bool, success);
QObject *o = qvariant_cast<QObject *>(data);
QCOMPARE(o != 0, success);
if (success) {
QCOMPARE(o->objectName(), QString::fromLatin1("Hello"));
QVERIFY(data.canConvert<QObject*>());
QVERIFY(data.canConvert(QMetaType(QMetaType::QObjectStar)));
QVERIFY(data.canConvert(QMetaType::fromType<QObject*>()));
QVERIFY(data.value<QObject*>());
QVERIFY(data.convert(QMetaType(QMetaType::QObjectStar)));
QCOMPARE(data.metaType().id(), int(QMetaType::QObjectStar));
QVERIFY(data.canConvert<QWidget*>());
QVERIFY(data.canConvert(QMetaType::fromType<QWidget*>()));
QVERIFY(data.value<QWidget*>());
QVERIFY(data.convert(QMetaType::fromType<QWidget*>()));
QCOMPARE(data.metaType(), QMetaType::fromType<QWidget*>());
} else {
QVERIFY(!data.canConvert<QObject*>());
QVERIFY(!data.canConvert(QMetaType(QMetaType::QObjectStar)));
QVERIFY(!data.canConvert(QMetaType::fromType<QObject*>()));
QVERIFY(!data.value<QObject*>());
QVERIFY(!data.convert(QMetaType(QMetaType::QObjectStar)));
QVERIFY(data.metaType().id() != QMetaType::QObjectStar);
}
delete o;
}
void tst_QWidgetsVariant::qvariant_cast_QObject_derived()
{
CustomQWidget customWidget;
QWidget *widget = &customWidget;
QVariant data = QVariant::fromValue(widget);
QCOMPARE(data.userType(), qMetaTypeId<QWidget*>());
QCOMPARE(data.value<QObject*>(), widget);
QCOMPARE(data.value<QWidget*>(), widget);
QCOMPARE(data.value<CustomQWidget*>(), widget);
}
void tst_QWidgetsVariant::debugStream_data()
{
QTest::addColumn<QVariant>("variant");
QTest::addColumn<int>("typeId");
for (int id = QMetaType::LastGuiType + 1; id < QMetaType::User; ++id) {
const char *tagName = QMetaType(id).name();
if (!tagName)
continue;
QTest::newRow(tagName) << QVariant(QMetaType(id)) << id;
}
}
void tst_QWidgetsVariant::debugStream()
{
QFETCH(QVariant, variant);
QFETCH(int, typeId);
MessageHandler msgHandler(typeId);
qDebug() << variant;
QVERIFY(msgHandler.testPassed());
}
void tst_QWidgetsVariant::widgetsVariantAtExit()
{
// crash test, it should not crash at QApplication exit
static QVariant sizePolicy = QSizePolicy();
Q_UNUSED(sizePolicy);
QVERIFY(true);
}
void tst_QWidgetsVariant::implicitConstruction()
{
// This is a compile-time test
QVariant v;
#define FOR_EACH_WIDGETS_CLASS(F) \
F(SizePolicy) \
#define CONSTRUCT(TYPE) \
{ \
Q##TYPE t; \
v = t; \
QVERIFY(true); \
}
FOR_EACH_WIDGETS_CLASS(CONSTRUCT)
#undef CONSTRUCT
#undef FOR_EACH_WIDGETS_CLASS
}
QTEST_MAIN(tst_QWidgetsVariant)
#include "tst_qwidgetsvariant.moc"

View File

@ -0,0 +1,5 @@
# QTBUG-87413
[testActivation]
android
[testAncestorChange]
android

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qwindowcontainer Test:
#####################################################################
qt_internal_add_test(tst_qwindowcontainer
SOURCES
tst_qwindowcontainer.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
)

View File

@ -0,0 +1,415 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qapplication.h>
#include <qwindow.h>
#include <qwidget.h>
#include <qdockwidget.h>
#include <qmainwindow.h>
#include <qscreen.h>
#include <qscopedpointer.h>
#include <qevent.h>
class Window : public QWindow
{
public:
Window()
: numberOfExposes(0)
, numberOfObscures(0)
{
}
void exposeEvent(QExposeEvent *) override
{
if (isExposed())
++numberOfExposes;
else
++numberOfObscures;
}
int numberOfExposes;
int numberOfObscures;
};
class tst_QWindowContainer: public QObject
{
Q_OBJECT
public:
tst_QWindowContainer() : m_availableGeometry(QGuiApplication::primaryScreen()->availableGeometry()) {}
private slots:
void testShow();
void testPositionAndSize();
void testExposeObscure();
void testOwnership();
void testBehindTheScenesDeletion();
void testUnparenting();
void testReparenting();
void testUnparentReparent();
void testActivation();
void testAncestorChange();
void testDockWidget();
void testNativeContainerParent();
void testPlatformSurfaceEvent();
void cleanup();
private:
const QRect m_availableGeometry;
};
void tst_QWindowContainer::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
}
void tst_QWindowContainer::testShow()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QWidget root;
root.setWindowTitle(QTest::currentTestFunction());
root.setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 400, 400);
Window *window = new Window();
QWidget *container = QWidget::createWindowContainer(window, &root);
container->setGeometry(50, 50, 200, 200);
root.show();
QVERIFY(QTest::qWaitForWindowExposed(window));
}
void tst_QWindowContainer::testPositionAndSize()
{
QWindow *window = new QWindow();
window->setGeometry(m_availableGeometry.x() + 300, m_availableGeometry.y() + 400, 500, 600);
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window));
container->setWindowTitle(QTest::currentTestFunction());
container->setGeometry(50, 50, 200, 200);
container->show();
QVERIFY(QTest::qWaitForWindowExposed(container.data()));
QCOMPARE(window->x(), 0);
QCOMPARE(window->y(), 0);
QCOMPARE(window->width(), container->width());
QCOMPARE(window->height(), container->height());
}
void tst_QWindowContainer::testExposeObscure()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
Window *window = new Window();
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window));
container->setWindowTitle(QTest::currentTestFunction());
container->setGeometry(m_availableGeometry.x() + 50, m_availableGeometry.y() + 50, 200, 200);
container->show();
QVERIFY(QTest::qWaitForWindowExposed(container.data()));
QVERIFY(QTest::qWaitForWindowExposed(window));
QVERIFY(window->numberOfExposes > 0);
container->hide();
QTRY_VERIFY(window->numberOfObscures > 0);
}
void tst_QWindowContainer::testOwnership()
{
QPointer<QWindow> window(new QWindow());
QWidget *container = QWidget::createWindowContainer(window);
delete container;
QCOMPARE(window.data(), nullptr);
}
void tst_QWindowContainer::testBehindTheScenesDeletion()
{
QWindow *window = new QWindow();
QWidget *container = QWidget::createWindowContainer(window);
delete window;
// The child got removed, showing not should not have any side effects,
// such as for instance, crashing...
container->show();
QVERIFY(QTest::qWaitForWindowExposed(container));
delete container;
}
void tst_QWindowContainer::testActivation()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QWidget root;
root.setWindowTitle(QTest::currentTestFunction());
QWindow *window = new QWindow();
QWidget *container = QWidget::createWindowContainer(window, &root);
container->setGeometry(100, 100, 200, 100);
root.setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 400, 300);
root.show();
root.activateWindow();
QVERIFY(QTest::qWaitForWindowExposed(&root));
QVERIFY(QTest::qWaitForWindowActive(root.windowHandle()));
QCOMPARE(QGuiApplication::focusWindow(), root.windowHandle());
// Verify that all states in the root widget indicate it is active
QVERIFY(root.windowHandle()->isActive());
QVERIFY(root.isActiveWindow());
QCOMPARE(root.palette().currentColorGroup(), QPalette::Active);
// Under KDE (ubuntu 12.10), we experience that doing two activateWindow in a row
// does not work. The second gets ignored by the window manager, even though the
// timestamp in the xcb connection is unique for both.
if (!QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive))
QTest::qWait(100);
window->requestActivate();
QTRY_COMPARE(QGuiApplication::focusWindow(), window);
// Verify that all states in the root widget still indicate it is active
QVERIFY(root.windowHandle()->isActive());
QVERIFY(root.isActiveWindow());
QCOMPARE(root.palette().currentColorGroup(), QPalette::Active);
}
void tst_QWindowContainer::testUnparenting()
{
QPointer<QWindow> window(new QWindow());
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window));
container->setWindowTitle(QTest::currentTestFunction());
container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100);
window->setParent(nullptr);
container->show();
QVERIFY(QTest::qWaitForWindowExposed(container.data()));
// Window should not be made visible by container..
QVERIFY(!window->isVisible());
container.reset();
QVERIFY(window);
delete window;
}
void tst_QWindowContainer::testReparenting()
{
QPointer<QWindow> window1(new QWindow());
QScopedPointer<QWindow> window2(new QWindow());
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window1));
window1->setParent(window2.data());
// Not deleted with container
container.reset();
QVERIFY(window1);
// but deleted with new parent
window2.reset();
QVERIFY(!window1);
}
void tst_QWindowContainer::testUnparentReparent()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QWidget root;
QWindow *window = new QWindow();
QScopedPointer<QWidget> container(QWidget::createWindowContainer(window, &root));
container->setWindowTitle(QTest::currentTestFunction());
container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100);
root.show();
QVERIFY(QTest::qWaitForWindowExposed(&root));
QTRY_VERIFY(window->isVisible());
container->setParent(nullptr);
QTRY_VERIFY(!window->isVisible());
container->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
QTRY_VERIFY(window->isVisible());
container->setParent(&root); // This should not crash (QTBUG-63168)
}
void tst_QWindowContainer::testAncestorChange()
{
QWidget root;
root.setWindowTitle(QStringLiteral("Root ") + QTest::currentTestFunction());
QWidget *left = new QWidget(&root);
QWidget *right = new QWidget(&root);
root.setGeometry(m_availableGeometry.x() + 50, m_availableGeometry.y() + 50, 200, 100);
left->setGeometry(0, 0, 100, 100);
right->setGeometry(100, 0, 100, 100);
QWindow *window = new QWindow();
QWidget *container = QWidget::createWindowContainer(window, left);
container->setGeometry(0, 0, 100, 100);
// Root
// + left
// | + container
// | + window
// + right
root.show();
QVERIFY(QTest::qWaitForWindowExposed(&root));
QCOMPARE(window->geometry(), QRect(0, 0, 100, 100));
container->setParent(right);
// Root
// + left
// + right
// + container
// + window
QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
QWidget *newRoot = new QWidget(&root);
newRoot->setWindowTitle(QStringLiteral("newRoot ") + QTest::currentTestFunction());
newRoot->setGeometry(50, 50, 200, 200);
right->setParent(newRoot);
// Root
// + left
// + newRoot
// + right
// + container
// + window
QCOMPARE(window->geometry(), QRect(150, 50, 100, 100));
newRoot->move(0, 0);
QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
newRoot->setParent(0);
QScopedPointer<QWidget> newRootGuard(newRoot);
newRoot->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 200);
newRoot->show();
QVERIFY(QTest::qWaitForWindowExposed(newRoot));
QCOMPARE(newRoot->windowHandle(), window->parent());
// newRoot
// + right
// + container
// + window
QCOMPARE(window->geometry(), QRect(100, 0, 100, 100));
}
void tst_QWindowContainer::testDockWidget()
{
QMainWindow mainWindow;
mainWindow.setWindowTitle(QTest::currentTestFunction());
mainWindow.resize(200, 200);
mainWindow.move(m_availableGeometry.center() - QPoint(100, 100));
QDockWidget *dock = new QDockWidget(QStringLiteral("Dock ") + QTest::currentTestFunction());
QWindow *window = new QWindow();
QWidget *container = QWidget::createWindowContainer(window);
dock->setWidget(container);
mainWindow.addDockWidget(Qt::RightDockWidgetArea, dock);
mainWindow.show();
QVERIFY(QTest::qWaitForWindowExposed(&mainWindow));
QCOMPARE(window->parent(), mainWindow.window()->windowHandle());
dock->setFloating(true);
QTRY_VERIFY(window->parent() != mainWindow.window()->windowHandle());
dock->setFloating(false);
QTRY_COMPARE(window->parent(), mainWindow.window()->windowHandle());
}
void tst_QWindowContainer::testNativeContainerParent()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
QSKIP("Wayland: This fails. Figure out why.");
QWidget root;
root.setWindowTitle(QTest::currentTestFunction());
root.setGeometry(m_availableGeometry.x() + 50, m_availableGeometry.y() + 50, 200, 200);
Window *window = new Window();
QWidget *container = QWidget::createWindowContainer(window, &root);
container->setAttribute(Qt::WA_NativeWindow);
container->setGeometry(50, 50, 150, 150);
root.show();
QVERIFY(QTest::qWaitForWindowExposed(window));
QTRY_COMPARE(window->parent(), container->windowHandle());
}
class EventWindow : public QWindow
{
public:
EventWindow(bool *surfaceDestroyFlag) : m_surfaceDestroyFlag(surfaceDestroyFlag) { }
bool event(QEvent *e) override;
private:
bool *m_surfaceDestroyFlag;
};
bool EventWindow::event(QEvent *e)
{
if (e->type() == QEvent::PlatformSurface) {
if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
*m_surfaceDestroyFlag = true;
}
return QWindow::event(e);
}
void tst_QWindowContainer::testPlatformSurfaceEvent()
{
// Verify that SurfaceAboutToBeDestroyed is delivered and the
// window subclass still gets a chance to process it.
bool ok = false;
QPointer<EventWindow> window(new EventWindow(&ok));
window->create();
QWidget *container = QWidget::createWindowContainer(window);
delete container;
QCOMPARE(window.data(), nullptr);
QVERIFY(ok);
}
QTEST_MAIN(tst_QWindowContainer)
#include "tst_qwindowcontainer.moc"