mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 23:35:28 +08:00
qt 6.5.1 original
This commit is contained in:
28
tests/auto/widgets/kernel/CMakeLists.txt
Normal file
28
tests/auto/widgets/kernel/CMakeLists.txt
Normal 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()
|
17
tests/auto/widgets/kernel/qaction/CMakeLists.txt
Normal file
17
tests/auto/widgets/kernel/qaction/CMakeLists.txt
Normal 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
|
||||
)
|
478
tests/auto/widgets/kernel/qaction/tst_qaction.cpp
Normal file
478
tests/auto/widgets/kernel/qaction/tst_qaction.cpp
Normal 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"
|
14
tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt
Normal file
14
tests/auto/widgets/kernel/qactiongroup/CMakeLists.txt
Normal 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
|
||||
)
|
56
tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp
Normal file
56
tests/auto/widgets/kernel/qactiongroup/tst_qactiongroup.cpp
Normal 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"
|
7
tests/auto/widgets/kernel/qapplication/BLACKLIST
Normal file
7
tests/auto/widgets/kernel/qapplication/BLACKLIST
Normal file
@ -0,0 +1,7 @@
|
||||
[sendEventsOnProcessEvents]
|
||||
ubuntu-20.04
|
||||
ubuntu-22.04
|
||||
rhel-9.0
|
||||
[touchEventPropagation]
|
||||
# QTBUG-66745
|
||||
opensuse-leap
|
11
tests/auto/widgets/kernel/qapplication/CMakeLists.txt
Normal file
11
tests/auto/widgets/kernel/qapplication/CMakeLists.txt
Normal 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
|
||||
)
|
3
tests/auto/widgets/kernel/qapplication/customstyle.json
Normal file
3
tests/auto/widgets/kernel/qapplication/customstyle.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"Keys": [ "customstyle" ]
|
||||
}
|
@ -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:
|
||||
#####################################################################
|
@ -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;
|
||||
}
|
55
tests/auto/widgets/kernel/qapplication/heart.svg
Normal file
55
tests/auto/widgets/kernel/qapplication/heart.svg
Normal 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 |
20
tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt
Normal file
20
tests/auto/widgets/kernel/qapplication/modal/CMakeLists.txt
Normal 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:
|
||||
#####################################################################
|
24
tests/auto/widgets/kernel/qapplication/modal/base.cpp
Normal file
24
tests/auto/widgets/kernel/qapplication/modal/base.cpp
Normal 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;
|
||||
}
|
24
tests/auto/widgets/kernel/qapplication/modal/base.h
Normal file
24
tests/auto/widgets/kernel/qapplication/modal/base.h
Normal 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
|
13
tests/auto/widgets/kernel/qapplication/modal/main.cpp
Normal file
13
tests/auto/widgets/kernel/qapplication/modal/main.cpp
Normal 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();
|
||||
}
|
21
tests/auto/widgets/kernel/qapplication/test/BLACKLIST
Normal file
21
tests/auto/widgets/kernel/qapplication/test/BLACKLIST
Normal 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
|
31
tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt
Normal file
31
tests/auto/widgets/kernel/qapplication/test/CMakeLists.txt
Normal 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
|
||||
)
|
3
tests/auto/widgets/kernel/qapplication/tmp/README
Normal file
3
tests/auto/widgets/kernel/qapplication/tmp/README
Normal 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...
|
2696
tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
Normal file
2696
tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
Normal file
File diff suppressed because it is too large
Load Diff
15
tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt
Normal file
15
tests/auto/widgets/kernel/qboxlayout/CMakeLists.txt
Normal 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
|
||||
)
|
579
tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp
Normal file
579
tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp
Normal 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"
|
0
tests/auto/widgets/kernel/qformlayout/BLACKLIST
Normal file
0
tests/auto/widgets/kernel/qformlayout/BLACKLIST
Normal file
16
tests/auto/widgets/kernel/qformlayout/CMakeLists.txt
Normal file
16
tests/auto/widgets/kernel/qformlayout/CMakeLists.txt
Normal 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
|
||||
)
|
1477
tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp
Normal file
1477
tests/auto/widgets/kernel/qformlayout/tst_qformlayout.cpp
Normal file
File diff suppressed because it is too large
Load Diff
16
tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt
Normal file
16
tests/auto/widgets/kernel/qgesturerecognizer/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
3
tests/auto/widgets/kernel/qgridlayout/BLACKLIST
Normal file
3
tests/auto/widgets/kernel/qgridlayout/BLACKLIST
Normal file
@ -0,0 +1,3 @@
|
||||
# QTBUG-87404
|
||||
[minMaxSize]
|
||||
android
|
21
tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt
Normal file
21
tests/auto/widgets/kernel/qgridlayout/CMakeLists.txt
Normal 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
|
||||
)
|
135
tests/auto/widgets/kernel/qgridlayout/sortdialog.ui
Normal file
135
tests/auto/widgets/kernel/qgridlayout/sortdialog.ui
Normal 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>&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>
|
1760
tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp
Normal file
1760
tests/auto/widgets/kernel/qgridlayout/tst_qgridlayout.cpp
Normal file
File diff suppressed because it is too large
Load Diff
23
tests/auto/widgets/kernel/qlayout/CMakeLists.txt
Normal file
23
tests/auto/widgets/kernel/qlayout/CMakeLists.txt
Normal 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}
|
||||
)
|
1792
tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize
Normal file
1792
tests/auto/widgets/kernel/qlayout/baseline/smartmaxsize
Normal file
File diff suppressed because it is too large
Load Diff
401
tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp
Normal file
401
tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp
Normal 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"
|
18
tests/auto/widgets/kernel/qshortcut/CMakeLists.txt
Normal file
18
tests/auto/widgets/kernel/qshortcut/CMakeLists.txt
Normal 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
|
||||
)
|
1362
tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
Normal file
1362
tests/auto/widgets/kernel/qshortcut/tst_qshortcut.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt
Normal file
18
tests/auto/widgets/kernel/qsizepolicy/CMakeLists.txt
Normal 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:
|
||||
#####################################################################
|
355
tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
Normal file
355
tests/auto/widgets/kernel/qsizepolicy/tst_qsizepolicy.cpp
Normal 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"
|
15
tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt
Normal file
15
tests/auto/widgets/kernel/qstackedlayout/CMakeLists.txt
Normal 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
|
||||
)
|
359
tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
Normal file
359
tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp
Normal 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"
|
||||
|
15
tests/auto/widgets/kernel/qtooltip/CMakeLists.txt
Normal file
15
tests/auto/widgets/kernel/qtooltip/CMakeLists.txt
Normal 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
|
||||
)
|
217
tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
Normal file
217
tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp
Normal 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"
|
47
tests/auto/widgets/kernel/qwidget/BLACKLIST
Normal file
47
tests/auto/widgets/kernel/qwidget/BLACKLIST
Normal 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
|
42
tests/auto/widgets/kernel/qwidget/CMakeLists.txt
Normal file
42
tests/auto/widgets/kernel/qwidget/CMakeLists.txt
Normal 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
|
||||
)
|
BIN
tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat
Normal file
BIN
tests/auto/widgets/kernel/qwidget/geometry-fullscreen.dat
Normal file
Binary file not shown.
BIN
tests/auto/widgets/kernel/qwidget/geometry-maximized.dat
Normal file
BIN
tests/auto/widgets/kernel/qwidget/geometry-maximized.dat
Normal file
Binary file not shown.
BIN
tests/auto/widgets/kernel/qwidget/geometry.dat
Normal file
BIN
tests/auto/widgets/kernel/qwidget/geometry.dat
Normal file
Binary file not shown.
BIN
tests/auto/widgets/kernel/qwidget/hellotr_la.qm
Normal file
BIN
tests/auto/widgets/kernel/qwidget/hellotr_la.qm
Normal file
Binary file not shown.
13369
tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
Normal file
13369
tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
22
tests/auto/widgets/kernel/qwidget_window/BLACKLIST
Normal file
22
tests/auto/widgets/kernel/qwidget_window/BLACKLIST
Normal 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
|
18
tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt
Normal file
18
tests/auto/widgets/kernel/qwidget_window/CMakeLists.txt
Normal 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
|
||||
)
|
1676
tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
Normal file
1676
tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp
Normal file
File diff suppressed because it is too large
Load Diff
15
tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt
Normal file
15
tests/auto/widgets/kernel/qwidgetaction/CMakeLists.txt
Normal 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
|
||||
)
|
405
tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp
Normal file
405
tests/auto/widgets/kernel/qwidgetaction/tst_qwidgetaction.cpp
Normal 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"
|
14
tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt
Normal file
14
tests/auto/widgets/kernel/qwidgetmetatype/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
@ -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
|
||||
)
|
@ -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"
|
16
tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt
Normal file
16
tests/auto/widgets/kernel/qwidgetsvariant/CMakeLists.txt
Normal 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
|
||||
)
|
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>stream/qt4.9/</file>
|
||||
<file>stream/qt5.0/</file>
|
||||
</qresource>
|
||||
</RCC>
|
Binary file not shown.
Binary file not shown.
@ -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"
|
5
tests/auto/widgets/kernel/qwindowcontainer/BLACKLIST
Normal file
5
tests/auto/widgets/kernel/qwindowcontainer/BLACKLIST
Normal file
@ -0,0 +1,5 @@
|
||||
# QTBUG-87413
|
||||
[testActivation]
|
||||
android
|
||||
[testAncestorChange]
|
||||
android
|
14
tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt
Normal file
14
tests/auto/widgets/kernel/qwindowcontainer/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
Reference in New Issue
Block a user