summaryrefslogtreecommitdiffstats
path: root/tests/auto/widgets/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/widgets/widgets')
-rw-r--r--tests/auto/widgets/widgets/CMakeLists.txt2
-rw-r--r--tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp2
-rw-r--r--tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp55
-rw-r--r--tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp2
-rw-r--r--tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp2
-rw-r--r--tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp2
-rw-r--r--tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp2
-rw-r--r--tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp48
-rw-r--r--tests/auto/widgets/widgets/qcombobox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp222
-rw-r--r--tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp2
-rw-r--r--tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp150
-rw-r--r--tests/auto/widgets/widgets/qdial/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qdial/tst_qdial.cpp12
-rw-r--r--tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt7
-rw-r--r--tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp159
-rw-r--r--tests/auto/widgets/widgets/qdockwidget/BLACKLIST33
-rw-r--r--tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp345
-rw-r--r--tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp2
-rw-r--r--tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp2
-rw-r--r--tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp2
-rw-r--r--tests/auto/widgets/widgets/qframe/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qframe/tst_qframe.cpp2
-rw-r--r--tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp8
-rw-r--r--tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp2
-rw-r--r--tests/auto/widgets/widgets/qlabel/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp41
-rw-r--r--tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp2
-rw-r--r--tests/auto/widgets/widgets/qlineedit/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp166
-rw-r--r--tests/auto/widgets/widgets/qmainwindow/BLACKLIST2
-rw-r--r--tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp125
-rw-r--r--tests/auto/widgets/widgets/qmdiarea/BLACKLIST8
-rw-r--r--tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp65
-rw-r--r--tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp11
-rw-r--r--tests/auto/widgets/widgets/qmenu/BLACKLIST1
-rw-r--r--tests/auto/widgets/widgets/qmenu/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp90
-rw-r--r--tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm2
-rw-r--r--tests/auto/widgets/widgets/qmenubar/BLACKLIST6
-rw-r--r--tests/auto/widgets/widgets/qmenubar/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp201
-rw-r--r--tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm2
-rw-r--r--tests/auto/widgets/widgets/qopenglwidget/BLACKLIST3
-rw-r--r--tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp69
-rw-r--r--tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp23
-rw-r--r--tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp2
-rw-r--r--tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp50
-rw-r--r--tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp2
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/CMakeLists.txt25
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/data/simple.frag8
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/data/simple.frag.qsbbin0 -> 724 bytes
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/data/simple.vert8
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/data/simple.vert.qsbbin0 -> 783 bytes
-rw-r--r--tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp834
-rw-r--r--tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp2
-rw-r--r--tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp2
-rw-r--r--tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp2
-rw-r--r--tests/auto/widgets/widgets/qslider/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qslider/tst_qslider.cpp2
-rw-r--r--tests/auto/widgets/widgets/qspinbox/BLACKLIST2
-rw-r--r--tests/auto/widgets/widgets/qspinbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp6
-rw-r--r--tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp20
-rw-r--r--tests/auto/widgets/widgets/qsplitter/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp4
-rw-r--r--tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp2
-rw-r--r--tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp2
-rw-r--r--tests/auto/widgets/widgets/qtabbar/BLACKLIST2
-rw-r--r--tests/auto/widgets/widgets/qtabbar/CMakeLists.txt7
-rw-r--r--tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp252
-rw-r--r--tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp66
-rw-r--r--tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp2
-rw-r--r--tests/auto/widgets/widgets/qtextedit/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp23
-rw-r--r--tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp2
-rw-r--r--tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp2
-rw-r--r--tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt6
-rw-r--r--tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp20
113 files changed, 2969 insertions, 536 deletions
diff --git a/tests/auto/widgets/widgets/CMakeLists.txt b/tests/auto/widgets/widgets/CMakeLists.txt
index 8fe11d09ac..eb44f3d103 100644
--- a/tests/auto/widgets/widgets/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/CMakeLists.txt
@@ -29,6 +29,7 @@ add_subdirectory(qscrollbar)
add_subdirectory(qsizegrip)
add_subdirectory(qslider)
add_subdirectory(qspinbox)
+add_subdirectory(qsplashscreen)
add_subdirectory(qsplitter)
add_subdirectory(qstackedwidget)
add_subdirectory(qstatusbar)
@@ -58,3 +59,4 @@ endif()
if(QT_FEATURE_opengl)
add_subdirectory(qopenglwidget)
endif()
+add_subdirectory(qrhiwidget)
diff --git a/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt
index 327edc6868..883614fc04 100644
--- a/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qabstractbutton Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qabstractbutton LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qabstractbutton
SOURCES
tst_qabstractbutton.cpp
diff --git a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
index c2bcbe73f5..dc5c42513c 100644
--- a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
+++ b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt
index 34272b3375..ac1d8ad54a 100644
--- a/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qabstractscrollarea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qabstractscrollarea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qabstractscrollarea
SOURCES
tst_qabstractscrollarea.cpp
diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp
index 86c42a6522..fa1f799855 100644
--- a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp
+++ b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -13,6 +13,7 @@
#include <qwidget.h>
#include <qdialog.h>
#include <qscroller.h>
+#include <qstyle.h>
class tst_QAbstractScrollArea : public QObject
{
@@ -34,6 +35,7 @@ private slots:
void margins();
void resizeWithOvershoot();
+ void sizeHint();
};
tst_QAbstractScrollArea::tst_QAbstractScrollArea()
@@ -408,5 +410,56 @@ void tst_QAbstractScrollArea::resizeWithOvershoot()
QTRY_COMPARE(scrollArea.viewport()->pos(), originAtRest);
}
+void tst_QAbstractScrollArea::sizeHint()
+{
+ class ScrollArea : public QAbstractScrollArea
+ {
+ public:
+ QSize viewportSizeHint() const override { return {200, 200}; }
+ } scrollArea;
+ // We cannot reliable test the impact of the scrollbars on the size hint
+ // if the style uses transient scrollbars, so use the class Windows style.
+ const QString defaultStyle = QApplication::style()->name();
+ QApplication::setStyle("Windows");
+ auto resetStyle = qScopeGuard([defaultStyle]{
+ QApplication::setStyle(defaultStyle);
+ });
+ scrollArea.setFrameShape(QFrame::NoFrame);
+ scrollArea.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+ scrollArea.show();
+
+ QSize sizeHint = scrollArea.sizeHint();
+ QCOMPARE(sizeHint, scrollArea.viewportSizeHint());
+
+ scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ const QSize sizeHintWithScrollBars = scrollArea.sizeHint();
+ QTRY_COMPARE_GT(sizeHintWithScrollBars.width(), sizeHint.width());
+ QTRY_COMPARE_GT(sizeHintWithScrollBars.height(), sizeHint.height());
+
+ sizeHint = scrollArea.sizeHint();
+
+ // whether the scroll area itself is visible or not should not influence
+ // the size hint
+ scrollArea.hide();
+ QCOMPARE(scrollArea.sizeHint(), sizeHint);
+ scrollArea.show();
+ QCOMPARE(scrollArea.sizeHint(), sizeHint);
+
+ scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ QCOMPARE(scrollArea.sizeHint(), scrollArea.viewportSizeHint());
+
+ scrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ scrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+
+ scrollArea.verticalScrollBar()->setRange(0, 1);
+ scrollArea.horizontalScrollBar()->setRange(0, 1);
+ scrollArea.resize(sizeHint / 2);
+ QApplication::processEvents(); // trigger lazy layout process
+ QCOMPARE(scrollArea.sizeHint(), sizeHintWithScrollBars);
+}
+
QTEST_MAIN(tst_QAbstractScrollArea)
#include "tst_qabstractscrollarea.moc"
diff --git a/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt
index 8d1c7d5afe..711c73931d 100644
--- a/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qabstractslider Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qabstractslider LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qabstractslider
SOURCES
tst_qabstractslider.cpp
diff --git a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp
index 170c29922a..9be41ad799 100644
--- a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp
+++ b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt
index f692c6b162..adaef01601 100644
--- a/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qabstractspinbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qabstractspinbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qabstractspinbox
SOURCES
tst_qabstractspinbox.cpp
diff --git a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp
index 6c3eaa5e9c..00d0fdaf94 100644
--- a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp
+++ b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt b/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt
index 6b3492930d..b58775d2ff 100644
--- a/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qbuttongroup Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbuttongroup LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qbuttongroup
SOURCES
tst_qbuttongroup.cpp
diff --git a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
index 7ab2868e9a..06d2435601 100644
--- a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
+++ b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt
index a1608d6bbc..5140c37e94 100644
--- a/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qcalendarwidget Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcalendarwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qcalendarwidget
SOURCES
tst_qcalendarwidget.cpp
diff --git a/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp b/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp
index 2fd9d1b48d..ca5cc06e99 100644
--- a/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp
+++ b/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt b/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt
index b0cb425de8..9e3f0e9874 100644
--- a/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qcheckbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcheckbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qcheckbox
SOURCES
tst_qcheckbox.cpp
diff --git a/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp b/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp
index 9055b13901..42eb81d3c7 100644
--- a/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp
+++ b/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -16,6 +16,7 @@ private slots:
void initTestCase();
void setChecked();
+ void setCheckedSignal();
void setTriState();
void setText_data();
void setText();
@@ -25,7 +26,7 @@ private slots:
void toggle();
void pressed();
void toggled();
- void stateChanged();
+ void checkStateChanged();
void foregroundRole();
void minimumSizeHint();
};
@@ -59,6 +60,25 @@ void tst_QCheckBox::setChecked()
QVERIFY(!testWidget.isChecked());
}
+void tst_QCheckBox::setCheckedSignal()
+{
+ QCheckBox testWidget;
+ testWidget.setCheckState(Qt::Unchecked);
+ QSignalSpy checkStateChangedSpy(&testWidget, &QCheckBox::checkStateChanged);
+ testWidget.setCheckState(Qt::Checked);
+ testWidget.setCheckState(Qt::Checked);
+ QTRY_COMPARE(checkStateChangedSpy.size(), 1); // get signal only once
+ QCOMPARE(testWidget.checkState(), Qt::Checked);
+ testWidget.setCheckState(Qt::Unchecked);
+ testWidget.setCheckState(Qt::Unchecked);
+ QTRY_COMPARE(checkStateChangedSpy.size(), 2); // get signal only once
+ QCOMPARE(testWidget.checkState(), Qt::Unchecked);
+ testWidget.setCheckState(Qt::PartiallyChecked);
+ testWidget.setCheckState(Qt::PartiallyChecked);
+ QTRY_COMPARE(checkStateChangedSpy.size(), 3); // get signal only once
+ QCOMPARE(testWidget.checkState(), Qt::PartiallyChecked);
+}
+
void tst_QCheckBox::setTriState()
{
QCheckBox testWidget;
@@ -188,35 +208,49 @@ void tst_QCheckBox::toggled()
QCOMPARE(click_count, 0);
}
-void tst_QCheckBox::stateChanged()
+void tst_QCheckBox::checkStateChanged()
{
QCheckBox testWidget;
QCOMPARE(testWidget.checkState(), Qt::Unchecked);
Qt::CheckState cur_state = Qt::Unchecked;
+ QSignalSpy checkStateChangedSpy(&testWidget, &QCheckBox::checkStateChanged);
+#if QT_DEPRECATED_SINCE(6, 9)
+ QT_IGNORE_DEPRECATIONS(
QSignalSpy stateChangedSpy(&testWidget, &QCheckBox::stateChanged);
- connect(&testWidget, &QCheckBox::stateChanged, this, [&](auto state) { cur_state = Qt::CheckState(state); });
+ )
+#endif
+ connect(&testWidget, &QCheckBox::checkStateChanged, this, [&](auto state) { cur_state = state; });
testWidget.setChecked(true);
- QVERIFY(QTest::qWaitFor([&]() { return stateChangedSpy.size() == 1; }));
+ QTRY_COMPARE(checkStateChangedSpy.size(), 1);
+#if QT_DEPRECATED_SINCE(6, 9)
QCOMPARE(stateChangedSpy.size(), 1);
+#endif
QCOMPARE(cur_state, Qt::Checked);
QCOMPARE(testWidget.checkState(), Qt::Checked);
testWidget.setChecked(false);
- QVERIFY(QTest::qWaitFor([&]() { return stateChangedSpy.size() == 2; }));
+ QTRY_COMPARE(checkStateChangedSpy.size(), 2);
+#if QT_DEPRECATED_SINCE(6, 9)
QCOMPARE(stateChangedSpy.size(), 2);
+#endif
QCOMPARE(cur_state, Qt::Unchecked);
QCOMPARE(testWidget.checkState(), Qt::Unchecked);
testWidget.setCheckState(Qt::PartiallyChecked);
- QVERIFY(QTest::qWaitFor([&]() { return stateChangedSpy.size() == 3; }));
+ QTRY_COMPARE(checkStateChangedSpy.size(), 3);
+#if QT_DEPRECATED_SINCE(6, 9)
QCOMPARE(stateChangedSpy.size(), 3);
+#endif
QCOMPARE(cur_state, Qt::PartiallyChecked);
QCOMPARE(testWidget.checkState(), Qt::PartiallyChecked);
testWidget.setCheckState(Qt::PartiallyChecked);
QCoreApplication::processEvents();
+ QCOMPARE(checkStateChangedSpy.size(), 3);
+#if QT_DEPRECATED_SINCE(6, 9)
QCOMPARE(stateChangedSpy.size(), 3);
+#endif
}
void tst_QCheckBox::isToggleButton()
diff --git a/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt b/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt
index c52beca6ae..87ac247b24 100644
--- a/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qcombobox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcombobox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
list(APPEND test_data "qtlogo.png")
list(APPEND test_data "qtlogoinverted.png")
diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
index 245c4c8ca4..dc6ef789d7 100644
--- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
+++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
@@ -42,11 +42,13 @@
#include <qstandarditemmodel.h>
#include <qproxystyle.h>
#include <qfont.h>
+#include <qstylehints.h>
#include "../../../shared/platforminputcontext.h"
#include <private/qinputmethod_p.h>
#include <QtTest/private/qtesthelpers_p.h>
+#include <QtTest/private/qemulationdetector_p.h>
#include <QtWidgets/private/qapplication_p.h>
@@ -109,6 +111,7 @@ private slots:
#ifndef QT_NO_STYLE_FUSION
void task190351_layout();
void task191329_size();
+ void popupPositionAfterStyleChange();
#endif
void task166349_setEditableOnReturn();
void task190205_setModelAdjustToContents();
@@ -152,6 +155,7 @@ private slots:
void buttonPressKeys();
void clearModel();
void cancelClosesPopupNotDialog();
+ void closePopupWithCheckableItems();
private:
PlatformInputContext m_platformInputContext;
@@ -1283,11 +1287,12 @@ void tst_QComboBox::insertItem_data()
initialItems << "foo" << "bar";
for(int e = 0 ; e<2 ; e++) {
bool editable = (e==0);
- QTest::newRow("Insert less then 0") << initialItems << -1 << "inserted" << 0 << editable;
- QTest::newRow("Insert at 0") << initialItems << 0 << "inserted" << 0 << editable;
- QTest::newRow("Insert beyond count") << initialItems << 3 << "inserted" << 2 << editable;
- QTest::newRow("Insert at count") << initialItems << 2 << "inserted" << 2 << editable;
- QTest::newRow("Insert in the middle") << initialItems << 1 << "inserted" << 1 << editable;
+ const auto txt = editable ? QByteArray("editable: ") : QByteArray("non-editable: ");
+ QTest::newRow(txt + "Insert less then 0") << initialItems << -1 << "inserted" << 0 << editable;
+ QTest::newRow(txt + "Insert at 0") << initialItems << 0 << "inserted" << 0 << editable;
+ QTest::newRow(txt + "Insert beyond count") << initialItems << 3 << "inserted" << 2 << editable;
+ QTest::newRow(txt + "Insert at count") << initialItems << 2 << "inserted" << 2 << editable;
+ QTest::newRow(txt + "Insert in the middle") << initialItems << 1 << "inserted" << 1 << editable;
}
}
@@ -1502,42 +1507,70 @@ void tst_QComboBox::currentTextChanged()
testWidget->addItems(QStringList() << "foo" << "bar");
QCOMPARE(testWidget->count(), 2);
- QSignalSpy spy(testWidget, SIGNAL(currentTextChanged(QString)));
+ QSignalSpy textChangedSpy(testWidget, &QComboBox::currentTextChanged);
testWidget->setEditable(editable);
// set text in list
testWidget->setCurrentIndex(0);
QCOMPARE(testWidget->currentIndex(), 0);
- spy.clear();
+ textChangedSpy.clear();
testWidget->setCurrentText(QString("bar"));
- QCOMPARE(spy.size(), 1);
- QCOMPARE(qvariant_cast<QString>(spy.at(0).at(0)), QString("bar"));
+ QCOMPARE(textChangedSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QString>(textChangedSpy.at(0).at(0)), QString("bar"));
// set text not in list
testWidget->setCurrentIndex(0);
QCOMPARE(testWidget->currentIndex(), 0);
- spy.clear();
+ textChangedSpy.clear();
testWidget->setCurrentText(QString("qt"));
if (editable) {
- QCOMPARE(spy.size(), 1);
- QCOMPARE(qvariant_cast<QString>(spy.at(0).at(0)), QString("qt"));
+ QCOMPARE(textChangedSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QString>(textChangedSpy.at(0).at(0)), QString("qt"));
} else {
- QCOMPARE(spy.size(), 0);
+ QCOMPARE(textChangedSpy.size(), 0);
}
// item changed
testWidget->setCurrentIndex(0);
QCOMPARE(testWidget->currentIndex(), 0);
- spy.clear();
+ textChangedSpy.clear();
testWidget->setItemText(0, QString("ape"));
- QCOMPARE(spy.size(), 1);
- QCOMPARE(qvariant_cast<QString>(spy.at(0).at(0)), QString("ape"));
+ QCOMPARE(textChangedSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QString>(textChangedSpy.at(0).at(0)), QString("ape"));
+
// change it back
- spy.clear();
+ textChangedSpy.clear();
testWidget->setItemText(0, QString("foo"));
- QCOMPARE(spy.size(), 1);
- QCOMPARE(qvariant_cast<QString>(spy.at(0).at(0)), QString("foo"));
+ QCOMPARE(textChangedSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QString>(textChangedSpy.at(0).at(0)), QString("foo"));
+
+ // currentIndexChanged vs. currentTextChanged
+ testWidget->clear();
+ testWidget->addItems(QStringList() << "first" << "second" << "third" << "fourth" << "fourth");
+ testWidget->setCurrentIndex(4);
+ textChangedSpy.clear();
+ QSignalSpy indexChangedSpy(testWidget, &QComboBox::currentIndexChanged);
+
+ // Index change w/o text change
+ testWidget->removeItem(3);
+ QCOMPARE(textChangedSpy.count(), 0);
+ QCOMPARE(indexChangedSpy.count(), 1);
+
+ // Index and text change
+ testWidget->setCurrentIndex(0);
+ QCOMPARE(textChangedSpy.count(), 1);
+ QCOMPARE(indexChangedSpy.count(), 2);
+
+ // remove item above current index
+ testWidget->removeItem(2);
+ QCOMPARE(textChangedSpy.count(), 1);
+ QCOMPARE(indexChangedSpy.count(), 2);
+
+ // Text change w/o index change
+ testWidget->setItemText(0, "first class");
+ QCOMPARE(textChangedSpy.count(), 2);
+ QCOMPARE(indexChangedSpy.count(), 2);
}
void tst_QComboBox::editTextChanged()
@@ -1989,7 +2022,7 @@ void tst_QComboBox::flaggedItems_data()
disableFlagList << 1;
keyMovementList.clear();
keyMovementList << Qt::Key_T << Qt::Key_Enter;
- QTest::newRow(testCase.toLatin1() + "disabled") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
+ QTest::newRow(testCase.toLatin1() + "disabled with key") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
QTest::newRow(testCase.toLatin1() + "broken autocompletion") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
}
}
@@ -2001,8 +2034,8 @@ void tst_QComboBox::flaggedItems()
QSKIP("Wayland: This fails. Figure out why.");
QFETCH(QStringList, itemList);
- QFETCH(IntList, deselectFlagList);
- QFETCH(IntList, disableFlagList);
+ QFETCH(const IntList, deselectFlagList);
+ QFETCH(const IntList, disableFlagList);
QFETCH(KeyList, keyMovementList);
QFETCH(bool, editable);
QFETCH(int, expectedIndex);
@@ -2013,10 +2046,10 @@ void tst_QComboBox::flaggedItems()
listWidget.addItems(itemList);
comboBox.setEditable(editable);
- foreach (int index, deselectFlagList)
+ for (int index : deselectFlagList)
listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsSelectable);
- foreach (int index, disableFlagList)
+ for (int index : disableFlagList)
listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsEnabled);
comboBox.setModel(listWidget.model());
@@ -2099,7 +2132,7 @@ void tst_QComboBox::mouseWheel_data()
void tst_QComboBox::mouseWheel()
{
- QFETCH(IntList, disabledItems);
+ QFETCH(const IntList, disabledItems);
QFETCH(int, startIndex);
QFETCH(int, wheelDirection);
QFETCH(int, expectedIndex);
@@ -2114,7 +2147,7 @@ void tst_QComboBox::mouseWheel()
QListWidget listWidget;
listWidget.addItems(list);
- foreach (int index, disabledItems)
+ for (int index : disabledItems)
listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsEnabled);
box.setModel(listWidget.model());
@@ -2248,11 +2281,11 @@ void tst_QComboBox::separatorItem_data()
void tst_QComboBox::separatorItem()
{
QFETCH(QStringList, items);
- QFETCH(IntList, separators);
+ QFETCH(const IntList, separators);
QComboBox box;
box.addItems(items);
- foreach(int index, separators)
+ for (int index : separators)
box.insertSeparator(index);
QCOMPARE(box.count(), (items.size() + separators.size()));
for (int i = 0, s = 0; i < box.count(); ++i) {
@@ -2373,7 +2406,8 @@ void tst_QComboBox::task191329_size()
QFrame *container = tableCombo.findChild<QComboBoxPrivateContainer *>();
QVERIFY(container);
QCOMPARE(static_cast<QAbstractItemView *>(table), container->findChild<QAbstractItemView *>());
- foreach (QWidget *button, container->findChildren<QComboBoxPrivateScroller *>()) {
+ const auto buttons = container->findChildren<QComboBoxPrivateScroller *>();
+ for (QWidget *button : buttons) {
//the popup should be large enough to contains everithing so the top and left button are hidden
QVERIFY(!button->isVisible());
}
@@ -3172,31 +3206,55 @@ void tst_QComboBox::task_QTBUG_54191_slotOnEditTextChangedSetsComboBoxToReadOnly
QCOMPARE(cb.currentIndex(), 1);
}
+class ComboBox : public QComboBox {
+public:
+ using QComboBox::QComboBox;
+
+ void keyPressEvent(QKeyEvent *e) override
+ {
+ QComboBox::keyPressEvent(e);
+ accepted = e->isAccepted();
+ }
+ bool accepted = false;
+};
+
void tst_QComboBox::keyboardSelection()
{
- QComboBox comboBox;
+ ComboBox comboBox;
const int keyboardInterval = QApplication::keyboardInputInterval();
- QStringList list;
- list << "OA" << "OB" << "OC" << "OO" << "OP" << "PP";
+ const QStringList list = {"OA", "OB", "OC", "OO", "OP", "PP"};
comboBox.addItems(list);
// Clear any remaining keyboard input from previous tests.
QTest::qWait(keyboardInterval);
QTest::keyClicks(&comboBox, "oo", Qt::NoModifier, 50);
QCOMPARE(comboBox.currentText(), list.at(3));
+ QCOMPARE(comboBox.accepted, true);
QTest::qWait(keyboardInterval);
QTest::keyClicks(&comboBox, "op", Qt::NoModifier, 50);
QCOMPARE(comboBox.currentText(), list.at(4));
+ QCOMPARE(comboBox.accepted, true);
QTest::keyClick(&comboBox, Qt::Key_P, Qt::NoModifier, keyboardInterval);
QCOMPARE(comboBox.currentText(), list.at(5));
+ QCOMPARE(comboBox.accepted, true);
QTest::keyClick(&comboBox, Qt::Key_O, Qt::NoModifier, keyboardInterval);
QCOMPARE(comboBox.currentText(), list.at(0));
+ QCOMPARE(comboBox.accepted, true);
QTest::keyClick(&comboBox, Qt::Key_O, Qt::NoModifier, keyboardInterval);
QCOMPARE(comboBox.currentText(), list.at(1));
+ QCOMPARE(comboBox.accepted, true);
+
+ QTest::keyClick(&comboBox, Qt::Key_Tab, Qt::NoModifier, keyboardInterval);
+ QCOMPARE(comboBox.currentText(), list.at(1));
+ QCOMPARE(comboBox.accepted, false);
+
+ QTest::keyClick(&comboBox, Qt::Key_Tab, Qt::ControlModifier, keyboardInterval);
+ QCOMPARE(comboBox.currentText(), list.at(1));
+ QCOMPARE(comboBox.accepted, false);
}
void tst_QComboBox::updateDelegateOnEditableChange()
@@ -3273,10 +3331,10 @@ void tst_QComboBox::task_QTBUG_49831_scrollerNotActivated()
QVERIFY(container);
QVERIFY(QTest::qWaitForWindowExposed(container));
- QList<QComboBoxPrivateScroller *> scrollers = container->findChildren<QComboBoxPrivateScroller *>();
+ const QList<QComboBoxPrivateScroller *> scrollers = container->findChildren<QComboBoxPrivateScroller *>();
// Not all styles support scrollers. We rely only on those platforms that do to catch any regression.
if (!scrollers.isEmpty()) {
- Q_FOREACH (QComboBoxPrivateScroller *scroller, scrollers) {
+ for (QComboBoxPrivateScroller *scroller : scrollers) {
if (scroller->isVisible()) {
QSignalSpy doScrollSpy(scroller, SIGNAL(doScroll(int)));
QTest::mouseMove(scroller, QPoint(5, 5), 500);
@@ -3358,6 +3416,65 @@ void tst_QComboBox::task_QTBUG_56693_itemFontFromModel()
box.hidePopup();
}
+#ifndef QT_NO_STYLE_FUSION
+void tst_QComboBox::popupPositionAfterStyleChange()
+{
+#ifdef Q_OS_QNX
+ QSKIP("Fails on QNX, QTBUG-123798");
+#endif
+ // Check that the popup opens up centered on top of the current
+ // index if the style has changed since the last time it was
+ // opened (QTBUG-113765).
+ QComboBox box;
+ QStyleOptionComboBox opt;
+ const bool usePopup = qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, &box);
+ if (!usePopup)
+ QSKIP("This test is only relevant for styles that centers the popup on top of the combo!");
+ if (QTestPrivate::isRunningArmOnX86())
+ QSKIP("Flaky on QEMU, QTBUG-114760");
+
+ box.addItems({"first", "middle", "last"});
+ box.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&box));
+ box.showPopup();
+
+ QFrame *container = box.findChild<QComboBoxPrivateContainer *>();
+ QVERIFY(container);
+ QVERIFY(QTest::qWaitForWindowExposed(container));
+
+ // Select the last menu item, which will close the popup. This item is then expected
+ // to be centered on top of the combobox the next time the popup opens.
+ const QRect lastItemRect = box.view()->visualRect(box.view()->model()->index(2, 0));
+ QTest::mouseClick(box.view(), Qt::LeftButton, Qt::NoModifier, lastItemRect.center());
+
+ // Change style. This can make the popup smaller, which will result in up-and-down
+ // scroll widgets showing in the menu, directly underneath the mouse before the popup
+ // ends up hidden. This again will trigger the item view to scroll, which seems to be
+ // the root cause of QTBUG-113765.
+ qApp->setStyle(QStringLiteral("Fusion"));
+
+ // Click on the combobox again to reopen it. But since both QComboBox
+ // (QComboBoxPrivateScroller) is using its own internal timer to do scrolling, we
+ // need to wait a bit until the scrolling is done before we can reopen it (since
+ // the scrolling is the sore spot that we want to test).
+ // But note, we expect, but don't require, the popup to scroll. And for that
+ // reason, we don't see it as a failure if the scrolling doesn't happen.
+ (void) QTest::qWaitFor([&box]{ return box.view()->verticalScrollBar()->value() > 0; }, 1000);
+
+ // Verify that the popup is hidden before we click the button
+ QTRY_VERIFY(!container->isVisible());
+ QTest::mouseClick(&box, Qt::LeftButton);
+
+ // Click on item under mouse. But wait a bit, to avoid a double click
+ QTest::qWait(2 * QGuiApplication::styleHints()->mouseDoubleClickInterval());
+ QTest::mouseClick(&box, Qt::LeftButton);
+
+ // Ensure that the item that was centered on top of the combobox, and which
+ // we therefore clicked, was the same item we clicked on the first time.
+ QTRY_COMPARE(box.currentText(), QStringLiteral("last"));
+}
+#endif // QT_NO_STYLE_FUSION
+
void tst_QComboBox::inputMethodUpdate()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
@@ -3696,5 +3813,40 @@ void tst_QComboBox::cancelClosesPopupNotDialog()
QVERIFY(!dialog.isVisible());
}
+void tst_QComboBox::closePopupWithCheckableItems()
+{
+ QWidget widget;
+
+ QVBoxLayout *vb = new QVBoxLayout(&widget);
+
+ QLabel *dlgLabel = new QLabel("Click when combo expanded.");
+ vb->addWidget(dlgLabel);
+
+ QComboBox *combo = new QComboBox();
+ vb->addWidget(combo);
+
+ QStandardItemModel model;
+ const int rowCount = 10;
+ for (int r = 0; r < rowCount; ++r) {
+ QString str = "Item: " + QString::number(r);
+ QStandardItem *item = new QStandardItem(str);
+ const bool isChecked = (r % 2);
+
+ item->setData(isChecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
+ item->setFlags(Qt::ItemIsUserCheckable | (item->flags() & ~(Qt::ItemIsSelectable)) );
+ model.appendRow(item);
+ }
+
+ combo->setModel(&model);
+
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ QTest::mouseClick(widget.windowHandle(), Qt::LeftButton, {}, combo->geometry().center());
+ QVERIFY(QTest::qWaitForWindowExposed(combo->view()));
+ QTest::mouseClick(widget.windowHandle(), Qt::LeftButton, {}, dlgLabel->geometry().center());
+ QTRY_VERIFY(!combo->view()->isVisible());
+}
+
QTEST_MAIN(tst_QComboBox)
#include "tst_qcombobox.moc"
diff --git a/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt b/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt
index 8cf7859fef..b89c5aa1dd 100644
--- a/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qcommandlinkbutton Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcommandlinkbutton LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qcommandlinkbutton
SOURCES
tst_qcommandlinkbutton.cpp
diff --git a/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp b/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
index 6b02775786..e0c63e5ced 100644
--- a/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
+++ b/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt b/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt
index 018070c5a4..9c2e777380 100644
--- a/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qdatetimeedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdatetimeedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdatetimeedit
SOURCES
tst_qdatetimeedit.cpp
diff --git a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
index a5e9594ada..f5f22d05b9 100644
--- a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
+++ b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qapplication.h>
#include <qgroupbox.h>
@@ -233,10 +233,12 @@ private slots:
void nextPrevSection();
void dateEditTimeEditFormats();
+#if QT_DEPRECATED_SINCE(6, 10)
void timeSpec_data();
void timeSpec();
- void timeSpecBug();
- void timeSpecInit();
+#endif
+ void timeZoneBug();
+ void timeZoneInit();
void setDateTime_data();
void setDateTime();
@@ -252,7 +254,7 @@ private slots:
void task196924();
void focusNextPrevChild();
- void taskQTBUG_12384_timeSpecShowTimeOnly();
+ void taskQTBUG_12384_timeZoneShowTimeOnly();
void deleteCalendarWidget();
@@ -406,7 +408,7 @@ void tst_QDateTimeEdit::initTestCase()
qWarning("Running under locale %s/%s -- this test may generate failures due to language differences",
qPrintable(QLocale::languageToString(system.language())),
qPrintable(QLocale::territoryToString(system.territory())));
- testWidget = new EditorDateEdit(nullptr);
+ testWidget = new EditorDateEdit;
testFocusWidget = new QWidget(nullptr);
testFocusWidget->resize(200, 100);
testFocusWidget->show();
@@ -436,7 +438,7 @@ void tst_QDateTimeEdit::cleanup()
{
testWidget->clearMinimumDateTime();
testWidget->clearMaximumDateTime();
- testWidget->setTimeSpec(Qt::LocalTime);
+ testWidget->setTimeZone(QTimeZone::LocalTime);
testWidget->setSpecialValueText(QString());
testWidget->setWrapping(false);
// Restore the default.
@@ -3365,7 +3367,7 @@ void tst_QDateTimeEdit::wheelEvent()
QFETCH(QDate, startDate);
QFETCH(DateList, expectedDates);
- EditorDateEdit edit(0);
+ EditorDateEdit edit;
edit.setDate(startDate);
edit.setCurrentSection(section);
@@ -3491,6 +3493,7 @@ void tst_QDateTimeEdit::dateEditTimeEditFormats()
QCOMPARE(d.displayedSections(), QDateTimeEdit::YearSection);
}
+#if QT_DEPRECATED_SINCE(6, 10)
void tst_QDateTimeEdit::timeSpec_data()
{
QTest::addColumn<bool>("useSetProperty");
@@ -3498,6 +3501,8 @@ void tst_QDateTimeEdit::timeSpec_data()
QTest::newRow("setTimeSpec") << false;
}
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
void tst_QDateTimeEdit::timeSpec()
{
QFETCH(bool, useSetProperty);
@@ -3538,10 +3543,12 @@ void tst_QDateTimeEdit::timeSpec()
QSKIP("Not tested in the GMT timezone");
}
}
+QT_WARNING_POP
+#endif // test deprecated timeSpec property
-void tst_QDateTimeEdit::timeSpecBug()
+void tst_QDateTimeEdit::timeZoneBug()
{
- testWidget->setTimeSpec(Qt::UTC);
+ testWidget->setTimeZone(QTimeZone::UTC);
testWidget->setDisplayFormat("hh:mm");
testWidget->setTime(QTime(2, 2));
const QString oldText = testWidget->text();
@@ -3551,7 +3558,7 @@ void tst_QDateTimeEdit::timeSpecBug()
QCOMPARE(oldText, testWidget->text());
}
-void tst_QDateTimeEdit::timeSpecInit()
+void tst_QDateTimeEdit::timeZoneInit()
{
QDateTime utc(QDate(2000, 1, 1), QTime(12, 0), QTimeZone::UTC);
QDateTimeEdit widget(utc);
@@ -3560,28 +3567,24 @@ void tst_QDateTimeEdit::timeSpecInit()
void tst_QDateTimeEdit::setDateTime_data()
{
- QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0));
- // TODO QTBUG-80417: port away from spec, to use QTimeZone instead.
- QTest::addColumn<Qt::TimeSpec>("spec");
+ const QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0));
+ const QTimeZone UTC(QTimeZone::UTC), local(QTimeZone::LocalTime);
+ QTest::addColumn<QTimeZone>("zone");
QTest::addColumn<QDateTime>("store");
QTest::addColumn<QDateTime>("expect");
- QTest::newRow("LocalTime/LocalTime")
- << Qt::LocalTime << localNoon << localNoon;
- QTest::newRow("LocalTime/UTC")
- << Qt::LocalTime << localNoon.toUTC() << localNoon;
- QTest::newRow("UTC/LocalTime")
- << Qt::UTC << localNoon << localNoon.toUTC();
- QTest::newRow("UTC/UTC")
- << Qt::UTC << localNoon.toUTC() << localNoon.toUTC();
+ QTest::newRow("LocalTime/LocalTime") << local << localNoon << localNoon;
+ QTest::newRow("LocalTime/UTC") << local << localNoon.toUTC() << localNoon;
+ QTest::newRow("UTC/LocalTime") << UTC << localNoon << localNoon.toUTC();
+ QTest::newRow("UTC/UTC") << UTC << localNoon.toUTC() << localNoon.toUTC();
}
void tst_QDateTimeEdit::setDateTime()
{
- QFETCH(const Qt::TimeSpec, spec);
+ QFETCH(const QTimeZone, zone);
QFETCH(const QDateTime, store);
QFETCH(const QDateTime, expect);
QDateTimeEdit editor;
- editor.setTimeSpec(spec);
+ editor.setTimeZone(zone);
editor.setDateTime(store);
QCOMPARE(editor.dateTime(), expect);
}
@@ -3775,14 +3778,14 @@ void tst_QDateTimeEdit::focusNextPrevChild()
QCOMPARE(edit.currentSection(), QDateTimeEdit::MonthSection);
}
-void tst_QDateTimeEdit::taskQTBUG_12384_timeSpecShowTimeOnly()
+void tst_QDateTimeEdit::taskQTBUG_12384_timeZoneShowTimeOnly()
{
QDateTime time = QDateTime::fromString("20100723 04:02:40", "yyyyMMdd hh:mm:ss");
time.setTimeZone(QTimeZone::UTC);
EditorDateEdit edit;
edit.setDisplayFormat("hh:mm:ss");
- edit.setTimeSpec(Qt::UTC);
+ edit.setTimeZone(QTimeZone::UTC);
edit.setDateTime(time);
QCOMPARE(edit.minimumTime(), QTime(0, 0, 0, 0));
@@ -3798,7 +3801,7 @@ void tst_QDateTimeEdit::deleteCalendarWidget()
QVERIFY(!edit.calendarWidget());
edit.setCalendarPopup(true);
QVERIFY(edit.calendarWidget());
- edit.calendarWidget()->setObjectName("cw1");;
+ edit.calendarWidget()->setObjectName("cw1");
// delete
delete edit.calendarWidget();
@@ -4424,7 +4427,7 @@ void tst_QDateTimeEdit::stepModifierButtons()
testWidget->hide();
- EditorDateEdit edit(0);
+ EditorDateEdit edit;
edit.setTime(startTime);
edit.show();
QVERIFY(QTest::qWaitForWindowActive(&edit));
@@ -4518,7 +4521,7 @@ void tst_QDateTimeEdit::stepModifierPressAndHold()
testWidget->hide();
- EditorDateEdit edit(0);
+ EditorDateEdit edit;
edit.setDate(startDate);
QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle(
@@ -4568,13 +4571,20 @@ static QDateTime findSpring(int year, const QTimeZone &timeZone)
const QTimeZone::OffsetData transition =
midSummer.isDaylightTime() ? timeZone.previousTransition(midSummer)
: timeZone.nextTransition(midSummer);
- const QDateTime spring = transition.atUtc.toLocalTime();
+ const QDateTime spring = transition.atUtc.toTimeZone(timeZone);
// there might have been DST at some point, but not in the year we care about
if (spring.date().year() != year || !spring.isDaylightTime())
return QDateTime();
return spring;
};
+
+// Number of missing seconds between a day before and a day after when.
+// If when is the time of a spring-forward transition, this is the width of its gap.
+static int missingSecondsNear(const QDateTime &when)
+{
+ return 2 * 24 * 60 * 60 - when.addDays(-1).secsTo(when.addDays(1));
+}
#endif
/*!
@@ -4598,36 +4608,40 @@ void tst_QDateTimeEdit::springForward_data()
QSKIP("Failed to obtain valid spring forward datetime for 2019!");
const QDate springDate = springTransition.date();
- const int gapWidth = timeZone.daylightTimeOffset(springTransition.addDays(1));
+ const int gapWidth = missingSecondsNear(springTransition);
+ if (gapWidth <= 0)
+ QSKIP("Spring forward transition did not actually skip any time!");
+
const QTime springGap = springTransition.time().addSecs(-gapWidth);
- const QByteArray springTime = springGap.toString("hh:mm").toLocal8Bit();
- const QTime springGapMiddle = springTransition.time().addSecs(-gapWidth/2);
+ const QTime springGapMiddle = springTransition.time().addSecs(-gapWidth / 2);
+ const QByteArray startGapTime = springGap.toString("hh:mm").toLocal8Bit();
+ const QByteArray midGapTime = springGapMiddle.toString("hh:mm").toLocal8Bit();
- QTest::addRow("forward to %s, correct to previous", springTime.data())
+ QTest::addRow("forward to %s, correct to previous", startGapTime.data())
<< QDateTime(springDate, springGap.addSecs(-gapWidth))
<< QAbstractSpinBox::CorrectToPreviousValue
<< springGap
<< QDateTime(springDate, springGap.addSecs(-gapWidth));
- QTest::addRow("back to %s, correct to previous", springTime.data())
+ QTest::addRow("back to %s, correct to previous", startGapTime.data())
<< springTransition
<< QAbstractSpinBox::CorrectToPreviousValue
<< springGap
<< springTransition;
- QTest::addRow("forward to %s, correct to nearest", springTime.data())
+ QTest::addRow("forward to %s, correct to nearest", midGapTime.data())
<< QDateTime(springDate, springGap.addSecs(-gapWidth))
<< QAbstractSpinBox::CorrectToNearestValue
<< springGapMiddle
<< springTransition;
- QTest::addRow("back to %s, correct to nearest", springTime.data())
+ QTest::addRow("back to %s, correct to nearest", midGapTime.data())
<< springTransition
<< QAbstractSpinBox::CorrectToNearestValue
<< springGapMiddle
<< springTransition;
- QTest::addRow("jump to %s, correct to nearest", qPrintable(springGapMiddle.toString("hh:mm")))
+ QTest::addRow("jump to %s, correct to nearest", midGapTime.data())
<< QDateTime(QDate(1980, 5, 10), springGap)
<< QAbstractSpinBox::CorrectToNearestValue
<< springGapMiddle
@@ -4655,11 +4669,11 @@ void tst_QDateTimeEdit::springForward()
edit.setSelectedSection(QDateTimeEdit::DaySection);
const QDate date = expected.date();
- const QString day = QString::number(date.day()).rightJustified(2, QLatin1Char('0'));
- const QString month = QString::number(date.month()).rightJustified(2, QLatin1Char('0'));
+ const QString day = QString::number(date.day()).rightJustified(2, u'0');
+ const QString month = QString::number(date.month()).rightJustified(2, u'0');
const QString year = QString::number(date.year());
- const QString hour = QString::number(inputTime.hour()).rightJustified(2, QLatin1Char('0'));
- const QString minute = QString::number(inputTime.minute()).rightJustified(2, QLatin1Char('0'));
+ const QString hour = QString::number(inputTime.hour()).rightJustified(2, u'0');
+ const QString minute = QString::number(inputTime.minute()).rightJustified(2, u'0');
QTest::keyClicks(&edit, day);
QTest::keyClicks(&edit, month);
QTest::keyClicks(&edit, year);
@@ -4686,7 +4700,7 @@ void tst_QDateTimeEdit::stepIntoDSTGap_data()
QTest::addColumn<int>("steps");
QTest::addColumn<QDateTime>("end");
- const QTimeZone timeZone = QTimeZone("Europe/Oslo");
+ const QTimeZone timeZone = QTimeZone::systemTimeZone();
if (!timeZone.hasDaylightTime())
QSKIP("This test needs to run in a timezone that observes DST!");
@@ -4695,11 +4709,14 @@ void tst_QDateTimeEdit::stepIntoDSTGap_data()
QSKIP("Failed to obtain valid spring forward datetime for 2007!");
const QDate spring = springTransition.date();
- const int gapWidth = timeZone.daylightTimeOffset(springTransition.addDays(1));
+ const int gapWidth = missingSecondsNear(springTransition);
+ if (gapWidth <= 0)
+ QSKIP("Spring forward transition did not actually skip any time!");
+
const QTime springGap = springTransition.time().addSecs(-gapWidth);
const QByteArray springTime = springGap.toString("hh:mm").toLocal8Bit();
- // change hour
+ // change hour (can't change day):
if (springGap.hour() != 0) {
QTest::addRow("hour up into %s gap", springTime.data())
<< QDateTime(spring, springGap.addSecs(-3600))
@@ -4709,7 +4726,7 @@ void tst_QDateTimeEdit::stepIntoDSTGap_data()
// 3:00:10 into 2:00:10 should get us to 1:00:10
QTest::addRow("hour down into %s gap", springTime.data())
- << QDateTime(spring, springGap.addSecs(3610))
+ << QDateTime(spring, springGap.addSecs(gapWidth + 10))
<< QDateTimeEdit::HourSection
<< -1
<< QDateTime(spring, springGap.addSecs(-3590));
@@ -4734,28 +4751,31 @@ void tst_QDateTimeEdit::stepIntoDSTGap_data()
}
// change month
- QTest::addRow("month up into %s gap", springTime.data())
- << QDateTime(spring.addMonths(-1), springGap)
- << QDateTimeEdit::MonthSection
- << +1
- << springTransition;
- QTest::addRow("month down into %s gap", springTime.data())
- << QDateTime(spring.addMonths(1), springGap)
- << QDateTimeEdit::MonthSection
- << -1
- << springTransition;
+ // Previous month may well be February, so lack the day-of-month that
+ // matches spring (e.g. Asia/Jerusalem, March 30).
+ if (QDate prior = spring.addMonths(-1); prior.day() == spring.day()) {
+ QTest::addRow("month up into %s gap", springTime.data())
+ << QDateTime(prior, springGap) << QDateTimeEdit::MonthSection << +1 << springTransition;
+ }
+ // America/{Jujuy,Cordoba,Catamarca} did a 2007 Dec 30th 00:00 spring
+ // forward; and QDTE month steps won't change the year.
+ if (QDate prior = spring.addMonths(1);
+ prior.year() == spring.year() && prior.day() == spring.day()) {
+ QTest::addRow("month down into %s gap", springTime.data())
+ << QDateTime(prior, springGap) << QDateTimeEdit::MonthSection << -1 << springTransition;
+ }
// change year
- QTest::addRow("year up into %s gap", springTime.data())
- << QDateTime(spring.addYears(-1), springGap)
- << QDateTimeEdit::YearSection
- << +1
- << springTransition;
- QTest::addRow("year down into %s gap", springTime.data())
- << QDateTime(spring.addYears(1), springGap)
- << QDateTimeEdit::YearSection
- << -1
- << springTransition;
+ // Some zones (e.g. Asia/Baghdad) do transitions on a fixed date; for these,
+ // the springGap moment is invalid every year, so skip this test.
+ if (QDateTime prior = QDateTime(spring.addYears(-1), springGap); prior.isValid()) {
+ QTest::addRow("year up into %s gap", springTime.data())
+ << prior << QDateTimeEdit::YearSection << +1 << springTransition;
+ }
+ if (QDateTime later(spring.addYears(1), springGap); later.isValid()) {
+ QTest::addRow("year down into %s gap", springTime.data())
+ << later << QDateTimeEdit::YearSection << -1 << springTransition;
+ }
#else
QSKIP("Needs timezone feature enabled");
#endif
diff --git a/tests/auto/widgets/widgets/qdial/CMakeLists.txt b/tests/auto/widgets/widgets/qdial/CMakeLists.txt
index dc8b011293..5e300eec94 100644
--- a/tests/auto/widgets/widgets/qdial/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qdial/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qdial Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdial LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdial
SOURCES
tst_qdial.cpp
diff --git a/tests/auto/widgets/widgets/qdial/tst_qdial.cpp b/tests/auto/widgets/widgets/qdial/tst_qdial.cpp
index 1d8c970ef4..d0274ace2a 100644
--- a/tests/auto/widgets/widgets/qdial/tst_qdial.cpp
+++ b/tests/auto/widgets/widgets/qdial/tst_qdial.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -17,6 +17,7 @@ private slots:
void valueChanged();
void sliderMoved();
void wrappingCheck();
+ void minEqualMaxValueOutsideRange();
void notchSize_data();
void notchSize();
@@ -172,6 +173,15 @@ void tst_QDial::wrappingCheck()
}
}
+// QTBUG-104641
+void tst_QDial::minEqualMaxValueOutsideRange()
+{
+ QDial dial;
+ dial.setRange(30, 30);
+ dial.setWrapping(true);
+ dial.setValue(45);
+}
+
/*
Verify that the notchSizes calculated don't change compared
to Qt 5.15 results for dial sizes at the edge values of the
diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt b/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt
index a7eb85b140..098b129cbc 100644
--- a/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt
@@ -5,10 +5,17 @@
## tst_qdialogbuttonbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdialogbuttonbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdialogbuttonbox
SOURCES
tst_qdialogbuttonbox.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp
index df26b4c5da..3e7dc92da1 100644
--- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp
+++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp
@@ -1,13 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStyle>
#include <QtWidgets/QLayout>
#include <QtWidgets/QDialog>
+#include <QtWidgets/QLineEdit>
#include <QtGui/QAction>
+#include <QtGui/QStyleHints>
#include <qdialogbuttonbox.h>
+#include <QtWidgets/private/qdialogbuttonbox_p.h>
+#include <QtWidgets/private/qabstractbutton_p.h>
#include <limits.h>
Q_DECLARE_METATYPE(QDialogButtonBox::ButtonRole)
@@ -49,6 +53,10 @@ private slots:
void clear();
void removeButton_data();
void removeButton();
+#ifdef QT_BUILD_INTERNAL
+ void hideAndShowButton();
+#endif
+ void hideAndShowStandardButton();
void buttonRole_data();
void buttonRole();
void setStandardButtons_data();
@@ -74,6 +82,9 @@ private slots:
void task191642_default();
void testDeletedStandardButton();
+ void automaticDefaultButton();
+ void initialFocus_data();
+ void initialFocus();
private:
qint64 timeStamp;
@@ -372,6 +383,70 @@ void tst_QDialogButtonBox::removeButton()
delete button;
}
+#ifdef QT_BUILD_INTERNAL
+void tst_QDialogButtonBox::hideAndShowButton()
+{
+ if (QGuiApplication::styleHints()->tabFocusBehavior() == Qt::NoTabFocus)
+ QSKIP("Test skipped with Qt::NoTabFocus");
+
+ QDialogButtonBox buttonBox;
+ QDialogButtonBoxPrivate *d = static_cast<QDialogButtonBoxPrivate *>(QObjectPrivate::get(&buttonBox));
+ auto *apply = buttonBox.addButton( "Apply", QDialogButtonBox::ApplyRole );
+ auto *accept = buttonBox.addButton( "Accept", QDialogButtonBox::AcceptRole );
+ buttonBox.addButton( "Reject", QDialogButtonBox::RejectRole );
+ auto *widget = new QWidget();
+ auto *layout = new QHBoxLayout(widget);
+ layout->addWidget(&buttonBox);
+
+ // apply button shows first on macOS. accept button on all other OSes.
+ QAbstractButton *hideButton;
+#ifdef Q_OS_MACOS
+ hideButton = apply;
+ Q_UNUSED(accept);
+#else
+ hideButton = accept;
+ Q_UNUSED(apply);
+#endif
+
+ hideButton->hide();
+ widget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(widget));
+ QTRY_VERIFY(buttonBox.focusWidget()); // QTBUG-114377: Without fixing, focusWidget() == nullptr
+ QCOMPARE(d->visibleButtons().count(), 2);
+ QCOMPARE(d->hiddenButtons.count(), 1);
+ QVERIFY(d->hiddenButtons.contains(hideButton));
+ QCOMPARE(buttonBox.buttons().count(), 3);
+ QSignalSpy spy(qApp, &QApplication::focusChanged);
+ QTest::sendKeyEvent(QTest::KeyAction::Click, &buttonBox, Qt::Key_Tab, QString(), Qt::KeyboardModifiers());
+ QCOMPARE(spy.count(), 1); // QTBUG-114377: Without fixing, tabbing wouldn't work.
+ hideButton->show();
+ QCOMPARE_GE(spy.count(), 1);
+ QTRY_COMPARE(QApplication::focusWidget(), hideButton);
+ QCOMPARE(d->visibleButtons().count(), 3);
+ QCOMPARE(d->hiddenButtons.count(), 0);
+ QCOMPARE(buttonBox.buttons().count(), 3);
+ spy.clear();
+ QTest::sendKeyEvent(QTest::KeyAction::Click, &buttonBox, Qt::Key_Backtab, QString(), Qt::KeyboardModifiers());
+ QCOMPARE(spy.count(), 1);
+}
+#endif
+
+void tst_QDialogButtonBox::hideAndShowStandardButton()
+{
+ QDialogButtonBox buttonBox;
+ buttonBox.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ buttonBox.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&buttonBox));
+ auto *button = buttonBox.button(QDialogButtonBox::Cancel);
+ QVERIFY(button);
+ button->hide();
+ QVERIFY(QTest::qWaitFor([button](){ return !button->isVisible(); }));
+ QCOMPARE(button, buttonBox.button(QDialogButtonBox::Cancel));
+ button->show();
+ QVERIFY(QTest::qWaitForWindowExposed(button));
+ QCOMPARE(button, buttonBox.button(QDialogButtonBox::Cancel));
+}
+
void tst_QDialogButtonBox::testDelete()
{
QDialogButtonBox buttonBox;
@@ -838,5 +913,87 @@ void tst_QDialogButtonBox::testDeletedStandardButton()
QVERIFY(!buttonC);
}
+void tst_QDialogButtonBox::automaticDefaultButton()
+{
+ // Having a QDialogButtonBox inside a QDialog triggers Qt to
+ // enable autoDefault for QPushButtons inside the button box.
+ // Check that the logic for resolving a default button based
+ // on the Accept role is not overridden by the first button
+ // in the dialog (the focus proxy) taking focus, and hence
+ // stealing the default button state.
+
+ {
+ QDialog dialog;
+ QDialogButtonBox *bb = new QDialogButtonBox(&dialog);
+ // Force horizontal orientation, where we know the order between
+ // Reset and Accept roles are always the same for all layouts.
+ bb->setOrientation(Qt::Horizontal);
+ auto *okButton = bb->addButton(QDialogButtonBox::Ok);
+ auto *resetButton = bb->addButton(QDialogButtonBox::Reset);
+ // Double check our assumption about Reset being first
+ QCOMPARE(bb->layout()->itemAt(0)->widget(), resetButton);
+
+ dialog.show();
+ QVERIFY(QTest::qWaitForWindowActive(&dialog));
+
+ QVERIFY(okButton->isDefault());
+ QSignalSpy buttonClicked(okButton, &QPushButton::clicked);
+ QTest::keyPress(&dialog, Qt::Key_Enter);
+ QCOMPARE(buttonClicked.count(), 1);
+ }
+
+ // However, if an explicit button has been focused, we respect that.
+
+ {
+ QDialog dialog;
+ QDialogButtonBox *bb = new QDialogButtonBox(&dialog);
+ bb->setOrientation(Qt::Horizontal);
+ bb->addButton(QDialogButtonBox::Ok);
+ auto *resetButton = bb->addButton(QDialogButtonBox::Reset);
+ resetButton->setFocus();
+ dialog.show();
+ QVERIFY(QTest::qWaitForWindowActive(&dialog));
+
+ QVERIFY(resetButton->isDefault());
+ QSignalSpy buttonClicked(resetButton, &QPushButton::clicked);
+ QTest::keyPress(&dialog, Qt::Key_Enter);
+ QCOMPARE(buttonClicked.count(), 1);
+ }
+}
+
+void tst_QDialogButtonBox::initialFocus_data()
+{
+ QTest::addColumn<Qt::FocusPolicy>("focusPolicy");
+ QTest::addColumn<bool>("lineEditHasFocus");
+
+ QTest::addRow("TabFocus") << Qt::FocusPolicy::TabFocus << false;
+ QTest::addRow("StrongFocus") << Qt::FocusPolicy::StrongFocus << true;
+ QTest::addRow("NoFocus") << Qt::FocusPolicy::NoFocus << false;
+ QTest::addRow("ClickFocus") << Qt::FocusPolicy::ClickFocus << false;
+ QTest::addRow("WheelFocus") << Qt::FocusPolicy::WheelFocus << false;
+}
+
+void tst_QDialogButtonBox::initialFocus()
+{
+ QFETCH(const Qt::FocusPolicy, focusPolicy);
+ QFETCH(const bool, lineEditHasFocus);
+ QDialog dialog;
+ QVBoxLayout *layout = new QVBoxLayout(&dialog);
+ QLineEdit *lineEdit = new QLineEdit(&dialog);
+ lineEdit->setFocusPolicy(focusPolicy);
+ layout->addWidget(lineEdit);
+ QDialogButtonBox *dialogButtonBox = new QDialogButtonBox(&dialog);
+ layout->addWidget(dialogButtonBox);
+ dialogButtonBox->addButton(QDialogButtonBox::Reset);
+ const auto *firstAcceptButton = dialogButtonBox->addButton(QDialogButtonBox::Ok);
+ dialogButtonBox->addButton(QDialogButtonBox::Cancel);
+ dialog.show();
+ dialog.activateWindow();
+ if (lineEditHasFocus)
+ QTRY_VERIFY(lineEdit->hasFocus());
+ else
+ QTRY_VERIFY(firstAcceptButton->hasFocus());
+}
+
QTEST_MAIN(tst_QDialogButtonBox)
#include "tst_qdialogbuttonbox.moc"
diff --git a/tests/auto/widgets/widgets/qdockwidget/BLACKLIST b/tests/auto/widgets/widgets/qdockwidget/BLACKLIST
index 8b7a126b4d..8873589ff4 100644
--- a/tests/auto/widgets/widgets/qdockwidget/BLACKLIST
+++ b/tests/auto/widgets/widgets/qdockwidget/BLACKLIST
@@ -5,23 +5,32 @@ android
# QDockWidget::isFloating() is flaky after state change on these OS
[closeAndDelete]
macos
+b2qt
+arm
+android
+
+# QTBUG-103091
[floatingTabs]
+arm
+android
+qnx
+macos
+b2qt
+
# QTBUG-103091
+[hoverWithoutDrop]
+arm
+android
qnx
macos
-[closeAndDelete]
b2qt
-[floatingTabs]
-macos b2qt arm android
-[closeAndDelete]
+
+# OSes are flaky because of unplugging and plugging requires
+# precise calculation of the title bar area for mouse emulation
+# That's not possible for floating dock widgets.
+[deleteFloatingTabWithSingleDockWidget]
+qnx
b2qt
-[floatingTabs]
arm
-[closeAndDelete]
-macos b2qt arm android
-[floatingTabs]
-arm
-[closeAndDelete]
-android
-[floatingTabs]
android
+macos
diff --git a/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt
index 2f8a7a266d..21d8fb60cc 100644
--- a/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qdockwidget Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdockwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdockwidget
SOURCES
tst_qdockwidget.cpp
diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
index 35a05f768a..63a432578e 100644
--- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
+++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
@@ -10,6 +10,7 @@
#include "private/qmainwindowlayout_p.h"
#include <QAbstractButton>
#include <qlineedit.h>
+#include <QtGui/qpa/qplatformwindow.h>
#include <qtabbar.h>
#include <QScreen>
#include <QTimer>
@@ -65,14 +66,20 @@ private slots:
// Dock area permissions for DockWidgets and DockWidgetGroupWindows
void dockPermissions();
- // test floating tabs and item_tree consistency
+ // test floating tabs, item_tree and window title consistency
void floatingTabs();
+ void hoverWithoutDrop();
+
+ // floating tab gets removed, when last child goes away
+ void deleteFloatingTabWithSingleDockWidget_data();
+ void deleteFloatingTabWithSingleDockWidget();
// test hide & show
void hideAndShow();
// test closing and deleting consistency
void closeAndDelete();
+ void closeUnclosable();
// test save and restore consistency
void saveAndRestore();
@@ -80,9 +87,15 @@ private slots:
private:
// helpers and consts for dockPermissions, hideAndShow, closeAndDelete
#ifdef QT_BUILD_INTERNAL
- void createTestWidgets(QMainWindow* &MainWindow, QPointer<QWidget> &cent, QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2) const;
+ void createTestWidgets(QMainWindow* &MainWindow, QPointer<QWidget> &cent,
+ QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2) const;
+
void unplugAndResize(QMainWindow* MainWindow, QDockWidget* dw, QPoint home, QSize size) const;
+ void createFloatingTabs(QMainWindow* &MainWindow, QPointer<QWidget> &cent,
+ QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2,
+ QList<int> &path1, QList<int> &path2) const;
+
static inline QPoint dragPoint(QDockWidget* dockWidget);
static inline QPoint home1(QMainWindow* MainWindow)
{ return MainWindow->mapToGlobal(MainWindow->rect().topLeft() + QPoint(0.1 * MainWindow->width(), 0.1 * MainWindow->height())); }
@@ -102,12 +115,27 @@ private:
bool checkFloatingTabs(QMainWindow* MainWindow, QPointer<QDockWidgetGroupWindow> &ftabs, const QList<QDockWidget*> &dwList = {}) const;
// move a dock widget
- void moveDockWidget(QDockWidget* dw, QPoint to, QPoint from = QPoint()) const;
+ enum class MoveDockWidgetRule {
+ Drop,
+ Abort
+ };
+
+ void moveDockWidget(QDockWidget* dw, QPoint to, QPoint from, MoveDockWidgetRule rule) const;
+#ifdef QT_BUILD_INTERNAL
// Message handling for xcb error QTBUG 82059
static void xcbMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+
+ enum class ChildRemovalReason {
+ Destroyed,
+ Closed,
+ Reparented
+ };
+
public:
bool xcbError = false;
+ bool platformSupportingRaise = true;
+#endif
private:
#ifdef QT_DEBUG
@@ -128,11 +156,6 @@ private:
};
-// Statics for xcb error / msg handler
-static tst_QDockWidget *qThis = nullptr;
-static void (*oldMessageHandler)(QtMsgType, const QMessageLogContext&, const QString&);
-#define QXCBVERIFY(cond) do { if (xcbError) QSKIP("Test skipped due to XCB error"); QVERIFY(cond); } while (0)
-
// Testing get/set functions
void tst_QDockWidget::getSetCheck()
{
@@ -675,6 +698,9 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
mw.tabifyDockWidget(dw1, dw2);
mw.tabifyDockWidget(dw2, dw3);
+ const auto list1 = QList<QDockWidget *>{dw1, dw2, dw3};
+ QCOMPARE(mw.tabifiedDockWidgets(dw0), list1);
+
QTabBar *tabBar = mw.findChild<QTabBar *>();
QVERIFY(tabBar);
tabBar->setCurrentIndex(2);
@@ -688,6 +714,8 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
dw1->hide();
QTRY_COMPARE(tabBar->count(), 2);
QCOMPARE(tabBar->currentIndex(), 0);
+
+ QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3});
}
Q_DECLARE_METATYPE(Qt::DockWidgetArea)
@@ -1074,9 +1102,10 @@ void tst_QDockWidget::setWindowTitle()
QMainWindow window;
QDockWidget dock1(&window);
QDockWidget dock2(&window);
- const QString dock1Title = QStringLiteral("&Window");
- const QString dock2Title = QStringLiteral("&Modifiable Window [*]");
+ constexpr QLatin1StringView dock1Title("&Window");
+ constexpr QLatin1StringView dock2Title("&Modifiable Window [*]");
+ // Set title on docked dock widgets, before main window is shown
dock1.setWindowTitle(dock1Title);
dock2.setWindowTitle(dock2Title);
window.addDockWidget(Qt::RightDockWidgetArea, &dock1);
@@ -1087,6 +1116,7 @@ void tst_QDockWidget::setWindowTitle()
QCOMPARE(dock1.windowTitle(), dock1Title);
QCOMPARE(dock2.windowTitle(), dock2Title);
+ // Check if title remains unchanged when docking / undocking
dock1.setFloating(true);
dock1.show();
QVERIFY(QTest::qWaitForWindowExposed(&dock1));
@@ -1096,12 +1126,16 @@ void tst_QDockWidget::setWindowTitle()
dock1.setFloating(true);
dock1.show();
QVERIFY(QTest::qWaitForWindowExposed(&dock1));
- const QString changed = QStringLiteral("Changed ");
+
+ // Change a floating dock widget's title and check remains unchanged when docking
+ constexpr QLatin1StringView changed("Changed ");
dock1.setWindowTitle(QString(changed + dock1Title));
QCOMPARE(dock1.windowTitle(), QString(changed + dock1Title));
dock1.setFloating(false);
+ QVERIFY(QTest::qWaitFor([&dock1](){ return !dock1.windowHandle(); }));
QCOMPARE(dock1.windowTitle(), QString(changed + dock1Title));
+ // Test consistency after toggling modified and floating
dock2.setWindowModified(true);
QCOMPARE(dock2.windowTitle(), dock2Title);
dock2.setFloating(true);
@@ -1116,6 +1150,12 @@ void tst_QDockWidget::setWindowTitle()
dock2.show();
QVERIFY(QTest::qWaitForWindowExposed(&dock2));
QCOMPARE(dock2.windowTitle(), dock2Title);
+
+ // Test title change of a closed dock widget
+ static constexpr QLatin1StringView closedDock2("Closed D2");
+ dock2.close();
+ dock2.setWindowTitle(closedDock2);
+ QCOMPARE(dock2.windowTitle(), closedDock2);
}
// helpers for dockPermissions, hideAndShow, closeAndDelete
@@ -1175,7 +1215,7 @@ QPoint tst_QDockWidget::dragPoint(QDockWidget* dockWidget)
return dockWidget->mapToGlobal(dwlayout->titleArea().center());
}
-void tst_QDockWidget::moveDockWidget(QDockWidget* dw, QPoint to, QPoint from) const
+void tst_QDockWidget::moveDockWidget(QDockWidget* dw, QPoint to, QPoint from, MoveDockWidgetRule rule) const
{
Q_ASSERT(dw);
@@ -1192,12 +1232,22 @@ void tst_QDockWidget::moveDockWidget(QDockWidget* dw, QPoint to, QPoint from) co
QTest::mouseMove(dw, target);
qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "to" << target;
qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "to" << to;
- QTest::mouseRelease(dw, Qt::LeftButton, Qt::KeyboardModifiers(), target);
- QTest::qWait(waitingTime);
+ if (rule == MoveDockWidgetRule::Drop) {
+ QTest::mouseRelease(dw, Qt::LeftButton, Qt::KeyboardModifiers(), target);
+ QTest::qWait(waitingTime);
- // Verify WindowActive only for floating dock widgets
- if (dw->isFloating())
- QTRY_VERIFY(QTest::qWaitForWindowActive(dw));
+ // Verify WindowActive only for floating dock widgets
+ if (dw->isFloating())
+ QTRY_VERIFY(QTest::qWaitForWindowActive(dw));
+ return;
+ }
+ qCDebug(lcTestDockWidget) << "Aborting move and dropping at origin";
+
+ // Give animations some time
+ QTest::qWait(waitingTime);
+ QTest::mouseMove(dw, from);
+ QTest::mouseRelease(dw, Qt::LeftButton, Qt::KeyboardModifiers(), from);
+ QTest::qWait(waitingTime);
}
void tst_QDockWidget::unplugAndResize(QMainWindow* mainWindow, QDockWidget* dw, QPoint home, QSize size) const
@@ -1245,7 +1295,7 @@ void tst_QDockWidget::unplugAndResize(QMainWindow* mainWindow, QDockWidget* dw,
QPoint pos1 = dw->mapToGlobal(dw->rect().center());
pos1.rx() += mx;
pos1.ry() += my;
- moveDockWidget(dw, pos1, dw->mapToGlobal(dw->rect().center()));
+ moveDockWidget(dw, pos1, dw->mapToGlobal(dw->rect().center()), MoveDockWidgetRule::Drop);
QTRY_VERIFY(dw->isFloating());
// Unplugged object's size may differ max. by 2x frame size
@@ -1307,20 +1357,71 @@ bool tst_QDockWidget::checkFloatingTabs(QMainWindow* mainWindow, QPointer<QDockW
return true;
}
-// detect xcb error
+#ifdef QT_BUILD_INTERNAL
+// Statics for xcb error, raise() suppert / msg handler
+static tst_QDockWidget *qThis = nullptr;
+static void (*oldMessageHandler)(QtMsgType, const QMessageLogContext &, const QString &);
+#define QXCBVERIFY(cond) do { if (xcbError) QSKIP("Test skipped due to XCB error"); QVERIFY(cond); } while (0)
+
+// detect xcb error and missing raise() support
// qt.qpa.xcb: internal error: void QXcbWindow::setNetWmStateOnUnmappedWindow() called on mapped window
void tst_QDockWidget::xcbMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
Q_ASSERT(oldMessageHandler);
- if (type == QtWarningMsg && QString(context.category) == "qt.qpa.xcb" && msg.contains("internal error")) {
+ if (type == QtWarningMsg) {
Q_ASSERT(qThis);
- qThis->xcbError = true;
+ if (QString(context.category) == "qt.qpa.xcb" && msg.contains("internal error"))
+ qThis->xcbError = true;
+ if (msg.contains("does not support raise"))
+ qThis->platformSupportingRaise = false;
}
return oldMessageHandler(type, context, msg);
}
+#endif
+void tst_QDockWidget::createFloatingTabs(QMainWindow* &mainWindow, QPointer<QWidget> &cent,
+ QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2,
+ QList<int> &path1, QList<int> &path2) const
+{
+ createTestWidgets(mainWindow, cent, d1, d2);
+
+#ifdef QT_BUILD_INTERNAL
+ qThis = const_cast<tst_QDockWidget *>(this);
+ oldMessageHandler = qInstallMessageHandler(xcbMessageHandler);
+ auto resetMessageHandler = qScopeGuard([] { qInstallMessageHandler(oldMessageHandler); });
+#endif
+
+ // Test will fail if platform doesn't support raise.
+ mainWindow->windowHandle()->handle()->raise();
+ if (!platformSupportingRaise)
+ QSKIP("Platform not supporting raise(). Floating tab based tests will fail.");
+
+ // remember paths to d1 and d2
+ QMainWindowLayout* layout = qobject_cast<QMainWindowLayout *>(mainWindow->layout());
+ path1 = layout->layoutState.indexOf(d1);
+ path2 = layout->layoutState.indexOf(d2);
+
+ // unplug and resize both dock widgets
+ unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow));
+ unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow));
+
+ // docks must be parented to the main window, no group window must exist
+ QCOMPARE(d1->parentWidget(), mainWindow);
+ QCOMPARE(d2->parentWidget(), mainWindow);
+ QVERIFY(mainWindow->findChildren<QDockWidgetGroupWindow *>().isEmpty());
+
+ // Test plugging
+ qCDebug(lcTestDockWidget) << "*** move d1 dock over d2 dock ***";
+ qCDebug(lcTestDockWidget) << "**********(test plugging)*************";
+ qCDebug(lcTestDockWidget) << "Move d1 over d2";
+ moveDockWidget(d1, d2->mapToGlobal(d2->rect().center()), QPoint(), MoveDockWidgetRule::Drop);
+
+ // Now MainWindow has to have a floatingTab child
+ QPointer<QDockWidgetGroupWindow> ftabs;
+ QTRY_VERIFY(checkFloatingTabs(mainWindow, ftabs, QList<QDockWidget *>() << d1 << d2));
+}
#endif // QT_BUILD_INTERNAL
// test floating tabs and item_tree consistency
@@ -1337,33 +1438,20 @@ void tst_QDockWidget::floatingTabs()
QPointer<QDockWidget> d2;
QPointer<QWidget> cent;
QMainWindow* mainWindow;
- createTestWidgets(mainWindow, cent, d1, d2);
+ QList<int> path1;
+ QList<int> path2;
+ createFloatingTabs(mainWindow, cent, d1, d2, path1, path2);
std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);
+ QCOMPARE(mainWindow->tabifiedDockWidgets(d1), {d2});
+ QCOMPARE(mainWindow->tabifiedDockWidgets(d2), {d1});
+
/*
* unplug both dockwidgets, resize them and plug them into a joint floating tab
* expected behavior: QDOckWidgetGroupWindow with both widgets is created
*/
- // remember paths to d1 and d2
- QMainWindowLayout* layout = qobject_cast<QMainWindowLayout*>(mainWindow->layout());
- const QList<int> path1 = layout->layoutState.indexOf(d1);
- const QList<int> path2 = layout->layoutState.indexOf(d2);
-
- // unplug and resize both dock widgets
- unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow));
- unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow));
-
- // Test plugging
- qCDebug(lcTestDockWidget) << "*** move d1 dock over d2 dock ***";
- qCDebug(lcTestDockWidget) << "**********(test plugging)*************";
- qCDebug(lcTestDockWidget) << "Move d1 over d2";
- moveDockWidget(d1, d2->mapToGlobal(d2->rect().center()));
-
- // Both dock widgets must no longer be floating
// disabled due to flakiness on macOS and Windows
- //QTRY_VERIFY(!d1->isFloating());
- //QTRY_VERIFY(!d2->isFloating());
if (d1->isFloating())
qWarning("OS flakiness: D1 is docked and reports being floating");
if (d2->isFloating())
@@ -1371,11 +1459,25 @@ void tst_QDockWidget::floatingTabs()
// Now MainWindow has to have a floatingTab child
QPointer<QDockWidgetGroupWindow> ftabs;
- QTRY_VERIFY(checkFloatingTabs(mainWindow, ftabs, QList<QDockWidget*>() << d1 << d2));
+ QTRY_VERIFY(checkFloatingTabs(mainWindow, ftabs, QList<QDockWidget *>() << d1 << d2));
+
+ // Hide both dock widgets. Verify that the group window is also hidden.
+ qCDebug(lcTestDockWidget) << "*** Hide and show tabbed dock widgets ***";
+ d1->hide();
+ d2->hide();
+ QTRY_VERIFY(ftabs->isHidden());
+
+ // Show both dockwidgets again. Verify that the group window is visible.
+ d1->show();
+ d2->show();
+ QTRY_VERIFY(ftabs->isVisible());
/*
* replug both dock widgets into their initial position
- * expected behavior: both docks are plugged and no longer floating
+ * expected behavior:
+ - both docks are plugged
+ - both docks are no longer floating
+ - title changes have been propagated
*/
@@ -1399,10 +1501,9 @@ void tst_QDockWidget::floatingTabs()
// Plug back into dock areas
qCDebug(lcTestDockWidget) << "*** test plugging back to dock areas ***";
qCDebug(lcTestDockWidget) << "Move d1 to left dock";
- //moveDockWidget(d1, d1->mapFrom(MainWindow, dockPoint(MainWindow, Qt::LeftDockWidgetArea)));
- moveDockWidget(d1, dockPoint(mainWindow, Qt::LeftDockWidgetArea));
+ moveDockWidget(d1, dockPoint(mainWindow, Qt::LeftDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop);
qCDebug(lcTestDockWidget) << "Move d2 to right dock";
- moveDockWidget(d2, dockPoint(mainWindow, Qt::RightDockWidgetArea));
+ moveDockWidget(d2, dockPoint(mainWindow, Qt::RightDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop);
qCDebug(lcTestDockWidget) << "Waiting" << waitBeforeClose << "ms before plugging back.";
QTest::qWait(waitBeforeClose);
@@ -1416,13 +1517,98 @@ void tst_QDockWidget::floatingTabs()
QTRY_VERIFY(ftabs.isNull());
// Check if paths are consistent
+ QMainWindowLayout* layout = qobject_cast<QMainWindowLayout *>(mainWindow->layout());
qCDebug(lcTestDockWidget) << "Checking path consistency" << layout->layoutState.indexOf(d1) << layout->layoutState.indexOf(d2);
- // Path1 must be identical
- QTRY_VERIFY(path1 == layout->layoutState.indexOf(d1));
+ // Paths must be identical
+ QTRY_COMPARE(layout->layoutState.indexOf(d1), path1);
+ QTRY_COMPARE(layout->layoutState.indexOf(d2), path2);
- // d1 must have a gap item due to size change
- QTRY_VERIFY(layout->layoutState.indexOf(d2) == QList<int>() << path2 << 0);
+ QCOMPARE(mainWindow->tabifiedDockWidgets(d1), {});
+ QCOMPARE(mainWindow->tabifiedDockWidgets(d2), {});
+#else
+ QSKIP("test requires -developer-build option");
+#endif // QT_BUILD_INTERNAL
+}
+
+void tst_QDockWidget::deleteFloatingTabWithSingleDockWidget_data()
+{
+#ifdef QT_BUILD_INTERNAL
+ QTest::addColumn<int>("reason");
+ QTest::addRow("Delete child") << static_cast<int>(ChildRemovalReason::Destroyed);
+ QTest::addRow("Close child") << static_cast<int>(ChildRemovalReason::Closed);
+ QTest::addRow("Reparent child") << static_cast<int>(ChildRemovalReason::Reparented);
+#endif
+}
+
+void tst_QDockWidget::deleteFloatingTabWithSingleDockWidget()
+{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Test skipped on Wayland.");
+#ifdef Q_OS_WIN
+ QSKIP("Test skipped on Windows platforms");
+#endif // Q_OS_WIN
+#ifdef QT_BUILD_INTERNAL
+
+ QFETCH(int, reason);
+ const ChildRemovalReason removalReason = static_cast<ChildRemovalReason>(reason);
+
+ QPointer<QDockWidget> d1;
+ QPointer<QDockWidget> d2;
+ QPointer<QWidget> cent;
+ QMainWindow* mainWindow;
+ QList<int> path1;
+ QList<int> path2;
+ createFloatingTabs(mainWindow, cent, d1, d2, path1, path2);
+ std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);
+
+ switch (removalReason) {
+ case ChildRemovalReason::Destroyed:
+ delete d1;
+ break;
+ case ChildRemovalReason::Closed:
+ d1->close();
+ break;
+ case ChildRemovalReason::Reparented:
+ // This will create an invalid state, because setParent() doesn't fix the item_list.
+ // Testing this case anyway, because setParent() includig item_list fixup is executed,
+ // when the 2nd last dock widget is dragged out of a floating tab.
+ // => despite of the broken state, the group window has to be gone.
+ d1->setParent(mainWindow);
+ break;
+ }
+
+ QTRY_VERIFY(!qobject_cast<QDockWidgetGroupWindow *>(d2->parentWidget()));
+ QTRY_VERIFY(mainWindow->findChildren<QDockWidgetGroupWindow *>().isEmpty());
+#endif // QT_BUILD_INTERNAL
+}
+
+void tst_QDockWidget::hoverWithoutDrop()
+{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Test skipped on Wayland.");
+#ifdef QT_BUILD_INTERNAL
+
+ QPointer<QDockWidget> d1;
+ QPointer<QDockWidget> d2;
+ QPointer<QWidget> cent;
+ QMainWindow* mainWindow;
+ createTestWidgets(mainWindow, cent, d1, d2);
+ std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);
+
+ // unplug and resize both dock widgets
+ unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow));
+ unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow));
+
+ // Test plugging
+ qCDebug(lcTestDockWidget) << "*** move d1 dock over d2 dock ***";
+ qCDebug(lcTestDockWidget) << "*******(test hovering)***********";
+ qCDebug(lcTestDockWidget) << "Move d1 over d2, wait and return to origin";
+ const QPoint source = d1->mapToGlobal(d1->rect().center());
+ const QPoint target = d2->mapToGlobal(d2->rect().center());
+ moveDockWidget(d1, target, source, MoveDockWidgetRule::Abort);
+ auto *groupWindow = mainWindow->findChild<QDockWidgetGroupWindow *>();
+ QCOMPARE(groupWindow, nullptr);
#else
QSKIP("test requires -developer-build option");
#endif // QT_BUILD_INTERNAL
@@ -1431,6 +1617,8 @@ void tst_QDockWidget::floatingTabs()
// test hide & show
void tst_QDockWidget::hideAndShow()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Test skipped on Wayland.");
#ifdef QT_BUILD_INTERNAL
// Skip test if xcb error is launched
qThis = this;
@@ -1473,7 +1661,7 @@ void tst_QDockWidget::hideAndShow()
unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow));
unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow));
- // Check hiding of undocked widgets
+ // Check hiding of undocked widgets
qCDebug(lcTestDockWidget) << "Hiding mainWindow with unplugged dock widgets" << mainWindow;
mainWindow->hide();
QTRY_VERIFY(!mainWindow->isVisible());
@@ -1484,6 +1672,16 @@ void tst_QDockWidget::hideAndShow()
QTRY_VERIFY(!d1->isVisible());
QTRY_VERIFY(!d2->isVisible());
+
+ // Check floating, hidden dock widgets remain hidden, when their state is restored
+ qCDebug(lcTestDockWidget) << "Restoring state of unplugged, hidden dock widgets" << mainWindow;
+ const QByteArray state = mainWindow->saveState();
+ mainWindow->restoreState(state);
+ mainWindow->show();
+ QVERIFY(QTest::qWaitForWindowExposed(mainWindow));
+ QTRY_VERIFY(!d1->isVisible());
+ QTRY_VERIFY(!d2->isVisible());
+
qCDebug(lcTestDockWidget) << "Waiting" << waitBeforeClose << "ms before closing.";
QTest::qWait(waitBeforeClose);
#else
@@ -1494,6 +1692,8 @@ void tst_QDockWidget::hideAndShow()
// test closing and deleting consistency
void tst_QDockWidget::closeAndDelete()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Test skipped on Wayland.");
#ifdef QT_BUILD_INTERNAL
// Create a mainwindow with a central widget and two dock widgets
QPointer<QDockWidget> d1;
@@ -1509,7 +1709,7 @@ void tst_QDockWidget::closeAndDelete()
// Create a floating tab and unplug it again
qCDebug(lcTestDockWidget) << "Move d1 over d2";
- moveDockWidget(d1, d2->mapToGlobal(d2->rect().center()));
+ moveDockWidget(d1, d2->mapToGlobal(d2->rect().center()), QPoint(), MoveDockWidgetRule::Drop);
// Both dock widgets must no longer be floating
// disabled due to flakiness on macOS and Windows
@@ -1521,8 +1721,10 @@ void tst_QDockWidget::closeAndDelete()
qWarning("OS flakiness: D2 is docked and reports being floating");
// Close everything with a single shot. Expected behavior: Event loop stops
- bool eventLoopStopped = true;
- QTimer::singleShot(0, this, [mainWindow, d1, d2] {
+ QSignalSpy closeSpy(qApp, &QApplication::lastWindowClosed);
+ QObject localContext;
+
+ QTimer::singleShot(0, &localContext, [&](){
mainWindow->close();
QTRY_VERIFY(!mainWindow->isVisible());
QTRY_VERIFY(d1->isVisible());
@@ -1531,19 +1733,12 @@ void tst_QDockWidget::closeAndDelete()
d2->close();
QTRY_VERIFY(!d1->isVisible());
QTRY_VERIFY(!d2->isVisible());
- });
-
- // Fallback timer to report event loop still running
- QTimer::singleShot(100, this, [&eventLoopStopped] {
- qCDebug(lcTestDockWidget) << "Last dock widget hasn't shout down event loop!";
- eventLoopStopped = false;
+ QTRY_COMPARE(closeSpy.count(), 1);
QApplication::quit();
});
QApplication::exec();
- QTRY_VERIFY(eventLoopStopped);
-
// Check heap cleanup
qCDebug(lcTestDockWidget) << "Deleting mainWindow";
up_mainWindow.reset();
@@ -1555,9 +1750,29 @@ void tst_QDockWidget::closeAndDelete()
#endif // QT_BUILD_INTERNAL
}
+void tst_QDockWidget::closeUnclosable()
+{
+ QDockWidget *dockWidget = new QDockWidget("dock");
+ dockWidget->setWidget(new QScrollArea);
+ dockWidget->setFeatures(QDockWidget::DockWidgetFloatable);
+
+ QMainWindow mw;
+ mw.addDockWidget(Qt::TopDockWidgetArea, dockWidget);
+ mw.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&mw));
+ dockWidget->setFloating(true);
+
+ QCOMPARE(dockWidget->close(), false);
+ mw.close();
+ QCOMPARE(dockWidget->close(), true);
+}
+
// Test dock area permissions
void tst_QDockWidget::dockPermissions()
{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
+ QSKIP("Test skipped on Wayland.");
#ifdef Q_OS_WIN
QSKIP("Test skipped on Windows platforms");
#endif // Q_OS_WIN
@@ -1599,16 +1814,16 @@ void tst_QDockWidget::dockPermissions()
// Move d2 to non allowed dock areas and verify it remains floating
qCDebug(lcTestDockWidget) << "Move d2 to top dock";
- moveDockWidget(d2, dockPoint(mainWindow, Qt::TopDockWidgetArea));
+ moveDockWidget(d2, dockPoint(mainWindow, Qt::TopDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop);
QTRY_VERIFY(d2->isFloating());
qCDebug(lcTestDockWidget) << "Move d2 to left dock";
//moveDockWidget(d2, d2->mapFrom(MainWindow, dockPoint(MainWindow, Qt::LeftDockWidgetArea)));
- moveDockWidget(d2, dockPoint(mainWindow, Qt::LeftDockWidgetArea));
+ moveDockWidget(d2, dockPoint(mainWindow, Qt::LeftDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop);
QTRY_VERIFY(d2->isFloating());
qCDebug(lcTestDockWidget) << "Move d2 to bottom dock";
- moveDockWidget(d2, dockPoint(mainWindow, Qt::BottomDockWidgetArea));
+ moveDockWidget(d2, dockPoint(mainWindow, Qt::BottomDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop);
QTRY_VERIFY(d2->isFloating());
qCDebug(lcTestDockWidget) << "Waiting" << waitBeforeClose << "ms before closing.";
diff --git a/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt b/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt
index 88e19e218d..b023174dc9 100644
--- a/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qdoublespinbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qdoublespinbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qdoublespinbox
SOURCES
tst_qdoublespinbox.cpp
diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
index c365e09277..28752cd40d 100644
--- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
+++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt b/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt
index 4f02720fc7..5e2f3bd955 100644
--- a/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qfocusframe Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qfocusframe LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qfocusframe
SOURCES
tst_qfocusframe.cpp
diff --git a/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp b/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp
index ce711b7ed7..560ba686cc 100644
--- a/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp
+++ b/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt b/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt
index 319aba0723..15dad99b9c 100644
--- a/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qfontcombobox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qfontcombobox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qfontcombobox
SOURCES
tst_qfontcombobox.cpp
diff --git a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp
index 149b6586ae..abb9262288 100644
--- a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp
+++ b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qframe/CMakeLists.txt b/tests/auto/widgets/widgets/qframe/CMakeLists.txt
index 104fb07bca..2213f4a7d9 100644
--- a/tests/auto/widgets/widgets/qframe/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qframe/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qframe Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qframe LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp
index 40cb897ed1..324c512219 100644
--- a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp
+++ b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp
@@ -1,6 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QFrame>
diff --git a/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt b/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt
index c440f902bd..0414ce0cf5 100644
--- a/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qgroupbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qgroupbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qgroupbox
SOURCES
tst_qgroupbox.cpp
diff --git a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
index 065310398c..0d716cce97 100644
--- a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
+++ b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -430,7 +430,7 @@ void tst_QGroupBox::childrenAreDisabled()
layout->addWidget(new QRadioButton);
box.setLayout(layout);
- foreach (QObject *object, box.children()) {
+ for (QObject *object : box.children()) {
if (QWidget *widget = qobject_cast<QWidget *>(object)) {
QVERIFY(!widget->isEnabled());
QVERIFY(!widget->testAttribute(Qt::WA_ForceDisabled));
@@ -438,7 +438,7 @@ void tst_QGroupBox::childrenAreDisabled()
}
box.setChecked(true);
- foreach (QObject *object, box.children()) {
+ for (QObject *object : box.children()) {
if (QWidget *widget = qobject_cast<QWidget *>(object)) {
QVERIFY(widget->isEnabled());
QVERIFY(!widget->testAttribute(Qt::WA_ForceDisabled));
@@ -446,7 +446,7 @@ void tst_QGroupBox::childrenAreDisabled()
}
box.setChecked(false);
- foreach (QObject *object, box.children()) {
+ for (QObject *object : box.children()) {
if (QWidget *widget = qobject_cast<QWidget *>(object)) {
QVERIFY(!widget->isEnabled());
QVERIFY(!widget->testAttribute(Qt::WA_ForceDisabled));
diff --git a/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt b/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt
index 8d445b5090..0cf0b1bdd3 100644
--- a/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qkeysequenceedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qkeysequenceedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qkeysequenceedit
SOURCES
tst_qkeysequenceedit.cpp
diff --git a/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp b/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp
index 2bd0c6ed85..301be319bf 100644
--- a/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp
+++ b/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qlabel/CMakeLists.txt b/tests/auto/widgets/widgets/qlabel/CMakeLists.txt
index 08cf667ded..e29000a6ca 100644
--- a/tests/auto/widgets/widgets/qlabel/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qlabel/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qlabel Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlabel LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
index 2775e2c683..325e188091 100644
--- a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
+++ b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -77,6 +77,8 @@ private Q_SLOTS:
#ifndef QT_NO_CONTEXTMENU
void taskQTBUG_7902_contextMenuCrash();
+ void contextMenu_data();
+ void contextMenu();
#endif
void taskQTBUG_48157_dprPixmap();
@@ -561,6 +563,43 @@ void tst_QLabel::taskQTBUG_7902_contextMenuCrash()
QTest::qWait(350);
// No crash, it's allright.
}
+
+void tst_QLabel::contextMenu_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<Qt::TextInteractionFlag>("interactionFlags");
+ QTest::addColumn<bool>("showsContextMenu");
+
+ QTest::addRow("Read-only") << "Plain Text"
+ << Qt::NoTextInteraction
+ << false;
+ QTest::addRow("Selectable") << "Plain Text"
+ << Qt::TextEditorInteraction
+ << true;
+ QTest::addRow("Link") << "<a href=\"nowhere\">Rich text with link</a>"
+ << Qt::TextBrowserInteraction
+ << true;
+ QTest::addRow("Rich text") << "<b>Rich text without link</b>"
+ << Qt::TextBrowserInteraction
+ << true;
+}
+
+void tst_QLabel::contextMenu()
+{
+ QFETCH(QString, text);
+ QFETCH(Qt::TextInteractionFlag, interactionFlags);
+ QFETCH(bool, showsContextMenu);
+
+ QLabel label(text);
+ label.setTextInteractionFlags(interactionFlags);
+ label.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&label));
+
+ const QPoint menuPosition = label.rect().center();
+ QContextMenuEvent cme(QContextMenuEvent::Mouse, menuPosition, label.mapToGlobal(menuPosition));
+ QApplication::sendEvent(&label, &cme);
+ QCOMPARE(cme.isAccepted(), showsContextMenu);
+}
#endif
void tst_QLabel::taskQTBUG_48157_dprPixmap()
diff --git a/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt b/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt
index 06f701892e..954ec095e5 100644
--- a/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qlcdnumber Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlcdnumber LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qlcdnumber
SOURCES
tst_qlcdnumber.cpp
diff --git a/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp b/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp
index c339268e8e..8fcf9c49fe 100644
--- a/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp
+++ b/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt b/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt
index 50ef23f1bc..22ecf40aed 100644
--- a/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qlineedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlineedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qlineedit
SOURCES
tst_qlineedit.cpp
diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
index efd59059d0..be185c1e7a 100644
--- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -292,6 +292,13 @@ private slots:
void QTBUG_60319_setInputMaskCheckImSurroundingText();
void testQuickSelectionWithMouse();
void inputRejected();
+ void keyReleasePropagates();
+
+#if QT_CONFIG(shortcut)
+ void deleteWordByKeySequence_data();
+ void deleteWordByKeySequence();
+#endif
+
protected slots:
void editingFinished();
@@ -3517,11 +3524,12 @@ void tst_QLineEdit::textMargin_data()
QLineEdit testWidget;
QFontMetrics metrics(testWidget.font());
const QString s = QLatin1String("MMM MMM MMM");
+ const int windows11StyleHorizontalOffset = qApp->style()->inherits("QWindows11Style") ? 8 : 0;
// Different styles generate different offsets, so
// calculate the width rather than hardcode it.
- const int pixelWidthOfM = metrics.horizontalAdvance(s, 1);
- const int pixelWidthOfMMM_MM = metrics.horizontalAdvance(s, 6);
+ const int pixelWidthOfM = windows11StyleHorizontalOffset + metrics.horizontalAdvance(s, 1);
+ const int pixelWidthOfMMM_MM = windows11StyleHorizontalOffset + metrics.horizontalAdvance(s, 6);
QTest::newRow("default-0") << 0 << 0 << 0 << 0 << QPoint(pixelWidthOfMMM_MM, 0) << 6;
QTest::newRow("default-1") << 0 << 0 << 0 << 0 << QPoint(1, 1) << 0;
@@ -4685,7 +4693,8 @@ void tst_QLineEdit::sideWidgets()
testWidget.move(300, 300);
testWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&testWidget));
- foreach (QToolButton *button, lineEdit->findChildren<QToolButton *>())
+ const auto buttons = lineEdit->findChildren<QToolButton *>();
+ for (QToolButton *button : buttons)
QCOMPARE(button->cursor().shape(), Qt::ArrowCursor);
// Arbitrarily add/remove actions, trying to detect crashes. Add QTRY_VERIFY(false) to view the result.
delete label3Action;
@@ -4700,7 +4709,8 @@ void tst_QLineEdit::sideWidgets()
template <class T> T *findAssociatedWidget(const QAction *a)
{
- foreach (QObject *w, a->associatedObjects()) {
+ const auto associatedObjects = a->associatedObjects();
+ for (QObject *w : associatedObjects) {
if (T *result = qobject_cast<T *>(w))
return result;
}
@@ -4974,7 +4984,7 @@ void tst_QLineEdit::QTBUG59957_clearButtonLeftmostAction()
bool tst_QLineEdit::unselectingWithLeftOrRightChangesCursorPosition()
{
-#if defined Q_OS_WIN || defined Q_OS_QNX //Windows and QNX do not jump to the beginning of the selection
+#if defined Q_OS_WIN || defined Q_OS_QNX || defined Q_OS_VXWORKS //Windows, QNX and VxWorks do not jump to the beginning of the selection
return true;
#endif
// Platforms minimal/offscreen also need left after unselecting with right
@@ -5143,5 +5153,149 @@ void tst_QLineEdit::inputRejected()
QCOMPARE(spyInputRejected.size(), 2);
}
+void tst_QLineEdit::keyReleasePropagates()
+{
+ struct Dialog : QWidget
+ {
+ QLineEdit *lineEdit;
+ int releasedKey = {};
+
+ Dialog()
+ {
+ lineEdit = new QLineEdit;
+ QHBoxLayout *hbox = new QHBoxLayout;
+
+ hbox->addWidget(lineEdit);
+ setLayout(hbox);
+ }
+
+ protected:
+ void keyReleaseEvent(QKeyEvent *e) override
+ {
+ releasedKey = e->key();
+ }
+ } dialog;
+
+ dialog.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&dialog));
+
+ QTest::keyPress(dialog.lineEdit, Qt::Key_A);
+ QTest::keyRelease(dialog.lineEdit, Qt::Key_A);
+
+ QCOMPARE(dialog.releasedKey, Qt::Key_A);
+
+ QTest::keyPress(dialog.lineEdit, Qt::Key_Alt);
+ QTest::keyRelease(dialog.lineEdit, Qt::Key_Alt);
+
+ QCOMPARE(dialog.releasedKey, Qt::Key_Alt);
+}
+
+#if QT_CONFIG(shortcut)
+
+void tst_QLineEdit::deleteWordByKeySequence_data()
+{
+ QTest::addColumn<QString>("startText");
+ QTest::addColumn<int>("selectionStart");
+ QTest::addColumn<int>("selectionEnd");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<QKeySequence::StandardKey>("key");
+ QTest::addColumn<QString>("expectedText");
+ QTest::addColumn<int>("expectedCursorPosition");
+
+ QTest::newRow("Delete start, no selection")
+ << QStringLiteral("Some Text") << 0 << 0 << 9 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Some ") << 5;
+ QTest::newRow("Delete end, no selection")
+ << QStringLiteral("Some Text") << 0 << 0 << 5 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Some ") << 5;
+ QTest::newRow("Delete start from middle, no selection")
+ << QStringLiteral("Some Text") << 0 << 0 << 7 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Some xt") << 5;
+ QTest::newRow("Delete end from middle, no selection")
+ << QStringLiteral("Some Text") << 0 << 0 << 7 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Some Te") << 7;
+ QTest::newRow("Delete end from first, no selection")
+ << QStringLiteral("Some Text") << 0 << 0 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Text") << 0;
+
+ QTest::newRow("Delete start, full selection")
+ << QStringLiteral("Some Text") << 0 << 9 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("") << 0;
+ QTest::newRow("Delete end, full selection")
+ << QStringLiteral("Some Text") << 0 << 9 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("") << 0;
+ QTest::newRow("Delete start, full selection, single word")
+ << QStringLiteral("Some") << 0 << 4 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("") << 0;
+ QTest::newRow("Delete end, full selection, single word")
+ << QStringLiteral("Some") << 0 << 4 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("") << 0;
+
+ QTest::newRow("Delete start, word selection")
+ << QStringLiteral("Some Text") << 5 << 9 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Some ") << 5;
+ QTest::newRow("Delete end, word selection")
+ << QStringLiteral("Some Text") << 5 << 9 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Some ") << 5;
+ QTest::newRow("Delete start, partial word selection")
+ << QStringLiteral("Some Text") << 5 << 7 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Some xt") << 5;
+ QTest::newRow("Delete end, partial word selection")
+ << QStringLiteral("Some Text") << 5 << 7 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Some xt") << 5;
+ QTest::newRow("Delete start, partial inner word selection")
+ << QStringLiteral("Some Text") << 6 << 8 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Some Tt") << 6;
+ QTest::newRow("Delete end, partial inner word selection")
+ << QStringLiteral("Some Text") << 6 << 8 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Some Tt") << 6;
+ QTest::newRow("Delete start, selection with space")
+ << QStringLiteral("Some Text") << 3 << 9 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Som") << 3;
+ QTest::newRow("Delete end, selection with space")
+ << QStringLiteral("Some Text") << 3 << 9 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Som") << 3;
+ QTest::newRow("Delete start, partial word selection with space")
+ << QStringLiteral("Some Text") << 3 << 7 << 0 << QKeySequence::DeleteStartOfWord
+ << QStringLiteral("Somxt") << 3;
+ QTest::newRow("Delete end, partial selection with space")
+ << QStringLiteral("Some Text") << 3 << 7 << 0 << QKeySequence::DeleteEndOfWord
+ << QStringLiteral("Somxt") << 3;
+}
+
+void tst_QLineEdit::deleteWordByKeySequence()
+{
+ QFETCH(QString, startText);
+ QFETCH(int, selectionStart);
+ QFETCH(int, selectionEnd);
+ QFETCH(int, cursorPosition);
+ QFETCH(QKeySequence::StandardKey, key);
+ QFETCH(QString, expectedText);
+ QFETCH(int, expectedCursorPosition);
+
+ QWidget widget;
+
+ QLineEdit *lineEdit = new QLineEdit(startText, &widget);
+ lineEdit->setFocus();
+ lineEdit->setCursorPosition(cursorPosition);
+ if (selectionStart != selectionEnd)
+ lineEdit->setSelection(selectionStart, selectionEnd - selectionStart);
+
+ widget.show();
+
+ QVERIFY(QTest::qWaitForWindowActive(&widget));
+
+ QTestEventList keys;
+ addKeySequenceStandardKey(keys, key);
+ keys.simulate(lineEdit);
+
+ QCOMPARE(lineEdit->text(), expectedText);
+ QCOMPARE(lineEdit->selectionStart(), -1);
+ QCOMPARE(lineEdit->selectionEnd(), -1);
+ QCOMPARE(lineEdit->cursorPosition(), expectedCursorPosition);
+}
+
+#endif // QT_CONFIG(shortcut)
+
QTEST_MAIN(tst_QLineEdit)
#include "tst_qlineedit.moc"
diff --git a/tests/auto/widgets/widgets/qmainwindow/BLACKLIST b/tests/auto/widgets/widgets/qmainwindow/BLACKLIST
new file mode 100644
index 0000000000..28b08026d8
--- /dev/null
+++ b/tests/auto/widgets/widgets/qmainwindow/BLACKLIST
@@ -0,0 +1,2 @@
+[QTBUG52175_tabifiedDockWidgetActivated]
+macos arm ci
diff --git a/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt b/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt
index 5cbc23dade..93f94f78c7 100644
--- a/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qmainwindow Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmainwindow LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qmainwindow
SOURCES
tst_qmainwindow.cpp
diff --git a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
index 91aa651bab..093af90d1c 100644
--- a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
+++ b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -104,6 +104,7 @@ private slots:
void restoreStateFromPreviousVersion();
void restoreStateSizeChanged_data();
void restoreStateSizeChanged();
+ void restoreAndModify();
void createPopupMenu();
void hideBeforeLayout();
#ifdef QT_BUILD_INTERNAL
@@ -1358,12 +1359,13 @@ void tst_QMainWindow::restoreState()
//tests the restoration of the previous versions of window settings
void tst_QMainWindow::restoreStateFromPreviousVersion()
{
- QList<QByteArray> restoreData;
- restoreData << QByteArray((char*)restoreData41, sizeof(restoreData41))
- << QByteArray((char*)restoreData42, sizeof(restoreData42))
- << QByteArray((char*)restoreData43, sizeof(restoreData43));
+ const QByteArray restoreData[] = {
+ QByteArray((char*)restoreData41, sizeof(restoreData41)),
+ QByteArray((char*)restoreData42, sizeof(restoreData42)),
+ QByteArray((char*)restoreData43, sizeof(restoreData43)),
+ };
- foreach(QByteArray ba, restoreData) {
+ for (const QByteArray &ba : restoreData) {
QMainWindow win;
win.setCentralWidget(new QTextEdit);
@@ -1475,6 +1477,70 @@ void tst_QMainWindow::restoreStateSizeChanged()
}
}
+/*!
+ If a main window's state is restored but also modified, then we
+ might have to forget the restored state to avoid dangling pointers.
+ See comment in QMainWindowLayout::applyRestoredState() and QTBUG-120025.
+*/
+void tst_QMainWindow::restoreAndModify()
+{
+ class MainWindow : public QMainWindow
+ {
+ public:
+ MainWindow()
+ {
+ setCentralWidget(new QTextEdit);
+
+ customers = new QDockWidget(tr("Customers"), this);
+ customers->setObjectName("Customers");
+ customers->setAllowedAreas(Qt::LeftDockWidgetArea |
+ Qt::RightDockWidgetArea);
+ customers->setWidget(new QTextEdit);
+ addDockWidget(Qt::RightDockWidgetArea, customers);
+
+ paragraphs = new QDockWidget(tr("Paragraphs"), this);
+ paragraphs->setObjectName("Paragraphs");
+ paragraphs->setWidget(new QTextEdit);
+ addDockWidget(Qt::RightDockWidgetArea, paragraphs);
+ }
+
+ void restore()
+ {
+ if (!savedGeometry.isEmpty())
+ restoreGeometry(savedGeometry);
+ setWindowState(Qt::WindowMaximized);
+ if (!savedState.isEmpty())
+ restoreState(savedState);
+
+ tabifyDockWidget(customers, paragraphs);
+ }
+ protected:
+ void closeEvent(QCloseEvent *event) override
+ {
+ savedGeometry = saveGeometry();
+ savedState = saveState();
+
+ return QMainWindow::closeEvent(event);
+ }
+ private:
+ QByteArray savedGeometry;
+ QByteArray savedState;
+
+ QDockWidget *customers;
+ QDockWidget *paragraphs;
+
+ } mainWindow;
+
+ mainWindow.restore();
+ mainWindow.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&mainWindow));
+ mainWindow.close();
+
+ mainWindow.restore();
+ mainWindow.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&mainWindow));
+}
+
void tst_QMainWindow::createPopupMenu()
{
{
@@ -1671,25 +1737,25 @@ void MoveSeparator::apply(QMainWindow *mw) const
QMap<QString, QRect> dockWidgetGeometries(QMainWindow *mw)
{
QMap<QString, QRect> result;
- QList<QDockWidget*> dockWidgets = mw->findChildren<QDockWidget*>();
- foreach (QDockWidget *dw, dockWidgets)
+ const QList<QDockWidget*> dockWidgets = mw->findChildren<QDockWidget*>();
+ for (QDockWidget *dw : dockWidgets)
result.insert(dw->objectName(), dw->geometry());
return result;
}
#define COMPARE_DOCK_WIDGET_GEOS(_oldGeos, _newGeos) \
{ \
- QMap<QString, QRect> __oldGeos = _oldGeos; \
- QMap<QString, QRect> __newGeos = _newGeos; \
- QCOMPARE(__newGeos.keys(), __oldGeos.keys()); \
- QStringList __keys = __newGeos.keys(); \
- foreach (const QString &key, __keys) { \
- QRect __r1 = __oldGeos[key]; \
- QRect __r2 = __newGeos[key]; \
- if (__r1 != __r2) \
- qWarning() << key << __r1 << __r2; \
+ QMap<QString, QRect> _v_oldGeos = _oldGeos; \
+ QMap<QString, QRect> _v_newGeos = _newGeos; \
+ QCOMPARE(_v_newGeos.keys(), _v_oldGeos.keys()); \
+ const QStringList _v_keys = _v_newGeos.keys(); \
+ for (const QString &key : _v_keys) { \
+ QRect _v_r1 = _v_oldGeos[key]; \
+ QRect _v_r2 = _v_newGeos[key]; \
+ if (_v_r1 != _v_r2) \
+ qWarning() << key << _v_r1 << _v_r2; \
} \
- QCOMPARE(__newGeos, __oldGeos); \
+ QCOMPARE(_v_newGeos, _v_oldGeos); \
}
#ifdef QT_BUILD_INTERNAL
@@ -1735,8 +1801,8 @@ void tst_QMainWindow::saveRestore_data()
#ifdef QT_BUILD_INTERNAL
void tst_QMainWindow::saveRestore()
{
- QFETCH(AddList, addList);
- QFETCH(MoveList, moveList);
+ QFETCH(const AddList, addList);
+ QFETCH(const MoveList, moveList);
QByteArray stateData;
QMap<QString, QRect> dockWidgetGeos;
@@ -1748,12 +1814,12 @@ void tst_QMainWindow::saveRestore()
QTextEdit centralWidget("The rain in Spain falls mainly on the plains");
mainWindow.setCentralWidget(&centralWidget);
- foreach (const AddDockWidget &adw, addList)
+ for (const AddDockWidget &adw : addList)
adw.apply(&mainWindow);
mainWindow.show();
- foreach (const MoveSeparator &ms, moveList)
+ for (const MoveSeparator &ms : moveList)
ms.apply(&mainWindow);
dockWidgetGeos = dockWidgetGeometries(&mainWindow);
@@ -1771,7 +1837,7 @@ void tst_QMainWindow::saveRestore()
QTextEdit centralWidget("The rain in Spain falls mainly on the plains");
mainWindow.setCentralWidget(&centralWidget);
- foreach (const AddDockWidget &adw, addList)
+ for (const AddDockWidget &adw : addList)
adw.apply(&mainWindow);
mainWindow.show();
@@ -1788,7 +1854,7 @@ void tst_QMainWindow::saveRestore()
QTextEdit centralWidget("The rain in Spain falls mainly on the plains");
mainWindow.setCentralWidget(&centralWidget);
- foreach (const AddDockWidget &adw, addList)
+ for (const AddDockWidget &adw : addList)
adw.apply(&mainWindow);
mainWindow.resize(size);
mainWindow.restoreState(stateData);
@@ -1864,7 +1930,7 @@ void tst_QMainWindow::addToolbarAfterShow()
void tst_QMainWindow::centralWidgetSize()
{
if (qGuiApp->styleHints()->showIsFullScreen())
- QSKIP("The platform is auto maximizing, so the test makes no sense");;
+ QSKIP("The platform is auto maximizing, so the test makes no sense");
QMainWindow mainWindow;
mainWindow.menuBar()->addMenu("menu");
@@ -2096,10 +2162,11 @@ void tst_QMainWindow::resizeDocks()
mw.setDockNestingEnabled(true);
mw.resize(1800, 600);
- foreach (const AddDockWidget &i, addList)
+ for (const AddDockWidget &i : std::as_const(addList))
i.apply(&mw);
- foreach (QDockWidget *dw, mw.findChildren<QDockWidget *>())
+ const auto dockWidgets = mw.findChildren<QDockWidget *>();
+ for (QDockWidget *dw : dockWidgets)
dw->setStyleSheet( "* { background-color: " + dw->objectName() +" }");
mw.setCentralWidget(new QTextEdit);
@@ -2108,11 +2175,11 @@ void tst_QMainWindow::resizeDocks()
QVERIFY(QTest::qWaitForWindowExposed(&mw));
QFETCH(Qt::Orientation, orientation);
- QFETCH(QStringList, docks);
+ QFETCH(const QStringList, docks);
QFETCH(QList<int>, sizes);
QList<QDockWidget *> list;
- foreach (const QString &name, docks) {
+ for (const QString &name : docks) {
QDockWidget *d = mw.findChild<QDockWidget *>(name);
QVERIFY(d);
list << d;
diff --git a/tests/auto/widgets/widgets/qmdiarea/BLACKLIST b/tests/auto/widgets/widgets/qmdiarea/BLACKLIST
index 3091b73269..c3234bf56c 100644
--- a/tests/auto/widgets/widgets/qmdiarea/BLACKLIST
+++ b/tests/auto/widgets/widgets/qmdiarea/BLACKLIST
@@ -1,15 +1,7 @@
[tileSubWindows]
-ubuntu-16.04
-rhel-7.6
centos
opensuse-leap
macos
-ubuntu-18.04
-ubuntu-20.04
-macos
-rhel-7.4
-macos
-opensuse-42.3
[resizeTimer]
macos
diff --git a/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt b/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt
index 34332758b6..5f61dc8664 100644
--- a/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qmdiarea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmdiarea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qmdiarea
SOURCES
tst_qmdiarea.cpp
diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
index 946688f8b9..0f652f2900 100644
--- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
+++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -176,7 +176,7 @@ static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const
// QWidget::childAt with the position of the first one and subsequently adding
// dx and dy.
QPoint subWindowPos(20, 5);
- foreach (int expectedIndex, expectedIndices) {
+ for (int expectedIndex : expectedIndices) {
QMdiSubWindow *expected = subWindows.at(expectedIndex);
expected->raise();
if (mdiArea->viewport()->childAt(subWindowPos) != expected)
@@ -187,7 +187,7 @@ static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const
}
// Restore stacking order.
- foreach (QMdiSubWindow *subWindow, activationOrderList) {
+ for (QMdiSubWindow *subWindow : activationOrderList) {
mdiArea->setActiveSubWindow(subWindow);
qApp->processEvents();
}
@@ -260,6 +260,7 @@ private slots:
void task_236750();
void qtbug92240_title_data();
void qtbug92240_title();
+ void tabbedview_singleSubWindow();
void tabbedview_activefirst();
void tabbedview_activesecond();
void tabbedview_activethird();
@@ -1135,7 +1136,8 @@ void tst_QMdiArea::addAndRemoveWindows()
}
// removeSubWindow
- foreach (QWidget *window, workspace.subWindowList()) {
+ const auto subWindows = workspace.subWindowList();
+ for (QWidget *window : subWindows) {
workspace.removeSubWindow(window);
delete window;
}
@@ -1685,7 +1687,8 @@ void tst_QMdiArea::tileSubWindows()
QTRY_COMPARE(workspace.size(), QSize(350, 150));
const QSize minSize(600, 130);
- foreach (QMdiSubWindow *subWindow, workspace.subWindowList())
+ const auto subWindows = workspace.subWindowList();
+ for (QMdiSubWindow *subWindow : subWindows)
subWindow->setMinimumSize(minSize);
QCOMPARE(workspace.size(), QSize(350, 150));
@@ -1843,7 +1846,7 @@ void tst_QMdiArea::resizeMaximizedChildWindows()
int newSize = startSize + increment * windowCount;
QCOMPARE(workspaceSize, QSize(newSize, newSize));
- foreach (QWidget *window, windows)
+ for (QWidget *window : std::as_const(windows))
QCOMPARE(window->rect(), workspace.contentsRect());
}
@@ -1893,7 +1896,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation()
}
// Verify that activated windows still are maximized on activation.
- QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
+ const QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
for (int i = 0; i < subWindows.size(); ++i) {
mdiArea.activateNextSubWindow();
QMdiSubWindow *window = subWindows.at(i);
@@ -1930,7 +1933,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation()
QVERIFY(mdiArea.activeSubWindow()->isMaximized());
// Minimize all windows.
- foreach (QMdiSubWindow *window, subWindows) {
+ for (QMdiSubWindow *window : subWindows) {
window->showMinimized();
QVERIFY(window->isMinimized());
qApp->processEvents();
@@ -2317,7 +2320,7 @@ void tst_QMdiArea::setViewMode()
QVERIFY(QTest::qWaitForWindowExposed(&mdiArea));
QMdiSubWindow *activeSubWindow = mdiArea.activeSubWindow();
- QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
+ const QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
// Default.
QVERIFY(!activeSubWindow->isMaximized());
@@ -2386,13 +2389,12 @@ void tst_QMdiArea::setViewMode()
QVERIFY(tabBar->isTabEnabled(tabIndex));
// Remove sub-windows and make sure the tab is removed.
- foreach (QMdiSubWindow *subWindow, subWindows) {
+ for (QMdiSubWindow *subWindow : subWindows) {
if (subWindow != activeSubWindow) {
mdiArea.removeSubWindow(subWindow);
delete subWindow;
}
}
- subWindows.clear();
QCOMPARE(tabBar->count(), 1);
// Go back to default (QMdiArea::SubWindowView).
@@ -2593,8 +2595,11 @@ void tst_QMdiArea::nativeSubWindows()
// No native widgets.
QVERIFY(!mdiArea.viewport()->internalWinId());
- foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
- QVERIFY(!subWindow->internalWinId());
+ {
+ const auto subWindows = mdiArea.subWindowList();
+ for (QMdiSubWindow *subWindow : subWindows)
+ QVERIFY(!subWindow->internalWinId());
+ }
QWidget *nativeWidget = new QWidget;
QVERIFY(nativeWidget->winId()); // enforce native window.
@@ -2603,8 +2608,11 @@ void tst_QMdiArea::nativeSubWindows()
// The viewport and all the sub-windows must be native.
QVERIFY(mdiArea.viewport()->internalWinId());
- foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
- QVERIFY(subWindow->internalWinId());
+ {
+ const auto subWindows = mdiArea.subWindowList();
+ for (QMdiSubWindow *subWindow : subWindows)
+ QVERIFY(subWindow->internalWinId());
+ }
// Add a non-native widget. This should become native.
QMdiSubWindow *subWindow = new QMdiSubWindow;
@@ -2625,8 +2633,11 @@ void tst_QMdiArea::nativeSubWindows()
// The viewport and all the sub-windows must be native.
QVERIFY(mdiArea.viewport()->internalWinId());
- foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
- QVERIFY(subWindow->internalWinId());
+ {
+ const auto subWindows = mdiArea.subWindowList();
+ for (QMdiSubWindow *subWindow : subWindows)
+ QVERIFY(subWindow->internalWinId());
+ }
}
{ // Make a sub-window native *after* it's added to the area.
@@ -2642,9 +2653,12 @@ void tst_QMdiArea::nativeSubWindows()
// All the sub-windows should be native at this point
QVERIFY(mdiArea.viewport()->internalWinId());
- foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
+ {
+ const auto subWindows = mdiArea.subWindowList();
+ for (QMdiSubWindow *subWindow : subWindows)
QVERIFY(subWindow->internalWinId());
}
+ }
}
void tst_QMdiArea::task_209615()
@@ -2715,6 +2729,21 @@ void tst_QMdiArea::qtbug92240_title()
QTRY_COMPARE(w.windowTitle(), QLatin1String("QTBUG-92240 - [2]"));
}
+void tst_QMdiArea::tabbedview_singleSubWindow()
+{
+ // With only one sub-window, setViewMode() before addSubWindow(); and addSubWindow()
+ // before show(), ensure the sub-window is properly activated.
+ QMdiArea mdiArea;
+ mdiArea.setViewMode(QMdiArea::TabbedView);
+ auto *w = new QWidget(&mdiArea);
+ mdiArea.addSubWindow(w);
+ mdiArea.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&mdiArea));
+ auto *sub = mdiArea.subWindowList().at(0);
+ QCOMPARE(mdiArea.activeSubWindow(), sub);
+ QVERIFY(sub->isMaximized());
+}
+
static void setupMdiAreaWithTabbedView(QMdiArea &mdiArea)
{
mdiArea.setViewMode(QMdiArea::TabbedView);
diff --git a/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt b/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt
index 23b3b89296..45b7b74ac4 100644
--- a/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qmdisubwindow Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmdisubwindow LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qmdisubwindow
SOURCES
tst_qmdisubwindow.cpp
diff --git a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
index 9adaf81116..38808d1702 100644
--- a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
+++ b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qmdisubwindow.h"
#include "private/qmdisubwindow_p.h"
@@ -954,6 +954,8 @@ void tst_QMdiSubWindow::mouseDoubleClick()
if (!window->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, window))
height += window->isMinimized() ? 8 : 4;
QPoint mousePosition(window->width() / 2, height - 1);
+ if (window->style()->inherits("QWindows11Style"))
+ mousePosition = QPoint(8, height - 1);
sendMouseMove(window, mousePosition, Qt::NoButton);
// Without Qt::WindowShadeButtonHint flag set
@@ -981,8 +983,10 @@ void tst_QMdiSubWindow::mouseDoubleClick()
window->showMinimized();
QVERIFY(window->isMinimized());
+ //Process QEvent::WindowStateChange
+ QCoreApplication::processEvents();
sendMouseDoubleClick(window, mousePosition);
- QVERIFY(!window->isMinimized());
+ QTRY_VERIFY(!window->isMinimized());
QCOMPARE(window->geometry(), originalGeometry);
}
@@ -1373,7 +1377,7 @@ void tst_QMdiSubWindow::setWindowTitle()
// other widgets which are not real top-level widgets).
QCOMPARE(window->windowTitle(), expectedWindowTitle);
- textEdit->setWindowModified(true);;
+ textEdit->setWindowModified(true);
expectedWindowTitle = QLatin1String("Override child title");
window->setWindowTitle(expectedWindowTitle);
QVERIFY(window->isWindowModified());
@@ -1867,7 +1871,6 @@ void tst_QMdiSubWindow::closeOnDoubleClick()
void tst_QMdiSubWindow::setFont()
{
- QSKIP("This test function is unstable in CI, please see QTBUG-22544");
QMdiArea mdiArea;
mdiArea.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
QMdiSubWindow *subWindow = mdiArea.addSubWindow(new TestPushButton(QLatin1String("test")));
diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST
index dc1ab8ddd3..88484ddffa 100644
--- a/tests/auto/widgets/widgets/qmenu/BLACKLIST
+++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST
@@ -16,6 +16,7 @@ android
android
[pushButtonPopulateOnAboutToShow]
android
+wayland
[QTBUG8122_widgetActionCrashOnClose]
android
[click_while_dismissing_submenu]
diff --git a/tests/auto/widgets/widgets/qmenu/CMakeLists.txt b/tests/auto/widgets/widgets/qmenu/CMakeLists.txt
index d639119bb3..1716ab85da 100644
--- a/tests/auto/widgets/widgets/qmenu/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qmenu/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qmenu Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmenu LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qmenu
SOURCES
tst_qmenu.cpp
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
index 73cdbe87fe..5602b8cd3f 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QtTest/private/qtesthelpers_p.h>
@@ -28,6 +28,7 @@
#include <qpa/qplatformintegration.h>
#include <QtWidgets/private/qapplication_p.h>
+#include <QtWidgets/private/qmenu_p.h>
using namespace QTestPrivate;
@@ -114,6 +115,8 @@ private slots:
void screenOrientationChangedCloseMenu();
void deleteWhenTriggered();
+ void nestedTearOffDetached();
+
protected slots:
void onActivated(QAction*);
void onHighlighted(QAction*);
@@ -1143,14 +1146,18 @@ void tst_QMenu::pushButtonPopulateOnAboutToShow()
QSKIP("Your window manager won't allow a window against the bottom of the screen");
}
- QTimer::singleShot(300, buttonMenu, SLOT(hide()));
QTest::mouseClick(&b, Qt::LeftButton, Qt::NoModifier, b.rect().center());
+ QVERIFY(QTest::qWaitForWindowExposed(buttonMenu));
+ QTest::qWait(300);
+ buttonMenu->hide();
QVERIFY2(!buttonMenu->geometry().intersects(b.geometry()), msgGeometryIntersects(buttonMenu->geometry(), b.geometry()));
// note: we're assuming that, if we previously got the desired geometry, we'll get it here too
b.move(10, screen.bottom()-buttonMenu->height()-5);
- QTimer::singleShot(300, buttonMenu, SLOT(hide()));
QTest::mouseClick(&b, Qt::LeftButton, Qt::NoModifier, b.rect().center());
+ QVERIFY(QTest::qWaitForWindowExposed(buttonMenu));
+ QTest::qWait(300);
+ buttonMenu->hide();
QVERIFY2(!buttonMenu->geometry().intersects(b.geometry()), msgGeometryIntersects(buttonMenu->geometry(), b.geometry()));
}
@@ -2031,5 +2038,82 @@ void tst_QMenu::deleteWhenTriggered()
QTRY_VERIFY(!menu);
}
+/*
+ QMenu uses the caused-stack to create the parent/child relationship
+ for tear-off menus. Since QTornOffMenu set the DeleteOnClose flag, closing a
+ tear-off in the parent chain will result in a null-pointer in the caused-stack.
+ Verify that we don't crash when traversing the chain, as reported in QTBUG-112217.
+
+ The test has to open the submenus by hovering of the menu action, otherwise
+ the caused-stack remains empty and the issue doesn't reproduce. Due to QMenu's
+ timing and "sloppiness", we need to move the mouse within the action, with some
+ waiting and event processing in between to trigger the opening of the submenu.
+ If this fails we skip, as we then can't test what we are trying to test.
+*/
+void tst_QMenu::nestedTearOffDetached()
+{
+ // Since QTornOffMenu is not declared in qmenuprivate.h we can't access the
+ // object even through QMenuPrivate. So use an event filter to watch out for
+ // a QTornOffMenu showing.
+ class TearOffWatcher : public QObject
+ {
+ public:
+ QMenu *tornOffMenu = nullptr;
+ protected:
+ bool eventFilter(QObject *receiver, QEvent *event) override
+ {
+ if (event->type() == QEvent::Show && receiver->inherits("QTornOffMenu"))
+ tornOffMenu = qobject_cast<QMenu *>(receiver);
+ return QObject::eventFilter(receiver, event);
+ }
+ } watcher;
+ qApp->installEventFilter(&watcher);
+
+ QWidget widget;
+ QMenu *menu = new QMenu("Context", &widget);
+
+ MenuMetrics mm(menu);
+ const int tearOffOffset = mm.fw + mm.vmargin + mm.tearOffHeight / 2;
+
+ QMenu *subMenu = menu->addMenu("SubMenu");
+ menu->setTearOffEnabled(true);
+ QMenu *subSubMenu = subMenu->addMenu("SubSubMenu");
+ subMenu->setTearOffEnabled(true);
+ subSubMenu->addAction("Action!");
+ subSubMenu->setTearOffEnabled(true);
+
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ // open and tear off context menu
+ menu->popup(widget.geometry().center());
+ QTest::mouseClick(menu, Qt::LeftButton, {}, QPoint(menu->width() / 2, tearOffOffset));
+
+ QMenu *menuTorn = watcher.tornOffMenu;
+ watcher.tornOffMenu = nullptr;
+ QVERIFY(menuTorn);
+ QVERIFY(QTest::qWaitForWindowExposed(menuTorn));
+
+ // open second menu and tear-off
+ QTest::mouseMove(menuTorn, menuTorn->actionGeometry(subMenu->menuAction()).topLeft());
+ QTest::qWait(100);
+ QTest::mouseMove(menuTorn, menuTorn->actionGeometry(subMenu->menuAction()).center());
+ if (!QTest::qWaitFor([subMenu]{ return subMenu->isVisible(); }))
+ QSKIP("Menu failed to show, skipping test");
+
+ QTest::mouseClick(subMenu, Qt::LeftButton, {}, QPoint(subMenu->width() / 2, tearOffOffset));
+ menuTorn = watcher.tornOffMenu;
+ QVERIFY(menuTorn);
+ QVERIFY(QTest::qWaitForWindowExposed(menuTorn));
+ // close the top level tear off
+ menu->hideTearOffMenu();
+ // open third menu and tear-off
+ QTest::mouseMove(menuTorn, menuTorn->actionGeometry(subSubMenu->menuAction()).topLeft());
+ QTest::qWait(100);
+ QTest::mouseMove(menuTorn, menuTorn->actionGeometry(subSubMenu->menuAction()).center());
+ QTRY_VERIFY(subSubMenu->isVisible());
+ QTest::mouseClick(subSubMenu, Qt::LeftButton, {}, QPoint(subSubMenu->width() / 2, tearOffOffset));
+}
+
QTEST_MAIN(tst_QMenu)
#include "tst_qmenu.moc"
diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm b/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm
index be58cff8e6..ba76c28fd4 100644
--- a/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm
+++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#import <AppKit/AppKit.h>
diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST
index 05984b6039..516fd39f86 100644
--- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST
+++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST
@@ -1,11 +1,5 @@
[check_menuPosition]
-ubuntu-16.04
-#QTBUG-66255
-ubuntu-18.04
-ubuntu-20.04
ubuntu-22.04
-[activatedCount]
-opensuse-42.3
# QTBUG-87421
[cornerWidgets]
android
diff --git a/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt b/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt
index d8c136cd5c..f2b1c1bec6 100644
--- a/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qmenubar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmenubar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qmenubar
SOURCES
tst_qmenubar.cpp
diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
index 86169ca1de..8524b4212c 100644
--- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
+++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -93,13 +93,6 @@ private slots:
#endif
void allowActiveAndDisabled();
void taskQTBUG56860_focus();
- void check_endKey();
- void check_homeKey();
-
-// void check_mouse1_data();
-// void check_mouse1();
-// void check_mouse2_data();
-// void check_mouse2();
void check_altPress();
void check_altClosePress();
@@ -785,85 +778,6 @@ void tst_QMenuBar::taskQTBUG56860_focus()
}
/*!
- If a popupmenu is active you can use home to go quickly to the first item in the menu.
-*/
-void tst_QMenuBar::check_homeKey()
-{
- // I'm temporarily shutting up this testcase.
- // Seems like the behaviour i'm expecting isn't ok.
- QSKIP("This test has been \"temporarily\" disabled at least since 2009 :)");
-
- QEXPECT_FAIL( "0", "Popupmenu should respond to a Home key", Abort );
-
- QMainWindow w;
- initWindowWithComplexMenuBar(w);
- w.show();
- QApplicationPrivate::setActiveWindow(&w);
- QVERIFY(QTest::qWaitForWindowActive(&w));
-
- // select Popupmenu 2
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
-
- // Simulate some keys
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down );
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Home );
- // and press ENTER
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
- // Let's see if the correct slot is called...
-// QVERIFY2( m_complexActionTriggerCount[int('c')] == 1, "Popupmenu should respond to a Home key" );
- QCOMPARE(m_complexTriggerCount[int('c')], 1);
- QCOMPARE(m_complexTriggerCount[3], 0);
- QCOMPARE(m_complexTriggerCount[4], 0);
- QCOMPARE(m_complexTriggerCount[int('a')], 0);
- QCOMPARE(m_complexTriggerCount[int('b')], 0);
- QCOMPARE(m_complexTriggerCount[int('d')], 0);
- QCOMPARE(m_complexTriggerCount[int('e')], 0);
- QCOMPARE(m_complexTriggerCount[int('f')], 0);
- QCOMPARE(m_complexTriggerCount[int('g')], 0);
- QCOMPARE(m_complexTriggerCount[int('h')], 0);
-}
-
-/*!
- If a popupmenu is active you can use end to go quickly to the last item in the menu.
-*/
-void tst_QMenuBar::check_endKey()
-{
- // I'm temporarily silenting this testcase.
- // Seems like the behaviour i'm expecting isn't ok.
- QSKIP("This test has been \"temporarily\" disabled at least since 2009 :)");
-
- QEXPECT_FAIL( "0", "Popupmenu should respond to an End key", Abort );
-
- QMainWindow w;
- initWindowWithComplexMenuBar(w);
- w.show();
- QApplicationPrivate::setActiveWindow(&w);
- QVERIFY(QTest::qWaitForWindowActive(&w));
-
- // select Popupmenu 2
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_2, Qt::AltModifier );
-
- // Simulate some keys
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_End );
- // and press ENTER
- QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter );
- // Let's see if the correct slot is called...
-// QVERIFY2( m_complexActionTriggerCount[int('h')] == 1, "Popupmenu should respond to an End key" );
- QCOMPARE(m_complexTriggerCount[int('h')], 1);//, "Popupmenu should respond to an End key");
- QCOMPARE(m_complexTriggerCount[3], 0);
- QCOMPARE(m_complexTriggerCount[4], 0);
- QCOMPARE(m_complexTriggerCount[int('a')], 0);
- QCOMPARE(m_complexTriggerCount[int('b')], 0);
- QCOMPARE(m_complexTriggerCount[int('c')], 0);
- QCOMPARE(m_complexTriggerCount[int('d')], 0);
- QCOMPARE(m_complexTriggerCount[int('e')], 0);
- QCOMPARE(m_complexTriggerCount[int('f')], 0);
- QCOMPARE(m_complexTriggerCount[int('g')], 0);
-}
-
-/*!
If a popupmenu is active you can use esc to hide the menu and then the
menubar should become active.
If Down is pressed next the popup is activated again.
@@ -918,112 +832,6 @@ void tst_QMenuBar::check_escKey()
#endif
-// void tst_QMenuBar::check_mouse1_data()
-// {
-// QTest::addColumn<QString>("popup_item");
-// QTest::addColumn<int>("itemA_count");
-// QTest::addColumn<int>("itemB_count");
-
-// QTest::newRow( "A" ) << QString( "Item A Ctrl+A" ) << 1 << 0;
-// QTest::newRow( "B" ) << QString( "Item B Ctrl+B" ) << 0 << 1;
-// }
-
-// /*!
-// Check if the correct signals are emitted if we select a popupmenu.
-// */
-// void tst_QMenuBar::check_mouse1()
-// {
-// if (QSystem::curStyle() == "Motif")
-// QSKIP("This fails in Motif due to a bug in the testing framework");
-// QFETCH( QString, popup_item );
-// QFETCH( int, itemA_count );
-// QFETCH( int, itemB_count );
-
-// // initComplexMenubar();
-// QVERIFY( !pm1->isActiveWindow() );
-// QVERIFY( !pm2->isActiveWindow() );
-
-// QTest::qWait(1000);
-// QtTestMouse mouse;
-// mouse.mouseEvent( QtTestMouse::MouseClick, mb, "Menu &1", Qt::LeftButton );
-
-// QVERIFY( pm1->isActiveWindow() );
-// QVERIFY( !pm2->isActiveWindow() );
-
-// QTest::qWait(1000);
-// mouse.mouseEvent( QtTestMouse::MouseClick, pm1, popup_item, Qt::LeftButton );
-
-// QCOMPARE(m_complexActionTriggerCount[3], 0);
-// QCOMPARE(m_complexActionTriggerCount[4], 0);
-// QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count); // this option should have fired
-// QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count);
-// QCOMPARE(m_complexActionTriggerCount['c'], 0);
-// QCOMPARE(m_complexActionTriggerCount['d'], 0);
-// QCOMPARE(m_complexActionTriggerCount['e'], 0);
-// QCOMPARE(m_complexActionTriggerCount['f'], 0);
-// QCOMPARE(m_complexActionTriggerCount['g'], 0);
-// }
-
-// void tst_QMenuBar::check_mouse2_data()
-// {
-// QTest::addColumn<QString>("label");
-// QTest::addColumn<int>("itemA_count");
-// QTest::addColumn<int>("itemB_count");
-// QTest::addColumn<int>("itemC_count");
-// QTest::addColumn<int>("itemD_count");
-// QTest::addColumn<int>("itemE_count");
-// QTest::addColumn<int>("itemF_count");
-// QTest::addColumn<int>("itemG_count");
-// QTest::addColumn<int>("itemH_count");
-// QTest::addColumn<int>("menu3_count");
-
-// QTest::newRow( "A" ) << QString( "Menu &1/Item A Ctrl+A" ) << 1 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0;
-// QTest::newRow( "B" ) << QString( "Menu &1/Item B Ctrl+B" ) << 0 << 1 << 0 << 0 << 0 << 0 << 0 << 0 << 0;
-// QTest::newRow( "C" ) << QString( "Menu &2/Item C Ctrl+C" ) << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 0 << 0;
-// QTest::newRow( "D" ) << QString( "Menu &2/Item D Ctrl+D" ) << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0 << 0;
-// QTest::newRow( "E" ) << QString( "Menu &2/Item E Ctrl+E" ) << 0 << 0 << 0 << 0 << 1 << 0 << 0 << 0 << 0;
-// QTest::newRow( "F" ) << QString( "Menu &2/Item F Ctrl+F" ) << 0 << 0 << 0 << 0 << 0 << 1 << 0 << 0 << 0;
-// QTest::newRow( "G" ) << QString( "Menu &2/Item G Ctrl+G" ) << 0 << 0 << 0 << 0 << 0 << 0 << 1 << 0 << 0;
-// QTest::newRow( "H" ) << QString( "Menu &2/Item H Ctrl+H" ) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 1 << 0;
-// QTest::newRow( "menu 3" ) << QString( "M&enu 3" ) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 1;
-// }
-
-// /*!
-// Check if the correct signals are emitted if we select a popupmenu.
-// This time, we use a little bit more magic from the testframework.
-// */
-// void tst_QMenuBar::check_mouse2()
-// {
-// if (QSystem::curStyle() == "Motif")
-// QSKIP("This fails in Motif due to a bug in the testing framework");
-// QFETCH( QString, label );
-// QFETCH( int, itemA_count );
-// QFETCH( int, itemB_count );
-// QFETCH( int, itemC_count );
-// QFETCH( int, itemD_count );
-// QFETCH( int, itemE_count );
-// QFETCH( int, itemF_count );
-// QFETCH( int, itemG_count );
-// QFETCH( int, itemH_count );
-// QFETCH( int, menu3_count );
-
-// // initComplexMenubar();
-// QtTestMouse mouse;
-// mouse.click( QtTestMouse::Menu, label, Qt::LeftButton );
-
-// // check if the correct signals have fired
-// QCOMPARE(m_complexActionTriggerCount[3], (uint)menu3_count);
-// QCOMPARE(m_complexActionTriggerCount[4], 0);
-// QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count);
-// QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count);
-// QCOMPARE(m_complexActionTriggerCount['c'], (uint)itemC_count);
-// QCOMPARE(m_complexActionTriggerCount['d'], (uint)itemD_count);
-// QCOMPARE(m_complexActionTriggerCount['e'], (uint)itemE_count);
-// QCOMPARE(m_complexActionTriggerCount['f'], (uint)itemF_count);
-// QCOMPARE(m_complexActionTriggerCount['g'], (uint)itemG_count);
-// QCOMPARE(m_complexActionTriggerCount['h'], (uint)itemH_count);
-// }
-
void tst_QMenuBar::allowActiveAndDisabled()
{
QMenuBar menuBar;
@@ -1361,8 +1169,8 @@ void tst_QMenuBar::menubarSizeHint()
mb.setStyle(&style);
//this is a list of arbitrary strings so that we check the geometry
- QStringList list = QStringList() << "trer" << "ezrfgtgvqd" << "sdgzgzerzerzer" << "eerzertz" << "er";
- foreach(QString str, list)
+ const auto list = QStringList{"trer", "ezrfgtgvqd", "sdgzgzerzerzer", "eerzertz", "er"};
+ for (const QString &str : list)
mb.addAction(str);
const int panelWidth = style.pixelMetric(QStyle::PM_MenuBarPanelWidth);
@@ -1373,7 +1181,8 @@ void tst_QMenuBar::menubarSizeHint()
centerOnScreen(&mb);
mb.show();
QRect result;
- foreach(QAction *action, mb.actions()) {
+ const auto actions = mb.actions();
+ for (QAction *action : actions) {
const QRect actionRect = mb.actionGeometry(action);
if (!result.isNull()) //this is the first item
QCOMPARE(actionRect.left() - result.right() - 1, spacing);
diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm
index fd8086772a..55e983a4d1 100644
--- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm
+++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#import <Cocoa/Cocoa.h>
diff --git a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST
index 81fd4ddb72..6b96499889 100644
--- a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST
+++ b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST
@@ -3,9 +3,6 @@ ubuntu
rhel
opensuse-leap
-[stackWidgetOpaqueChildIsVisible]
-windows-10 msvc-2017
-
# QTBUG-87436
[clearAndGrab]
android
diff --git a/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt
index 91dcf2d4f4..78cef5300a 100644
--- a/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qopenglwidget Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qopenglwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qopenglwidget
LOWDPI
SOURCES
diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
index 07cce4cdc3..773ccd894c 100644
--- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
+++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtOpenGLWidgets/QOpenGLWidget>
#include <QtGui/QOpenGLFunctions>
@@ -24,8 +24,7 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformbackingstore.h>
#include <qpa/qplatformintegration.h>
-#include <private/qrhi_p.h>
-#include <private/qrhigles2_p.h>
+#include <rhi/qrhi.h>
class tst_QOpenGLWidget : public QObject
{
@@ -327,10 +326,6 @@ void tst_QOpenGLWidget::reparentToNotYetCreated()
void tst_QOpenGLWidget::reparentHidden()
{
-#ifdef Q_OS_ANDROID
- if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31)
- QSKIP("Fails on Android 12 (QTBUG-111235)");
-#endif
// Tests QTBUG-60896
QWidget topLevel1;
@@ -574,6 +569,21 @@ void tst_QOpenGLWidget::showHide()
QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
}
+QtMessageHandler oldHandler = nullptr;
+
+void nativeWindowMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ if (oldHandler)
+ oldHandler(type, context, msg);
+
+ if (type == QtWarningMsg
+ && (msg.contains("QOpenGLContext::makeCurrent() called with non-opengl surface")
+ || msg.contains("Failed to make context current")))
+ {
+ QFAIL("Unexpected warning got printed");
+ }
+}
+
void tst_QOpenGLWidget::nativeWindow()
{
#ifdef Q_OS_ANDROID
@@ -585,6 +595,10 @@ void tst_QOpenGLWidget::nativeWindow()
// presented correctly as we can only do verification with
// grabFramebuffer() here which only exercises a part of the pipeline.
+ // Install a message handler that looks for some typical warnings from
+ // QRhi/QOpenGLConext that occur when the RHI-related logic in widgets goes wrong.
+ oldHandler = qInstallMessageHandler(nativeWindowMessageHandler);
+
{
QScopedPointer<ClearWidget> w(new ClearWidget(nullptr, 800, 600));
w->resize(800, 600);
@@ -600,7 +614,33 @@ void tst_QOpenGLWidget::nativeWindow()
QVERIFY(w->internalWinId());
}
- // Now as a native child
+ // QTBUG-113557: a plain _raster_ QWidget that is a _native_ child in a toplevel
+ // combined with a RHI-based (non-native) widget (QOpenGLWidget in this case)
+ // in the same toplevel.
+ {
+ QWidget topLevel;
+ topLevel.resize(800, 600);
+
+ ClearWidget *child = new ClearWidget(&topLevel, 800, 600);
+ child->setClearColor(1, 0, 0);
+ child->resize(400, 400);
+ child->move(23, 34);
+
+ QWidget *raster = new QWidget(&topLevel);
+ raster->setGeometry(23, 240, 120, 120);
+ raster->setStyleSheet("QWidget { background-color: yellow; }");
+
+ raster->winId();
+
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+
+ // Do not bother checking the output, i.e. if the yellow raster native child
+ // shows up as it should, but rather rely on the message handler catching the
+ // qWarnings if they occur.
+ }
+
+ // Now with the QOpenGLWidget being a native child
{
QWidget topLevel;
topLevel.resize(800, 600);
@@ -666,7 +706,7 @@ void tst_QOpenGLWidget::nativeWindow()
ClearWidget *child = new ClearWidget(nullptr, 800, 600);
// set the parent separately, this is important, see next test case
child->setParent(container);
- child->setClearColor(0, 1, 0);
+ child->setClearColor(0, 0, 1);
child->resize(400, 400);
child->move(23, 34);
@@ -680,7 +720,7 @@ void tst_QOpenGLWidget::nativeWindow()
QImage image = child->grabFramebuffer();
QCOMPARE(image.width(), child->width());
QCOMPARE(image.height(), child->height());
- QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
}
// Again as a child of a native child, but this time specifying the parent
@@ -692,7 +732,7 @@ void tst_QOpenGLWidget::nativeWindow()
container->winId();
// parent it right away
ClearWidget *child = new ClearWidget(container, 800, 600);
- child->setClearColor(0, 1, 0);
+ child->setClearColor(0, 0, 1);
child->resize(400, 400);
child->move(23, 34);
topLevel.show();
@@ -703,7 +743,12 @@ void tst_QOpenGLWidget::nativeWindow()
QImage image = child->grabFramebuffer();
QCOMPARE(image.width(), child->width());
QCOMPARE(image.height(), child->height());
- QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0));
+ QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
+ }
+
+ if (oldHandler) {
+ qInstallMessageHandler(oldHandler);
+ oldHandler = nullptr;
}
}
diff --git a/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt b/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt
index 69746c24d1..b7528498cb 100644
--- a/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qplaintextedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qplaintextedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qplaintextedit
SOURCES
tst_qplaintextedit.cpp
diff --git a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
index ed68c735d4..ca7cc6d4b4 100644
--- a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
+++ b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -133,6 +133,7 @@ private slots:
void placeholderVisibility_data();
void placeholderVisibility();
void scrollBarSignals();
+ void dontCrashWithCss();
private:
void createSelection();
@@ -995,7 +996,7 @@ void tst_QPlainTextEdit::copyAvailable_data()
//Tests the copyAvailable slot for several cases
void tst_QPlainTextEdit::copyAvailable()
{
- QFETCH(pairListType,keystrokes);
+ QFETCH(const pairListType, keystrokes);
QFETCH(QList<bool>, copyAvailable);
QFETCH(QString, function);
@@ -1008,9 +1009,8 @@ void tst_QPlainTextEdit::copyAvailable()
QSignalSpy spyCopyAvailabe(ed, SIGNAL(copyAvailable(bool)));
//Execute Keystrokes
- foreach(keyPairType keyPair, keystrokes) {
+ for (keyPairType keyPair : keystrokes)
QTest::keyClick(ed, keyPair.first, keyPair.second );
- }
//Execute ed->"function"
if (function == "cut")
@@ -1830,7 +1830,7 @@ void tst_QPlainTextEdit::placeholderVisibility_data()
QTest::addColumn<QList<SetupCommand>>("setupCommands");
QTest::addColumn<bool>("placeholderVisible");
QTest::addRow("no placeholder set + no text set")
- << QList<SetupCommand>{} << true;
+ << QList<SetupCommand>{} << false;
QTest::addRow("no placeholder set + text set or text set + no placeholder set")
<< QList<SetupCommand>{ SetContent } << false;
QTest::addRow("no placeholder set + text set + empty text set")
@@ -1840,7 +1840,7 @@ void tst_QPlainTextEdit::placeholderVisibility_data()
<< QList<SetupCommand>{ ClearContent, SetContent }
<< false;
QTest::addRow("empty placeholder set + no text set")
- << QList<SetupCommand>{ ClearPlaceHolder } << true;
+ << QList<SetupCommand>{ ClearPlaceHolder } << false;
QTest::addRow("empty placeholder set + text set")
<< QList<SetupCommand>{ ClearPlaceHolder, SetContent }
<< false;
@@ -1917,7 +1917,7 @@ void tst_QPlainTextEdit::placeholderVisibility()
plainTextEdit.show();
QVERIFY(QTest::qWaitForWindowExposed(&plainTextEdit));
- QTRY_VERIFY(plainTextEdit_d->placeholderVisible == placeholderVisible);
+ QTRY_COMPARE(plainTextEdit_d->placeholderTextShown, placeholderVisible);
}
@@ -1945,5 +1945,14 @@ void tst_QPlainTextEdit::scrollBarSignals()
QTRY_COMPARE(spy.count(), 5);
}
+void tst_QPlainTextEdit::dontCrashWithCss()
+{
+ qApp->setStyleSheet("QWidget { font: 10pt; }");
+ QPlainTextEdit edit;
+ edit.show();
+ qApp->setStyleSheet(QString());
+}
+
+
QTEST_MAIN(tst_QPlainTextEdit)
#include "tst_qplaintextedit.moc"
diff --git a/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt b/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt
index 04891c0e52..61ce6c2692 100644
--- a/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qprogressbar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qprogressbar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qprogressbar
SOURCES
tst_qprogressbar.cpp
diff --git a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp
index ae6013e764..4a90ed6667 100644
--- a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp
+++ b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt b/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt
index e6e84822e0..afd052fa17 100644
--- a/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qpushbutton Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qpushbutton LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qpushbutton
SOURCES
tst_qpushbutton.cpp
diff --git a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
index 8acbfeb6cf..92ce1f5419 100644
--- a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
+++ b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -15,6 +15,7 @@
#include <QGridLayout>
#include <QStyleFactory>
#include <QTabWidget>
+#include <QStyleOption>
#include <private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
@@ -54,6 +55,7 @@ private slots:
void hitButton();
void iconOnlyStyleSheet();
void mousePressAndMove();
+ void reactToMenuClosed();
protected slots:
void resetCounters();
@@ -760,5 +762,51 @@ void tst_QPushButton::mousePressAndMove()
QCOMPARE(releaseSpy.size(), 1);
}
+/*
+ Test checking that a QPushButton with a QMenu has a sunken style only
+ when the menu is open
+ QTBUG-120976
+*/
+void tst_QPushButton::reactToMenuClosed()
+{
+ // create a subclass of QPushButton to expose the initStyleOption method
+ class PushButton : public QPushButton {
+ public:
+ virtual void initStyleOption(QStyleOptionButton *option) const override
+ {
+ QPushButton::initStyleOption(option);
+ }
+ };
+
+ PushButton button;
+ QStyleOptionButton opt;
+ QMenu menu;
+
+ // add a menu to the button
+ menu.addAction(tr("string"));
+ button.setMenu(&menu);
+
+ // give the button a size and show it
+ button.setGeometry(0, 0, 50, 50);
+ button.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&button));
+
+ // click the button to open the menu
+ QTest::mouseClick(&button, Qt::LeftButton);
+
+ // check the menu is visible and the button style is sunken
+ QTRY_VERIFY(menu.isVisible());
+ button.initStyleOption(&opt);
+ QVERIFY(opt.state.testFlag(QStyle::StateFlag::State_Sunken));
+
+ // close the menu
+ menu.close();
+
+ // check the menu isn't visible and the style isn't sunken
+ QTRY_VERIFY(!menu.isVisible());
+ button.initStyleOption(&opt);
+ QVERIFY(!opt.state.testFlag(QStyle::StateFlag::State_Sunken));
+}
+
QTEST_MAIN(tst_QPushButton)
#include "tst_qpushbutton.moc"
diff --git a/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt b/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt
index 28af7e23a1..ce016975c8 100644
--- a/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qradiobutton Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qradiobutton LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qradiobutton
SOURCES
tst_qradiobutton.cpp
diff --git a/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp b/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp
index 2fcf2e5545..144d91e9f2 100644
--- a/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp
+++ b/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qrhiwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qrhiwidget/CMakeLists.txt
new file mode 100644
index 0000000000..f8d18bcf53
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qrhiwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+file(GLOB_RECURSE qrhiwidget_resource_files
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ data/*
+)
+
+qt_internal_add_test(tst_qrhiwidget
+ SOURCES
+ tst_qrhiwidget.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::Widgets
+ TESTDATA ${qrhiwidget_resource_files}
+ BUILTIN_TESTDATA
+)
diff --git a/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag b/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag
new file mode 100644
index 0000000000..2aa500e09a
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag
@@ -0,0 +1,8 @@
+#version 440
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
diff --git a/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag.qsb b/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag.qsb
new file mode 100644
index 0000000000..40d0a296ac
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag.qsb
Binary files differ
diff --git a/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert b/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert
new file mode 100644
index 0000000000..6b954cdaec
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert
@@ -0,0 +1,8 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+
+void main()
+{
+ gl_Position = position;
+}
diff --git a/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert.qsb b/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert.qsb
new file mode 100644
index 0000000000..5b7fd39668
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert.qsb
Binary files differ
diff --git a/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp b/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp
new file mode 100644
index 0000000000..7a102180e7
--- /dev/null
+++ b/tests/auto/widgets/widgets/qrhiwidget/tst_qrhiwidget.cpp
@@ -0,0 +1,834 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtWidgets/QRhiWidget>
+#include <QtGui/QPainter>
+#include <QTest>
+#include <QSignalSpy>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <rhi/qrhi.h>
+
+#include <QApplication>
+#include <QFile>
+#include <QVBoxLayout>
+#include <QScrollArea>
+
+#if QT_CONFIG(vulkan)
+#include <private/qvulkandefaultinstance_p.h>
+#endif
+
+class tst_QRhiWidget : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void create_data();
+ void create();
+ void noCreate();
+ void simple_data();
+ void simple();
+ void msaa_data();
+ void msaa();
+ void fixedSize_data();
+ void fixedSize();
+ void autoRt_data();
+ void autoRt();
+ void reparent_data();
+ void reparent();
+ void grabFramebufferWhileStillInvisible_data();
+ void grabFramebufferWhileStillInvisible();
+ void grabViaQWidgetGrab_data();
+ void grabViaQWidgetGrab();
+ void mirror_data();
+ void mirror();
+
+private:
+ void testData();
+};
+
+void tst_QRhiWidget::initTestCase()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
+ QSKIP("RhiBasedRendering capability is reported as unsupported on this platform.");
+
+ qputenv("QT_RHI_LEAK_CHECK", "1");
+}
+
+void tst_QRhiWidget::testData()
+{
+ QTest::addColumn<QRhiWidget::Api>("api");
+
+#ifndef Q_OS_WEBOS
+ QTest::newRow("Null") << QRhiWidget::Api::Null;
+#endif
+
+#if QT_CONFIG(opengl)
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
+ QTest::newRow("OpenGL") << QRhiWidget::Api::OpenGL;
+#endif
+
+#if QT_CONFIG(vulkan)
+ // Have to probe to be sure Vulkan is actually working (the test cases
+ // themselves will assume QRhi init succeeds).
+ if (QVulkanDefaultInstance::instance()) {
+ QRhiVulkanInitParams vulkanInitParams;
+ vulkanInitParams.inst = QVulkanDefaultInstance::instance();
+ if (QRhi::probe(QRhi::Vulkan, &vulkanInitParams))
+ QTest::newRow("Vulkan") << QRhiWidget::Api::Vulkan;
+ }
+#endif
+
+#if QT_CONFIG(metal)
+ QRhiMetalInitParams metalInitParams;
+ if (QRhi::probe(QRhi::Metal, &metalInitParams))
+ QTest::newRow("Metal") << QRhiWidget::Api::Metal;
+#endif
+
+#ifdef Q_OS_WIN
+ QTest::newRow("D3D11") << QRhiWidget::Api::Direct3D11;
+ // D3D12 needs to be probed too due to being disabled if the SDK headers
+ // are too old (clang, mingw).
+ QRhiD3D12InitParams d3d12InitParams;
+ if (QRhi::probe(QRhi::D3D12, &d3d12InitParams))
+ QTest::newRow("D3D12") << QRhiWidget::Api::Direct3D12;
+#endif
+}
+
+void tst_QRhiWidget::create_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::create()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ {
+ QRhiWidget w;
+ w.setApi(api);
+ w.resize(320, 240);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ }
+
+ {
+ QWidget topLevel;
+ topLevel.resize(320, 240);
+ QRhiWidget *w = new QRhiWidget(&topLevel);
+ w->setApi(api);
+ w->resize(100, 100);
+ topLevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
+ }
+}
+
+void tst_QRhiWidget::noCreate()
+{
+ // Now try something that is guaranteed to fail.
+ // E.g. try using Metal on Windows.
+ // The error signal should be emitted. The frame signal should not.
+#ifdef Q_OS_WIN
+ qDebug("Warnings will be printed below, this is as expected");
+ QRhiWidget rhiWidget;
+ rhiWidget.setApi(QRhiWidget::Api::Metal);
+ QSignalSpy frameSpy(&rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(&rhiWidget, &QRhiWidget::renderFailed);
+ rhiWidget.resize(320, 240);
+ rhiWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&rhiWidget));
+ QTRY_VERIFY(errorSpy.count() > 0);
+ QCOMPARE(frameSpy.count(), 0);
+#endif
+}
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
+}
+
+static bool submitResourceUpdates(QRhi *rhi, QRhiResourceUpdateBatch *batch)
+{
+ QRhiCommandBuffer *cb = nullptr;
+ QRhi::FrameOpResult result = rhi->beginOffscreenFrame(&cb);
+ if (result != QRhi::FrameOpSuccess) {
+ qWarning("beginOffscreenFrame returned %d", result);
+ return false;
+ }
+ if (!cb) {
+ qWarning("No command buffer from beginOffscreenFrame");
+ return false;
+ }
+ cb->resourceUpdate(batch);
+ rhi->endOffscreenFrame();
+ return true;
+}
+
+inline bool imageRGBAEquals(const QImage &a, const QImage &b, int maxFuzz = 1)
+{
+ if (a.size() != b.size())
+ return false;
+
+ const QImage image0 = a.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+ const QImage image1 = b.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+
+ const int width = image0.width();
+ const int height = image0.height();
+ for (int y = 0; y < height; ++y) {
+ const quint32 *p0 = reinterpret_cast<const quint32 *>(image0.constScanLine(y));
+ const quint32 *p1 = reinterpret_cast<const quint32 *>(image1.constScanLine(y));
+ int x = width - 1;
+ while (x-- >= 0) {
+ const QRgb c0(*p0++);
+ const QRgb c1(*p1++);
+ const int red = qAbs(qRed(c0) - qRed(c1));
+ const int green = qAbs(qGreen(c0) - qGreen(c1));
+ const int blue = qAbs(qBlue(c0) - qBlue(c1));
+ const int alpha = qAbs(qAlpha(c0) - qAlpha(c1));
+ if (red > maxFuzz || green > maxFuzz || blue > maxFuzz || alpha > maxFuzz)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+class SimpleRhiWidget : public QRhiWidget
+{
+public:
+ SimpleRhiWidget(int sampleCount = 1, QWidget *parent = nullptr)
+ : QRhiWidget(parent),
+ m_sampleCount(sampleCount)
+ { }
+
+ ~SimpleRhiWidget()
+ {
+ delete m_rt;
+ delete m_rp;
+ }
+
+ void initialize(QRhiCommandBuffer *cb) override;
+ void render(QRhiCommandBuffer *cb) override;
+ void releaseResources() override;
+
+ int m_sampleCount;
+ QRhi *m_rhi = nullptr;
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ std::unique_ptr<QRhiBuffer> m_ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> m_srb;
+ std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
+ QRhiTextureRenderTarget *m_rt = nullptr; // used when autoRenderTarget is off
+ QRhiRenderPassDescriptor *m_rp = nullptr; // used when autoRenderTarget is off
+
+ friend class tst_QRhiWidget;
+};
+
+void SimpleRhiWidget::initialize(QRhiCommandBuffer *cb)
+{
+ if (m_rhi != rhi()) {
+ m_pipeline.reset();
+ m_rhi = rhi();
+ }
+
+ if (!m_pipeline) {
+ if (!isAutoRenderTargetEnabled()) {
+ delete m_rt;
+ delete m_rp;
+ QRhiTextureRenderTargetDescription rtDesc;
+ if (colorTexture()) {
+ rtDesc.setColorAttachments({ colorTexture() });
+ } else if (msaaColorBuffer()) {
+ QRhiColorAttachment att;
+ att.setRenderBuffer(msaaColorBuffer());
+ rtDesc.setColorAttachments({ att });
+ }
+ m_rt = m_rhi->newTextureRenderTarget(rtDesc);
+ m_rp = m_rt->newCompatibleRenderPassDescriptor();
+ m_rt->setRenderPassDescriptor(m_rp);
+ m_rt->create();
+ }
+
+ static float vertexData[] = {
+ 0, 1,
+ -1, -1,
+ 1, -1
+ };
+
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ m_vbuf->create();
+
+ m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
+ m_ubuf->create();
+
+ m_srb.reset(m_rhi->newShaderResourceBindings());
+ m_srb->create();
+
+ m_pipeline.reset(m_rhi->newGraphicsPipeline());
+ m_pipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/data/simple.vert.qsb")) },
+ { QRhiShaderStage::Fragment, getShader(QLatin1String(":/data/simple.frag.qsb")) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 2 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 }
+ });
+ m_pipeline->setSampleCount(m_sampleCount);
+ m_pipeline->setVertexInputLayout(inputLayout);
+ m_pipeline->setShaderResourceBindings(m_srb.get());
+ m_pipeline->setRenderPassDescriptor(renderTarget() ? renderTarget()->renderPassDescriptor() : m_rp);
+ m_pipeline->create();
+
+ QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
+ cb->resourceUpdate(resourceUpdates);
+ }
+}
+
+void SimpleRhiWidget::render(QRhiCommandBuffer *cb)
+{
+ const QSize outputSize = colorTexture() ? colorTexture()->pixelSize() : msaaColorBuffer()->pixelSize();
+ if (renderTarget()) {
+ QCOMPARE(outputSize, renderTarget()->pixelSize());
+ if (rhi()->backend() != QRhi::Null && rhi()->supportedSampleCounts().contains(m_sampleCount))
+ QCOMPARE(m_sampleCount, renderTarget()->sampleCount());
+ }
+
+ const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f);
+ cb->beginPass(renderTarget() ? renderTarget() : m_rt, clearColor, { 1.0f, 0 });
+ cb->setGraphicsPipeline(m_pipeline.get());
+ cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
+ cb->endPass();
+}
+
+void SimpleRhiWidget::releaseResources()
+{
+ m_pipeline.reset();
+ m_srb.reset();
+ m_ubuf.reset();
+ m_vbuf.reset();
+
+}
+
+void tst_QRhiWidget::simple_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::simple()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget;
+ rhiWidget->setApi(api);
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(rhiWidget);
+
+ QWidget w;
+ w.setLayout(layout);
+ w.resize(1280, 720);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ QCOMPARE(rhiWidget->sampleCount(), 1);
+ QCOMPARE(rhiWidget->colorBufferFormat(), QRhiWidget::TextureFormat::RGBA8);
+ QVERIFY(rhiWidget->isAutoRenderTargetEnabled());
+
+ // Pull out the QRhiTexture (we know colorTexture() and rhi() and friends
+ // are all there even outside initialize() and render(), even though this
+ // is not quite documented), and read it back.
+ QRhiTexture *backingTexture = rhiWidget->colorTexture();
+ QVERIFY(backingTexture);
+ QCOMPARE(backingTexture->format(), QRhiTexture::RGBA8);
+ QVERIFY(rhiWidget->depthStencilBuffer());
+ QVERIFY(rhiWidget->renderTarget());
+ QVERIFY(!rhiWidget->resolveTexture());
+ QRhi *rhi = rhiWidget->rhi();
+ QVERIFY(rhi);
+
+ switch (api) {
+ case QRhiWidget::Api::OpenGL:
+ QCOMPARE(rhi->backend(), QRhi::OpenGLES2);
+ break;
+ case QRhiWidget::Api::Metal:
+ QCOMPARE(rhi->backend(), QRhi::Metal);
+ break;
+ case QRhiWidget::Api::Vulkan:
+ QCOMPARE(rhi->backend(), QRhi::Vulkan);
+ break;
+ case QRhiWidget::Api::Direct3D11:
+ QCOMPARE(rhi->backend(), QRhi::D3D11);
+ break;
+ case QRhiWidget::Api::Direct3D12:
+ QCOMPARE(rhi->backend(), QRhi::D3D12);
+ break;
+ case QRhiWidget::Api::Null:
+ QCOMPARE(rhi->backend(), QRhi::Null);
+ break;
+ default:
+ break;
+ }
+
+ const int maxFuzz = 1;
+ QImage resultOne;
+ if (rhi->backend() != QRhi::Null) {
+ QRhiReadbackResult readResult;
+ bool readCompleted = false;
+ readResult.completed = [&readCompleted] { readCompleted = true; };
+ QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
+ rub->readBackTexture(backingTexture, &readResult);
+ QVERIFY(submitResourceUpdates(rhi, rub));
+ QVERIFY(readCompleted);
+
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ if (rhi->isYUpInFramebuffer())
+ resultOne = wrapperImage.mirrored();
+ else
+ resultOne = wrapperImage.copy();
+
+ // result is now a red triangle upon greenish background, where the
+ // triangle's edges are (0, 1), (-1, -1), and (1, -1).
+ // It's upside down with Vulkan (Y is not corrected, clipSpaceCorrMatrix() is not used),
+ // but that won't matter for the test.
+
+ // Check that the center is a red pixel.
+ QRgb c = resultOne.pixel(resultOne.width() / 2, resultOne.height() / 2);
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+
+ // Now through grabFramebuffer().
+ QImage resultTwo;
+ if (rhi->backend() != QRhi::Null) {
+ resultTwo = rhiWidget->grabFramebuffer();
+ QCOMPARE(errorSpy.count(), 0);
+ QVERIFY(!resultTwo.isNull());
+ QRgb c = resultTwo.pixel(resultTwo.width() / 2, resultTwo.height() / 2);
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+
+ // Check we got the same result from our manual readback and when the
+ // texture was rendered to again and grabFramebuffer() was called.
+ QVERIFY(imageRGBAEquals(resultOne, resultTwo, maxFuzz));
+}
+
+void tst_QRhiWidget::msaa_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::msaa()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ const int SAMPLE_COUNT = 4;
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget(SAMPLE_COUNT);
+ rhiWidget->setApi(api);
+ rhiWidget->setSampleCount(SAMPLE_COUNT);
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(rhiWidget);
+
+ QWidget w;
+ w.setLayout(layout);
+ w.resize(1280, 720);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ QCOMPARE(rhiWidget->sampleCount(), 4);
+ QCOMPARE(rhiWidget->colorBufferFormat(), QRhiWidget::TextureFormat::RGBA8);
+ QVERIFY(!rhiWidget->colorTexture());
+ QVERIFY(rhiWidget->msaaColorBuffer());
+ QVERIFY(rhiWidget->depthStencilBuffer());
+ QVERIFY(rhiWidget->renderTarget());
+ QVERIFY(rhiWidget->resolveTexture());
+ QCOMPARE(rhiWidget->resolveTexture()->format(), QRhiTexture::RGBA8);
+ QRhi *rhi = rhiWidget->rhi();
+ QVERIFY(rhi);
+
+ if (rhi->backend() != QRhi::Null) {
+ QRhiReadbackResult readResult;
+ QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
+ rub->readBackTexture(rhiWidget->resolveTexture(), &readResult);
+ QVERIFY(submitResourceUpdates(rhi, rub));
+
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ QImage result;
+ if (rhi->isYUpInFramebuffer())
+ result = wrapperImage.mirrored();
+ else
+ result = wrapperImage.copy();
+
+ // Check that the center is a red pixel.
+ const int maxFuzz = 1;
+ QRgb c = result.pixel(result.width() / 2, result.height() / 2);
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+
+ // See if switching back and forth works.
+ frameSpy.clear();
+ rhiWidget->m_pipeline.reset();
+ rhiWidget->m_sampleCount = 1;
+ rhiWidget->setSampleCount(1);
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+ QVERIFY(rhiWidget->colorTexture());
+ QVERIFY(!rhiWidget->msaaColorBuffer());
+
+ frameSpy.clear();
+ rhiWidget->m_pipeline.reset();
+ rhiWidget->m_sampleCount = SAMPLE_COUNT;
+ rhiWidget->setSampleCount(SAMPLE_COUNT);
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+ QVERIFY(!rhiWidget->colorTexture());
+ QVERIFY(rhiWidget->msaaColorBuffer());
+}
+
+void tst_QRhiWidget::fixedSize_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::fixedSize()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget;
+ rhiWidget->setApi(api);
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(rhiWidget);
+
+ rhiWidget->setFixedColorBufferSize(QSize(320, 200));
+
+ QWidget w;
+ w.setLayout(layout);
+ w.resize(1280, 720);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ QVERIFY(rhiWidget->rhi());
+ QVERIFY(rhiWidget->colorTexture());
+ QCOMPARE(rhiWidget->colorTexture()->pixelSize(), QSize(320, 200));
+ QVERIFY(rhiWidget->depthStencilBuffer());
+ QCOMPARE(rhiWidget->depthStencilBuffer()->pixelSize(), QSize(320, 200));
+ QVERIFY(rhiWidget->renderTarget());
+ QVERIFY(!rhiWidget->resolveTexture());
+
+ frameSpy.clear();
+ rhiWidget->setFixedColorBufferSize(640, 480); // should also trigger update()
+ QTRY_VERIFY(frameSpy.count() > 0);
+
+ QVERIFY(rhiWidget->colorTexture());
+ QCOMPARE(rhiWidget->colorTexture()->pixelSize(), QSize(640, 480));
+ QVERIFY(rhiWidget->depthStencilBuffer());
+ QCOMPARE(rhiWidget->depthStencilBuffer()->pixelSize(), QSize(640, 480));
+
+ frameSpy.clear();
+ rhiWidget->setFixedColorBufferSize(QSize());
+ QTRY_VERIFY(frameSpy.count() > 0);
+
+ QVERIFY(rhiWidget->colorTexture());
+ QVERIFY(rhiWidget->colorTexture()->pixelSize() != QSize(640, 480));
+ QVERIFY(rhiWidget->depthStencilBuffer());
+ QVERIFY(rhiWidget->depthStencilBuffer()->pixelSize() != QSize(640, 480));
+}
+
+void tst_QRhiWidget::autoRt_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::autoRt()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget;
+ rhiWidget->setApi(api);
+ QVERIFY(rhiWidget->isAutoRenderTargetEnabled());
+ rhiWidget->setAutoRenderTarget(false);
+ QVERIFY(!rhiWidget->isAutoRenderTargetEnabled());
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(rhiWidget);
+
+ QWidget w;
+ w.setLayout(layout);
+ w.resize(1280, 720);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ QVERIFY(rhiWidget->rhi());
+ QVERIFY(rhiWidget->colorTexture());
+ QVERIFY(!rhiWidget->depthStencilBuffer());
+ QVERIFY(!rhiWidget->renderTarget());
+ QVERIFY(!rhiWidget->resolveTexture());
+
+ QVERIFY(rhiWidget->m_rt);
+ QVERIFY(rhiWidget->m_rp);
+ QCOMPARE(rhiWidget->m_rt->description().cbeginColorAttachments()->texture(), rhiWidget->colorTexture());
+
+ frameSpy.clear();
+ // do something that triggers creating a new backing texture
+ rhiWidget->setFixedColorBufferSize(QSize(320, 200));
+ QTRY_VERIFY(frameSpy.count() > 0);
+
+ QVERIFY(rhiWidget->colorTexture());
+ QCOMPARE(rhiWidget->m_rt->description().cbeginColorAttachments()->texture(), rhiWidget->colorTexture());
+}
+
+void tst_QRhiWidget::reparent_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::reparent()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows))
+ QSKIP("MultipleWindows capability is reported as unsupported, skipping reparenting test.");
+
+ QFETCH(QRhiWidget::Api, api);
+
+ QWidget *windowOne = new QWidget;
+ windowOne->resize(1280, 720);
+
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget(1);
+ rhiWidget->setApi(api);
+ rhiWidget->resize(800, 600);
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ rhiWidget->show();
+ QVERIFY(QTest::qWaitForWindowExposed(rhiWidget));
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ frameSpy.clear();
+ rhiWidget->setParent(windowOne);
+ windowOne->show();
+ QVERIFY(QTest::qWaitForWindowExposed(windowOne));
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ frameSpy.clear();
+ QWidget windowTwo;
+ windowTwo.resize(1280, 720);
+
+ rhiWidget->setParent(&windowTwo);
+
+ // There's nothing saying the old top-level parent is going to be around,
+ // which is interesting wrt to its QRhi and resources created with that;
+ // exercise this.
+ delete windowOne;
+
+ windowTwo.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&windowTwo));
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ // now reparent after show() has already been called
+ frameSpy.clear();
+ QWidget windowThree;
+ windowThree.resize(1280, 720);
+ windowThree.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&windowThree));
+
+ rhiWidget->setParent(&windowThree);
+ // this case needs a show() on rhiWidget
+ rhiWidget->show();
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+}
+
+void tst_QRhiWidget::grabFramebufferWhileStillInvisible_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::grabFramebufferWhileStillInvisible()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ const int maxFuzz = 1;
+
+ SimpleRhiWidget w;
+ w.setApi(api);
+ w.resize(1280, 720);
+ QSignalSpy errorSpy(&w, &QRhiWidget::renderFailed);
+
+ QImage image = w.grabFramebuffer(); // creates its own QRhi just to render offscreen
+ QVERIFY(!image.isNull());
+ QVERIFY(w.rhi());
+ QVERIFY(w.colorTexture());
+ QCOMPARE(errorSpy.count(), 0);
+ if (api != QRhiWidget::Api::Null) {
+ QRgb c = image.pixel(image.width() / 2, image.height() / 2);
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+
+ // Make the window visible, this under the hood drops the QRhiWidget's
+ // own QRhi and attaches to the backingstore's.
+ QSignalSpy frameSpy(&w, &QRhiWidget::frameSubmitted);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ QTRY_VERIFY(frameSpy.count() > 0);
+
+ QCOMPARE(errorSpy.count(), 0);
+
+ if (api != QRhiWidget::Api::Null) {
+ QRhiReadbackResult readResult;
+ QRhiResourceUpdateBatch *rub = w.rhi()->nextResourceUpdateBatch();
+ rub->readBackTexture(w.colorTexture(), &readResult);
+ QVERIFY(submitResourceUpdates(w.rhi(), rub));
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ if (w.rhi()->isYUpInFramebuffer())
+ image = wrapperImage.mirrored();
+ else
+ image = wrapperImage.copy();
+ QRgb c = image.pixel(image.width() / 2, image.height() / 2);
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+}
+
+void tst_QRhiWidget::grabViaQWidgetGrab_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::grabViaQWidgetGrab()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ SimpleRhiWidget w;
+ w.setApi(api);
+ w.resize(1280, 720);
+ QSignalSpy frameSpy(&w, &QRhiWidget::frameSubmitted);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ QTRY_VERIFY(frameSpy.count() > 0);
+
+ QImage image = w.grab().toImage();
+
+ if (w.rhi()->backend() != QRhi::Null) {
+ // It's upside down with Vulkan (Y is not corrected, clipSpaceCorrMatrix() is not used),
+ // but that won't matter for the test.
+ QRgb c = image.pixel(image.width() / 2, image.height() / 2);
+ const int maxFuzz = 1;
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+}
+
+void tst_QRhiWidget::mirror_data()
+{
+ testData();
+}
+
+void tst_QRhiWidget::mirror()
+{
+ QFETCH(QRhiWidget::Api, api);
+
+ SimpleRhiWidget *rhiWidget = new SimpleRhiWidget;
+ rhiWidget->setApi(api);
+ QVERIFY(!rhiWidget->isMirrorVerticallyEnabled());
+
+ QSignalSpy frameSpy(rhiWidget, &QRhiWidget::frameSubmitted);
+ QSignalSpy errorSpy(rhiWidget, &QRhiWidget::renderFailed);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(rhiWidget);
+ QWidget w;
+ w.setLayout(layout);
+ w.resize(1280, 720);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ frameSpy.clear();
+ rhiWidget->setMirrorVertically(true);
+ QVERIFY(rhiWidget->isMirrorVerticallyEnabled());
+ QTRY_VERIFY(frameSpy.count() > 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ if (api != QRhiWidget::Api::Null) {
+ QRhi *rhi = rhiWidget->rhi();
+ QRhiReadbackResult readResult;
+ QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
+ rub->readBackTexture(rhiWidget->colorTexture(), &readResult);
+ QVERIFY(submitResourceUpdates(rhi, rub));
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ QImage image;
+ if (rhi->isYUpInFramebuffer())
+ image = wrapperImage.mirrored();
+ else
+ image = wrapperImage.copy();
+
+ const int maxFuzz = 1;
+ QRgb c = image.pixel(50, 5);
+ if (api != QRhiWidget::Api::Vulkan) {
+ // this should be the background (greenish), not the red triangle
+ QVERIFY(qGreen(c) > qRed(c));
+ } else {
+ // remember that Vulkan is upside down due to not correcting for Y down in NDC
+ // hence this is red
+ QVERIFY(qRed(c) >= 255 - maxFuzz);
+ QVERIFY(qGreen(c) <= maxFuzz);
+ }
+ QVERIFY(qBlue(c) <= maxFuzz);
+ }
+}
+
+QTEST_MAIN(tst_QRhiWidget)
+
+#include "tst_qrhiwidget.moc"
diff --git a/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt b/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt
index d6fdd1f617..5e84614407 100644
--- a/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qscrollarea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qscrollarea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qscrollarea
SOURCES
tst_qscrollarea.cpp
diff --git a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp
index edb59b5a7a..87a623b223 100644
--- a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp
+++ b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt b/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt
index a0c5416175..23e31327e1 100644
--- a/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qscrollbar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qscrollbar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qscrollbar
SOURCES
tst_qscrollbar.cpp
diff --git a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp
index 8b53c73361..fc836dec4a 100644
--- a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp
+++ b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt b/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt
index 2c4f1de384..2de1583233 100644
--- a/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qsizegrip Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsizegrip LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qsizegrip
SOURCES
tst_qsizegrip.cpp
diff --git a/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp b/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp
index e7a2cd5f42..a543efe44e 100644
--- a/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp
+++ b/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qslider/CMakeLists.txt b/tests/auto/widgets/widgets/qslider/CMakeLists.txt
index a7a732bfd8..664e9a52af 100644
--- a/tests/auto/widgets/widgets/qslider/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qslider/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qslider Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qslider LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qslider
SOURCES
tst_qslider.cpp
diff --git a/tests/auto/widgets/widgets/qslider/tst_qslider.cpp b/tests/auto/widgets/widgets/qslider/tst_qslider.cpp
index c5f0b9a812..a70c8c484e 100644
--- a/tests/auto/widgets/widgets/qslider/tst_qslider.cpp
+++ b/tests/auto/widgets/widgets/qslider/tst_qslider.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qspinbox/BLACKLIST b/tests/auto/widgets/widgets/qspinbox/BLACKLIST
deleted file mode 100644
index 96a7732165..0000000000
--- a/tests/auto/widgets/widgets/qspinbox/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[stepModifierPressAndHold]
-opensuse-42.3
diff --git a/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt b/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt
index c1a47f4ba7..826ce16d64 100644
--- a/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qspinbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qspinbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qspinbox
SOURCES
tst_qspinbox.cpp
diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
index 928d7f9c4e..dfb0f71139 100644
--- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
+++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qdebug.h>
#include <qapplication.h>
@@ -1830,10 +1830,6 @@ void tst_QSpinBox::stepModifierPressAndHold()
spin.setStyle(stepModifierStyle.data());
QSignalSpy spy(&spin, &SpinBox::valueChanged);
- // TODO: remove debug output when QTBUG-69492 is fixed
- connect(&spin, &SpinBox::valueChanged, [=]() {
- qDebug() << QTime::currentTime() << "valueChanged emitted";
- });
spin.show();
QVERIFY(QTest::qWaitForWindowActive(&spin));
diff --git a/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt b/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt
index 80f2de964c..12602328c3 100644
--- a/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qsplashscreen Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsplashscreen LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qsplashscreen
SOURCES
tst_qsplashscreen.cpp
diff --git a/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp b/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp
index f397777065..f57634152a 100644
--- a/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp
+++ b/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp
@@ -1,9 +1,10 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSplashScreen>
+#include <QTimer>
class tst_QSplashScreen : public QObject
{
@@ -11,7 +12,7 @@ class tst_QSplashScreen : public QObject
private slots:
void checkCloseTime();
- void checkScreenConstructor();
+ void checkConstructorAndShow();
};
class CloseEventSplash : public QSplashScreen
@@ -20,7 +21,7 @@ public:
CloseEventSplash(const QPixmap &pix) : QSplashScreen(pix), receivedCloseEvent(false) {}
bool receivedCloseEvent;
protected:
- void closeEvent(QCloseEvent *event)
+ void closeEvent(QCloseEvent *event) override
{
receivedCloseEvent = true;
QSplashScreen::closeEvent(event);
@@ -35,23 +36,26 @@ void tst_QSplashScreen::checkCloseTime()
QVERIFY(!splash.receivedCloseEvent);
QWidget w;
splash.show();
- QTimer::singleShot(500, &w, SLOT(show()));
+ QTimer::singleShot(10, &w, &QWidget::show);
QVERIFY(!splash.receivedCloseEvent);
splash.finish(&w);
QVERIFY(splash.receivedCloseEvent);
// We check the window handle because if this is not valid, then
// it can't have been exposed
QVERIFY(w.windowHandle());
- QVERIFY(w.windowHandle()->isExposed());
+ QVERIFY(w.windowHandle()->isVisible());
}
-void tst_QSplashScreen::checkScreenConstructor()
+void tst_QSplashScreen::checkConstructorAndShow()
{
- for (const auto screen : QGuiApplication::screens()) {
- QSplashScreen splash(screen);
+ QPixmap pix(100, 100);
+ pix.fill(Qt::red);
+ for (auto *screen : QGuiApplication::screens()) {
+ QSplashScreen splash(screen, pix);
splash.show();
QCOMPARE(splash.screen(), screen);
QVERIFY(splash.windowHandle());
+ QVERIFY(splash.windowHandle()->isVisible());
QCOMPARE(splash.windowHandle()->screen(), screen);
}
}
diff --git a/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt b/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt
index 3c826c153b..16244c8834 100644
--- a/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qsplitter Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsplitter LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
list(APPEND test_data "extradata.txt")
list(APPEND test_data "setSizes3.dat")
diff --git a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp
index ec3df1f03d..071e6d4cbc 100644
--- a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp
+++ b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -1032,7 +1032,7 @@ void tst_QSplitter::taskQTBUG_4101_ensureOneNonCollapsedWidget()
QFETCH(bool, testingHide);
MyFriendlySplitter s;
- QLabel *l;
+ QLabel *l = nullptr;
for (int i = 0; i < 5; ++i) {
l = new QLabel(QString("Label ") + QChar('A' + i));
l->setAlignment(Qt::AlignCenter);
diff --git a/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt
index 3d18ecae88..0c79cf29f4 100644
--- a/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qstackedwidget Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qstackedwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qstackedwidget
SOURCES
tst_qstackedwidget.cpp
diff --git a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
index 10563137c3..0a1b140867 100644
--- a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
+++ b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt b/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt
index 9794718bd3..3bda170936 100644
--- a/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qstatusbar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qstatusbar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qstatusbar
SOURCES
tst_qstatusbar.cpp
diff --git a/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp b/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp
index 15007e8a90..b0a53ba01a 100644
--- a/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp
+++ b/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qtabbar/BLACKLIST b/tests/auto/widgets/widgets/qtabbar/BLACKLIST
deleted file mode 100644
index 735b044d8b..0000000000
--- a/tests/auto/widgets/widgets/qtabbar/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[sizeHints]
-redhatenterpriselinuxworkstation-6.6
diff --git a/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt b/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt
index 4abe0685a5..b79e763819 100644
--- a/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt
@@ -5,10 +5,17 @@
## tst_qtabbar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtabbar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtabbar
SOURCES
tst_qtabbar.cpp
LIBRARIES
Qt::Gui
Qt::Widgets
+ Qt::WidgetsPrivate
)
diff --git a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
index 1d7e999b10..03131cebe4 100644
--- a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
+++ b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
@@ -14,6 +14,8 @@
#include <QScreen>
#include <QWindow>
+#include <QtWidgets/private/qtabbar_p.h>
+
using namespace Qt::StringLiterals;
class TabBar;
@@ -48,6 +50,7 @@ private slots:
void hideTab_data();
void hideTab();
void hideAllTabs();
+ void checkHiddenTab();
void setElideMode_data();
void setElideMode();
@@ -94,6 +97,13 @@ private slots:
void hoverTab_data();
void hoverTab();
+ void resizeKeepsScroll_data();
+ void resizeKeepsScroll();
+ void changeTabTextKeepsScroll();
+ void settingCurrentTabBeforeShowDoesntScroll();
+ void checkPositionsAfterShapeChange();
+ void checkScrollOffsetAfterTabRemoval();
+
private:
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
};
@@ -360,6 +370,25 @@ void tst_QTabBar::hideAllTabs()
QVERIFY(sizeHint.width() < prevSizeHint.width());
}
+void tst_QTabBar::checkHiddenTab()
+{
+ QTabBar tabbar;
+
+ tabbar.addTab("foo");
+ tabbar.addTab("bar");
+ tabbar.addTab("baz");
+ tabbar.setCurrentIndex(0);
+ tabbar.setTabVisible(1, false);
+
+ QKeyEvent keyRight(QKeyEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
+ QVERIFY(QApplication::sendEvent(&tabbar, &keyRight));
+ QCOMPARE(tabbar.currentIndex(), 2);
+
+ QKeyEvent keyLeft(QKeyEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
+ QVERIFY(QApplication::sendEvent(&tabbar, &keyLeft));
+ QCOMPARE(tabbar.currentIndex(), 0);
+}
+
void tst_QTabBar::setElideMode_data()
{
QTest::addColumn<int>("tabElideMode");
@@ -1346,5 +1375,226 @@ void tst_QTabBar::hoverTab()
QCOMPARE(tabbar.styleOptions[1].state & QStyle::State_MouseOver, QStyle::State_None);
}
+
+void tst_QTabBar::resizeKeepsScroll_data()
+{
+ QTest::addColumn<QTabBar::Shape>("tabShape");
+ QTest::addColumn<bool>("expanding");
+
+ QTest::addRow("North, expanding") << QTabBar::RoundedNorth << true;
+ QTest::addRow("East, expanding") << QTabBar::RoundedEast << true;
+ QTest::addRow("South, expanding") << QTabBar::RoundedSouth << true;
+ QTest::addRow("West, expanding") << QTabBar::RoundedWest << true;
+
+ QTest::addRow("North, not expanding") << QTabBar::RoundedNorth << false;
+ QTest::addRow("South, not expanding") << QTabBar::RoundedSouth << false;
+}
+
+void tst_QTabBar::resizeKeepsScroll()
+{
+ QFETCH(QTabBar::Shape, tabShape);
+ QFETCH(const bool, expanding);
+
+ QTabBar tabBar;
+ TabBarScrollingProxyStyle proxyStyle;
+ tabBar.setStyle(&proxyStyle);
+
+ for (int i = 0; i < 10; ++i)
+ tabBar.addTab(u"Tab Number %1"_s.arg(i));
+
+ tabBar.setShape(tabShape);
+ tabBar.setUsesScrollButtons(true);
+ tabBar.setExpanding(expanding);
+
+ // resize to half
+ const QSize fullSize = tabBar.sizeHint();
+ const bool horizontal = fullSize.width() > fullSize.height();
+ if (horizontal)
+ tabBar.resize(fullSize.width() / 2, fullSize.height());
+ else
+ tabBar.resize(fullSize.width(), fullSize.height() / 2);
+
+ tabBar.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabBar));
+
+ const auto getScrollOffset = [&]() -> int {
+ return static_cast<QTabBarPrivate *>(QObjectPrivate::get(&tabBar))->scrollOffset;
+ };
+
+ // select a tab outside, this will scroll
+ tabBar.setCurrentIndex(6);
+ // the first tab is now scrolled out
+ const int scrollOffset = getScrollOffset();
+ QCOMPARE_GT(scrollOffset, 0);
+ // the current index is now fully visible, with margin on both sides
+ tabBar.setCurrentIndex(5);
+
+ // make the tab bar a bit larger, by the width of a tab
+ if (horizontal)
+ tabBar.resize(tabBar.width() + tabBar.tabRect(5).width(), tabBar.height());
+ else
+ tabBar.resize(tabBar.width(), tabBar.height() + tabBar.tabRect(5).height());
+
+ // this should not change the scroll
+ QCOMPARE(getScrollOffset(), scrollOffset);
+
+ // make the tab bar large enough to fit everything with extra space
+ tabBar.resize(fullSize + QSize(50, 50));
+
+ // there should be no scroll
+ QCOMPARE(getScrollOffset(), 0);
+
+ for (int i = 0; i < tabBar.count(); ++i) {
+ tabBar.setCurrentIndex(i);
+ QCOMPARE(getScrollOffset(), 0);
+ }
+}
+
+void tst_QTabBar::changeTabTextKeepsScroll()
+{
+ QTabBar tabBar;
+ TabBarScrollingProxyStyle proxyStyle;
+ tabBar.setStyle(&proxyStyle);
+
+ for (int i = 0; i < 6; ++i)
+ tabBar.addTab(u"Tab Number %1"_s.arg(i));
+
+ const QSize fullSize = tabBar.sizeHint();
+ tabBar.resize(fullSize.width() / 2, fullSize.height());
+
+ tabBar.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabBar));
+
+ const auto getScrollOffset = [&]() -> int {
+ return static_cast<QTabBarPrivate *>(QObjectPrivate::get(&tabBar))->scrollOffset;
+ };
+
+ tabBar.setCurrentIndex(3);
+ const int scrollOffset = getScrollOffset();
+ tabBar.setTabText(3, "New title");
+ QCOMPARE(getScrollOffset(), scrollOffset);
+}
+
+void tst_QTabBar::settingCurrentTabBeforeShowDoesntScroll()
+{
+ QTabBar tabBar;
+ TabBarScrollingProxyStyle proxyStyle;
+ tabBar.setStyle(&proxyStyle);
+
+ for (int i = 0; i < 6; ++i)
+ tabBar.addTab(u"Tab Number %1"_s.arg(i));
+
+ const auto getScrollOffset = [&]() -> int {
+ return static_cast<QTabBarPrivate *>(QObjectPrivate::get(&tabBar))->scrollOffset;
+ };
+
+ tabBar.setCurrentIndex(5);
+
+ // changing the current index while the tab bar isn't visible shouldn't scroll yet
+ QCOMPARE(getScrollOffset(), 0);
+
+ // now show the tab bar with a size that's too small to fit the current index
+ const QSize fullSize = tabBar.sizeHint();
+ tabBar.resize(fullSize.width() / 2, fullSize.height());
+
+ tabBar.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabBar));
+
+ // this should scroll
+ QCOMPARE_GT(getScrollOffset(), 0);
+}
+
+void tst_QTabBar::checkPositionsAfterShapeChange()
+{
+ class TabWidget : public QTabWidget
+ {
+ public:
+ using QTabWidget::QTabWidget;
+ using QTabWidget::setTabBar;
+ };
+
+ class TabBar : public QTabBar
+ {
+ public:
+ using QTabBar::initStyleOption;
+ void resizeEvent(QResizeEvent *e) override
+ {
+ QTabBar::resizeEvent(e);
+ resized = true;
+ }
+ bool resized = false;
+ };
+
+ TabWidget tabWidget;
+ auto *tabBar = new TabBar;
+ tabWidget.setTabBar(tabBar);
+ for (int i = 0; i < 3; ++i)
+ tabWidget.addTab(new QWidget, u"Tab %1"_s.arg(i));
+ tabWidget.setTabPosition(QTabWidget::North);
+ tabWidget.setCurrentIndex(2);
+ tabWidget.resize(300, 300);
+ tabWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));
+
+ tabBar->resized = false;
+ tabWidget.setTabPosition(QTabWidget::East);
+ QVERIFY(QTest::qWaitFor([&]() { return tabBar->resized; }));
+ QStyleOptionTab opt;
+ tabBar->initStyleOption(&opt, 2);
+ QVERIFY(opt.rect.top() > 0);
+}
+
+void tst_QTabBar::checkScrollOffsetAfterTabRemoval()
+{
+ QTabWidget tabWidget;
+ QTabBar *tabBar = tabWidget.tabBar();
+ for (int i = 0; i < 10; ++i)
+ tabWidget.addTab(new QWidget, u"Tab %1"_s.arg(i));
+ tabWidget.setTabPosition(QTabWidget::North);
+ tabWidget.resize(300, 300);
+ tabWidget.setCurrentIndex(0);
+ tabWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));
+
+ auto *rightButton = tabBar->findChild<QAbstractButton *>(u"ScrollRightButton"_s);
+ auto *leftButton = tabBar->findChild<QAbstractButton *>(u"ScrollLeftButton"_s);
+ QVERIFY(leftButton);
+ QVERIFY(rightButton);
+ QVERIFY(rightButton->isEnabled());
+ QVERIFY(!leftButton->isEnabled());
+ // scroll to the right
+ tabBar->setCurrentIndex(9);
+ QVERIFY(!rightButton->isEnabled());
+ QVERIFY(leftButton->isEnabled());
+ // scroll to the center
+ tabBar->setCurrentIndex(2);
+ QVERIFY(rightButton->isEnabled());
+ QVERIFY(leftButton->isEnabled());
+
+ const auto getScrollOffset = [&]() -> int {
+ return static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar))->scrollOffset;
+ };
+ // the scroll offset should not change when a tab right outside
+ // the scroll rect is removed
+ auto oldOffset = getScrollOffset();
+ tabWidget.removeTab(9);
+ QCOMPARE(getScrollOffset(), oldOffset);
+ // the scroll offset must change when a tab left outside
+ // the scroll rect is removed
+ oldOffset = getScrollOffset();
+ tabWidget.removeTab(0);
+ QVERIFY(getScrollOffset() < oldOffset);
+
+ // the scroll offset must change when there is empty
+ // place in the right after tab removal
+ oldOffset = getScrollOffset();
+ QVERIFY(oldOffset > 0);
+ for (int i : { 7, 6, 5, 4, 3 })
+ tabWidget.removeTab(i);
+ QCOMPARE(getScrollOffset(), 0);
+ QVERIFY(!rightButton->isVisible());
+ QVERIFY(!leftButton->isVisible());
+}
+
QTEST_MAIN(tst_QTabBar)
#include "tst_qtabbar.moc"
diff --git a/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt
index d6f1fa1541..a8b48e925c 100644
--- a/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtabwidget Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtabwidget LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtabwidget
SOURCES
tst_qtabwidget.cpp
diff --git a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp
index 00cb26c2d3..d7bfdfaad2 100644
--- a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp
+++ b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -60,6 +60,7 @@ private slots:
void tabPosition();
void tabEnabled();
void tabHidden();
+ void checkHiddenTab();
void tabText();
void tabShape();
void tabTooltip();
@@ -79,6 +80,9 @@ private slots:
void moveCurrentTab();
void autoHide();
+ void setCurrentBeforeShow_data();
+ void setCurrentBeforeShow();
+
private:
int addPage();
void removePage(int index);
@@ -249,6 +253,32 @@ void tst_QTabWidget::tabHidden()
}
}
+void tst_QTabWidget::checkHiddenTab()
+{
+ tw->addTab(new QWidget(), "foo");
+ tw->addTab(new QWidget(), "bar");
+ tw->addTab(new QWidget(), "baz");
+ QCOMPARE(tw->count(), 3);
+ tw->setCurrentIndex(0);
+ tw->setTabVisible(1, false);
+
+ QKeyEvent keyTab(QKeyEvent::KeyPress, Qt::Key_Tab, Qt::ControlModifier);
+ QVERIFY(QApplication::sendEvent(tw, &keyTab));
+ QCOMPARE(tw->currentIndex(), 2);
+ QVERIFY(QApplication::sendEvent(tw, &keyTab));
+ QCOMPARE(tw->currentIndex(), 0);
+ QVERIFY(QApplication::sendEvent(tw, &keyTab));
+ QCOMPARE(tw->currentIndex(), 2);
+
+ QKeyEvent keyBacktab(QKeyEvent::KeyPress, Qt::Key_Backtab, Qt::ControlModifier);
+ QVERIFY(QApplication::sendEvent(tw, &keyBacktab));
+ QCOMPARE(tw->currentIndex(), 0);
+ QVERIFY(QApplication::sendEvent(tw, &keyBacktab));
+ QCOMPARE(tw->currentIndex(), 2);
+ QVERIFY(QApplication::sendEvent(tw, &keyBacktab));
+ QCOMPARE(tw->currentIndex(), 0);
+}
+
void tst_QTabWidget::tabText()
{
// Test bad arguments
@@ -750,5 +780,39 @@ void tst_QTabWidget::autoHide()
QVERIFY(heightForWidth1 > tabWidget.heightForWidth(20));
}
+void tst_QTabWidget::setCurrentBeforeShow_data()
+{
+ QTest::addColumn<QTabWidget::TabPosition>("tabPosition");
+ QTest::newRow("West") << QTabWidget::West;
+ QTest::newRow("North") << QTabWidget::North;
+ QTest::newRow("East") << QTabWidget::East;
+ QTest::newRow("South") << QTabWidget::South;
+}
+
+void tst_QTabWidget::setCurrentBeforeShow()
+{
+ QFETCH(QTabWidget::TabPosition, tabPosition);
+
+ QTabWidget tabWidget;
+ tabWidget.setTabPosition(tabPosition);
+
+ QPixmap pm(50, 50);
+ pm.fill(Qt::red);
+ const QIcon icon(pm);
+ for (int i = 0; i < 4; ++i)
+ tabWidget.addTab(new QWidget, icon, QString("Tab %1").arg(i));
+
+ // the tab widget has space for the entire tab bar
+ tabWidget.resize(tabWidget.tabBar()->sizeHint() + QSize(50, 50));
+ tabWidget.setCurrentIndex(2);
+ tabWidget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));
+
+ QCOMPARE_GE(tabWidget.tabBar()->tabRect(0).x(), 0);
+ QCOMPARE_GE(tabWidget.tabBar()->tabRect(0).y(), 0);
+
+ QTest::qWait(2000);
+}
+
QTEST_MAIN(tst_QTabWidget)
#include "tst_qtabwidget.moc"
diff --git a/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt b/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt
index b2d6664783..4a80068d75 100644
--- a/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtextbrowser Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtextbrowser LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
index 8bc991a962..5d66f5922a 100644
--- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
+++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt b/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt
index fdaf6a7046..e406e088ca 100644
--- a/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtextedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtextedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
list(APPEND test_data "fullWidthSelection")
diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
index 241b0e64f3..0136e5b5de 100644
--- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
+++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -198,6 +198,8 @@ private slots:
void nextFormatAfterEnterPressed_data();
void nextFormatAfterEnterPressed();
+ void dontCrashWithCss();
+
private:
void createSelection();
int blockCount() const;
@@ -757,6 +759,11 @@ void tst_QTextEdit::cursorPositionChanged()
QCOMPARE(spy2.cursorPositions.size(), 1);
QCOMPARE(spy2.cursorPositions.at(0), 0);
QCOMPARE(ed->textCursor().position(), 0);
+
+ ed->selectAll();
+ QCOMPARE(spy2.cursorPositions.size(), 2);
+ QCOMPARE(spy2.cursorPositions.at(1), 11);
+ QCOMPARE(ed->textCursor().position(), 11);
}
void tst_QTextEdit::setTextCursor()
@@ -1347,7 +1354,7 @@ void tst_QTextEdit::copyAvailable_data()
//Tests the copyAvailable slot for several cases
void tst_QTextEdit::copyAvailable()
{
- QFETCH(pairListType,keystrokes);
+ QFETCH(const pairListType, keystrokes);
QFETCH(QList<bool>, copyAvailable);
QFETCH(QString, function);
@@ -1360,9 +1367,8 @@ void tst_QTextEdit::copyAvailable()
QSignalSpy spyCopyAvailabe(ed, SIGNAL(copyAvailable(bool)));
//Execute Keystrokes
- foreach(keyPairType keyPair, keystrokes) {
+ for (keyPairType keyPair : keystrokes)
QTest::keyClick(ed, keyPair.first, keyPair.second );
- }
//Execute ed->"function"
if (function == "cut")
@@ -3060,5 +3066,14 @@ void tst_QTextEdit::nextFormatAfterEnterPressed()
QCOMPARE(prevBlockCursor.charFormat().property(it.key()), it.value());
}
+void tst_QTextEdit::dontCrashWithCss()
+{
+ qApp->setStyleSheet("QWidget { font: 10pt; }");
+ QTextEdit edit;
+ edit.show();
+ qApp->setStyleSheet(QString());
+}
+
+
QTEST_MAIN(tst_QTextEdit)
#include "tst_qtextedit.moc"
diff --git a/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt b/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt
index f2543fb75f..e9fb01c3e8 100644
--- a/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtoolbar Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtoolbar LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtoolbar
SOURCES
tst_qtoolbar.cpp
diff --git a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
index 670839feb6..6336b792ed 100644
--- a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
+++ b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt b/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt
index 2a18840839..362fba25a4 100644
--- a/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtoolbox Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtoolbox LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtoolbox
SOURCES
tst_qtoolbox.cpp
diff --git a/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp b/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp
index 5fe06707be..fb14ceb79c 100644
--- a/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp
+++ b/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
diff --git a/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt b/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt
index 7d4c36ddb2..7c8b41b5e6 100644
--- a/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt
+++ b/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt
@@ -5,6 +5,12 @@
## tst_qtoolbutton Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtoolbutton LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qtoolbutton
SOURCES
tst_qtoolbutton.cpp
diff --git a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
index c5ed718edb..20472861d9 100644
--- a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
+++ b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
@@ -34,6 +34,7 @@ private slots:
void qtbug_26956_popupTimerDone();
void qtbug_34759_sizeHintResetWhenSettingMenu();
void defaultActionSynced();
+ void deleteInHandler();
protected slots:
void sendMouseClick();
@@ -316,5 +317,22 @@ void tst_QToolButton::defaultActionSynced()
QCOMPARE(bSpy.size(), ++bToggledCount);
}
+void tst_QToolButton::deleteInHandler()
+{
+ // Tests that if something deletes the button
+ // while its event handler is still on the callstack, we don't crash
+
+ QPointer<QToolButton> tb = new QToolButton();
+ tb->show();
+ QVERIFY(QTest::qWaitForWindowActive(tb));
+
+ connect(tb, &QToolButton::clicked, this, [tb] {
+ delete tb;
+ });
+
+ QTest::mouseClick(tb, Qt::LeftButton);
+ QVERIFY(!tb);
+}
+
QTEST_MAIN(tst_QToolButton)
#include "tst_qtoolbutton.moc"