diff options
Diffstat (limited to 'tests/auto/widgets/widgets')
191 files changed, 6764 insertions, 3276 deletions
diff --git a/tests/auto/widgets/widgets/CMakeLists.txt b/tests/auto/widgets/widgets/CMakeLists.txt index c64b86b3de..eb44f3d103 100644 --- a/tests/auto/widgets/widgets/CMakeLists.txt +++ b/tests/auto/widgets/widgets/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from widgets.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause add_subdirectory(qabstractbutton) add_subdirectory(qabstractscrollarea) @@ -28,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) @@ -46,17 +48,15 @@ endif() if(QT_FEATURE_shortcut) add_subdirectory(qkeysequenceedit) endif() +add_subdirectory(qmenu) +add_subdirectory(qlineedit) if(NOT ANDROID) - # QTBUG-87417 # special case - add_subdirectory(qlineedit) - # QTBUG-87420 # special case + # QTBUG-87420 add_subdirectory(qmdiarea) - # QTBUG-87671 # special case - add_subdirectory(qmenu) - # QTBUG-87421 # special case + # QTBUG-87421 add_subdirectory(qmenubar) endif() -# QTBUG-87671 # special case -if(QT_FEATURE_opengl AND NOT ANDROID) +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 d192549f94..883614fc04 100644 --- a/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qabstractbutton/CMakeLists.txt @@ -1,14 +1,22 @@ -# Generated from qabstractbutton.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp index 878647f4a4..cb91f0c6e6 100644 --- a/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp +++ b/tests/auto/widgets/widgets/qabstractbutton/tst_qabstractbutton.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -42,6 +17,9 @@ #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> +#include <qpa/qplatformtheme.h> + +#include <QtWidgets/private/qapplication_p.h> class tst_QAbstractButton : public QObject { @@ -81,6 +59,8 @@ private slots: void keyNavigation(); #endif + void buttonPressKeys(); + protected slots: void onClicked(); void onToggled( bool on ); @@ -276,7 +256,13 @@ void tst_QAbstractButton::setAutoRepeat() QCOMPARE(press_count, click_count); QVERIFY(click_count > 1); break; - case 4: + case 4: { + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + QSKIP("platform theme has Key_Enter in ButtonPressKeys"); + } // check that pressing ENTER has no effect when autorepeat is false testWidget->setDown( false ); testWidget->setAutoRepeat( false ); @@ -293,7 +279,14 @@ void tst_QAbstractButton::setAutoRepeat() QVERIFY( click_count == 0 ); break; - case 5: + } + case 5: { + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + QSKIP("platform theme has Key_Enter in ButtonPressKeys"); + } // check that pressing ENTER has no effect when autorepeat is true testWidget->setDown( false ); testWidget->setAutoRepeat( true ); @@ -311,6 +304,7 @@ void tst_QAbstractButton::setAutoRepeat() QVERIFY( click_count == 0 ); break; + } case 6: // verify autorepeat is off by default. MyButton tmp( 0); @@ -486,7 +480,6 @@ void tst_QAbstractButton::setShortcut() QKeySequence seq( Qt::Key_A ); testWidget->setShortcut( seq ); - QApplication::setActiveWindow(testWidget); testWidget->activateWindow(); // must be active to get shortcuts QVERIFY(QTest::qWaitForWindowActive(testWidget)); @@ -514,11 +507,34 @@ void tst_QAbstractButton::setShortcut() void tst_QAbstractButton::animateClick() { - testWidget->animateClick(); - QVERIFY( testWidget->isDown() ); - qApp->processEvents(); - QVERIFY( testWidget->isDown() ); - QTRY_VERIFY( !testWidget->isDown() ); + MyButton button; + QSignalSpy pressedSpy(&button, &QAbstractButton::pressed); + QSignalSpy releasedSpy(&button, &QAbstractButton::released); + QSignalSpy clickedSpy(&button, &QAbstractButton::clicked); + + QElapsedTimer elapsed; + elapsed.start(); + button.animateClick(); + + QVERIFY(button.isDown()); + QCOMPARE(pressedSpy.size(), 1); + QCOMPARE(releasedSpy.size(), 0); + QCOMPARE(clickedSpy.size(), 0); + qApp->processEvents(QEventLoop::AllEvents, 10); + // QAbstractButton starts a 100ms timer which performs the click. If it + // took more than 100ms to get here, then the button might no longer be down. + if (elapsed.elapsed() < 100) { + QVERIFY(button.isDown()); + QCOMPARE(pressedSpy.size(), 1); + QCOMPARE(releasedSpy.size(), 0); + QCOMPARE(clickedSpy.size(), 0); + } + QTRY_VERIFY(!button.isDown()); + // but once the button has been clicked, it must have taken at least 100ms + QVERIFY(elapsed.elapsed() >= 100); + QCOMPARE(pressedSpy.size(), 1); + QCOMPARE(releasedSpy.size(), 1); + QCOMPARE(clickedSpy.size(), 1); } #if QT_CONFIG(shortcut) @@ -541,9 +557,9 @@ void tst_QAbstractButton::shortcutEvents() QTest::qWait(1000); // ensure animate timer is expired - QCOMPARE(pressedSpy.count(), 3); - QCOMPARE(releasedSpy.count(), 3); - QCOMPARE(clickedSpy.count(), 3); + QCOMPARE(pressedSpy.size(), 3); + QCOMPARE(releasedSpy.size(), 3); + QCOMPARE(clickedSpy.size(), 3); } #endif // QT_CONFIG(shortcut) @@ -585,26 +601,26 @@ void tst_QAbstractButton::mouseReleased() // QTBUG-53244 QSignalSpy spyRelease(&button, &QAbstractButton::released); QTest::mousePress(&button, Qt::LeftButton); - QCOMPARE(spyPress.count(), 1); + QCOMPARE(spyPress.size(), 1); QCOMPARE(button.isDown(), true); - QCOMPARE(spyRelease.count(), 0); + QCOMPARE(spyRelease.size(), 0); QTest::mouseClick(&button, Qt::RightButton); - QCOMPARE(spyPress.count(), 1); + QCOMPARE(spyPress.size(), 1); QCOMPARE(button.isDown(), true); - QCOMPARE(spyRelease.count(), 0); + QCOMPARE(spyRelease.size(), 0); QPointF posOutOfWidget = QPointF(30, 30); QMouseEvent me(QEvent::MouseMove, - posOutOfWidget, Qt::NoButton, - Qt::MouseButtons(Qt::LeftButton), - Qt::NoModifier); // mouse press and move + posOutOfWidget, button.mapToGlobal(posOutOfWidget), + Qt::NoButton, Qt::MouseButtons(Qt::LeftButton), + Qt::NoModifier); // mouse press and move qApp->sendEvent(&button, &me); // should emit released signal once mouse is dragging out of boundary - QCOMPARE(spyPress.count(), 1); + QCOMPARE(spyPress.size(), 1); QCOMPARE(button.isDown(), false); - QCOMPARE(spyRelease.count(), 1); + QCOMPARE(spyRelease.size(), 1); } #ifdef QT_KEYPAD_NAVIGATION @@ -624,7 +640,7 @@ void tst_QAbstractButton::keyNavigation() } widget.show(); - qApp->setActiveWindow(&widget); + QApplicationPrivate::setActiveWindow(&widget); widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); @@ -664,5 +680,16 @@ void tst_QAbstractButton::keyNavigation() } #endif +void tst_QAbstractButton::buttonPressKeys() +{ + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + for (uint i = 0; i < buttonPressKeys.size(); ++i) { + QTest::keyClick(testWidget, buttonPressKeys[i]); + QCOMPARE(click_count, i + 1); + } +} + QTEST_MAIN(tst_QAbstractButton) #include "tst_qabstractbutton.moc" diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt index d756d28952..ac1d8ad54a 100644 --- a/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qabstractscrollarea/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qabstractscrollarea.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp index 9d7cc484cd..fa1f799855 100644 --- a/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp +++ b/tests/auto/widgets/widgets/qabstractscrollarea/tst_qabstractscrollarea.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -38,6 +13,7 @@ #include <qwidget.h> #include <qdialog.h> #include <qscroller.h> +#include <qstyle.h> class tst_QAbstractScrollArea : public QObject { @@ -59,6 +35,7 @@ private slots: void margins(); void resizeWithOvershoot(); + void sizeHint(); }; tst_QAbstractScrollArea::tst_QAbstractScrollArea() @@ -433,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 37c725c391..711c73931d 100644 --- a/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qabstractslider/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qabstractslider.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::TestPrivate Qt::Widgets diff --git a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp index 7ab609a7ca..9be41ad799 100644 --- a/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp +++ b/tests/auto/widgets/widgets/qabstractslider/tst_qabstractslider.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -1484,7 +1459,7 @@ void tst_QAbstractSlider::keyPressed() slider->setOrientation(Qt::Horizontal); slider->setInvertedAppearance(invertedAppearance); slider->setInvertedControls(invertedControls); - for (int i=0;i<keySequence.count();i++) { + for (int i=0;i<keySequence.size();i++) { QTest::keyClick(slider, keySequence.at(i)); } QCOMPARE(slider->sliderPosition(), expectedSliderPosition); @@ -1691,8 +1666,8 @@ void tst_QAbstractSlider::wheelEvent() #endif QCOMPARE(slider->sliderPosition(),expectedSliderPosition); int expectedSignalCount = (initialSliderPosition == expectedSliderPosition) ? 0 : 1; - QCOMPARE(spy1.count(), expectedSignalCount); - QCOMPARE(spy2.count(), expectedSignalCount); + QCOMPARE(spy1.size(), expectedSignalCount); + QCOMPARE(spy2.size(), expectedSignalCount); if (expectedSignalCount) QVERIFY(actionTriggeredTimeStamp < valueChangedTimeStamp); } @@ -1839,9 +1814,9 @@ void tst_QAbstractSlider::sliderPressedReleased() QTest::mousePress(slider, Qt::LeftButton, {}, QPoint(rect.center().x() + 2, rect.center().y() + 2)); - QCOMPARE(spy1.count(), expectedCount); + QCOMPARE(spy1.size(), expectedCount); QTest::mouseRelease(slider, Qt::LeftButton, {}, rect.center()); - QCOMPARE(spy2.count(), expectedCount); + QCOMPARE(spy2.size(), expectedCount); delete slider; } @@ -1910,7 +1885,7 @@ void tst_QAbstractSlider::sliderMoved() slider->setMaximum(maximum); slider->setSliderDown(sliderDown); slider->setSliderPosition(position); - QCOMPARE(spy.count(), expectedCount); + QCOMPARE(spy.size(), expectedCount); delete slider; } @@ -1982,7 +1957,7 @@ void tst_QAbstractSlider::rangeChanged() slider.setRange(minimum, maximum); QSignalSpy spy(&slider, SIGNAL(rangeChanged(int,int))); slider.setRange(newMin, newMax); - QCOMPARE(spy.count(), expectedCount); + QCOMPARE(spy.size(), expectedCount); } void tst_QAbstractSlider::setSliderPosition_data() @@ -2021,8 +1996,8 @@ void tst_QAbstractSlider::setSliderPosition() QSignalSpy spy2(slider, SIGNAL(valueChanged(int))); slider->setSliderPosition(targetPosition); QCOMPARE(slider->sliderPosition(), targetPosition); - QCOMPARE(spy1.count(), down ? 1 : 0); - QCOMPARE(spy2.count(), tracking ? 1 : 0); + QCOMPARE(spy1.size(), down ? 1 : 0); + QCOMPARE(spy2.size(), tracking ? 1 : 0); QCOMPARE(slider->value(), tracking ? targetPosition : initialValue); if (tracking && down) QVERIFY(sliderMovedTimeStamp < valueChangedTimeStamp); @@ -2046,17 +2021,21 @@ void tst_QAbstractSlider::setValue() slider->setRange(minimum, maximum); slider->setSliderDown(down); slider->setValue(49); // to force a valueChanged() below - QSignalSpy spy1(slider, SIGNAL(sliderMoved(int))); - QSignalSpy spy2(slider, SIGNAL(valueChanged(int))); - QSignalSpy spy3(slider, SIGNAL(actionTriggered(int))); + QSignalSpy spy1(slider, &QAbstractSlider::sliderMoved); + QSignalSpy spy2(slider, &QAbstractSlider::valueChanged); + QSignalSpy spy3(slider, &QAbstractSlider::actionTriggered); slider->setValue(50); - QCOMPARE(spy1.count(), down ? 1 : 0); - QCOMPARE(spy2.count(), 1); - QCOMPARE(spy3.count(), 0); + QCOMPARE(spy1.size(), down ? 1 : 0); + QCOMPARE(spy2.size(), 1); + QCOMPARE(spy3.size(), 0); QCOMPARE(slider->value(), reportedValue); QCOMPARE(slider->sliderPosition(), reportedSliderPosition); if (down) QVERIFY(sliderMovedTimeStamp < valueChangedTimeStamp); + + slider->setValue(50); + QApplication::processEvents(); + QCOMPARE(spy2.size(), 1); } void tst_QAbstractSlider::waitUntilTimeElapsed(const QElapsedTimer &t, int ms) @@ -2076,37 +2055,37 @@ void tst_QAbstractSlider::setRepeatAction() // Start repeat action with initial delay of 500 ms, and then repeating // every 250 ms. slider->setRepeatAction(QAbstractSlider::SliderPageStepAdd, 500, 250); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QCOMPARE(slider->value(), 55); QElapsedTimer t; t.start(); QTest::qWait(300); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QCOMPARE(slider->value(), 55); waitUntilTimeElapsed(t, 550); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(slider->value(), 65); QCOMPARE(spy.at(0).at(0).toUInt(), (uint)QAbstractSlider::SliderPageStepAdd); waitUntilTimeElapsed(t, 790); - QTRY_COMPARE(spy.count(), 2); + QTRY_COMPARE(spy.size(), 2); QCOMPARE(slider->value(), 75); QCOMPARE(spy.at(1).at(0).toUInt(), (uint)QAbstractSlider::SliderPageStepAdd); waitUntilTimeElapsed(t, 1790); - QTRY_COMPARE(spy.count(), 6); + QTRY_COMPARE(spy.size(), 6); QCOMPARE(slider->value(), 115); QCOMPARE(spy.at(4).at(0).toUInt(), (uint)QAbstractSlider::SliderPageStepAdd); QCOMPARE(spy.at(5).at(0).toUInt(), (uint)QAbstractSlider::SliderPageStepAdd); slider->setRepeatAction(QAbstractSlider::SliderNoAction); - QCOMPARE(spy.count(), 6); + QCOMPARE(spy.size(), 6); QCOMPARE(slider->value(), 115); QTest::qWait(300); - QCOMPARE(spy.count(), 6); + QCOMPARE(spy.size(), 6); QCOMPARE(slider->value(), 115); } diff --git a/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt b/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt index df077a0bbd..adaef01601 100644 --- a/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qabstractspinbox/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qabstractspinbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp index 6898cf18dc..00d0fdaf94 100644 --- a/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp +++ b/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -39,15 +14,12 @@ #include "../../../shared/platforminputcontext.h" #include <private/qinputmethod_p.h> +#include <memory> class tst_QAbstractSpinBox : public QObject { Q_OBJECT -public: - tst_QAbstractSpinBox(); - virtual ~tst_QAbstractSpinBox(); - private slots: void initTestCase(); void cleanupTestCase(); @@ -64,32 +36,25 @@ private: PlatformInputContext m_platformInputContext; }; -tst_QAbstractSpinBox::tst_QAbstractSpinBox() -{ -} - -tst_QAbstractSpinBox::~tst_QAbstractSpinBox() -{ -} - class MyAbstractSpinBox : public QAbstractSpinBox { public: - MyAbstractSpinBox() : QAbstractSpinBox() {} - QLineEdit *lineEdit() { return QAbstractSpinBox::lineEdit(); } - void setLineEdit(QLineEdit *le) { QAbstractSpinBox::setLineEdit(le); } + using QAbstractSpinBox::QAbstractSpinBox; + + using QAbstractSpinBox::lineEdit; + using QAbstractSpinBox::setLineEdit; }; void tst_QAbstractSpinBox::initTestCase() { - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + auto *inputMethodPrivate = QInputMethodPrivate::get(QGuiApplication::inputMethod()); inputMethodPrivate->testContext = &m_platformInputContext; } void tst_QAbstractSpinBox::cleanupTestCase() { - QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + auto *inputMethodPrivate = QInputMethodPrivate::get(QGuiApplication::inputMethod()); + inputMethodPrivate->testContext = nullptr; } // Testing get/set functions @@ -112,11 +77,12 @@ void tst_QAbstractSpinBox::getSetCheck() // QLineEdit * QAbstractSpinBox::lineEdit() // void QAbstractSpinBox::setLineEdit(QLineEdit *) - QLineEdit *var3 = new QLineEdit(0); + auto *var3 = new QLineEdit(nullptr); obj1.setLineEdit(var3); QCOMPARE(var3, obj1.lineEdit()); -#ifndef QT_DEBUG - obj1.setLineEdit((QLineEdit *)0); // Will assert in debug, so only test in release + // Will assert in debug, so only test in release +#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) + obj1.setLineEdit(nullptr); QCOMPARE(var3, obj1.lineEdit()); // Setting 0 should keep the current editor #endif // delete var3; // No delete, since QAbstractSpinBox takes ownership @@ -124,45 +90,38 @@ void tst_QAbstractSpinBox::getSetCheck() void tst_QAbstractSpinBox::task183108_clear() { - QAbstractSpinBox *sbox; - - sbox = new QSpinBox; + auto sbox = std::make_unique<QSpinBox>(); sbox->clear(); sbox->show(); - qApp->processEvents(); + QCoreApplication::processEvents(); QVERIFY(sbox->text().isEmpty()); - delete sbox; - sbox = new QSpinBox; + sbox.reset(new QSpinBox); sbox->clear(); sbox->show(); sbox->hide(); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(sbox->text(), QString()); - delete sbox; - sbox = new QSpinBox; + sbox.reset(new QSpinBox); sbox->show(); sbox->clear(); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(sbox->text(), QString()); - delete sbox; - sbox = new QSpinBox; + sbox.reset(new QSpinBox); sbox->show(); sbox->clear(); sbox->hide(); - qApp->processEvents(); + QCoreApplication::processEvents(); QCOMPARE(sbox->text(), QString()); - - delete sbox; } void tst_QAbstractSpinBox::task228728_cssselector() { //QAbstractSpinBox does some call to stylehint into his constructor. //so while the stylesheet want to access property, it should not crash - qApp->setStyleSheet("[alignment=\"1\"], [text=\"foo\"] { color:black; }" ); + qApp->setStyleSheet(R"([alignment="1"], [text="foo"] { color:black; })"); QSpinBox box; } @@ -173,24 +132,23 @@ void tst_QAbstractSpinBox::inputMethodUpdate() QSpinBox box; - QSpinBox *testWidget = &box; - testWidget->setRange(0, 1); + box.setRange(0, 1); - QTestPrivate::centerOnScreen(testWidget); - testWidget->clear(); - testWidget->show(); - QVERIFY(QTest::qWaitForWindowExposed(testWidget)); + QTestPrivate::centerOnScreen(&box); + box.clear(); + box.show(); + QVERIFY(QTest::qWaitForWindowExposed(&box)); - testWidget->activateWindow(); - testWidget->setFocus(); - QTRY_VERIFY(testWidget->hasFocus()); - QTRY_COMPARE(qApp->focusObject(), testWidget); + box.activateWindow(); + box.setFocus(); + QTRY_VERIFY(box.hasFocus()); + QTRY_COMPARE(QGuiApplication::focusObject(), &box); m_platformInputContext.m_updateCallCount = 0; { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("1", attributes); - QApplication::sendEvent(testWidget, &event); + QCoreApplication::sendEvent(&box, &event); } QVERIFY(m_platformInputContext.m_updateCallCount >= 1); @@ -199,7 +157,7 @@ void tst_QAbstractSpinBox::inputMethodUpdate() QList<QInputMethodEvent::Attribute> attributes; attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 1, QVariant()); QInputMethodEvent event("1", attributes); - QApplication::sendEvent(testWidget, &event); + QCoreApplication::sendEvent(&box, &event); } QVERIFY(m_platformInputContext.m_updateCallCount >= 1); @@ -208,17 +166,17 @@ void tst_QAbstractSpinBox::inputMethodUpdate() QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("", attributes); event.setCommitString("1"); - QApplication::sendEvent(testWidget, &event); + QCoreApplication::sendEvent(&box, &event); } QVERIFY(m_platformInputContext.m_updateCallCount >= 1); - QCOMPARE(testWidget->value(), 1); + QCOMPARE(box.value(), 1); m_platformInputContext.m_updateCallCount = 0; { QList<QInputMethodEvent::Attribute> attributes; attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); QInputMethodEvent event("", attributes); - QApplication::sendEvent(testWidget, &event); + QCoreApplication::sendEvent(&box, &event); } QVERIFY(m_platformInputContext.m_updateCallCount >= 1); } diff --git a/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt b/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt index 1f876ec5d6..b58775d2ff 100644 --- a/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qbuttongroup/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qbuttongroup.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp index 8ab2faab43..3ff748ef27 100644 --- a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp +++ b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -44,6 +19,8 @@ #include <qsettings.h> #endif +#include <QtWidgets/private/qapplication_p.h> + class SpecialRadioButton: public QRadioButton { public: @@ -145,7 +122,6 @@ void tst_QButtonGroup::arrowKeyNavigation() layout.addWidget(&g2); dlg.show(); - qApp->setActiveWindow(&dlg); QVERIFY(QTest::qWaitForWindowActive(&dlg)); bt1.setFocus(); @@ -227,7 +203,6 @@ void tst_QButtonGroup::keyNavigationPushButtons() buttonGroup->addButton(pb3); dlg.show(); - qApp->setActiveWindow(&dlg); if (!QTest::qWaitForWindowActive(&dlg)) QSKIP("Window activation failed, skipping test"); @@ -374,17 +349,17 @@ void tst_QButtonGroup::testSignals() pb1.animateClick(); QTestEventLoop::instance().enterLoop(1); - QCOMPARE(clickedSpy.count(), 1); - QCOMPARE(clickedIdSpy.count(), 1); + QCOMPARE(clickedSpy.size(), 1); + QCOMPARE(clickedIdSpy.size(), 1); int expectedId = -2; QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), expectedId); - QCOMPARE(pressedSpy.count(), 1); - QCOMPARE(pressedIdSpy.count(), 1); + QCOMPARE(pressedSpy.size(), 1); + QCOMPARE(pressedIdSpy.size(), 1); QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), expectedId); - QCOMPARE(releasedSpy.count(), 1); - QCOMPARE(releasedIdSpy.count(), 1); + QCOMPARE(releasedSpy.size(), 1); + QCOMPARE(releasedIdSpy.size(), 1); QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), expectedId); clickedSpy.clear(); @@ -397,14 +372,14 @@ void tst_QButtonGroup::testSignals() pb2.animateClick(); QTestEventLoop::instance().enterLoop(1); - QCOMPARE(clickedSpy.count(), 1); - QCOMPARE(clickedIdSpy.count(), 1); + QCOMPARE(clickedSpy.size(), 1); + QCOMPARE(clickedIdSpy.size(), 1); QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), 23); - QCOMPARE(pressedSpy.count(), 1); - QCOMPARE(pressedIdSpy.count(), 1); + QCOMPARE(pressedSpy.size(), 1); + QCOMPARE(pressedIdSpy.size(), 1); QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), 23); - QCOMPARE(releasedSpy.count(), 1); - QCOMPARE(releasedIdSpy.count(), 1); + QCOMPARE(releasedSpy.size(), 1); + QCOMPARE(releasedIdSpy.size(), 1); QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), 23); @@ -414,18 +389,18 @@ void tst_QButtonGroup::testSignals() pb1.setCheckable(true); pb2.setCheckable(true); pb1.toggle(); - QCOMPARE(toggledSpy.count(), 1); - QCOMPARE(toggledIdSpy.count(), 1); + QCOMPARE(toggledSpy.size(), 1); + QCOMPARE(toggledIdSpy.size(), 1); pb2.toggle(); - QCOMPARE(toggledSpy.count(), 3); // equals 3 since pb1 and pb2 are both toggled - QCOMPARE(toggledIdSpy.count(), 3); + QCOMPARE(toggledSpy.size(), 3); // equals 3 since pb1 and pb2 are both toggled + QCOMPARE(toggledIdSpy.size(), 3); pb1.setCheckable(false); pb2.setCheckable(false); pb1.toggle(); - QCOMPARE(toggledSpy.count(), 3); - QCOMPARE(toggledIdSpy.count(), 3); + QCOMPARE(toggledSpy.size(), 3); + QCOMPARE(toggledIdSpy.size(), 3); } void tst_QButtonGroup::task106609() @@ -458,14 +433,13 @@ void tst_QButtonGroup::task106609() qRegisterMetaType<QAbstractButton*>("QAbstractButton*"); QSignalSpy spy1(buttons, SIGNAL(buttonClicked(QAbstractButton*))); - QApplication::setActiveWindow(&dlg); QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&dlg)); radio1->setFocus(); radio1->setChecked(true); QTestEventLoop::instance().enterLoop(1); - QCOMPARE(spy1.count(), 2); + QCOMPARE(spy1.size(), 2); } void tst_QButtonGroup::checkedButton() @@ -550,7 +524,7 @@ void tst_QButtonGroup::task209485_removeFromGroupInEventHandler() // NOTE: Reintroducing the bug of this task will cause the following line to crash: QTest::mouseClick(button, Qt::LeftButton); - QCOMPARE(spy1.count(), signalCount); + QCOMPARE(spy1.size(), signalCount); } void tst_QButtonGroup::autoIncrementId() diff --git a/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt index 853ff95a03..5140c37e94 100644 --- a/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qcalendarwidget/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qcalendarwidget.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp b/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp index 91da5dc69b..ca5cc06e99 100644 --- a/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp +++ b/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -109,7 +84,7 @@ void tst_QCalendarWidget::getSetCheck() QDate selectedDate(2005, 7, 3); QSignalSpy spy(&object, SIGNAL(selectionChanged())); object.setSelectedDate(selectedDate); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(selectedDate, object.selectedDate()); //month and year object.setCurrentPage(2004, 1); @@ -135,11 +110,19 @@ void tst_QCalendarWidget::getSetCheck() object.setSelectedDate(selectedDate); QCOMPARE(minDate, object.selectedDate()); QVERIFY(selectedDate != object.selectedDate()); + object.clearMinimumDate(); + object.setSelectedDate(selectedDate); + QCOMPARE(selectedDate, object.selectedDate()); + //date should not go beyond the maximum. selectedDate = maxDate.addDays(10); object.setSelectedDate(selectedDate); QCOMPARE(maxDate, object.selectedDate()); QVERIFY(selectedDate != object.selectedDate()); + object.clearMaximumDate(); + object.setSelectedDate(selectedDate); + QCOMPARE(selectedDate, object.selectedDate()); + //show today QDate today = QDate::currentDate(); object.showToday(); @@ -290,6 +273,9 @@ void tst_QCalendarWidget::showPrevNext() QFETCH(ShowFunc, function); QFETCH(QDate, dateOrigin); QFETCH(QDate, expectedDate); +#ifdef Q_OS_ANDROID + QSKIP("Crashes sometimes on Android emulator, figure out why (QTBUG-102258)"); +#endif QCalendarWidget calWidget; calWidget.show(); diff --git a/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt b/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt index df03bea079..9e3f0e9874 100644 --- a/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qcheckbox/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qcheckbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp b/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp index 33fb6b482a..42eb81d3c7 100644 --- a/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp +++ b/tests/auto/widgets/widgets/qcheckbox/tst_qcheckbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -41,6 +16,7 @@ private slots: void initTestCase(); void setChecked(); + void setCheckedSignal(); void setTriState(); void setText_data(); void setText(); @@ -50,7 +26,7 @@ private slots: void toggle(); void pressed(); void toggled(); - void stateChanged(); + void checkStateChanged(); void foregroundRole(); void minimumSizeHint(); }; @@ -84,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; @@ -213,30 +208,49 @@ void tst_QCheckBox::toggled() QCOMPARE(click_count, 0); } -void tst_QCheckBox::stateChanged() +void tst_QCheckBox::checkStateChanged() { QCheckBox testWidget; - int cur_state = -1; + 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, [&](int state) { ++cur_state = state; }); + ) +#endif + connect(&testWidget, &QCheckBox::checkStateChanged, this, [&](auto state) { cur_state = state; }); testWidget.setChecked(true); - QCoreApplication::processEvents(); - QCOMPARE(cur_state, 2); + 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); - cur_state = -1; testWidget.setChecked(false); - QCoreApplication::processEvents(); - QCOMPARE(cur_state, 0); + 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); - cur_state = -1; testWidget.setCheckState(Qt::PartiallyChecked); - QCoreApplication::processEvents(); - QCOMPARE(cur_state, 1); + 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); - QCOMPARE(stateChangedSpy.count(), 3); testWidget.setCheckState(Qt::PartiallyChecked); QCoreApplication::processEvents(); - QCOMPARE(stateChangedSpy.count(), 3); + 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 a1dded1384..87ac247b24 100644 --- a/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qcombobox/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qcombobox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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") @@ -13,7 +20,7 @@ qt_internal_add_test(tst_qcombobox tst_qcombobox.cpp DEFINES QTEST_QPA_MOUSE_HANDLING - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 4146a6632d..66c1359bd8 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QSignalSpy> @@ -33,6 +8,7 @@ #include "qcombobox.h" #include <private/qcombobox_p.h> #include <private/qguiapplication_p.h> +#include <qpa/qplatformintegration.h> #include <qpa/qplatformtheme.h> #include <qfontcombobox.h> @@ -49,6 +25,7 @@ #include <qtablewidget.h> #include <qscrollbar.h> #include <qboxlayout.h> +#include <qshortcut.h> #include <qstackedwidget.h> #include <qstandarditemmodel.h> @@ -65,11 +42,15 @@ #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> using namespace QTestPrivate; @@ -130,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(); @@ -170,6 +152,10 @@ private slots: void checkMenuItemPosWhenStyleSheetIsSet(); void checkEmbeddedLineEditWhenStyleSheetIsSet(); void propagateStyleChanges(); + void buttonPressKeys(); + void clearModel(); + void cancelClosesPopupNotDialog(); + void closePopupWithCheckableItems(); private: PlatformInputContext m_platformInputContext; @@ -472,11 +458,19 @@ void tst_QComboBox::setEditable() void tst_QComboBox::setPalette() { -#ifdef Q_OS_MAC - if (QApplication::style()->inherits("QMacStyle")) { - QSKIP("This test doesn't make sense for pixmap-based styles"); - } -#endif + // If (a) Palettes are pixmap based and/or (b) contain color groups/roles which the + // resolve mask prevents from being copied, the direct comparison of the inherited + // palette and the parent palette will fail. + // To prevent that, set a simple gray system palette for QComboBox and QLineEdit + const QPalette comboBoxPalette = qApp->palette("QComboBox"); + const QPalette lineEditPalette = qApp->palette("QLineEdit"); + auto guard = qScopeGuard([&]{ + qApp->setPalette(comboBoxPalette, "QComboBox"); + qApp->setPalette(lineEditPalette, "QLineEdit"); + }); + qApp->setPalette(QPalette(Qt::gray), "QComboBox"); + qApp->setPalette(QPalette(Qt::gray), "QLineEdit"); + TestWidget topLevel; topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); @@ -484,16 +478,15 @@ void tst_QComboBox::setPalette() QPalette pal = testWidget->palette(); pal.setColor(QPalette::Base, Qt::red); testWidget->setPalette(pal); - testWidget->setEditable(!testWidget->isEditable()); + testWidget->setEditable(true); pal.setColor(QPalette::Base, Qt::blue); testWidget->setPalette(pal); - const QObjectList comboChildren = testWidget->children(); - for (int i = 0; i < comboChildren.size(); ++i) { - QObject *o = comboChildren.at(i); - if (o->isWidgetType()) { - QCOMPARE(((QWidget*)o)->palette(), pal); + const QObjectList &comboChildren = testWidget->children(); + for (auto *child : comboChildren) { + if (auto *widget = qobject_cast<QWidget *>(child)) { + QCOMPARE(widget->palette(), pal); } } @@ -770,7 +763,7 @@ void tst_QComboBox::insertPolicy() testWidget->setInsertPolicy(insertPolicy); testWidget->addItems(initialEntries); testWidget->setEditable(true); - if (initialEntries.count() > 0) + if (initialEntries.size() > 0) testWidget->setCurrentIndex(currentIndex); // clear @@ -782,10 +775,10 @@ void tst_QComboBox::insertPolicy() // First check that there is the right number of entries, or // we may unwittingly pass - QCOMPARE((int)result.count(), testWidget->count()); + QCOMPARE((int)result.size(), testWidget->count()); // No need to compare if there are no strings to compare - if (result.count() > 0) { + if (result.size() > 0) { for (int i=0; i<testWidget->count(); ++i) { QCOMPARE(testWidget->itemText(i), result.at(i)); } @@ -856,7 +849,6 @@ void tst_QComboBox::autoCompletionCaseSensitivity() TestWidget topLevel; topLevel.show(); QComboBox *testWidget = topLevel.comboBox(); - qApp->setActiveWindow(&topLevel); testWidget->setFocus(); QVERIFY(QTest::qWaitForWindowActive(&topLevel)); QCOMPARE(qApp->focusWidget(), (QWidget *)testWidget); @@ -882,18 +874,18 @@ void tst_QComboBox::autoCompletionCaseSensitivity() QTest::keyClick(testWidget->lineEdit(), Qt::Key_A); qApp->processEvents(); QCOMPARE(testWidget->currentText(), QString("aww")); - QCOMPARE(spyReturn.count(), 0); + QCOMPARE(spyReturn.size(), 0); QTest::keyClick(testWidget->lineEdit(), Qt::Key_B); qApp->processEvents(); // autocompletions preserve userkey-case from 4.2 QCOMPARE(testWidget->currentText(), QString("abCDEF")); - QCOMPARE(spyReturn.count(), 0); + QCOMPARE(spyReturn.size(), 0); QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter); qApp->processEvents(); QCOMPARE(testWidget->currentText(), QString("aBCDEF")); // case restored to item's case - QCOMPARE(spyReturn.count(), 1); + QCOMPARE(spyReturn.size(), 1); testWidget->clearEditText(); QTest::keyClick(testWidget->lineEdit(), 'c'); @@ -1029,7 +1021,7 @@ void tst_QComboBox::currentIndex_data() expectedCurrentIndex = -1; expectedCurrentText = ""; expectedSignalCount = 2; - QTest::newRow("check that isetting the index to -1 works") + QTest::newRow("check that setting the index to -1 works") << initialItems << setCurrentIndex << removeIndex << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText << expectedSignalCount; @@ -1172,66 +1164,71 @@ void tst_QComboBox::currentIndex() TestWidget topLevel; topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); - QComboBox *testWidget = topLevel.comboBox(); + QComboBox *comboBox = topLevel.comboBox(); // test both editable/non-editable combobox for (int edit = 0; edit < 2; ++edit) { - testWidget->clear(); - testWidget->setEditable(edit ? true : false); + comboBox->clear(); + comboBox->setEditable(edit ? true : false); if (edit) - QVERIFY(testWidget->lineEdit()); + QVERIFY(comboBox->lineEdit()); // verify it is empty, has no current index and no current text - QCOMPARE(testWidget->count(), 0); - QCOMPARE(testWidget->currentIndex(), -1); - QVERIFY(testWidget->currentText().isEmpty()); + QCOMPARE(comboBox->count(), 0); + QCOMPARE(comboBox->currentIndex(), -1); + QVERIFY(comboBox->currentText().isEmpty()); // spy on currentIndexChanged - QSignalSpy indexChangedInt(testWidget, SIGNAL(currentIndexChanged(int))); + QSignalSpy indexChangedSpy(comboBox, &QComboBox::currentIndexChanged); // stuff items into it - foreach(QString text, initialItems) { - testWidget->addItem(text); - } - QCOMPARE(testWidget->count(), initialItems.count()); + for (const QString &text : initialItems) + comboBox->addItem(text); + + QCOMPARE(comboBox->count(), initialItems.size()); // set current index, remove and/or insert if (setCurrentIndex >= -1) { - testWidget->setCurrentIndex(setCurrentIndex); - QCOMPARE(testWidget->currentIndex(), setCurrentIndex); + comboBox->setCurrentIndex(setCurrentIndex); + QCOMPARE(comboBox->currentIndex(), setCurrentIndex); } if (removeIndex >= 0) - testWidget->removeItem(removeIndex); + comboBox->removeItem(removeIndex); if (insertIndex >= 0) - testWidget->insertItem(insertIndex, insertText); + comboBox->insertItem(insertIndex, insertText); // compare with expected index and text - QCOMPARE(testWidget->currentIndex(), expectedCurrentIndex); - QCOMPARE(testWidget->currentText(), expectedCurrentText); + QCOMPARE(comboBox->currentIndex(), expectedCurrentIndex); + QCOMPARE(comboBox->currentText(), expectedCurrentText); // check that signal count is correct - QCOMPARE(indexChangedInt.count(), expectedSignalCount); + QCOMPARE(indexChangedSpy.size(), expectedSignalCount); // compare with last sent signal values - if (indexChangedInt.count()) - QCOMPARE(indexChangedInt.at(indexChangedInt.count() - 1).at(0).toInt(), - testWidget->currentIndex()); + if (indexChangedSpy.size()) + QCOMPARE(indexChangedSpy.at(indexChangedSpy.size() - 1).at(0).toInt(), + comboBox->currentIndex()); + + // Test a no-op index change + const int index = comboBox->currentIndex(); + comboBox->setCurrentIndex(index); + QCOMPARE(indexChangedSpy.size(), expectedSignalCount); if (edit) { - testWidget->setCurrentIndex(-1); - testWidget->setInsertPolicy(QComboBox::InsertAtBottom); - QTest::keyPress(testWidget, 'a'); - QTest::keyPress(testWidget, 'b'); - QCOMPARE(testWidget->currentText(), QString("ab")); - QCOMPARE(testWidget->currentIndex(), -1); - int numItems = testWidget->count(); - QTest::keyPress(testWidget, Qt::Key_Return); - QCOMPARE(testWidget->count(), numItems + 1); - QCOMPARE(testWidget->currentIndex(), numItems); - testWidget->setCurrentIndex(-1); - QTest::keyPress(testWidget, 'a'); - QTest::keyPress(testWidget, 'b'); - QCOMPARE(testWidget->currentIndex(), -1); + comboBox->setCurrentIndex(-1); + comboBox->setInsertPolicy(QComboBox::InsertAtBottom); + QTest::keyPress(comboBox, 'a'); + QTest::keyPress(comboBox, 'b'); + QCOMPARE(comboBox->currentText(), QString("ab")); + QCOMPARE(comboBox->currentIndex(), -1); + int numItems = comboBox->count(); + QTest::keyPress(comboBox, Qt::Key_Return); + QCOMPARE(comboBox->count(), numItems + 1); + QCOMPARE(comboBox->currentIndex(), numItems); + comboBox->setCurrentIndex(-1); + QTest::keyPress(comboBox, 'a'); + QTest::keyPress(comboBox, 'b'); + QCOMPARE(comboBox->currentIndex(), -1); } } } @@ -1251,8 +1248,8 @@ void tst_QComboBox::insertItems_data() QTest::newRow("prepend") << initialItems << insertedItems << 0 << 0; QTest::newRow("prepend with negative value") << initialItems << insertedItems << -1 << 0; - QTest::newRow("append") << initialItems << insertedItems << initialItems.count() << initialItems.count(); - QTest::newRow("append with too high value") << initialItems << insertedItems << 999 << initialItems.count(); + QTest::newRow("append") << initialItems << insertedItems << initialItems.size() << initialItems.size(); + QTest::newRow("append with too high value") << initialItems << insertedItems << 999 << initialItems.size(); QTest::newRow("insert") << initialItems << insertedItems << 1 << 1; } @@ -1268,12 +1265,12 @@ void tst_QComboBox::insertItems() QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); QComboBox *testWidget = topLevel.comboBox(); testWidget->insertItems(0, initialItems); - QCOMPARE(testWidget->count(), initialItems.count()); + QCOMPARE(testWidget->count(), initialItems.size()); testWidget->insertItems(insertIndex, insertedItems); - QCOMPARE(testWidget->count(), initialItems.count() + insertedItems.count()); - for (int i=0; i<insertedItems.count(); ++i) + QCOMPARE(testWidget->count(), initialItems.size() + insertedItems.size()); + for (int i=0; i<insertedItems.size(); ++i) QCOMPARE(testWidget->itemText(expectedIndex + i), insertedItems.at(i)); } @@ -1289,11 +1286,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; } } @@ -1310,14 +1308,14 @@ void tst_QComboBox::insertItem() QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); QComboBox *testWidget = topLevel.comboBox(); testWidget->insertItems(0, initialItems); - QCOMPARE(testWidget->count(), initialItems.count()); + QCOMPARE(testWidget->count(), initialItems.size()); testWidget->setEditable(true); if (editable) testWidget->setEditText("FOO"); testWidget->insertItem(insertIndex, itemLabel); - QCOMPARE(testWidget->count(), initialItems.count() + 1); + QCOMPARE(testWidget->count(), initialItems.size() + 1); QCOMPARE(testWidget->itemText(expectedIndex), itemLabel); if (editable) @@ -1385,21 +1383,21 @@ void tst_QComboBox::textpixmapdata() QFETCH(IconList, icons); QFETCH(VariantList, variant); - QVERIFY(text.count() == icons.count() && text.count() == variant.count()); + QVERIFY(text.size() == icons.size() && text.size() == variant.size()); TestWidget topLevel; topLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); QComboBox *testWidget = topLevel.comboBox(); - for (int i = 0; i<text.count(); ++i) { + for (int i = 0; i<text.size(); ++i) { testWidget->insertItem(i, text.at(i)); testWidget->setItemIcon(i, icons.at(i)); testWidget->setItemData(i, variant.at(i), Qt::UserRole); } - QCOMPARE(testWidget->count(), text.count()); + QCOMPARE(testWidget->count(), text.size()); - for (int i = 0; i<text.count(); ++i) { + for (int i = 0; i<text.size(); ++i) { QIcon icon = testWidget->itemIcon(i); QCOMPARE(icon.cacheKey(), icons.at(i).cacheKey()); QPixmap original = icons.at(i).pixmap(1024); @@ -1407,7 +1405,7 @@ void tst_QComboBox::textpixmapdata() QCOMPARE(pixmap.toImage(), original.toImage()); } - for (int i = 0; i<text.count(); ++i) { + for (int i = 0; i<text.size(); ++i) { QCOMPARE(testWidget->itemText(i), text.at(i)); // ### we should test icons/pixmap as well, but I need to fix the api mismatch first QCOMPARE(testWidget->itemData(i, Qt::UserRole), variant.at(i)); @@ -1481,14 +1479,12 @@ void tst_QComboBox::setCurrentText() else QCOMPARE(testWidget->currentText(), QString("foo")); -#ifndef QT_NO_PROPERTIES // verify WRITE for currentText property testWidget->setCurrentIndex(0); const QByteArray n("currentText"); QCOMPARE(testWidget->property(n).toString(), QString("foo")); testWidget->setProperty(n, QString("bar")); QCOMPARE(testWidget->property(n).toString(), QString("bar")); -#endif } void tst_QComboBox::currentTextChanged_data() @@ -1510,42 +1506,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.count(), 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.count(), 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.count(), 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.count(), 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.count(), 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() @@ -1569,13 +1593,13 @@ void tst_QComboBox::editTextChanged() QCOMPARE(testWidget->currentIndex(), 0); testWidget->setCurrentIndex(0); QCOMPARE(testWidget->currentIndex(), 0); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // no signal should be sent when changing to other index because we are not editable QCOMPARE(testWidget->currentIndex(), 0); testWidget->setCurrentIndex(1); QCOMPARE(testWidget->currentIndex(), 1); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // now set to editable and reset current index testWidget->setEditable(true); @@ -1587,20 +1611,20 @@ void tst_QComboBox::editTextChanged() QCOMPARE(testWidget->currentIndex(), 0); testWidget->setCurrentIndex(0); QCOMPARE(testWidget->currentIndex(), 0); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // signal should be sent when changing to other index QCOMPARE(testWidget->currentIndex(), 0); testWidget->setCurrentIndex(1); QCOMPARE(testWidget->currentIndex(), 1); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<QString>(spy.at(0).at(0)), QString("bar")); // insert some keys and notice they are all signaled spy.clear(); QTest::keyClicks(testWidget, "bingo"); - QCOMPARE(spy.count(), 5); + QCOMPARE(spy.size(), 5); QCOMPARE(qvariant_cast<QString>(spy.at(4).at(0)), QString("barbingo")); } @@ -1653,6 +1677,16 @@ void tst_QComboBox::setModel() QCOMPARE(box.rootModelIndex(), rootModelIndex); box.setModel(box.model()); QCOMPARE(box.rootModelIndex(), rootModelIndex); + + // check that setting the same model as the completer's doesn't crash + QCompleter *completer = new QCompleter(&box); + box.setEditable(true); + box.setCompleter(completer); + auto *listModel = new QStringListModel({ "one", "two" }, completer); + completer->setModel(listModel); + QCOMPARE(listModel->rowCount(), 2); // make sure it wasn't deleted + box.setModel(listModel); + QCOMPARE(listModel->rowCount(), 2); // make sure it wasn't deleted } void tst_QComboBox::setCustomModelAndView() @@ -1757,7 +1791,7 @@ void tst_QComboBox::setMaxCount() // insert 5 items at pos 2. Make sure only two get inserted QSignalSpy spy(box.model(), SIGNAL(rowsInserted(QModelIndex,int,int))); box.insertItems(2, items); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(1).toInt(), 2); QCOMPARE(spy.at(0).at(2).toInt(), 3); @@ -1987,7 +2021,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; } } @@ -1999,8 +2033,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); @@ -2011,17 +2045,16 @@ 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()); comboBox.setView(&listWidget); comboBox.move(200, 200); comboBox.show(); - QApplication::setActiveWindow(&comboBox); comboBox.activateWindow(); comboBox.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&comboBox)); @@ -2031,7 +2064,7 @@ void tst_QComboBox::flaggedItems() if (editable) comboBox.lineEdit()->selectAll(); - for (int i = 0; i < keyMovementList.count(); ++i) { + for (int i = 0; i < keyMovementList.size(); ++i) { Qt::Key key = keyMovementList[i]; QTest::keyClick(&comboBox, key); } @@ -2097,7 +2130,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); @@ -2112,7 +2145,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()); @@ -2246,13 +2279,13 @@ 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.count() + separators.count())); + QCOMPARE(box.count(), (items.size() + separators.size())); for (int i = 0, s = 0; i < box.count(); ++i) { if (i == separators.at(s)) { QCOMPARE(box.itemText(i), QString()); @@ -2371,7 +2404,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()); } @@ -2450,7 +2484,6 @@ void tst_QComboBox::task247863_keyBoardSelection() combo.addItem( QLatin1String("111")); combo.addItem( QLatin1String("222")); combo.show(); - QApplication::setActiveWindow(&combo); QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&combo)); QSignalSpy spy(&combo, &QComboBox::activated); @@ -2460,7 +2493,7 @@ void tst_QComboBox::task247863_keyBoardSelection() QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down); QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter); QCOMPARE(combo.currentText(), QLatin1String("222")); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } void tst_QComboBox::task220195_keyBoardSelection2() @@ -2476,7 +2509,6 @@ void tst_QComboBox::task220195_keyBoardSelection2() combo.addItem( QLatin1String("foo2")); combo.addItem( QLatin1String("foo3")); combo.show(); - QApplication::setActiveWindow(&combo); QVERIFY(QTest::qWaitForWindowActive(&combo)); combo.setCurrentIndex(-1); @@ -2735,16 +2767,16 @@ void tst_QComboBox::resetModel() QComboBox cb; StringListModel model({"1", "2"}); QSignalSpy spy(&cb, &QComboBox::currentIndexChanged); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QCOMPARE(cb.currentIndex(), -1); //no selection cb.setModel(&model); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(cb.currentIndex(), 0); //first item selected model.reset(); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); QCOMPARE(cb.currentIndex(), 0); //first item selected } @@ -2762,7 +2794,6 @@ void tst_QComboBox::keyBoardNavigationWithMouse() combo.move(200, 200); combo.showNormal(); - QApplication::setActiveWindow(&combo); QVERIFY(QTest::qWaitForWindowActive(&combo)); QCOMPARE(combo.currentText(), QLatin1String("0")); @@ -2818,17 +2849,16 @@ void tst_QComboBox::task_QTBUG_1071_changingFocusEmitsActivated() layout.addWidget(&edit); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); cb.clearEditText(); cb.setFocus(); QApplication::processEvents(); QTRY_VERIFY(cb.hasFocus()); QTest::keyClick(static_cast<QWidget *>(0), '1'); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); edit.setFocus(); QTRY_VERIFY(edit.hasFocus()); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); } void tst_QComboBox::maxVisibleItems_data() @@ -3170,31 +3200,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() @@ -3246,11 +3300,11 @@ void tst_QComboBox::respectChangedOwnershipOfItemView() QTableView *v2 = new QTableView(&box1); box1.setView(v2); // Here we do not expect v1 to be deleted QApplication::processEvents(); - QCOMPARE(spy1.count(), 0); + QCOMPARE(spy1.size(), 0); QSignalSpy spy2(v2, SIGNAL(destroyed())); box1.setView(v1); - QCOMPARE(spy2.count(), 1); + QCOMPARE(spy2.size(), 1); } void tst_QComboBox::task_QTBUG_49831_scrollerNotActivated() @@ -3271,14 +3325,14 @@ 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); - QTRY_VERIFY(doScrollSpy.count() > 0); + QTRY_VERIFY(doScrollSpy.size() > 0); } } } @@ -3356,6 +3410,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)) @@ -3435,10 +3548,9 @@ void tst_QComboBox::task_QTBUG_52027_mapCompleterIndex() cbox.setCompleter(completer); QSignalSpy spy(&cbox, SIGNAL(activated(int))); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); cbox.move(200, 200); cbox.show(); - QApplication::setActiveWindow(&cbox); QVERIFY(QTest::qWaitForWindowActive(&cbox)); QTest::keyClicks(&cbox, "foobar2"); @@ -3464,7 +3576,6 @@ void tst_QComboBox::task_QTBUG_52027_mapCompleterIndex() cbox.activateWindow(); } - QApplication::setActiveWindow(&cbox); QVERIFY(QTest::qWaitForWindowActive(&cbox)); QTest::keyClicks(&cbox, "foobar1"); @@ -3532,7 +3643,6 @@ void tst_QComboBox::checkEmbeddedLineEditWhenStyleSheetIsSet() layout->addWidget(comboBox); topLevel.show(); comboBox->setEditable(true); - QApplication::setActiveWindow(&topLevel); QVERIFY(QTest::qWaitForWindowActive(&topLevel)); QImage grab = comboBox->grab().toImage(); @@ -3590,5 +3700,144 @@ void tst_QComboBox::propagateStyleChanges() QVERIFY(frameStyle.inquired); } +void tst_QComboBox::buttonPressKeys() +{ + QComboBox comboBox; + comboBox.setEditable(false); + comboBox.addItem(QString::number(1)); + comboBox.addItem(QString::number(2)); + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + for (int i = 0; i < buttonPressKeys.size(); ++i) { + QTest::keyClick(&comboBox, buttonPressKeys[i]); + // On some platforms, a window will not be immediately visible, + // but take some event-loop iterations to complete. + // Using QTRY_VERIFY to deal with that. + QTRY_VERIFY(comboBox.view()->isVisible()); + comboBox.hidePopup(); + } +} + +void tst_QComboBox::clearModel() +{ + using namespace Qt::StringLiterals; + QStringListModel model({ "one"_L1, "two"_L1, "three"_L1 }); + + QComboBox combo; + combo.setModel(&model); + combo.setCurrentIndex(1); + + QCOMPARE(combo.currentIndex(), 1); + QCOMPARE(combo.currentText(), model.index(1).data().toString()); + + QSignalSpy indexSpy(&combo, &QComboBox::currentIndexChanged); + QSignalSpy textSpy(&combo, &QComboBox::currentTextChanged); + + QVERIFY(indexSpy.isEmpty()); + QVERIFY(textSpy.isEmpty()); + + model.setStringList({}); + + QCOMPARE(indexSpy.size(), 1); + const int index = indexSpy.takeFirst().at(0).toInt(); + QCOMPARE(index, -1); + + QCOMPARE(textSpy.size(), 1); + const QString text = textSpy.takeFirst().at(0).toString(); + QCOMPARE(text, QString()); + + QCOMPARE(combo.currentIndex(), -1); + QCOMPARE(combo.currentText(), QString()); +} + +void tst_QComboBox::cancelClosesPopupNotDialog() +{ + if (QGuiApplication::platformName() == "offscreen") + QSKIP("The offscreen platform plugin doesn't activate popups."); + + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("QWindow::requestActivate() is not supported."); + + QDialog dialog; + QComboBox combobox; + combobox.addItems({"A", "B", "C"}); + + std::unique_ptr<QShortcut> shortcut(new QShortcut(QKeySequence::Cancel, &dialog)); + bool shortcutTriggered = false; + connect(shortcut.get(), &QShortcut::activated, [&shortcutTriggered]{ + shortcutTriggered = true; + }); + + QVBoxLayout vbox; + vbox.addWidget(&combobox); + dialog.setLayout(&vbox); + + dialog.show(); + QVERIFY(QTest::qWaitForWindowActive(&dialog)); + + // while the combobox is closed, escape key triggers the shortcut + QTest::keyClick(dialog.window()->windowHandle(), Qt::Key_Escape); + QVERIFY(shortcutTriggered); + shortcutTriggered = false; + + combobox.showPopup(); + QTRY_VERIFY(combobox.view()->isVisible()); + + // an open combobox overrides and accepts the escape key to close + QTest::keyClick(dialog.window()->windowHandle(), Qt::Key_Escape); + QVERIFY(!shortcutTriggered); + shortcutTriggered = false; + QTRY_VERIFY(!combobox.view()->isVisible()); + QVERIFY(dialog.isVisible()); + + // once closed, escape key triggers the shortcut again + QTest::keyClick(dialog.window()->windowHandle(), Qt::Key_Escape); + QVERIFY(shortcutTriggered); + shortcutTriggered = false; + QVERIFY(dialog.isVisible()); + + shortcut.reset(); + + // without shortcut, escape key propagates to the parent + QTest::keyClick(dialog.window()->windowHandle(), Qt::Key_Escape); + 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 dfb555673a..b89c5aa1dd 100644 --- a/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qcommandlinkbutton/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qcommandlinkbutton.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui + Qt::GuiPrivate Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp b/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp index 0d9e3a3198..e0c63e5ced 100644 --- a/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp +++ b/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -40,6 +15,9 @@ #include <QGridLayout> #include <QPainter> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformtheme.h> + class tst_QCommandLinkButton : public QObject { Q_OBJECT @@ -58,7 +36,6 @@ private slots: void setDown(); void popupCrash(); void isChecked(); - void animateClick(); void toggle(); void clicked(); void toggled(); @@ -227,6 +204,13 @@ void tst_QCommandLinkButton::setAutoRepeat() // check that pressing ENTER has no effect resetCounters(); testWidget->setDown( false ); + // Skip after reset if ButtonPressKeys has Key_Enter + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + return; + } testWidget->setAutoRepeat( false ); QTest::keyPress( testWidget, Qt::Key_Enter ); @@ -259,6 +243,14 @@ void tst_QCommandLinkButton::pressed() QCOMPARE( press_count, (uint)1 ); QCOMPARE( release_count, (uint)1 ); + // Skip if ButtonPressKeys has Key_Enter + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + return; + } + QTest::keyPress( testWidget,Qt::Key_Enter ); QCOMPARE( press_count, (uint)1 ); QCOMPARE( release_count, (uint)1 ); @@ -363,20 +355,6 @@ void tst_QCommandLinkButton::setAccel() #endif // QT_CONFIG(shortcut) -void tst_QCommandLinkButton::animateClick() -{ - QVERIFY( !testWidget->isDown() ); - testWidget->animateClick(); - QVERIFY( testWidget->isDown() ); - QTest::qWait( 200 ); - QVERIFY( !testWidget->isDown() ); - - QVERIFY( click_count == 1 ); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 1 ); - QVERIFY( toggle_count == 0 ); -} - void tst_QCommandLinkButton::clicked() { QTest::mousePress( testWidget, Qt::LeftButton ); diff --git a/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt b/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt index 8ddb0a3b0d..9c2e777380 100644 --- a/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qdatetimeedit/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qdatetimeedit.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::Widgets diff --git a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp index cc76bff416..2d9689db41 100644 --- a/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp +++ b/tests/auto/widgets/widgets/qdatetimeedit/tst_qdatetimeedit.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qapplication.h> #include <qgroupbox.h> @@ -72,6 +47,8 @@ #include <private/qdatetimeedit_p.h> +#include <QtWidgets/private/qapplication_p.h> + #ifdef Q_OS_WIN # include <qt_windows.h> #endif @@ -256,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(); @@ -275,7 +254,7 @@ private slots: void task196924(); void focusNextPrevChild(); - void taskQTBUG_12384_timeSpecShowTimeOnly(); + void taskQTBUG_12384_timeZoneShowTimeOnly(); void deleteCalendarWidget(); @@ -429,8 +408,8 @@ 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(0); - testFocusWidget = new QWidget(0); + testWidget = new EditorDateEdit; + testFocusWidget = new QWidget(nullptr); testFocusWidget->resize(200, 100); testFocusWidget->show(); } @@ -459,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. @@ -481,121 +460,104 @@ void tst_QDateTimeEdit::constructor_qwidget() void tst_QDateTimeEdit::constructor_qdatetime_data() { QTest::addColumn<QDateTime>("parameter"); - QTest::addColumn<QDateTime>("displayDateTime"); - QTest::addColumn<QDate>("minimumDate"); - QTest::addColumn<QTime>("minimumTime"); - QTest::addColumn<QDate>("maximumDate"); - QTest::addColumn<QTime>("maximumTime"); - - QTest::newRow("normal") << QDateTime(QDate(2004, 6, 16), QTime(13, 46, 32, 764)) - << QDateTime(QDate(2004, 6, 16), QTime(13, 46, 32, 764)) - << QDate(1752, 9, 14) << QTime(0, 0, 0, 0) - << QDate(9999, 12, 31) << QTime(23, 59, 59, 999); - QTest::newRow("invalid") << QDateTime(QDate(9999, 99, 99), QTime(13, 46, 32, 764)) - << QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0, 0)) - << QDate(1752, 9, 14) << QTime(0, 0, 0, 0) - << QDate(9999, 12, 31) << QTime(23, 59, 59, 999); + QTest::newRow("normal") << QDateTime(QDate(2004, 6, 16), QTime(13, 46, 32, 764)); + QTest::newRow("invalid") << QDateTime(QDate(9999, 99, 99), QTime(13, 46, 32, 764)); } void tst_QDateTimeEdit::constructor_qdatetime() { QFETCH(QDateTime, parameter); - QFETCH(QDateTime, displayDateTime); - QFETCH(QDate, minimumDate); - QFETCH(QTime, minimumTime); - QFETCH(QDate, maximumDate); - QFETCH(QTime, maximumTime); - testWidget->hide(); QDateTimeEdit dte(parameter); dte.show(); - QCOMPARE(dte.dateTime(), displayDateTime); - QCOMPARE(dte.minimumDate(), minimumDate); - QCOMPARE(dte.minimumTime(), minimumTime); - QCOMPARE(dte.maximumDate(), maximumDate); - QCOMPARE(dte.maximumTime(), maximumTime); + if (QByteArrayView(QTest::currentDataTag()) == "invalid") + QCOMPARE(dte.dateTime(), QDateTime(QDate(2000, 1, 1), QTime(0, 0))); + else + QCOMPARE(dte.dateTime(), parameter); + QCOMPARE(dte.minimumDate(), QDate(1752, 9, 14)); + QCOMPARE(dte.minimumTime(), QTime(0, 0)); + QCOMPARE(dte.maximumDate(), QDate(9999, 12, 31)); + QCOMPARE(dte.maximumTime(), QTime(23, 59, 59, 999)); } void tst_QDateTimeEdit::constructor_qdate_data() { QTest::addColumn<QDate>("parameter"); - QTest::addColumn<QDateTime>("displayDateTime"); - QTest::addColumn<QDate>("minimumDate"); - QTest::addColumn<QTime>("minimumTime"); - QTest::addColumn<QDate>("maximumDate"); - QTest::addColumn<QTime>("maximumTime"); - - QTest::newRow("normal") << QDate(2004, 6, 16) - << QDateTime(QDate(2004, 6, 16), QTime(0, 0, 0, 0)) - << QDate(1752, 9, 14) << QTime(0, 0, 0, 0) - << QDate(9999, 12, 31) << QTime(23, 59, 59, 999); - QTest::newRow("invalid") << QDate(9999, 99, 99) - << QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0, 0)) - << QDate(1752, 9, 14) << QTime(0, 0, 0, 0) - << QDate(9999, 12, 31) << QTime(23, 59, 59, 999); + QTest::newRow("normal") << QDate(2004, 6, 16); + QTest::newRow("invalid") << QDate(9999, 99, 99); } void tst_QDateTimeEdit::constructor_qdate() { QFETCH(QDate, parameter); - QFETCH(QDateTime, displayDateTime); - QFETCH(QDate, minimumDate); - QFETCH(QTime, minimumTime); - QFETCH(QDate, maximumDate); - QFETCH(QTime, maximumTime); - testWidget->hide(); - QDateTimeEdit dte(parameter); - dte.show(); - QCOMPARE(dte.dateTime(), displayDateTime); - QCOMPARE(dte.minimumDate(), minimumDate); - QCOMPARE(dte.minimumTime(), minimumTime); - QCOMPARE(dte.maximumDate(), maximumDate); - QCOMPARE(dte.maximumTime(), maximumTime); + { + QDateTimeEdit dte(parameter); + dte.show(); + if (QByteArrayView(QTest::currentDataTag()) == "invalid") + QCOMPARE(dte.dateTime(), QDateTime(QDate(2000, 1, 1), QTime(0, 0))); + else + QCOMPARE(dte.dateTime(), QDateTime(parameter, QTime(0, 0))); + QCOMPARE(dte.minimumDate(), QDate(1752, 9, 14)); + QCOMPARE(dte.minimumTime(), QTime(0, 0)); + QCOMPARE(dte.maximumDate(), QDate(9999, 12, 31)); + QCOMPARE(dte.maximumTime(), QTime(23, 59, 59, 999)); + } + { + QDateEdit dte(parameter); + dte.show(); + if (QByteArrayView(QTest::currentDataTag()) == "invalid") + QCOMPARE(dte.date(), QDate(2000, 1, 1)); + else + QCOMPARE(dte.date(), parameter); + QCOMPARE(dte.minimumDate(), QDate(1752, 9, 14)); + QCOMPARE(dte.minimumTime(), QTime(0, 0)); + QCOMPARE(dte.maximumDate(), QDate(9999, 12, 31)); + QCOMPARE(dte.maximumTime(), QTime(23, 59, 59, 999)); + } } void tst_QDateTimeEdit::constructor_qtime_data() { QTest::addColumn<QTime>("parameter"); - QTest::addColumn<QDateTime>("displayDateTime"); - QTest::addColumn<QDate>("minimumDate"); - QTest::addColumn<QTime>("minimumTime"); - QTest::addColumn<QDate>("maximumDate"); - QTest::addColumn<QTime>("maximumTime"); - - QTest::newRow("normal") << QTime(13, 46, 32, 764) - << QDateTime(QDate(2000, 1, 1), QTime(13, 46, 32, 764)) - << QDate(2000, 1, 1) << QTime(0, 0, 0, 0) - << QDate(2000, 1, 1) << QTime(23, 59, 59, 999); - QTest::newRow("invalid") << QTime(99, 99, 99, 5000) - << QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0, 0)) - << QDate(2000, 1, 1) << QTime(0, 0, 0, 0) - << QDate(2000, 1, 1) << QTime(23, 59, 59, 999); + QTest::newRow("normal") << QTime(13, 46, 32, 764); + QTest::newRow("invalid") << QTime(99, 99, 99, 5000); } void tst_QDateTimeEdit::constructor_qtime() { QFETCH(QTime, parameter); - QFETCH(QDateTime, displayDateTime); - QFETCH(QDate, minimumDate); - QFETCH(QTime, minimumTime); - QFETCH(QDate, maximumDate); - QFETCH(QTime, maximumTime); - testWidget->hide(); - QDateTimeEdit dte(parameter); - dte.show(); - QCOMPARE(dte.dateTime(), displayDateTime); - QCOMPARE(dte.minimumDate(), minimumDate); - QCOMPARE(dte.minimumTime(), minimumTime); - QCOMPARE(dte.maximumDate(), maximumDate); - QCOMPARE(dte.maximumTime(), maximumTime); + { + QDateTimeEdit dte(parameter); + dte.show(); + if (QByteArrayView(QTest::currentDataTag()) == "invalid") + QCOMPARE(dte.dateTime(), QDateTime(QDate(2000, 1, 1), QTime(0, 0))); + else + QCOMPARE(dte.dateTime(), QDateTime(QDate(2000, 1, 1), parameter)); + QCOMPARE(dte.minimumDate(), QDate(2000, 1, 1)); + QCOMPARE(dte.minimumTime(), QTime(0, 0)); + QCOMPARE(dte.maximumDate(), QDate(2000, 1, 1)); + QCOMPARE(dte.maximumTime(), QTime(23, 59, 59, 999)); + } + { + QTimeEdit dte(parameter); + dte.show(); + if (QByteArrayView(QTest::currentDataTag()) == "invalid") + QCOMPARE(dte.time(), QTime(0, 0)); + else + QCOMPARE(dte.time(), parameter); + QCOMPARE(dte.minimumDate(), QDate(2000, 1, 1)); + QCOMPARE(dte.minimumTime(), QTime(0, 0)); + QCOMPARE(dte.maximumDate(), QDate(2000, 1, 1)); + QCOMPARE(dte.maximumTime(), QTime(23, 59, 59, 999)); + } } void tst_QDateTimeEdit::minimumDate_data() @@ -865,7 +827,6 @@ void tst_QDateTimeEdit::selectAndScrollWithKeys() return; #endif - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("dd/MM/yyyy"); testWidget->show(); @@ -967,7 +928,6 @@ void tst_QDateTimeEdit::selectAndScrollWithKeys() void tst_QDateTimeEdit::backspaceKey() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("d/MM/yyyy"); testWidget->show(); @@ -1033,7 +993,6 @@ void tst_QDateTimeEdit::backspaceKey() void tst_QDateTimeEdit::deleteKey() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("d/MM/yyyy"); #ifdef Q_OS_MAC @@ -1052,7 +1011,6 @@ void tst_QDateTimeEdit::deleteKey() void tst_QDateTimeEdit::tabKeyNavigation() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("dd/MM/yyyy"); testWidget->show(); @@ -1070,7 +1028,6 @@ void tst_QDateTimeEdit::tabKeyNavigation() void tst_QDateTimeEdit::tabKeyNavigationWithPrefix() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("prefix dd/MM/yyyy"); @@ -1088,7 +1045,6 @@ void tst_QDateTimeEdit::tabKeyNavigationWithPrefix() void tst_QDateTimeEdit::tabKeyNavigationWithSuffix() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 05, 11)); testWidget->setDisplayFormat("dd/MM/yyyy 'suffix'"); @@ -1104,7 +1060,6 @@ void tst_QDateTimeEdit::tabKeyNavigationWithSuffix() void tst_QDateTimeEdit::enterKey() { - qApp->setActiveWindow(testWidget); testWidget->setDate(QDate(2004, 5, 11)); testWidget->setDisplayFormat("prefix d/MM/yyyy 'suffix'"); testWidget->lineEdit()->setFocus(); @@ -1162,7 +1117,7 @@ void tst_QDateTimeEdit::enterKey() // we include this test so a change to the behaviour can't go unnoticed. QSignalSpy enterSpy(testWidget, SIGNAL(dateChanged(QDate))); QTest::keyClick(testWidget, Qt::Key_Enter); - QCOMPARE(enterSpy.count(), 1); + QCOMPARE(enterSpy.size(), 1); QVariantList list = enterSpy.takeFirst(); QCOMPARE(list.at(0).toDate(), QDate(2004, 5, 9)); } @@ -1356,7 +1311,7 @@ void tst_QDateTimeEdit::editingRanged_data() << QDate(2010, 12, 30) << QTime() << QDate(2011, 1, 2) << QTime() << QString::fromLatin1("01012011") - << QDateTime(QDate(2011, 1, 1), QTime(), Qt::UTC); + << QDateTime(QDate(2011, 1, 1), QTime(), QTimeZone::UTC); } void tst_QDateTimeEdit::editingRanged() @@ -1392,7 +1347,6 @@ void tst_QDateTimeEdit::editingRanged() }); edit->show(); - QApplication::setActiveWindow(edit.get()); if (!QTest::qWaitForWindowActive(edit.get())) QSKIP("Failed to make window active, aborting"); edit->setFocus(); @@ -2237,7 +2191,7 @@ void tst_QDateTimeEdit::dateSignalChecking() QSignalSpy timeSpy(testWidget, SIGNAL(timeChanged(QTime))); testWidget->setDate(newDate); - QCOMPARE(dateSpy.count(), timesEmitted); + QCOMPARE(dateSpy.size(), timesEmitted); if (timesEmitted > 0) { QList<QVariant> list = dateSpy.takeFirst(); @@ -2245,8 +2199,8 @@ void tst_QDateTimeEdit::dateSignalChecking() d = qvariant_cast<QDate>(list.at(0)); QCOMPARE(d, newDate); } - QCOMPARE(dateTimeSpy.count(), timesEmitted); - QCOMPARE(timeSpy.count(), 0); + QCOMPARE(dateTimeSpy.size(), timesEmitted); + QCOMPARE(timeSpy.size(), 0); } void tst_QDateTimeEdit::timeSignalChecking_data() @@ -2273,7 +2227,7 @@ void tst_QDateTimeEdit::timeSignalChecking() QSignalSpy timeSpy(testWidget, SIGNAL(timeChanged(QTime))); testWidget->setTime(newTime); - QCOMPARE(timeSpy.count(), timesEmitted); + QCOMPARE(timeSpy.size(), timesEmitted); if (timesEmitted > 0) { QList<QVariant> list = timeSpy.takeFirst(); @@ -2281,8 +2235,8 @@ void tst_QDateTimeEdit::timeSignalChecking() t = qvariant_cast<QTime>(list.at(0)); QCOMPARE(t, newTime); } - QCOMPARE(dateTimeSpy.count(), timesEmitted); - QCOMPARE(dateSpy.count(), 0); + QCOMPARE(dateTimeSpy.size(), timesEmitted); + QCOMPARE(dateSpy.size(), 0); } void tst_QDateTimeEdit::dateTimeSignalChecking_data() @@ -2323,7 +2277,7 @@ void tst_QDateTimeEdit::dateTimeSignalChecking() QSignalSpy dateTimeSpy(testWidget, SIGNAL(dateTimeChanged(QDateTime))); testWidget->setDateTime(newDateTime); - QCOMPARE(dateSpy.count(), timesDateEmitted); + QCOMPARE(dateSpy.size(), timesDateEmitted); if (timesDateEmitted > 0) { QCOMPARE(timesDateEmitted, 1); QList<QVariant> list = dateSpy.takeFirst(); @@ -2331,14 +2285,14 @@ void tst_QDateTimeEdit::dateTimeSignalChecking() d = qvariant_cast<QDate>(list.at(0)); QCOMPARE(d, newDateTime.date()); } - QCOMPARE(timeSpy.count(), timesTimeEmitted); + QCOMPARE(timeSpy.size(), timesTimeEmitted); if (timesTimeEmitted > 0) { QList<QVariant> list = timeSpy.takeFirst(); QTime t; t = qvariant_cast<QTime>(list.at(0)); QCOMPARE(t, newDateTime.time()); } - QCOMPARE(dateTimeSpy.count(), timesDateTimeEmitted); + QCOMPARE(dateTimeSpy.size(), timesDateTimeEmitted); if (timesDateTimeEmitted > 0) { QList<QVariant> list = dateTimeSpy.takeFirst(); QDateTime dt; @@ -3202,22 +3156,22 @@ void tst_QDateTimeEdit::task149097() testWidget->setDisplayFormat("yyyy/MM/dd hh:mm:ss"); testWidget->setDateTime(QDateTime(QDate(2001, 02, 03), QTime(5, 1, 2))); // QTest::keyClick(testWidget, Qt::Key_Enter); - QCOMPARE(dtSpy.count(), 1); - QCOMPARE(dSpy.count(), 1); - QCOMPARE(tSpy.count(), 1); + QCOMPARE(dtSpy.size(), 1); + QCOMPARE(dSpy.size(), 1); + QCOMPARE(tSpy.size(), 1); testWidget->setCurrentSection(QDateTimeEdit::YearSection); testWidget->stepBy(1); - QCOMPARE(dtSpy.count(), 2); - QCOMPARE(dSpy.count(), 2); - QCOMPARE(tSpy.count(), 1); + QCOMPARE(dtSpy.size(), 2); + QCOMPARE(dSpy.size(), 2); + QCOMPARE(tSpy.size(), 1); testWidget->setCurrentSection(QDateTimeEdit::MinuteSection); testWidget->stepBy(1); - QCOMPARE(dtSpy.count(), 3); - QCOMPARE(dSpy.count(), 2); - QCOMPARE(tSpy.count(), 2); + QCOMPARE(dtSpy.size(), 3); + QCOMPARE(dSpy.size(), 2); + QCOMPARE(tSpy.size(), 2); } void tst_QDateTimeEdit::task148725() @@ -3405,7 +3359,7 @@ void tst_QDateTimeEdit::wheelEvent() QFETCH(QDate, startDate); QFETCH(DateList, expectedDates); - EditorDateEdit edit(0); + EditorDateEdit edit; edit.setDate(startDate); edit.setCurrentSection(section); @@ -3531,6 +3485,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"); @@ -3538,6 +3493,8 @@ void tst_QDateTimeEdit::timeSpec_data() QTest::newRow("setTimeSpec") << false; } +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void tst_QDateTimeEdit::timeSpec() { QFETCH(bool, useSetProperty); @@ -3563,7 +3520,7 @@ void tst_QDateTimeEdit::timeSpec() QCOMPARE(edit.timeSpec(), Qt::LocalTime); const QDateTime utc = dt.toUTC(); if (dt.time() != utc.time()) { - const QDateTime min(QDate(1999, 1, 1), QTime(1, 0, 0), Qt::LocalTime); + const QDateTime min(QDate(1999, 1, 1), QTime(1, 0)); edit.setMinimumDateTime(min); QCOMPARE(edit.minimumTime(), min.time()); if (useSetProperty) { @@ -3578,10 +3535,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(); @@ -3591,57 +3550,33 @@ 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, 0), Qt::UTC); + QDateTime utc(QDate(2000, 1, 1), QTime(12, 0), QTimeZone::UTC); QDateTimeEdit widget(utc); QCOMPARE(widget.dateTime(), utc); } void tst_QDateTimeEdit::setDateTime_data() { - QTest::addColumn<Qt::TimeSpec>("spec"); - QDateTime localNoon(QDate(2019, 12, 24), QTime(12, 0), Qt::LocalTime); -#if 0 // Not yet supported - QTest::addColumn<int>("offset"); - QTest::addColumn<QByteArray>("zoneName"); - - QTest::newRow("OffsetFromUTC/LocalTime") - << Qt::OffsetFromUTC << 7200 << "" - << localNoon << localNoon.toOffsetFromUtc(7200); -#if QT_CONFIG(timezone) - QTest::newRow("TimeZone/LocalTime") - << Qt::TimeZone << 0 << "Europe/Berlin" - << localNoon << localNoon.toTimeZone(QTimeZone("Europe/Berlin")); -#endif -#endif // unsupported + 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 // << 0 << "" - << localNoon << localNoon; - QTest::newRow("LocalTime/UTC") - << Qt::LocalTime // << 0 << "" - << localNoon.toUTC() << localNoon; - QTest::newRow("UTC/LocalTime") - << Qt::UTC // << 0 << "" - << localNoon << localNoon.toUTC(); - QTest::newRow("UTC/UTC") - << Qt::UTC // << 0 << "" - << 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); -#if 0 // Not yet supported - QFETCH(const int, offset); - QFETCH(const QByteArray, zoneName); -#endif // configuring the spec, when OffsetFromUTC or TimeZone + 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); } @@ -3835,14 +3770,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.setTimeSpec(Qt::UTC); + 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)); @@ -3858,7 +3793,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(); @@ -4484,7 +4419,7 @@ void tst_QDateTimeEdit::stepModifierButtons() testWidget->hide(); - EditorDateEdit edit(0); + EditorDateEdit edit; edit.setTime(startTime); edit.show(); QVERIFY(QTest::qWaitForWindowActive(&edit)); @@ -4570,11 +4505,15 @@ void tst_QDateTimeEdit::stepModifierPressAndHold() QFETCH(Qt::KeyboardModifiers, modifiers); QFETCH(int, expectedStepModifier); - const QDate startDate(2000, 1, 1); + // Some west African zones (e.g. Niamey, Conakry) changed from 1 hour west + // of GMT to GMT at the start of 1960; and spy.size() can get as high as 4, + // causing the expectedDate below, when expectedStepModifier is -10, to land + // in a transition gap for these zones, if we use Jan 1st; so use Jan 2nd. + const QDate startDate(2000, 1, 2); testWidget->hide(); - EditorDateEdit edit(0); + EditorDateEdit edit; edit.setDate(startDate); QScopedPointer<StepModifierStyle, QScopedPointerDeleteLater> stepModifierStyle( @@ -4595,12 +4534,12 @@ void tst_QDateTimeEdit::stepModifierPressAndHold() QStyle::CC_SpinBox, &spinBoxStyleOption, subControl, &edit); QTest::mousePress(&edit, Qt::LeftButton, modifiers, buttonRect.center()); - QTRY_VERIFY(spy.length() >= 3); + QTRY_VERIFY(spy.size() >= 3); QTest::mouseRelease(&edit, Qt::LeftButton, modifiers, buttonRect.center()); const auto value = spy.last().at(0); QVERIFY(value.userType() == QMetaType::QDate); - const QDate expectedDate = startDate.addYears(spy.length() * + const QDate expectedDate = startDate.addYears(spy.size() * expectedStepModifier); QCOMPARE(value.toDate(), expectedDate); } @@ -4624,13 +4563,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 /*! @@ -4654,36 +4600,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 @@ -4711,11 +4661,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); @@ -4742,7 +4692,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!"); @@ -4751,11 +4701,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)) @@ -4765,7 +4718,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)); @@ -4790,28 +4743,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 e76cc4a7db..5e300eec94 100644 --- a/tests/auto/widgets/widgets/qdial/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qdial/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qdial.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qdial/tst_qdial.cpp b/tests/auto/widgets/widgets/qdial/tst_qdial.cpp index 86928414c8..d0274ace2a 100644 --- a/tests/auto/widgets/widgets/qdial/tst_qdial.cpp +++ b/tests/auto/widgets/widgets/qdial/tst_qdial.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -42,6 +17,7 @@ private slots: void valueChanged(); void sliderMoved(); void wrappingCheck(); + void minEqualMaxValueOutsideRange(); void notchSize_data(); void notchSize(); @@ -77,14 +53,14 @@ void tst_QDial::valueChanged() dial.setMaximum(100); QSignalSpy spy(&dial, SIGNAL(valueChanged(int))); dial.setValue(50); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); dial.setValue(25); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); // repeat! dial.setValue(25); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QDial::sliderMoved() @@ -100,7 +76,7 @@ void tst_QDial::sliderMoved() QPoint init(dial.width()/4, dial.height()/2); - QMouseEvent pressevent(QEvent::MouseButtonPress, init, + QMouseEvent pressevent(QEvent::MouseButtonPress, init, dial.mapToGlobal(init), Qt::LeftButton, Qt::LeftButton, {}); qApp->sendEvent(&dial, &pressevent); @@ -110,27 +86,27 @@ void tst_QDial::sliderMoved() { //move on top of the slider init = QPoint(dial.width()/2, dial.height()/4); - QMouseEvent moveevent(QEvent::MouseMove, init, + QMouseEvent moveevent(QEvent::MouseMove, init, dial.mapToGlobal(init), Qt::LeftButton, Qt::LeftButton, {}); qApp->sendEvent(&dial, &moveevent); - QCOMPARE( sliderspy.count(), 1); - QCOMPARE( valuespy.count(), 0); + QCOMPARE( sliderspy.size(), 1); + QCOMPARE( valuespy.size(), 0); } { //move on the right of the slider init = QPoint(dial.width()*3/4, dial.height()/2); - QMouseEvent moveevent(QEvent::MouseMove, init, + QMouseEvent moveevent(QEvent::MouseMove, init, dial.mapToGlobal(init), Qt::LeftButton, Qt::LeftButton, {}); qApp->sendEvent(&dial, &moveevent); - QCOMPARE( sliderspy.count(), 2); - QCOMPARE( valuespy.count(), 0); + QCOMPARE( sliderspy.size(), 2); + QCOMPARE( valuespy.size(), 0); } - QMouseEvent releaseevent(QEvent::MouseButtonRelease, init, + QMouseEvent releaseevent(QEvent::MouseButtonRelease, init, dial.mapToGlobal(init), Qt::LeftButton, Qt::LeftButton, {}); qApp->sendEvent(&dial, &releaseevent); - QCOMPARE( valuespy.count(), 1); // valuechanged signal should be called at this point + QCOMPARE( valuespy.size(), 1); // valuechanged signal should be called at this point } @@ -197,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 c42fccd87f..098b129cbc 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qdialogbuttonbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + 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 2e7e248db7..3e7dc92da1 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp @@ -1,38 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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) @@ -74,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(); @@ -99,6 +82,9 @@ private slots: void task191642_default(); void testDeletedStandardButton(); + void automaticDefaultButton(); + void initialFocus_data(); + void initialFocus(); private: qint64 timeStamp; @@ -122,7 +108,7 @@ void tst_QDialogButtonBox::testConstructor1() QDialogButtonBox buttonbox; QCOMPARE(buttonbox.orientation(), Qt::Horizontal); - QCOMPARE(buttonbox.buttons().count(), 0); + QCOMPARE(buttonbox.buttons().size(), 0); } void tst_QDialogButtonBox::layoutReuse() @@ -155,7 +141,7 @@ void tst_QDialogButtonBox::testConstructor2() QDialogButtonBox buttonBox(orient); QCOMPARE(buttonBox.orientation(), orient); - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); } void tst_QDialogButtonBox::testConstructor3_data() @@ -192,7 +178,7 @@ void tst_QDialogButtonBox::testConstructor3() QDialogButtonBox buttonBox(buttons, (Qt::Orientation)orientation); QCOMPARE(int(buttonBox.orientation()), orientation); - QTEST(int(buttonBox.buttons().count()), "buttonCount"); + QTEST(int(buttonBox.buttons().size()), "buttonCount"); } void tst_QDialogButtonBox::testConstructor4_data() @@ -227,7 +213,7 @@ void tst_QDialogButtonBox::testConstructor4() QDialogButtonBox buttonBox(buttons); QCOMPARE(buttonBox.orientation(), Qt::Horizontal); - QTEST(int(buttonBox.buttons().count()), "buttonCount"); + QTEST(int(buttonBox.buttons().size()), "buttonCount"); } void tst_QDialogButtonBox::setOrientation_data() @@ -290,12 +276,12 @@ void tst_QDialogButtonBox::addButton1() { QFETCH(QDialogButtonBox::ButtonRole, role); QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QPushButton *button = new QPushButton(); buttonBox.addButton(button, role); - QTEST(int(buttonBox.buttons().count()), "totalCount"); + QTEST(int(buttonBox.buttons().size()), "totalCount"); QList<QAbstractButton *> children = buttonBox.findChildren<QAbstractButton *>(); - QTEST(int(children.count()), "totalCount"); + QTEST(int(children.size()), "totalCount"); delete button; } @@ -318,11 +304,11 @@ void tst_QDialogButtonBox::addButton2() QFETCH(QString, text); QFETCH(QDialogButtonBox::ButtonRole, role); QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); buttonBox.addButton(text, role); - QTEST(int(buttonBox.buttons().count()), "totalCount"); + QTEST(int(buttonBox.buttons().size()), "totalCount"); QList<QAbstractButton *> children = buttonBox.findChildren<QAbstractButton *>(); - QTEST(int(children.count()), "totalCount"); + QTEST(int(children.size()), "totalCount"); } void tst_QDialogButtonBox::addButton3_data() @@ -345,11 +331,11 @@ void tst_QDialogButtonBox::addButton3() { QFETCH(QDialogButtonBox::StandardButton, button); QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); buttonBox.addButton(button); - QTEST(int(buttonBox.buttons().count()), "totalCount"); + QTEST(int(buttonBox.buttons().size()), "totalCount"); QList<QAbstractButton *> children = buttonBox.findChildren<QAbstractButton *>(); - QTEST(int(children.count()), "totalCount"); + QTEST(int(children.size()), "totalCount"); } void tst_QDialogButtonBox::clear_data() @@ -369,9 +355,9 @@ void tst_QDialogButtonBox::clear() for (int i = 1; i < rolesToAdd; ++i) buttonBox.addButton("Happy", QDialogButtonBox::ButtonRole(i)); buttonBox.clear(); - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QList<QAbstractButton *> children = buttonBox.findChildren<QAbstractButton *>(); - QCOMPARE(children.count(), 0); + QCOMPARE(children.size(), 0); } void tst_QDialogButtonBox::removeButton_data() @@ -387,31 +373,95 @@ void tst_QDialogButtonBox::removeButton() QFETCH(QDialogButtonBox::ButtonRole, roleToAdd); QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QPushButton *button = new QPushButton("RemoveButton test"); buttonBox.addButton(button, roleToAdd); - QTEST(int(buttonBox.buttons().count()), "expectedCount"); + QTEST(int(buttonBox.buttons().size()), "expectedCount"); buttonBox.removeButton(button); - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); 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; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QPushButton *deleteMe = new QPushButton("Happy"); buttonBox.addButton(deleteMe, QDialogButtonBox::HelpRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); QList<QAbstractButton *> children = buttonBox.findChildren<QAbstractButton *>(); - QCOMPARE(children.count(), 1); + QCOMPARE(children.size(), 1); delete deleteMe; children = buttonBox.findChildren<QAbstractButton *>(); - QCOMPARE(children.count(), 0); - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(children.size(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); } class ObjectDeleter : public QObject @@ -433,7 +483,7 @@ void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() { { QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QSignalSpy buttonClickedSpy(&buttonBox, &QDialogButtonBox::clicked); QVERIFY(buttonClickedSpy.isValid()); @@ -442,21 +492,21 @@ void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() QVERIFY(buttonBoxAcceptedSpy.isValid()); QPushButton *button = buttonBox.addButton("Test", QDialogButtonBox::AcceptRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); ObjectDeleter objectDeleter; connect(&buttonBox, &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteButton); button->click(); - QCOMPARE(buttonBox.buttons().count(), 0); - QCOMPARE(buttonClickedSpy.count(), 1); - QCOMPARE(buttonBoxAcceptedSpy.count(), 1); + QCOMPARE(buttonBox.buttons().size(), 0); + QCOMPARE(buttonClickedSpy.size(), 1); + QCOMPARE(buttonBoxAcceptedSpy.size(), 1); } { QPointer<QDialogButtonBox> buttonBox(new QDialogButtonBox); - QCOMPARE(buttonBox->buttons().count(), 0); + QCOMPARE(buttonBox->buttons().size(), 0); QSignalSpy buttonClickedSpy(buttonBox.data(), &QDialogButtonBox::clicked); QVERIFY(buttonClickedSpy.isValid()); @@ -465,7 +515,7 @@ void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() QVERIFY(buttonBoxAcceptedSpy.isValid()); QPushButton *button = buttonBox->addButton("Test", QDialogButtonBox::AcceptRole); - QCOMPARE(buttonBox->buttons().count(), 1); + QCOMPARE(buttonBox->buttons().size(), 1); ObjectDeleter objectDeleter; connect(buttonBox.data(), &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteSender); @@ -473,8 +523,8 @@ void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() button->click(); QVERIFY(buttonBox.isNull()); - QCOMPARE(buttonClickedSpy.count(), 1); - QCOMPARE(buttonBoxAcceptedSpy.count(), 0); + QCOMPARE(buttonClickedSpy.size(), 1); + QCOMPARE(buttonBoxAcceptedSpy.size(), 0); } } @@ -482,24 +532,24 @@ void tst_QDialogButtonBox::testMultipleAdd() { // Add a button into the thing multiple times. QDialogButtonBox buttonBox; - QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonBox.buttons().size(), 0); QPushButton *button = new QPushButton("Foo away"); buttonBox.addButton(button, QDialogButtonBox::AcceptRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); QCOMPARE(buttonBox.buttonRole(button), QDialogButtonBox::AcceptRole); buttonBox.addButton(button, QDialogButtonBox::AcceptRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); QCOMPARE(buttonBox.buttonRole(button), QDialogButtonBox::AcceptRole); // Add it again with a different role buttonBox.addButton(button, QDialogButtonBox::RejectRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); QCOMPARE(buttonBox.buttonRole(button), QDialogButtonBox::RejectRole); // Add it as an "invalid" role buttonBox.addButton(button, QDialogButtonBox::InvalidRole); - QCOMPARE(buttonBox.buttons().count(), 1); + QCOMPARE(buttonBox.buttons().size(), 1); QCOMPARE(buttonBox.buttonRole(button), QDialogButtonBox::RejectRole); } @@ -619,13 +669,13 @@ void tst_QDialogButtonBox::testSignals() if (clickMe) clickMe->click(); - QTRY_COMPARE(clicked2.count(), clicked2Count); - if (clicked2.count() > 0) + QTRY_COMPARE(clicked2.size(), clicked2Count); + if (clicked2.size() > 0) QCOMPARE(qvariant_cast<QAbstractButton *>(clicked2.at(0).at(0)), clickMe); - QTEST(int(accept.count()), "acceptCount"); - QTEST(int(reject.count()), "rejectCount"); - QTEST(int(helpRequested.count()), "helpRequestedCount"); + QTEST(int(accept.size()), "acceptCount"); + QTEST(int(reject.size()), "rejectCount"); + QTEST(int(helpRequested.size()), "helpRequestedCount"); } void tst_QDialogButtonBox::testSignalOrder() @@ -781,7 +831,7 @@ void tst_QDialogButtonBox::testRemove() button->click(); QTest::qWait(100); - QCOMPARE(clicked.count(), 0); + QCOMPARE(clicked.size(), 0); delete button; } @@ -843,7 +893,7 @@ void tst_QDialogButtonBox::task191642_default() QVERIFY(QTest::qWaitForWindowActive(&dlg)); QVERIFY(def->isDefault()); QTest::keyPress( &dlg, Qt::Key_Enter ); - QCOMPARE(clicked.count(), 1); + QCOMPARE(clicked.size(), 1); } void tst_QDialogButtonBox::testDeletedStandardButton() @@ -863,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 6a3b189939..8873589ff4 100644 --- a/tests/auto/widgets/widgets/qdockwidget/BLACKLIST +++ b/tests/auto/widgets/widgets/qdockwidget/BLACKLIST @@ -1,3 +1,36 @@ # QTBUG-87415 [task169808_setFloating] 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 +b2qt + +# 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 +arm +android +macos diff --git a/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt index adf48ddb11..21d8fb60cc 100644 --- a/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qdockwidget/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qdockwidget.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES + Qt::Core Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index d726807b7c..88a7057d2e 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -1,42 +1,25 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QSignalSpy> - #include <qaction.h> #include <qdockwidget.h> #include <qmainwindow.h> +#include "private/qdockwidget_p.h" +#include "private/qmainwindowlayout_p.h" +#include <QAbstractButton> #include <qlineedit.h> +#include <QtGui/qpa/qplatformwindow.h> #include <qtabbar.h> #include <QScreen> +#include <QTimer> #include <QtGui/QPainter> -#include "private/qdockwidget_p.h" +#include <QLabel> + +Q_LOGGING_CATEGORY(lcTestDockWidget, "qt.widgets.tests.qdockwidget") + +#include <QtWidgets/private/qapplication_p.h> bool hasFeature(QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature) { return (dockwidget->features() & feature) == feature; } @@ -70,6 +53,7 @@ private slots: void restoreDockWidget(); void restoreStateWhileStillFloating(); void setWindowTitle(); + // task specific tests: void task165177_deleteFocusWidget(); void task169808_setFloating(); @@ -78,6 +62,112 @@ private slots: void task258459_visibilityChanged(); void taskQTBUG_1665_closableChanged(); void taskQTBUG_9758_undockedGeometry(); + + // Dock area permissions for DockWidgets and DockWidgetGroupWindows + void dockPermissions(); + + // 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(); + +private: + // helpers and consts for dockPermissions, hideAndShow, closeAndDelete +#ifdef QT_BUILD_INTERNAL + void createTestWidgets(QMainWindow* &MainWindow, QPointer<QWidget> ¢, + QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2) const; + + void unplugAndResize(QMainWindow* MainWindow, QDockWidget* dw, QPoint home, QSize size) const; + + void createFloatingTabs(QMainWindow* &MainWindow, QPointer<QWidget> ¢, + QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2, + QList<int> &path1, QList<int> &path2) const; + +#if defined(Q_OS_DARWIN) || defined(Q_OS_ANDROID) || defined(Q_OS_QNX) +#define qCreateFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2)\ + mainWindow = nullptr;\ + Q_UNUSED(path1);\ + Q_UNUSED(path2);\ + QSKIP("Platform not supported"); +#else +#define qCreateFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2)\ + createFloatingTabs(mainWindow, centralWidget, d1, d2, path1, path2);\ + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);\ + if (!platformSupportingRaise)\ + QSKIP("Platform not supporting raise(). Floating tab based tests will fail.") +#endif + + 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())); } + + static inline QPoint home2(QMainWindow* MainWindow) + { return MainWindow->mapToGlobal(MainWindow->rect().topLeft() + QPoint(0.6 * MainWindow->width(), 0.15 * MainWindow->height())); } + + static inline QSize size1(QMainWindow* MainWindow) + { return QSize (0.2 * MainWindow->width(), 0.25 * MainWindow->height()); } + + static inline QSize size2(QMainWindow* MainWindow) + { return QSize (0.1 * MainWindow->width(), 0.15 * MainWindow->height()); } + + static inline QPoint dockPoint(QMainWindow* mw, Qt::DockWidgetArea area) + { return mw->mapToGlobal(qobject_cast<QMainWindowLayout*>(mw->layout())->dockWidgetAreaRect(area, QMainWindowLayout::Maximum).center()); } + + bool checkFloatingTabs(QMainWindow* MainWindow, QPointer<QDockWidgetGroupWindow> &ftabs, const QList<QDockWidget*> &dwList = {}) const; + + // move a dock widget + 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 + // Grace time between mouse events. Set to 400 for debugging. + const int waitingTime = 400; + + // Waiting time before closing widgets successful test. Set to 20000 for debugging. + const int waitBeforeClose = 0; + + // Enable logging + const bool dockWidgetLog = true; +#else + const int waitingTime = 15; + const int waitBeforeClose = 0; + const bool dockWidgetLog = false; +#endif // QT_DEBUG +#endif // QT_BUILD_INTERNAL + }; // Testing get/set functions @@ -219,12 +309,12 @@ void tst_QDockWidget::features() QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*(static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData())), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); setFeature(&dw, QDockWidget::DockWidgetClosable); @@ -232,12 +322,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); setFeature(&dw, QDockWidget::DockWidgetMovable, false); @@ -245,12 +335,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); setFeature(&dw, QDockWidget::DockWidgetMovable); @@ -258,12 +348,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); setFeature(&dw, QDockWidget::DockWidgetFloatable, false); @@ -271,12 +361,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); setFeature(&dw, QDockWidget::DockWidgetFloatable); @@ -284,12 +374,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); // set all at once @@ -298,12 +388,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); dw.setFeatures(QDockWidget::DockWidgetClosable); @@ -311,12 +401,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); dw.setFeatures(allDockWidgetFeatures); @@ -324,12 +414,12 @@ void tst_QDockWidget::features() QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable)); QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()), (int)dw.features()); spy.clear(); dw.setFeatures(dw.features()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); } @@ -356,21 +446,38 @@ void tst_QDockWidget::setFloating() QVERIFY((dockedPosition - floatingPosition).manhattanLength() < 50); QVERIFY(dw.isFloating()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toBool(), dw.isFloating()); spy.clear(); dw.setFloating(dw.isFloating()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); dw.setFloating(false); QVERIFY(!dw.isFloating()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toBool(), dw.isFloating()); spy.clear(); dw.setFloating(dw.isFloating()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); + +#if defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) + // Check that setFloating() reparents the dock widget to the main window, + // in case it has a QDockWidgetGroupWindow parent + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + QList<int> path1; + QList<int> path2; + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); + QVERIFY(qobject_cast<QDockWidgetGroupWindow *>(d1->parentWidget())); + QVERIFY(qobject_cast<QDockWidgetGroupWindow *>(d2->parentWidget())); + d1->setFloating(true); + QTRY_COMPARE(mainWindow, d1->parentWidget()); + QTRY_COMPARE(mainWindow, d2->parentWidget()); +#endif // defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) } void tst_QDockWidget::allowedAreas() @@ -393,12 +500,12 @@ void tst_QDockWidget::allowedAreas() QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::RightDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::RightDockWidgetArea); @@ -406,12 +513,12 @@ void tst_QDockWidget::allowedAreas() QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::TopDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::TopDockWidgetArea); @@ -419,12 +526,12 @@ void tst_QDockWidget::allowedAreas() QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::BottomDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::BottomDockWidgetArea); @@ -432,12 +539,12 @@ void tst_QDockWidget::allowedAreas() QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // multiple dock window areas dw.setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); @@ -446,12 +553,13 @@ void tst_QDockWidget::allowedAreas() QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + //QVERIFY(!dw.isAreaAllowed(Qt::FloatingDockWidgetArea)); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); @@ -459,12 +567,13 @@ void tst_QDockWidget::allowedAreas() QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + //QVERIFY(!dw.isAreaAllowed(Qt::FloatingDockWidgetArea)); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea); @@ -472,12 +581,28 @@ void tst_QDockWidget::allowedAreas() QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + //QVERIFY(!dw.isAreaAllowed(Qt::FloatingDockWidgetArea)); + QCOMPARE(spy.size(), 1); + QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), + dw.allowedAreas()); + spy.clear(); + dw.setAllowedAreas(dw.allowedAreas()); + QCOMPARE(spy.size(), 0); + + //dw.setAllowedAreas(Qt::BottomDockWidgetArea | Qt::FloatingDockWidgetArea); + dw.setAllowedAreas(Qt::BottomDockWidgetArea); + //QCOMPARE(dw.allowedAreas(), Qt::BottomDockWidgetArea | Qt::FloatingDockWidgetArea); + QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea)); + QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea)); + QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); + QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea)); + //QVERIFY(dw.isAreaAllowed(Qt::FloatingDockWidgetArea)); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.setAllowedAreas(Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea); QCOMPARE(dw.allowedAreas(), Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea); @@ -485,12 +610,13 @@ void tst_QDockWidget::allowedAreas() QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea)); QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea)); QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea)); - QCOMPARE(spy.count(), 1); + //QVERIFY(!dw.isAreaAllowed(Qt::FloatingDockWidgetArea)); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()), dw.allowedAreas()); spy.clear(); dw.setAllowedAreas(dw.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QDockWidget::toggleViewAction() @@ -518,65 +644,65 @@ void tst_QDockWidget::visibilityChanged() mw.addDockWidget(Qt::LeftDockWidgetArea, &dw); mw.show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); dw.hide(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), false); spy.clear(); dw.hide(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw.show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); dw.show(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QDockWidget dw2; mw.tabifyDockWidget(&dw, &dw2); dw2.show(); dw2.raise(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), false); spy.clear(); dw2.hide(); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); dw2.show(); dw2.raise(); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), false); spy.clear(); dw.raise(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); dw.raise(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); dw2.raise(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), false); spy.clear(); dw2.raise(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); mw.addDockWidget(Qt::RightDockWidgetArea, &dw2); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); } @@ -603,6 +729,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); @@ -616,6 +745,11 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged() dw1->hide(); QTRY_COMPARE(tabBar->count(), 2); QCOMPARE(tabBar->currentIndex(), 0); + + QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3}); + + mw.removeDockWidget(dw3); + QCOMPARE(mw.tabifiedDockWidgets(dw2).count(), 0); } Q_DECLARE_METATYPE(Qt::DockWidgetArea) @@ -630,56 +764,56 @@ void tst_QDockWidget::dockLocationChanged() QSignalSpy spy(&dw, SIGNAL(dockLocationChanged(Qt::DockWidgetArea))); mw.addDockWidget(Qt::LeftDockWidgetArea, &dw); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::LeftDockWidgetArea); spy.clear(); mw.addDockWidget(Qt::LeftDockWidgetArea, &dw); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::LeftDockWidgetArea); spy.clear(); mw.addDockWidget(Qt::RightDockWidgetArea, &dw); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::RightDockWidgetArea); spy.clear(); mw.removeDockWidget(&dw); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QDockWidget dw2; dw2.setObjectName("dock2"); mw.addDockWidget(Qt::TopDockWidgetArea, &dw2); mw.tabifyDockWidget(&dw2, &dw); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::TopDockWidgetArea); spy.clear(); mw.splitDockWidget(&dw2, &dw, Qt::Horizontal); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::TopDockWidgetArea); spy.clear(); dw.setFloating(true); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::NoDockWidgetArea); spy.clear(); dw.setFloating(false); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::TopDockWidgetArea); spy.clear(); QByteArray ba = mw.saveState(); mw.restoreState(ba); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)), Qt::TopDockWidgetArea); } @@ -950,9 +1084,9 @@ void tst_QDockWidget::task258459_visibilityChanged() QSignalSpy spy2(&dock2, SIGNAL(visibilityChanged(bool))); win.show(); QVERIFY(QTest::qWaitForWindowActive(&win)); - QCOMPARE(spy1.count(), 1); + QCOMPARE(spy1.size(), 1); QCOMPARE(spy1.first().first().toBool(), false); //dock1 is invisible - QCOMPARE(spy2.count(), 1); + QCOMPARE(spy2.size(), 1); QCOMPARE(spy2.first().first().toBool(), true); //dock1 is visible } @@ -1002,9 +1136,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); @@ -1015,6 +1150,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)); @@ -1024,12 +1160,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); @@ -1044,6 +1184,852 @@ 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 +#ifdef QT_BUILD_INTERNAL +void tst_QDockWidget::createTestWidgets(QMainWindow* &mainWindow, QPointer<QWidget> ¢, QPointer<QDockWidget> &d1, QPointer<QDockWidget> &d2) const +{ + // Enable logging if required + if (dockWidgetLog) + QLoggingCategory::setFilterRules("qt.widgets.dockwidgets=true"); + + // Derive sizes and positions from primary screen + const QRect screen = QApplication::primaryScreen()->availableGeometry(); + const QPoint m_topLeft = screen.topLeft(); + const QSize s_mwindow = QApplication::primaryScreen()->availableSize() * 0.7; + + mainWindow = new QMainWindow; + mainWindow->setMouseTracking(true); + mainWindow->setFixedSize(s_mwindow); + cent = new QWidget; + mainWindow->setCentralWidget(cent); + cent->setLayout(new QGridLayout); + cent->layout()->setContentsMargins(0, 0, 0, 0); + cent->setMinimumSize(0, 0); + mainWindow->setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::GroupedDragging); + mainWindow->move(m_topLeft); + + const int minWidth = QApplication::style()->pixelMetric(QStyle::PM_TitleBarHeight); + const QSize minSize(minWidth, 2 * minWidth); + d1 = new QDockWidget(mainWindow); + d1->setMinimumSize(minSize); + d1->setWindowTitle("I am D1"); + d1->setObjectName("D1"); + d1->setFeatures(QDockWidget::DockWidgetFeatureMask); + d1->setAllowedAreas(Qt::DockWidgetArea::AllDockWidgetAreas); + + d2 = new QDockWidget(mainWindow); + d2->setMinimumSize(minSize); + d2->setWindowTitle("I am D2"); + d2->setObjectName("D2"); + d2->setFeatures(QDockWidget::DockWidgetFeatureMask); + d2->setAllowedAreas(Qt::DockWidgetArea::RightDockWidgetArea); + + mainWindow->addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, d1); + mainWindow->addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, d2); + d1->show(); + d2->show(); + mainWindow->show(); + QApplicationPrivate::setActiveWindow(mainWindow); + +} + +QPoint tst_QDockWidget::dragPoint(QDockWidget* dockWidget) +{ + Q_ASSERT(dockWidget); + QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout *>(dockWidget->layout()); + Q_ASSERT(dwlayout); + return dockWidget->mapToGlobal(dwlayout->titleArea().center()); +} + +void tst_QDockWidget::moveDockWidget(QDockWidget* dw, QPoint to, QPoint from, MoveDockWidgetRule rule) const +{ + Q_ASSERT(dw); + + // If no from point is given, use the drag point + if (from.isNull()) + from = dragPoint(dw); + + // move and log + const QPoint source = dw->mapFromGlobal(from); + const QPoint target = dw->mapFromGlobal(to); + qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "from" << source; + qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "from" << from; + QTest::mousePress(dw, Qt::LeftButton, Qt::KeyboardModifiers(), source); + QTest::mouseMove(dw, target); + qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "to" << target; + qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "to" << to; + 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)); + 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 +{ + Q_ASSERT(mainWindow); + Q_ASSERT(dw); + + // Return if floating + if (dw->isFloating()) + return; + + QMainWindowLayout* layout = qobject_cast<QMainWindowLayout*>(mainWindow->layout()); + Qt::DockWidgetArea area = layout->dockWidgetArea(dw); + + // calculate minimum lateral move to unplug a dock widget + const int unplugMargin = 80; + int my = 0; + int mx = 0; + + switch (area) { + case Qt::LeftDockWidgetArea: + mx = unplugMargin; + break; + case Qt::TopDockWidgetArea: + my = unplugMargin; + break; + case Qt::RightDockWidgetArea: + mx = -unplugMargin; + break; + case Qt::BottomDockWidgetArea: + my = -unplugMargin; + break; + default: + return; + } + + // Remember size for comparison with unplugged object +#ifdef Q_OS_LINUX + const int pluggedWidth = dw->width(); + const int pluggedHeight = dw->height(); +#endif + + // unplug and resize a dock Widget + qCDebug(lcTestDockWidget) << "*** unplug and resize" << dw->objectName(); + QPoint pos1 = dw->mapToGlobal(dw->rect().center()); + pos1.rx() += mx; + pos1.ry() += my; + 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 +#ifdef Q_OS_LINUX + const int xMargin = 2 * dw->frameSize().width(); + const int yMargin = 2 * dw->frameSize().height(); + QVERIFY(dw->height() - pluggedHeight <= xMargin); + QVERIFY(dw->width() - pluggedWidth <= yMargin); +#endif + + qCDebug(lcTestDockWidget) << "Resizing" << dw->objectName() << "to" << size; + dw->setFixedSize(size); + QTest::qWait(waitingTime); + qCDebug(lcTestDockWidget) << "Move" << dw->objectName() << "to its home" << dw->mapFromGlobal(home); + dw->move(home); +} + +bool tst_QDockWidget::checkFloatingTabs(QMainWindow* mainWindow, QPointer<QDockWidgetGroupWindow> &ftabs, const QList<QDockWidget*> &dwList) const +{ + Q_ASSERT(mainWindow); + + // Check if mainWindow has a floatingTab child + ftabs = mainWindow->findChild<QDockWidgetGroupWindow*>(); + if (ftabs.isNull()) { + qCDebug(lcTestDockWidget) << "MainWindow has no DockWidgetGroupWindow" << mainWindow; + return false; + } + + QTabBar* tab = ftabs->findChild<QTabBar*>(); + if (!tab) { + qCDebug(lcTestDockWidget) << "DockWidgetGroupWindow has no tab bar" << ftabs; + return false; + } + + // both dock widgets must be direct children of the main window + const QList<QDockWidget*> children = ftabs->findChildren<QDockWidget*>(QString(), Qt::FindDirectChildrenOnly); + if (dwList.size() > 0) + { + if (dwList.size() != children.size()) { + qCDebug(lcTestDockWidget) << "Expected DockWidgetGroupWindow children:" << dwList.size() + << "Children found:" << children.size(); + + qCDebug(lcTestDockWidget) << "Expected:" << dwList; + qCDebug(lcTestDockWidget) << "Found in" << ftabs << ":" << children.size(); + return false; + } + + for (const QDockWidget* child : dwList) { + if (!children.contains(child)) { + qCDebug(lcTestDockWidget) << "Expected child" << child << "not found in" << children; + return false; + } + } + } + + // Always select first tab position + qCDebug(lcTestDockWidget) << "click on first tab"; + QTest::mouseClick(tab, Qt::LeftButton, Qt::KeyboardModifiers(), tab->tabRect(0).center()); + return true; +} + +#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) { + Q_ASSERT(qThis); + 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> ¢, + 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) + return; + + // 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 +void tst_QDockWidget::floatingTabs() +{ + 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 + // Create a mainwindow with a central widget and two dock widgets + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + QList<int> path1; + QList<int> path2; + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); + + 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 + */ + + // disabled due to flakiness on macOS and Windows + if (d1->isFloating()) + qWarning("OS flakiness: D1 is docked and reports being floating"); + if (d2->isFloating()) + qWarning("OS flakiness: D2 is docked and reports being floating"); + + // Now MainWindow has to have a floatingTab child + QPointer<QDockWidgetGroupWindow> ftabs; + 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 + - both docks are no longer floating + - title changes have been propagated + */ + + + // limitation: QTest cannot handle drag to unplug. + // reason: Object under mouse mutates from QTabBar::tab to QDockWidget. QTest cannot handle that. + // => click float button to unplug + qCDebug(lcTestDockWidget) << "*** test unplugging from floating dock ***"; + + // QDockWidget must have a QAbstractButton with object name "qt_dockwidget_floatbutton" + QAbstractButton* floatButton = d1->findChild<QAbstractButton*>("qt_dockwidget_floatbutton", Qt::FindDirectChildrenOnly); + QTRY_VERIFY(floatButton != nullptr); + QPoint pos1 = floatButton->rect().center(); + qCDebug(lcTestDockWidget) << "unplug d1" << pos1; + QTest::mouseClick(floatButton, Qt::LeftButton, Qt::KeyboardModifiers(), pos1); + QTest::qWait(waitingTime); + + // d1 and d2 must be floating again + QTRY_VERIFY(d1->isFloating()); + QTRY_VERIFY(d2->isFloating()); + + // d2 was the active tab, so d1 was not visible + QTRY_VERIFY(d1->isVisible()); + QTRY_VERIFY(d2->isVisible()); + + // Plug back into dock areas + qCDebug(lcTestDockWidget) << "*** test plugging back to dock areas ***"; + qCDebug(lcTestDockWidget) << "Move d1 to left dock"; + moveDockWidget(d1, dockPoint(mainWindow, Qt::LeftDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop); + qCDebug(lcTestDockWidget) << "Move d2 to right dock"; + moveDockWidget(d2, dockPoint(mainWindow, Qt::RightDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop); + + qCDebug(lcTestDockWidget) << "Waiting" << waitBeforeClose << "ms before plugging back."; + QTest::qWait(waitBeforeClose); + + // Both dock widgets must no longer be floating + QTRY_VERIFY(!d1->isFloating()); + QTRY_VERIFY(!d2->isFloating()); + + // check if QDockWidgetGroupWindow has been removed from mainWindowLayout and properly deleted + QTRY_VERIFY(!mainWindow->findChild<QDockWidgetGroupWindow*>()); + 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); + + // Paths must be identical + QTRY_COMPARE(layout->layoutState.indexOf(d1), path1); + QTRY_COMPARE(layout->layoutState.indexOf(d2), path2); + + 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; + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); + + 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 +} + +// 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; + oldMessageHandler = qInstallMessageHandler(xcbMessageHandler); + auto resetMessageHandler = qScopeGuard([] { qInstallMessageHandler(oldMessageHandler); }); + + // Create a mainwindow with a central widget and two dock widgets + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + createTestWidgets(mainWindow, cent, d1, d2); + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + + // Check hiding of docked widgets + qCDebug(lcTestDockWidget) << "Hiding mainWindow with plugged dock widgets" << mainWindow; + mainWindow->hide(); + QXCBVERIFY(!mainWindow->isVisible()); + QXCBVERIFY(!d1->isVisible()); + QXCBVERIFY(!d2->isVisible()); + + // Check showing everything again + qCDebug(lcTestDockWidget) << "Showing mainWindow with plugged dock widgets" << mainWindow; + mainWindow->show(); + QXCBVERIFY(QTest::qWaitForWindowActive(mainWindow)); + QXCBVERIFY(QTest::qWaitForWindowExposed(mainWindow)); + QXCBVERIFY(mainWindow->isVisible()); + QXCBVERIFY(QTest::qWaitForWindowActive(d1)); + QXCBVERIFY(d1->isVisible()); + QXCBVERIFY(QTest::qWaitForWindowActive(d2)); + QXCBVERIFY(d2->isVisible()); + + // in case of XCB errors, unplugAndResize will block and cause the test to time out. + // => force skip + QTest::qWait(waitingTime); + if (xcbError) + QSKIP("Test skipped due to XCB error"); + + // unplug and resize both dock widgets + unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow)); + unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow)); + + // Check hiding of undocked widgets + qCDebug(lcTestDockWidget) << "Hiding mainWindow with unplugged dock widgets" << mainWindow; + mainWindow->hide(); + QTRY_VERIFY(!mainWindow->isVisible()); + QTRY_VERIFY(d1->isVisible()); + QTRY_VERIFY(d2->isVisible()); + d1->hide(); + d2->hide(); + 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 + QSKIP("test requires -developer-build option"); +#endif // QT_BUILD_INTERNAL +} + +// 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 + if (QSysInfo::productType() == "rhel") + QSKIP("Memory leak on RHEL 9.2 QTBUG-124559", TestFailMode::Abort); + + // Create a mainwindow with a central widget and two dock widgets + 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)); + + // Create a floating tab and unplug it again + qCDebug(lcTestDockWidget) << "Move d1 over d2"; + 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 + //QTRY_VERIFY(!d1->isFloating()); + //QTRY_VERIFY(!d2->isFloating()); + if (d1->isFloating()) + qWarning("OS flakiness: D1 is docked and reports being floating"); + if (d2->isFloating()) + qWarning("OS flakiness: D2 is docked and reports being floating"); + + // Close everything with a single shot. Expected behavior: Event loop stops + QSignalSpy closeSpy(qApp, &QApplication::lastWindowClosed); + QObject localContext; + + QTimer::singleShot(0, &localContext, [&](){ + mainWindow->close(); + QTRY_VERIFY(!mainWindow->isVisible()); + QTRY_VERIFY(d1->isVisible()); + QTRY_VERIFY(d2->isVisible()); + d1->close(); + d2->close(); + QTRY_VERIFY(!d1->isVisible()); + QTRY_VERIFY(!d2->isVisible()); + QTRY_COMPARE(closeSpy.count(), 1); + QApplication::quit(); + }); + + QApplication::exec(); + + // Check heap cleanup + qCDebug(lcTestDockWidget) << "Deleting mainWindow"; + up_mainWindow.reset(); + QTRY_VERIFY(d1.isNull()); + QTRY_VERIFY(d2.isNull()); + QTRY_VERIFY(cent.isNull()); +#else + QSKIP("test requires -developer-build option"); +#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 +#ifdef QT_BUILD_INTERNAL + // Create a mainwindow with a central widget and two dock widgets + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + createTestWidgets(mainWindow, cent, d1, d2); + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + + /* + * Unplug both dock widgets from their dock areas and hover them over each other + * expected behavior: + * - d2 hovering over d1 does nothing as d2 can only use right dock + * - hovering d2 over top, left and bottom dock area will do nothing due to lacking permissions + * - d1 hovering over d2 will create floating tabs as d1 has permission for DockWidgetArea::FloatingDockWidgetArea + * - resizing and tab creation will add two gap items in the right dock (d2) + */ + + // unplug and resize both dock widgets + unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow)); + unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow)); + + // both dock widgets must be direct children of the main window + { + const QList<QDockWidget*> children = mainWindow->findChildren<QDockWidget*>(QString(), Qt::FindDirectChildrenOnly); + QTRY_VERIFY(children.size() == 2); + for (const QDockWidget* child : children) + QTRY_VERIFY(child == d1 || child == d2); + } + + // The main window must not contain floating tabs + QTRY_VERIFY(mainWindow->findChild<QDockWidgetGroupWindow*>() == nullptr); + + // Test unpermitted dock areas with d2 + qCDebug(lcTestDockWidget) << "*** move d2 to forbidden docks ***"; + + // 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), 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), QPoint(), MoveDockWidgetRule::Drop); + QTRY_VERIFY(d2->isFloating()); + + qCDebug(lcTestDockWidget) << "Move d2 to bottom dock"; + moveDockWidget(d2, dockPoint(mainWindow, Qt::BottomDockWidgetArea), QPoint(), MoveDockWidgetRule::Drop); + QTRY_VERIFY(d2->isFloating()); + + qCDebug(lcTestDockWidget) << "Waiting" << waitBeforeClose << "ms before closing."; + QTest::qWait(waitBeforeClose); +#else + QSKIP("test requires -developer-build option"); +#endif // QT_BUILD_INTERNAL +} + +/*! + \internal + + This test checks consistency of QMainWindow::saveState() / QMainWindow::restoreState(). + These methods (de)serialize dock widget properties via a QDataStream into a QByteArray. + + If the logic of (de)serializing Qt datatypes and classes changes, old settings can fail + to restore properly without triggering warnings or assertions. + + The test consists of two parts: + \list 1 + \li Read properties from a hard coded byte array and check if it is deserialized correctly. + \li Serialize properties into a \a QByteArray and check if it is serialized correctly. + \endlist +*/ +void tst_QDockWidget::saveAndRestore() +{ + 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 +#ifndef QT_BUILD_INTERNAL + QSKIP("test requires -developer-build option"); +#else + + // Hard coded byte array for test initialization + const QByteArray testArray = QByteArrayLiteral( + "\x00\x00\x00\xFF\x00\x00\x00\x00\xFD\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x05\xE8\xFC\x02\x00\x00\x00\x01\xFB\x00\x00\x00\x04\x00" + "D\x00" + "1\x03\x00\x00\x01\f\x00\x00\x00\x97\x00\x00\x02\x19\x00\x00\x01z\x00\x00\x00\x01\x00\x00\x00\x13\x00\x00\x05\xE8\xFC\x02\x00\x00\x00\x01\xFB\x00\x00\x00\x04\x00" + "D\x00" + "2\x03\x00\x00\x06L\x00\x00\x00\xFF\x00\x00\x01\f\x00\x00\x00\xE2\x00\x00\n\x80\x00\x00\x05\xE8\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\b\x00\x00\x00\b\xFC\x00\x00\x00\x00" + ); + + QByteArray referenceArray; // Copy of testArray, corrected for current screen limits + QPoint topLeft1; // Top left point of dock widget d1 + QPoint topLeft2; // Top left point of dock widget d2 + QSize widgetSize1; // Size of dock widget d1 + QSize widgetSize2; // Size of dock widget d2 + bool isFloating1; // Floating status of dock widget d1 + bool isFloating2; // Floating status of dock widget d2 + + // Create a mainwindow with a central widget and two dock widgets. + // Import properties from hard coded byte array. + // Use a scope to delete objects from screen after test. + { + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + createTestWidgets(mainWindow, cent, d1, d2); + + // Failure to restore properties might lead to inconsistencies and crash. + // To leave a clean environment when the test inexpectedly goes out of scope, + // => store main window pointer in a std::unique_ptr + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + + // Restore, wait for events to be processed + mainWindow->restoreState(testArray); + QVERIFY(QTest::qWaitForWindowExposed(d1)); + QVERIFY(QTest::qWaitForWindowExposed(d2)); + + // Serialized dock widget positions and sizes might be overridden due + // screen size limitations => do not check them here. + // If the test fails between here and scope end, serialization format/sequence have changed + QTRY_VERIFY(d1->isFloating()); + QTRY_VERIFY(d2->isFloating()); + + // Hide main window and save their floating status. + // Reason: + // - KDE window managers do not take control over dock widgets. + // => They always close with the main window. + // - Some non KDE window managers do take control over dock widgets. + // => They prevent them from closing with the main window (QTBUG-103474). + // If properties are restored correctly, closing behavior must be consistent + // throughout this test. + mainWindow->hide(); + // FIXME: No method exists in 6.5 to wait for a window to be hidden. + // => wait and hope the best, replace with qWaitForWindowHidden once implemented. + QTest::qWait(200); + isFloating1 = d1->isFloating(); + isFloating2 = d2->isFloating(); + } + + // Create a mainwindow with a central widget and two dock widgets. + // Assign different properties to each dock widgets. + // Write properties to a byte array. + // Remember position and size properties for comparison. + // Use a scope to delete objects from screen after test. + { + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + createTestWidgets(mainWindow, cent, d1, d2); + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + + // unplug, position and resize both dock widgets relative to screen size + unplugAndResize(mainWindow, d1, home1(mainWindow), size1(mainWindow)); + unplugAndResize(mainWindow, d2, home2(mainWindow), size2(mainWindow)); + + topLeft1 = d1->pos(); + topLeft2 = d2->pos(); + widgetSize1 = d1->size(); + widgetSize2 = d2->size(); + + // save properties, potentially corrected for screen limits + referenceArray = mainWindow->saveState(); + + // Check closing behavior consistency + mainWindow->hide(); + QTRY_VERIFY(d1->isFloating()); + QTRY_VERIFY(d2->isFloating()); + QCOMPARE(d1->isFloating(), isFloating1); + QCOMPARE(d2->isFloating(), isFloating2); + } + + // Create a new main window, central window and two dock widgets. + QPointer<QDockWidget> d1; + QPointer<QDockWidget> d2; + QPointer<QWidget> cent; + QMainWindow* mainWindow; + createTestWidgets(mainWindow, cent, d1, d2); + + // Failure to restore properties might lead to inconsistencies and crash. + // To leave a clean environment when the test inexpectedly goes out of scope, + // - store main window pointer in a std::unique_ptr + std::unique_ptr<QMainWindow> up_mainWindow(mainWindow); + + // Restore properties and wait for events to be processed + mainWindow->restoreState(referenceArray); + QVERIFY(QTest::qWaitForWindowExposed(d1)); + QVERIFY(QTest::qWaitForWindowExposed(d2)); + + // Compare positions, sizes and floating status + // If the test fails in the following 12 lines, + // the de-serialization format/sequence have changed + QCOMPARE(topLeft1, d1->pos()); + QCOMPARE(topLeft2, d2->pos()); + QCOMPARE(widgetSize1, d1->size()); + QCOMPARE(widgetSize2, d2->size()); + QVERIFY(d1->isFloating()); + QVERIFY(d2->isFloating()); + + // Serialize again to compare all remaining properties + const QByteArray comparisonArray = mainWindow->saveState(); + QCOMPARE(comparisonArray, referenceArray); + + // Check closing behavior consistency + mainWindow->hide(); + QTRY_VERIFY(d1->isFloating()); + QTRY_VERIFY(d2->isFloating()); + QCOMPARE(d1->isFloating(), isFloating1); + QCOMPARE(d2->isFloating(), isFloating2); + +#undef qCreateFloatingTabs +#endif // QT_BUILD_INTERNAL } QTEST_MAIN(tst_QDockWidget) diff --git a/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt b/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt index 6be779bb81..b023174dc9 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qdoublespinbox/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qdoublespinbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp index dd67de2287..999b5cac07 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp +++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -47,6 +22,8 @@ #include <QStyle> #include <QProxyStyle> +#include <QtWidgets/private/qapplication_p.h> + class DoubleSpinBox : public QDoubleSpinBox { Q_OBJECT @@ -880,8 +857,15 @@ void tst_QDoubleSpinBox::editingFinished() testFocusWidget.show(); testFocusWidget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&testFocusWidget)); + + box->show(); + QVERIFY(QTest::qWaitForWindowExposed(box)); box->setFocus(); - QTRY_VERIFY(box->hasFocus()); + + // Box may fail to acquire focus due to a system popup + // it is fair in that case to skip the test + if (!QTest::qWaitForWindowActive(box)) + QSKIP("Focus acquisition failed."); QSignalSpy editingFinishedSpy1(box, SIGNAL(editingFinished())); QSignalSpy editingFinishedSpy2(box2, SIGNAL(editingFinished())); @@ -890,37 +874,37 @@ void tst_QDoubleSpinBox::editingFinished() QTest::keyClick(box, Qt::Key_Up); - QCOMPARE(editingFinishedSpy1.count(), 0); - QCOMPARE(editingFinishedSpy2.count(), 0); + QCOMPARE(editingFinishedSpy1.size(), 0); + QCOMPARE(editingFinishedSpy2.size(), 0); QTest::keyClick(box2, Qt::Key_Up); QTest::keyClick(box2, Qt::Key_Up); box2->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); box->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 1); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Up); - QCOMPARE(editingFinishedSpy1.count(), 1); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Enter); - QCOMPARE(editingFinishedSpy1.count(), 2); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 2); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Return); - QCOMPARE(editingFinishedSpy1.count(), 3); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 3); + QCOMPARE(editingFinishedSpy2.size(), 1); box2->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box2, Qt::Key_Enter); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 2); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 2); QTest::keyClick(box2, Qt::Key_Return); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 3); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 3); testFocusWidget.hide(); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 4); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 4); } void tst_QDoubleSpinBox::removeAll() @@ -1170,7 +1154,6 @@ void tst_QDoubleSpinBox::taskQTBUG_5008_textFromValueAndValidate() spinbox.show(); spinbox.activateWindow(); spinbox.setFocus(); - QApplication::setActiveWindow(&spinbox); QVERIFY(QTest::qWaitForWindowActive(&spinbox)); QCOMPARE(static_cast<QWidget *>(&spinbox), QApplication::activeWindow()); QTRY_VERIFY(spinbox.hasFocus()); @@ -1776,12 +1759,12 @@ void tst_QDoubleSpinBox::stepModifierPressAndHold() QStyle::CC_SpinBox, &spinBoxStyleOption, subControl, &spin); QTest::mousePress(&spin, Qt::LeftButton, modifiers, buttonRect.center()); - QTRY_VERIFY(spy.length() >= 3); + QTRY_VERIFY(spy.size() >= 3); QTest::mouseRelease(&spin, Qt::LeftButton, modifiers, buttonRect.center()); const auto value = spy.last().at(0); QVERIFY(value.userType() == QMetaType::Double); - QCOMPARE(value.toDouble(), spy.length() * expectedStepModifier); + QCOMPARE(value.toDouble(), spy.size() * expectedStepModifier); } QTEST_MAIN(tst_QDoubleSpinBox) diff --git a/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt b/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt index d5e32e9337..5e2f3bd955 100644 --- a/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qfocusframe/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qfocusframe.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp b/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp index d273d77e35..560ba686cc 100644 --- a/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp +++ b/tests/auto/widgets/widgets/qfocusframe/tst_qfocusframe.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -95,7 +70,7 @@ void tst_QFocusFrame::focusFrameInsideScrollview() window.show(); QFocusFrame *focusFrame = nullptr; - QTRY_VERIFY(focusFrame = window.findChild<QFocusFrame *>()); + QTRY_VERIFY((focusFrame = window.findChild<QFocusFrame *>())); const QPoint initialOffset = focusFrame->widget()->mapToGlobal(QPoint()) - focusFrame->mapToGlobal(QPoint()); tableView.scrollTo(itemModel->index(40, 0)); diff --git a/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt b/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt index 869666cb19..15dad99b9c 100644 --- a/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qfontcombobox/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qfontcombobox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp index a521b96e21..abb9262288 100644 --- a/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp +++ b/tests/auto/widgets/widgets/qfontcombobox/tst_qfontcombobox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -102,7 +77,7 @@ void tst_QFontComboBox::currentFont_data() if (!QFontDatabase::isPrivateFamily(defaultFont.family())) QTest::newRow("default2") << defaultFont; QStringList list = QFontDatabase::families(); - for (int i = 0; i < list.count(); ++i) { + for (int i = 0; i < list.size(); ++i) { QFont f = QFont(QStringList{QFontInfo(QFont(list.at(i))).family()}); if (!QFontDatabase::isPrivateFamily(f.families().first())) QTest::newRow(qPrintable(list.at(i))) << f; @@ -130,7 +105,7 @@ void tst_QFontComboBox::currentFont() if (oldCurrentFont != box.currentFont()) { //the signal may be emit twice if there is a foundry into brackets - QCOMPARE(spy0.count(),1); + QCOMPARE(spy0.size(),1); } } @@ -180,7 +155,7 @@ void tst_QFontComboBox::fontFilters() if((fontFilters & spacingMask) == spacingMask) fontFilters &= ~spacingMask; - for (int i = 0; i < list.count(); ++i) { + for (int i = 0; i < list.size(); ++i) { if (QFontDatabase::isPrivateFamily(list[i])) continue; if (fontFilters & QFontComboBox::ScalableFonts) { @@ -205,7 +180,7 @@ void tst_QFontComboBox::fontFilters() if (c == 0) QCOMPARE(box.currentFont(), QFont()); - QCOMPARE(spy0.count(), (currentFont != box.currentFont()) ? 1 : 0); + QCOMPARE(spy0.size(), (currentFont != box.currentFont()) ? 1 : 0); } // public QSize sizeHint() const @@ -246,17 +221,17 @@ void tst_QFontComboBox::writingSystem() QCOMPARE(box.writingSystem(), writingSystem); QStringList list = QFontDatabase::families(writingSystem); - int c = list.count(); - for (int i = 0; i < list.count(); ++i) { + int c = list.size(); + for (int i = 0; i < list.size(); ++i) { if (QFontDatabase::isPrivateFamily(list[i])) c--; } QCOMPARE(box.model()->rowCount(), c); - if (list.count() == 0) + if (list.size() == 0) QCOMPARE(box.currentFont(), QFont()); - QCOMPARE(spy0.count(), (currentFont != box.currentFont()) ? 1 : 0); + QCOMPARE(spy0.size(), (currentFont != box.currentFont()) ? 1 : 0); } // protected void currentFontChanged(QFont const& f) @@ -270,11 +245,11 @@ void tst_QFontComboBox::currentFontChanged() if (box->model()->rowCount() > 2) { QTest::keyPress(box, Qt::Key_Down); - QCOMPARE(spy0.count(), 1); + QCOMPARE(spy0.size(), 1); QFont f( "Sans Serif" ); box->setCurrentFont(f); - QCOMPARE(spy0.count(), 2); + QCOMPARE(spy0.size(), 2); } else qWarning("Not enough fonts installed on test system. Consider adding some"); } diff --git a/tests/auto/widgets/widgets/qframe/BLACKLIST b/tests/auto/widgets/widgets/qframe/BLACKLIST deleted file mode 100644 index 3a28dd1239..0000000000 --- a/tests/auto/widgets/widgets/qframe/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-69064 -[testPainting] -android diff --git a/tests/auto/widgets/widgets/qframe/CMakeLists.txt b/tests/auto/widgets/widgets/qframe/CMakeLists.txt index 968f9ac3f3..2213f4a7d9 100644 --- a/tests/auto/widgets/widgets/qframe/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qframe/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qframe.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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} @@ -11,10 +18,10 @@ file(GLOB_RECURSE test_data_glob list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qframe - LOWDPI # special case + LOWDPI SOURCES tst_qframe.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets TESTDATA ${test_data} diff --git a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp index b5272f6b1a..324c512219 100644 --- a/tests/auto/widgets/widgets/qframe/tst_qframe.cpp +++ b/tests/auto/widgets/widgets/qframe/tst_qframe.cpp @@ -1,31 +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> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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 #include <QTest> #include <QFrame> @@ -173,7 +148,16 @@ void tst_QFrame::testPainting() frame.setMidLineWidth(midLineWidth); frame.resize(16, 16); - const QPixmap pixmap = frame.grab(); + QPixmap pixmap = frame.grab(); +#ifdef Q_OS_ANDROID + // QPixmap is created with system's default format, which is + // ARGB32_Premultiplied for Android. For desktop systems the format is + // RGB32, so that's also the format of the images in resources. So on + // Android we need to explicitly convert the pixmap to a proper format. + QImage img = pixmap.toImage(); + QVERIFY(img.reinterpretAsFormat(QImage::Format_RGB32)); + pixmap = QPixmap::fromImage(img); +#endif const QString fileName = QLatin1String("images/") + basename + QLatin1Char('_') + QString::number(lineWidth) + QLatin1Char('_') + QString::number(midLineWidth) diff --git a/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt b/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt index ed08cce5f2..0414ce0cf5 100644 --- a/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qgroupbox/CMakeLists.txt @@ -1,13 +1,22 @@ -# Generated from qgroupbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui + Qt::GuiPrivate Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp index b9def66f7c..b178707e7a 100644 --- a/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp +++ b/tests/auto/widgets/widgets/qgroupbox/tst_qgroupbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -36,6 +11,11 @@ #include <QDialog> #include <QSignalSpy> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformtheme.h> + +#include <QtWidgets/private/qapplication_p.h> + #include "qgroupbox.h" class tst_QGroupBox : public QObject @@ -70,6 +50,7 @@ private slots: void propagateFocus(); void task_QTBUG_19170_ignoreMouseReleaseEvent(); void task_QTBUG_15519_propagateMouseEvents(); + void buttonPressKeys(); private: bool checked; @@ -392,8 +373,8 @@ void tst_QGroupBox::clicked() else QTest::mouseClick(&testWidget, Qt::LeftButton); - QTEST(int(spy.count()), "clickedCount"); - if (spy.count() > 0) + QTEST(int(spy.size()), "clickedCount"); + if (spy.size() > 0) QTEST(spy.at(0).at(0).toBool(), "finalCheck"); QTEST(testWidget.isChecked(), "finalCheck"); } @@ -407,9 +388,9 @@ void tst_QGroupBox::toggledVsClicked() QSignalSpy clickSpy(&groupBox, SIGNAL(clicked(bool))); groupBox.setChecked(!groupBox.isChecked()); - QCOMPARE(clickSpy.count(), 0); - QCOMPARE(toggleSpy.count(), 1); - if (toggleSpy.count() > 0) + QCOMPARE(clickSpy.size(), 0); + QCOMPARE(toggleSpy.size(), 1); + if (toggleSpy.size() > 0) QCOMPARE(toggleSpy.at(0).at(0).toBool(), groupBox.isChecked()); connect(&groupBox, SIGNAL(clicked(bool)), this, SLOT(clickTimestampSlot())); @@ -422,8 +403,8 @@ void tst_QGroupBox::toggledVsClicked() QStyle::SC_GroupBoxCheckBox, &groupBox); QTest::mouseClick(&groupBox, Qt::LeftButton, {}, rect.center()); - QCOMPARE(clickSpy.count(), 1); - QCOMPARE(toggleSpy.count(), 2); + QCOMPARE(clickSpy.size(), 1); + QCOMPARE(toggleSpy.size(), 2); QVERIFY(toggleTimeStamp < clickTimeStamp); } @@ -449,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)); @@ -457,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)); @@ -465,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)); @@ -481,7 +462,6 @@ void tst_QGroupBox::propagateFocus() QGroupBox box; QLineEdit lineEdit(&box); box.show(); - QApplication::setActiveWindow(&box); QVERIFY(QTest::qWaitForWindowActive(&box)); box.setFocus(); QTRY_COMPARE(qApp->focusWidget(), static_cast<QWidget*>(&lineEdit)); @@ -611,10 +591,25 @@ void tst_QGroupBox::task_QTBUG_15519_propagateMouseEvents() QCOMPARE(parent.mouseMoved, true); } +void tst_QGroupBox::buttonPressKeys() +{ + QGroupBox groupBox; + groupBox.setCheckable(true); + QSignalSpy clickedSpy(&groupBox, &QGroupBox::clicked); + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + for (int i = 0; i < buttonPressKeys.size(); ++i) { + QTest::keyClick(&groupBox, buttonPressKeys[i]); + QCOMPARE(clickedSpy.size(), i + 1); + } +} + void tst_QGroupBox::sendMouseMoveEvent(QWidget *widget, const QPoint &localPos) { // Send a MouseMove event without actually moving the pointer - QMouseEvent event(QEvent::MouseMove, localPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier); + QMouseEvent event(QEvent::MouseMove, localPos, widget->mapToGlobal(localPos), + Qt::NoButton, Qt::NoButton, Qt::NoModifier); QApplication::sendEvent(widget, &event); } diff --git a/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt b/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt index a016280b5d..0cf0b1bdd3 100644 --- a/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qkeysequenceedit/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qkeysequenceedit.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp b/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp index 1a0532ffa4..301be319bf 100644 --- a/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp +++ b/tests/auto/widgets/widgets/qkeysequenceedit/tst_qkeysequenceedit.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -45,6 +20,9 @@ private slots: void testKeys_data(); void testKeys(); void testLineEditContents(); + void testMaximumSequenceLength(); + void testFinishingKeyCombinations_data(); + void testFinishingKeyCombinations(); }; void tst_QKeySequenceEdit::testSetters() @@ -59,7 +37,7 @@ void tst_QKeySequenceEdit::testSetters() edit.clear(); QCOMPARE(edit.keySequence(), QKeySequence()); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); } void tst_QKeySequenceEdit::testKeys_data() @@ -74,6 +52,42 @@ void tst_QKeySequenceEdit::testKeys_data() QTest::newRow("4") << Qt::Key_N << Qt::KeyboardModifiers(Qt::ControlModifier | Qt::ShiftModifier) << QKeySequence("Ctrl+Shift+N"); } +void tst_QKeySequenceEdit::testMaximumSequenceLength() +{ + // + // GIVEN: + // - A QKeySequenceEdit with maxKeyCount == 1 + // - A QKeySequence with more than one key + // + QKeySequenceEdit edit; + edit.setMaximumSequenceLength(1); + QCOMPARE(edit.maximumSequenceLength(), 1); + + QKeySequence multi("Ctrl+X, S"); + QCOMPARE(multi.count(), 2); + + // + // WHEN: setting the key sequence on the edit + // + QTest::ignoreMessage(QtWarningMsg, + "QKeySequenceEdit: setting a key sequence of length 2 when " + "maximumSequenceLength is 1, truncating."); + edit.setKeySequence(multi); + + // + // THEN: + // - the maxKeyCount property doesn't change + // - the key sequence is truncated to maxKeyCount + // - and won't un-truncate by increasing maxKeyCount + // + QCOMPARE(edit.maximumSequenceLength(), 1); + const auto edited = edit.keySequence(); + QCOMPARE(edited.count(), 1); + QCOMPARE(edited, QKeySequence("Ctrl+X")); + edit.setMaximumSequenceLength(2); + QCOMPARE(edit.keySequence(), edited); +} + void tst_QKeySequenceEdit::testKeys() { QFETCH(Qt::Key, key); @@ -85,9 +99,9 @@ void tst_QKeySequenceEdit::testKeys() QTest::keyPress(&edit, key, modifiers); QTest::keyRelease(&edit, key, modifiers); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QCOMPARE(edit.keySequence(), keySequence); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); } void tst_QKeySequenceEdit::testLineEditContents() @@ -111,5 +125,43 @@ void tst_QKeySequenceEdit::testLineEditContents() QCOMPARE(le->text(), QString()); } +void tst_QKeySequenceEdit::testFinishingKeyCombinations_data() +{ + QTest::addColumn<Qt::Key>("key"); + QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); + QTest::addColumn<QKeySequence>("keySequence"); + + QTest::newRow("1") << Qt::Key_Backtab << Qt::KeyboardModifiers(Qt::NoModifier) << QKeySequence("Backtab"); + QTest::newRow("2") << Qt::Key_Tab << Qt::KeyboardModifiers(Qt::NoModifier) << QKeySequence("Tab"); + QTest::newRow("3") << Qt::Key_Return << Qt::KeyboardModifiers(Qt::NoModifier) << QKeySequence("Return"); + QTest::newRow("4") << Qt::Key_Enter << Qt::KeyboardModifiers(Qt::NoModifier) << QKeySequence("Enter"); + QTest::newRow("5") << Qt::Key_Enter << Qt::KeyboardModifiers(Qt::ShiftModifier) << QKeySequence("Shift+Enter"); +} + +void tst_QKeySequenceEdit::testFinishingKeyCombinations() +{ + QFETCH(Qt::Key, key); + QFETCH(Qt::KeyboardModifiers, modifiers); + QFETCH(QKeySequence, keySequence); + QKeySequenceEdit edit; + + QSignalSpy spy(&edit, SIGNAL(editingFinished())); + QCOMPARE(spy.size(), 0); + + edit.setFinishingKeyCombinations({QKeyCombination(modifiers, key)}); + QTest::keyPress(&edit, key, modifiers); + QTest::keyRelease(&edit, key, modifiers); + + QCOMPARE(edit.keySequence(), QKeySequence()); + QTRY_COMPARE(spy.size(), 1); + + edit.setFinishingKeyCombinations({}); + QTest::keyPress(&edit, key, modifiers); + QTest::keyRelease(&edit, key, modifiers); + + QCOMPARE(edit.keySequence(), keySequence); + QTRY_COMPARE(spy.size(), 2); +} + QTEST_MAIN(tst_QKeySequenceEdit) #include "tst_qkeysequenceedit.moc" diff --git a/tests/auto/widgets/widgets/qlabel/CMakeLists.txt b/tests/auto/widgets/widgets/qlabel/CMakeLists.txt index bbd51a206c..e29000a6ca 100644 --- a/tests/auto/widgets/widgets/qlabel/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qlabel/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qlabel.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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} @@ -17,7 +24,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qlabel SOURCES tst_qlabel.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_data0.qsnap Binary files differdeleted file mode 100644 index 522c173ac4..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index acd881d29a..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/acc_01/res_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 9e2c1764d3..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data1.qsnap Binary files differdeleted file mode 100644 index dcd708fdbf..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data10.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data10.qsnap Binary files differdeleted file mode 100644 index 2131f59fe9..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data10.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data2.qsnap Binary files differdeleted file mode 100644 index 2edd976830..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data3.qsnap Binary files differdeleted file mode 100644 index 2ce28d9816..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data4.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data4.qsnap Binary files differdeleted file mode 100644 index 6476f6c26b..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data4.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data5.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data5.qsnap Binary files differdeleted file mode 100644 index 6039742962..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data5.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data6.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data6.qsnap Binary files differdeleted file mode 100644 index 477d203960..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data6.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data7.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data7.qsnap Binary files differdeleted file mode 100644 index c673f4099e..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data7.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data8.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data8.qsnap Binary files differdeleted file mode 100644 index a490f77118..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data8.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data9.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data9.qsnap Binary files differdeleted file mode 100644 index 33342d3616..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Motif_data9.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data0.qsnap Binary files differdeleted file mode 100644 index 3fe9a82c2f..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data1.qsnap Binary files differdeleted file mode 100644 index 175235dc38..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data10.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data10.qsnap Binary files differdeleted file mode 100644 index b1ac74b531..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data10.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data2.qsnap Binary files differdeleted file mode 100644 index fdd3c7c701..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data3.qsnap Binary files differdeleted file mode 100644 index caa47f7292..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data4.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data4.qsnap Binary files differdeleted file mode 100644 index a0d2498e76..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data4.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data5.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data5.qsnap Binary files differdeleted file mode 100644 index 756d9fe827..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data5.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data6.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data6.qsnap Binary files differdeleted file mode 100644 index f973d14c38..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data6.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data7.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data7.qsnap Binary files differdeleted file mode 100644 index 720d807db2..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data7.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data8.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data8.qsnap Binary files differdeleted file mode 100644 index 20fd48e7cc..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data8.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data9.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data9.qsnap Binary files differdeleted file mode 100644 index 7db7c97a14..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_data9.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index d9912d8c92..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data1.qsnap Binary files differdeleted file mode 100644 index bfc3a6488e..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data10.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data10.qsnap Binary files differdeleted file mode 100644 index 09a35ef761..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data10.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data2.qsnap Binary files differdeleted file mode 100644 index 14e11232f0..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data3.qsnap Binary files differdeleted file mode 100644 index 6ef864e635..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data4.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data4.qsnap Binary files differdeleted file mode 100644 index eb029008e3..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data4.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data5.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data5.qsnap Binary files differdeleted file mode 100644 index 439e196b57..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data5.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data6.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data6.qsnap Binary files differdeleted file mode 100644 index 9637d1741a..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data6.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data7.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data7.qsnap Binary files differdeleted file mode 100644 index 9a553465c3..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data7.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data8.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data8.qsnap Binary files differdeleted file mode 100644 index 0d9184c316..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data8.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data9.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data9.qsnap Binary files differdeleted file mode 100644 index f2873b1c78..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setAlignment/alignRes_Windows_win32_data9.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 1385a50d38..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data1.qsnap Binary files differdeleted file mode 100644 index 38223cfba2..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data2.qsnap Binary files differdeleted file mode 100644 index 0b946a4968..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Motif_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data0.qsnap Binary files differdeleted file mode 100644 index e1d2c41d88..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data1.qsnap Binary files differdeleted file mode 100644 index b7bdee551b..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data2.qsnap Binary files differdeleted file mode 100644 index a20492ee70..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index 85e3306d0c..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data1.qsnap Binary files differdeleted file mode 100644 index 3bf991f674..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data2.qsnap Binary files differdeleted file mode 100644 index f05a9dcebd..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setIndent/indentRes_Windows_win32_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Motif_data0.qsnap Binary files differdeleted file mode 100644 index d7428df5ef..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_data0.qsnap Binary files differdeleted file mode 100644 index 905acd1283..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index e1dea4b76b..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 055ccda47e..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_data0.qsnap Binary files differdeleted file mode 100644 index 64b70763d4..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index fb0ea227ad..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/empty_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Motif_data0.qsnap Binary files differdeleted file mode 100644 index ae9cda541f..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_data0.qsnap Binary files differdeleted file mode 100644 index e21af3223a..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index 32cc40652b..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setPixmap/scaledVpix_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 7191b517d2..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data1.qsnap Binary files differdeleted file mode 100644 index d943ce960a..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data2.qsnap Binary files differdeleted file mode 100644 index 946432e66d..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data3.qsnap Binary files differdeleted file mode 100644 index dc5ac0c56d..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Motif_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data0.qsnap Binary files differdeleted file mode 100644 index 2ab392e50e..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data1.qsnap Binary files differdeleted file mode 100644 index 5769459ab6..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data2.qsnap Binary files differdeleted file mode 100644 index b4206c2a57..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data3.qsnap Binary files differdeleted file mode 100644 index f120ac2e76..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index 7644f53726..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data1.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data1.qsnap Binary files differdeleted file mode 100644 index 7902b1b087..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data1.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data2.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data2.qsnap Binary files differdeleted file mode 100644 index 60bd075c78..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data2.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data3.qsnap b/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data3.qsnap Binary files differdeleted file mode 100644 index c1dcb272b3..0000000000 --- a/tests/auto/widgets/widgets/qlabel/testdata/setText/res_Windows_win32_data3.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp index ad4f8e04bc..325e188091 100644 --- a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp +++ b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -38,10 +13,13 @@ #include <qmovie.h> #include <qpicture.h> #include <qmessagebox.h> +#include <qsizepolicy.h> #include <qfontmetrics.h> #include <qmath.h> #include <private/qlabel_p.h> +#include <QtWidgets/private/qapplication_p.h> + class Widget : public QWidget { Q_OBJECT @@ -75,6 +53,7 @@ private Q_SLOTS: #endif void setNum(); void clear(); + void wordWrap_data(); void wordWrap(); void eventPropagation_data(); void eventPropagation(); @@ -98,12 +77,16 @@ private Q_SLOTS: #ifndef QT_NO_CONTEXTMENU void taskQTBUG_7902_contextMenuCrash(); + void contextMenu_data(); + void contextMenu(); #endif void taskQTBUG_48157_dprPixmap(); void taskQTBUG_48157_dprMovie(); void resourceProvider(); + void mouseEventPropagation_data(); + void mouseEventPropagation(); private: QLabel *testWidget; @@ -115,16 +98,12 @@ private: void tst_QLabel::getSetCheck() { QLabel obj1; - // bool QLabel::wordWrap() - // void QLabel::setWordWrap(bool) obj1.setWordWrap(false); - QCOMPARE(false, obj1.wordWrap()); + QVERIFY(!obj1.wordWrap()); obj1.setWordWrap(true); - QCOMPARE(true, obj1.wordWrap()); + QVERIFY(obj1.wordWrap()); #if QT_CONFIG(shortcut) - // QWidget * QLabel::buddy() - // void QLabel::setBuddy(QWidget *) QWidget *var2 = new QWidget(); obj1.setBuddy(var2); QCOMPARE(var2, obj1.buddy()); @@ -133,8 +112,6 @@ void tst_QLabel::getSetCheck() delete var2; #endif // QT_CONFIG(shortcut) - // QMovie * QLabel::movie() - // void QLabel::setMovie(QMovie *) QMovie *var3 = new QMovie; obj1.setMovie(var3); QCOMPARE(var3, obj1.movie()); @@ -194,7 +171,7 @@ void tst_QLabel::setBuddy() layout->addWidget(test_edit); layout->addWidget(test_edit2); test_box->show(); - qApp->setActiveWindow(test_box); + QApplicationPrivate::setActiveWindow(test_box); QVERIFY(test_box->isActiveWindow()); test_label->setBuddy( test_edit ); @@ -274,21 +251,36 @@ void tst_QLabel::clear() QVERIFY(testWidget->text().isEmpty()); } +void tst_QLabel::wordWrap_data() +{ + QTest::addColumn<QString>("text"); + + QTest::newRow("Plain text") << "Plain text1"; + QTest::newRow("Rich text") << "<b>Rich text</b>"; + QTest::newRow("Long text") + << "This is a very long text to check that QLabel " + "does not wrap, even if the text would require wrapping to be fully displayed"; +} + void tst_QLabel::wordWrap() { - QLabel label; + QFETCH(QString, text); + QLabel label; + label.setText(text); QVERIFY(!label.wordWrap()); + QVERIFY(!label.sizePolicy().hasHeightForWidth()); - label.setText("Plain Text"); - QVERIFY(!label.wordWrap()); + const QSize unWrappedSizeHint = label.sizeHint(); - label.setText("<b>rich text</b>"); - QVERIFY(!label.wordWrap()); + label.setWordWrap(true); + QVERIFY(label.sizePolicy().hasHeightForWidth()); + + if (text.size() > 1 && text.contains(" ")) { + const int wrappedHeight = label.heightForWidth(unWrappedSizeHint.width() / 2); + QVERIFY(wrappedHeight > unWrappedSizeHint.height()); + } - label.setWordWrap(false); - label.setText("<b>rich text</b>"); - QVERIFY(!label.wordWrap()); } void tst_QLabel::eventPropagation_data() @@ -439,7 +431,6 @@ void tst_QLabel::emptyPixmap() void tst_QLabel::unicodeText_data() { QTest::addColumn<QString>("text"); - QTest::addColumn<QString>("languageName"); /* The "glass" phrase in Thai was the initial report for bug QTBUG-4848, was @@ -456,25 +447,21 @@ void tst_QLabel::unicodeText_data() speech, also translated using http://translate.google.com. */ - QTest::newRow("english") << QString::fromUtf8("I can eat glass and it doesn't hurt me.") << QString("english"); - QTest::newRow("thai") << QString::fromUtf8("ฉันจะกินแก้วและไม่เจ็บฉัน") << QString("thai"); - QTest::newRow("chinese") << QString::fromUtf8("我可以吃玻璃,并没有伤害我。") << QString("chinese"); - QTest::newRow("arabic") << QString::fromUtf8("أستطيع أكل الزجاج ، وأنه لا يؤذيني.") << QString("arabic"); - QTest::newRow("russian") << QString::fromUtf8("Я могу есть стекло, и не больно.") << QString("russian"); - QTest::newRow("korean") << QString::fromUtf8("유리를 먹을 수있는, 그리고 그게 날 다치게하지 않습니다.") << QString("korean"); - QTest::newRow("greek") << QString::fromUtf8("Μπορώ να φάτε γυαλί και δεν μου κάνει κακό.") << QString("greek"); - QTest::newRow("german") << QString::fromUtf8("Ich kann Glas essen und es macht mich nicht heiß.") << QString("german"); - + QTest::newRow("english") << QString::fromUtf8("I can eat glass and it doesn't hurt me."); + QTest::newRow("thai") << QString::fromUtf8("ฉันจะกินแก้วและไม่เจ็บฉัน"); + QTest::newRow("chinese") << QString::fromUtf8("我可以吃玻璃,并没有伤害我。"); + QTest::newRow("arabic") << QString::fromUtf8("أستطيع أكل الزجاج ، وأنه لا يؤذيني."); + QTest::newRow("russian") << QString::fromUtf8("Я могу есть стекло, и не больно."); + QTest::newRow("korean") << QString::fromUtf8("유리를 먹을 수있는, 그리고 그게 날 다치게하지 않습니다."); + QTest::newRow("greek") << QString::fromUtf8("Μπορώ να φάτε γυαλί και δεν μου κάνει κακό."); + QTest::newRow("german") << QString::fromUtf8("Ich kann Glas essen und es macht mich nicht heiß."); QTest::newRow("thai_long") << QString::fromUtf8("เราจะต่อสู้ในทะเลและมหาสมุทร. เราจะต่อสู้ด้วยความมั่นใจเติบโตและความเจริญเติบโตในอากาศเราจะปกป้องเกาะของเราค่าใช้จ่ายใดๆอาจ." - "เราจะต่อสู้บนชายหาดเราจะต่อสู้ในบริเวณเชื่อมโยงไปถึงเราจะต่อสู้ในช่องและในถนนที่เราจะต่อสู้ในภูเขานั้นเราจะไม่ยอม.") - << QString("thai_long"); + "เราจะต่อสู้บนชายหาดเราจะต่อสู้ในบริเวณเชื่อมโยงไปถึงเราจะต่อสู้ในช่องและในถนนที่เราจะต่อสู้ในภูเขานั้นเราจะไม่ยอม."); } void tst_QLabel::unicodeText() { - const QString testDataPath("testdata/unicodeText"); QFETCH(QString, text); - QFETCH(QString, languageName); QFrame frame; QVBoxLayout *layout = new QVBoxLayout(); QLabel *label = new QLabel(text, &frame); @@ -569,12 +556,50 @@ void tst_QLabel::taskQTBUG_7902_contextMenuCrash() w->connect(&ti, SIGNAL(timeout()), w, SLOT(deleteLater())); ti.start(300); - QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center()); + QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center(), + w->mapToGlobal(w->rect().center())); qApp->postEvent(w, cme); 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() @@ -616,5 +641,94 @@ void tst_QLabel::resourceProvider() QVERIFY(providerCalled > 0); } +// Test if mouse events are correctly propagated to the parent widget, +// even if a label contains rich text (QTBUG-110055) +void tst_QLabel::mouseEventPropagation_data() +{ + QTest::addColumn<const QString>("text"); + QTest::addColumn<const Qt::TextInteractionFlag>("interaction"); + QTest::addColumn<const QList<Qt::MouseButton>>("buttons"); + QTest::addColumn<const bool>("expectPropagation"); + + + QTest::newRow("RichText") + << QString("<b>This is a rich text propagating mouse events</b>") + << Qt::LinksAccessibleByMouse + << QList<Qt::MouseButton>{Qt::LeftButton, Qt::RightButton, Qt::MiddleButton} + << true; + QTest::newRow("PlainText") + << QString("This is a plain text propagating mouse events") + << Qt::LinksAccessibleByMouse + << QList<Qt::MouseButton>{Qt::LeftButton, Qt::RightButton, Qt::MiddleButton} + << true; + QTest::newRow("PlainTextConsume") + << QString("This is a plain text consuming mouse events") + << Qt::TextSelectableByMouse + << QList<Qt::MouseButton>{Qt::LeftButton} + << false; + QTest::newRow("RichTextConsume") + << QString("<b>This is a rich text consuming mouse events</b>") + << Qt::TextSelectableByMouse + << QList<Qt::MouseButton>{Qt::LeftButton} + << false; + QTest::newRow("PlainTextNoInteraction") + << QString("This is a text not interacting with mouse") + << Qt::NoTextInteraction + << QList<Qt::MouseButton>{Qt::LeftButton, Qt::RightButton, Qt::MiddleButton} + << true; + QTest::newRow("RichTextNoInteraction") + << QString("<b>This is a rich text not interacting with mouse</b>") + << Qt::NoTextInteraction + << QList<Qt::MouseButton>{Qt::LeftButton, Qt::RightButton, Qt::MiddleButton} + << true; +} + +void tst_QLabel::mouseEventPropagation() +{ + class MouseEventWidget : public QWidget + { + public: + uint pressed() const { return m_pressed; } + uint released() const { return m_released; } + + private: + uint m_pressed = 0; + uint m_released = 0; + void mousePressEvent(QMouseEvent *event) override + { + ++m_pressed; + return QWidget::mousePressEvent(event); + } + + void mouseReleaseEvent(QMouseEvent *event) override + { + ++m_released; + return QWidget::mouseReleaseEvent(event); + } + }; + + QFETCH(const QString, text); + QFETCH(const Qt::TextInteractionFlag, interaction); + QFETCH(const QList<Qt::MouseButton>, buttons); + QFETCH(const bool, expectPropagation); + + MouseEventWidget widget; + auto *layout = new QVBoxLayout(&widget); + auto *label = new QLabel(text); + label->setTextInteractionFlags(interaction); + + layout->addWidget(label); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + const QPoint labelCenter = label->rect().center(); + for (Qt::MouseButton mouseButton : buttons) + QTest::mouseClick(label, mouseButton, Qt::KeyboardModifiers(), labelCenter); + + const uint count = expectPropagation ? buttons.count() : 0; + QTRY_COMPARE(widget.pressed(), count); + QTRY_COMPARE(widget.released(), count); +} + QTEST_MAIN(tst_QLabel) #include "tst_qlabel.moc" diff --git a/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt b/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt index 4d6a8ff77a..954ec095e5 100644 --- a/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qlcdnumber/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qlcdnumber.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp b/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp index a97a090ebd..8fcf9c49fe 100644 --- a/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp +++ b/tests/auto/widgets/widgets/qlcdnumber/tst_qlcdnumber.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> diff --git a/tests/auto/widgets/widgets/qlineedit/BLACKLIST b/tests/auto/widgets/widgets/qlineedit/BLACKLIST index 9f87a6d921..a459495d1a 100644 --- a/tests/auto/widgets/widgets/qlineedit/BLACKLIST +++ b/tests/auto/widgets/widgets/qlineedit/BLACKLIST @@ -3,13 +3,7 @@ android [leftKeyOnSelectedText] android -[cutWithoutSelection] -android -[inlineCompletion] -android [textMargin] android -[task210502_caseInsensitiveInlineCompletion] -android [testQuickSelectionWithMouse] android diff --git a/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt b/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt index 8cdee2a111..22ecf40aed 100644 --- a/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qlineedit/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qlineedit.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate @@ -20,6 +27,6 @@ qt_internal_add_test(tst_qlineedit ##################################################################### qt_internal_extend_target(tst_qlineedit CONDITION MACOS - PUBLIC_LIBRARIES + LIBRARIES ${FWAppKit} ) diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index d6c6211e01..7a63c156f3 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -292,6 +267,8 @@ private slots: void inputMethodQueryImHints_data(); void inputMethodQueryImHints(); + void inputMethodQueryEnterKeyType(); + void inputMethodUpdate(); void undoRedoAndEchoModes_data(); @@ -315,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(); @@ -677,7 +661,7 @@ void tst_QLineEdit::setInputMask() testWidget->insert(input); } else { psKeyClick(testWidget, Qt::Key_Home); - for (int i=0; i<input.length(); i++) + for (int i=0; i<input.size(); i++) QTest::keyClick(testWidget, input.at(i).toLatin1()); } @@ -944,8 +928,8 @@ void tst_QLineEdit::hasAcceptableInputValidator() qApp->sendEvent(testWidget, &lostFocus); QVERIFY(testWidget->hasAcceptableInput()); - QCOMPARE(spyChanged.count(), 2); - QCOMPARE(spyEdited.count(), 0); + QCOMPARE(spyChanged.size(), 2); + QCOMPARE(spyEdited.size(), 0); } @@ -1617,7 +1601,7 @@ void tst_QLineEdit::setText() QSignalSpy editedSpy(testWidget, SIGNAL(textEdited(QString))); QSignalSpy changedSpy(testWidget, SIGNAL(textChanged(QString))); testWidget->setText("hello"); - QCOMPARE(editedSpy.count(), 0); + QCOMPARE(editedSpy.size(), 0); QCOMPARE(changedSpy.value(0).value(0).toString(), QString("hello")); } @@ -1689,7 +1673,7 @@ void tst_QLineEdit::displayText_data() QString input; QString pass; input = "Hello World"; - pass.resize(input.length()); + pass.resize(input.size()); pass.fill(passChar); QTest::newRow(QString(s + " text0").toLatin1()) << input << pass << m << bool(use_setText); QTest::newRow(QString(s + " text1").toLatin1()) << QString("") << @@ -1697,14 +1681,14 @@ void tst_QLineEdit::displayText_data() m << bool(use_setText); QTest::newRow(QString(s + " text2").toLatin1()) << QString("A") << QString(passChar) << m << bool(use_setText); input = QString("ryyryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryryrryryryryryryryryryryryryry"); - pass.resize(input.length()); + pass.resize(input.size()); pass.fill(passChar); QTest::newRow(QString(s + " text3").toLatin1()) << input << pass << m << bool(use_setText); input = QString("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890`~!@#$%^&*()_-+={[}]|\\:;'?/>.<,\""); - pass.fill(passChar, input.length()); + pass.fill(passChar, input.size()); QTest::newRow(QString(s + " text4").toLatin1()) << input << pass << m << bool(use_setText); input = QString("Hello") + QChar(0xa0) + "World"; - pass.resize(input.length()); + pass.resize(input.size()); pass.fill(passChar); QTest::newRow(QString(s + " text with nbsp").toLatin1()) << input << pass << m << bool(use_setText); } @@ -2317,7 +2301,7 @@ void tst_QLineEdit::deleteSelectedText() #ifndef QT_NO_CONTEXTMENU QMenu *menu = edit.createStandardContextMenu(); - for (int i = 0; i < menu->actions().count(); ++i) { + for (int i = 0; i < menu->actions().size(); ++i) { QAction *current = menu->actions().at(i); if (current->text() == QLineEdit::tr("Delete")) { current->trigger(); //this will delete the whole text selected @@ -2450,7 +2434,7 @@ class QIntFixValidator : public QIntValidator { public: QIntFixValidator(int min, int max, QObject *parent) : QIntValidator(min, max, parent) {} void fixup (QString &input) const override { - for (int i=0; i<input.length(); ++i) + for (int i=0; i<input.size(); ++i) if (!input.at(i).isNumber()) { input[(int)i] = QChar('0'); } @@ -3016,7 +3000,7 @@ void tst_QLineEdit::setSelection_data() QTest::newRow(selectionTestName(start, length).constData()) << text << start << length << pos << QString("Abc ") << true; - start = -1; length = 0; pos = text.length(); + start = -1; length = 0; pos = text.size(); QTest::newRow(selectionTestName(start, length).constData()) << text << start << length << pos << QString() << false; @@ -3036,7 +3020,7 @@ void tst_QLineEdit::setSelection_data() QTest::newRow(selectionTestName(start, length).constData()) << text << start << length << pos << QString("A") << true; - start = -1; length = -1; pos = text.length(); + start = -1; length = -1; pos = text.size(); QTest::newRow(selectionTestName(start, length).constData()) << text << start << length << pos << QString() << false; } @@ -3333,7 +3317,7 @@ void tst_QLineEdit::validateOnFocusOut() QTest::keyPress(testWidget, '0'); QCOMPARE(testWidget->text(), QString("10")); testWidget->clearFocus(); - QCOMPARE(editingFinishedSpy.count(), 0); + QCOMPARE(editingFinishedSpy.size(), 0); testWidget->setFocus(); centerOnScreen(testWidget); @@ -3346,7 +3330,7 @@ void tst_QLineEdit::validateOnFocusOut() QTRY_COMPARE(testWidget->text(), QString("100")); testWidget->clearFocus(); - QCOMPARE(editingFinishedSpy.count(), 1); + QCOMPARE(editingFinishedSpy.size(), 1); } void tst_QLineEdit::editInvalidText() @@ -3430,6 +3414,9 @@ void tst_QLineEdit::leftKeyOnSelectedText() void tst_QLineEdit::inlineCompletion() { +#ifdef Q_OS_ANDROID + QSKIP("QCompleter does not work on Android, see QTBUG-77174"); +#endif if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); @@ -3521,7 +3508,7 @@ void tst_QLineEdit::noTextEditedOnClear() testWidget->setText("Test"); QSignalSpy textEditedSpy(testWidget, SIGNAL(textEdited(QString))); testWidget->clear(); - QCOMPARE(textEditedSpy.count(), 0); + QCOMPARE(textEditedSpy.size(), 0); } void tst_QLineEdit::textMargin_data() @@ -3537,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; @@ -3625,7 +3613,7 @@ void tst_QLineEdit::returnKeyClearsEditedFlag() // Focus drop with no edits shouldn't emit signal, edited flag == false testWidget.clearFocus(); // Signal not emitted QVERIFY(!testWidget.hasFocus()); - QCOMPARE(leSpy.count(), 0); + QCOMPARE(leSpy.size(), 0); // Focus drop after edits should emit signal, edited flag == true testWidget.setFocus(); @@ -3633,7 +3621,7 @@ void tst_QLineEdit::returnKeyClearsEditedFlag() QTest::keyClicks(&testWidget, "edit1 "); // edited flag set testWidget.clearFocus(); // edited flag cleared, signal emitted QVERIFY(!testWidget.hasFocus()); - QCOMPARE(leSpy.count(), 1); + QCOMPARE(leSpy.size(), 1); // Only text related keys should set edited flag testWidget.setFocus(); @@ -3643,7 +3631,7 @@ void tst_QLineEdit::returnKeyClearsEditedFlag() QTest::keyClick(&testWidget, Qt::Key_PageUp); testWidget.clearFocus(); // Signal not emitted QVERIFY(!testWidget.hasFocus()); - QCOMPARE(leSpy.count(), 1); // No change + QCOMPARE(leSpy.size(), 1); // No change // Return should always emit signal testWidget.setFocus(); @@ -3651,12 +3639,12 @@ void tst_QLineEdit::returnKeyClearsEditedFlag() QTest::keyClick(&testWidget, Qt::Key_Return); /* Without edits, signal emitted, edited flag cleared */ - QCOMPARE(leSpy.count(), 2); + QCOMPARE(leSpy.size(), 2); QTest::keyClicks(&testWidget, "edit2 "); // edited flag set QTest::keyClick(&testWidget, Qt::Key_Return); /* With edits, signal emitted, edited flag cleared */ - QCOMPARE(leSpy.count(), 3); + QCOMPARE(leSpy.size(), 3); /* After editing the line edit following a Return key press with a focus drop should not emit signal a second time since Return now @@ -3664,10 +3652,10 @@ void tst_QLineEdit::returnKeyClearsEditedFlag() QTest::keyClicks(&testWidget, "edit3 "); // edited flag set QTest::keyClick(&testWidget, Qt::Key_Return); /* signal emitted, edited flag cleared */ - QCOMPARE(leSpy.count(), 4); + QCOMPARE(leSpy.size(), 4); testWidget.clearFocus(); // Signal not emitted since edited == false QVERIFY(!testWidget.hasFocus()); - QCOMPARE(leSpy.count(), 4); // No change + QCOMPARE(leSpy.size(), 4); // No change } #ifndef QT_NO_CURSOR @@ -3734,7 +3722,6 @@ void tst_QLineEdit::task174640_editingFinished() layout->addWidget(le2); mw.show(); - QApplication::setActiveWindow(&mw); mw.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&mw)); QCOMPARE(&mw, QApplication::activeWindow()); @@ -3743,19 +3730,19 @@ void tst_QLineEdit::task174640_editingFinished() le1->setFocus(); QTRY_VERIFY(le1->hasFocus()); - QCOMPARE(editingFinishedSpy.count(), 0); + QCOMPARE(editingFinishedSpy.size(), 0); le2->setFocus(); QTRY_VERIFY(le2->hasFocus()); // editingFinished will not be emitted anew because no editing happened - QCOMPARE(editingFinishedSpy.count(), 0); + QCOMPARE(editingFinishedSpy.size(), 0); le1->setFocus(); QTRY_VERIFY(le1->hasFocus()); QTest::keyPress(le1, Qt::Key_Plus); le2->setFocus(); QTRY_VERIFY(le2->hasFocus()); - QCOMPARE(editingFinishedSpy.count(), 1); + QCOMPARE(editingFinishedSpy.size(), 1); editingFinishedSpy.clear(); le1->setFocus(); @@ -3770,7 +3757,7 @@ void tst_QLineEdit::task174640_editingFinished() mw.activateWindow(); delete testMenu1; - QCOMPARE(editingFinishedSpy.count(), 0); + QCOMPARE(editingFinishedSpy.size(), 0); QTRY_VERIFY(le1->hasFocus()); // Ensure le1 has been edited QTest::keyPress(le1, Qt::Key_Plus); @@ -3783,7 +3770,7 @@ void tst_QLineEdit::task174640_editingFinished() QTest::qWait(20); mw.activateWindow(); delete testMenu2; - QCOMPARE(editingFinishedSpy.count(), 1); + QCOMPARE(editingFinishedSpy.size(), 1); } #if QT_CONFIG(completer) @@ -3827,6 +3814,9 @@ void tst_QLineEdit::task198789_currentCompletion() void tst_QLineEdit::task210502_caseInsensitiveInlineCompletion() { +#ifdef Q_OS_ANDROID + QSKIP("QCompleter does not work on Android, see QTBUG-77174"); +#endif if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); @@ -3839,7 +3829,6 @@ void tst_QLineEdit::task210502_caseInsensitiveInlineCompletion() completer.setCompletionMode(QCompleter::InlineCompletion); lineEdit.setCompleter(&completer); lineEdit.show(); - QApplication::setActiveWindow(&lineEdit); QVERIFY(QTest::qWaitForWindowActive(&lineEdit)); lineEdit.setFocus(); QTRY_VERIFY(lineEdit.hasFocus()); @@ -3865,7 +3854,7 @@ void tst_QLineEdit::task229938_dontEmitChangedWhenTextIsNotChanged() QTest::keyPress(&lineEdit, 'd'); QTest::keyPress(&lineEdit, 'e'); QTest::keyPress(&lineEdit, 'f'); - QCOMPARE(changedSpy.count(), 5); + QCOMPARE(changedSpy.size(), 5); } void tst_QLineEdit::task233101_cursorPosAfterInputMethod_data() @@ -3940,7 +3929,6 @@ void tst_QLineEdit::task241436_passwordEchoOnEditRestoreEchoMode() testWidget->setFocus(); centerOnScreen(testWidget); testWidget->show(); - QApplication::setActiveWindow(testWidget); QVERIFY(QTest::qWaitForWindowActive(testWidget)); QVERIFY(testWidget->hasFocus()); @@ -3991,7 +3979,6 @@ void tst_QLineEdit::taskQTBUG_4401_enterKeyClearsPassword() testWidget->selectAll(); centerOnScreen(testWidget); testWidget->show(); - QApplication::setActiveWindow(testWidget); QVERIFY(QTest::qWaitForWindowActive(testWidget)); QTest::keyPress(testWidget, Qt::Key_Enter); @@ -4047,7 +4034,8 @@ void tst_QLineEdit::taskQTBUG_7902_contextMenuCrash() w->connect(&ti, SIGNAL(timeout()), w, SLOT(deleteLater())); ti.start(200); - QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center()); + QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center(), + w->mapToGlobal(w->rect().center())); qApp->postEvent(w, cme); QTest::qWait(300); @@ -4073,13 +4061,12 @@ void tst_QLineEdit::taskQTBUG_7395_readOnlyShortcut() le.show(); QVERIFY(QTest::qWaitForWindowExposed(&le)); - QApplication::setActiveWindow(&le); QVERIFY(QTest::qWaitForWindowActive(&le)); le.setFocus(); QTRY_VERIFY(le.hasFocus()); QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_P); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } void tst_QLineEdit::QTBUG697_paletteCurrentColorGroup() @@ -4095,7 +4082,6 @@ void tst_QLineEdit::QTBUG697_paletteCurrentColorGroup() le.setPalette(p); le.show(); - QApplication::setActiveWindow(&le); QVERIFY(QTest::qWaitForWindowActive(&le)); le.setFocus(); QTRY_VERIFY(le.hasFocus()); @@ -4123,7 +4109,7 @@ void tst_QLineEdit::QTBUG13520_textNotVisible() QString sometext("01-ST16-01SIL-MPL001wfgsdfgsdgsdfgsdfgsdfgsdfgsdfg"); le.setText(sometext); le.setCursorPosition(0); - QTest::qWait(100); //just make sure we get he lineedit correcly painted + QTest::qWait(100); //just make sure we get he lineedit correctly painted auto expectedCursorCoordinate = le.width() - le.fontMetrics().horizontalAdvance(sometext); // cursor does not leave widget to the left: @@ -4366,14 +4352,14 @@ void tst_QLineEdit::inputMethodSelection() testWidget->setSelection(0,0); QSignalSpy selectionSpy(testWidget, SIGNAL(selectionChanged())); - QCOMPARE(selectionSpy.count(), 0); + QCOMPARE(selectionSpy.size(), 0); QCOMPARE(testWidget->selectionStart(), -1); QCOMPARE(testWidget->selectionEnd(), -1); QCOMPARE(testWidget->selectionLength(), 0); testWidget->setSelection(0,5); - QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(selectionSpy.size(), 1); QCOMPARE(testWidget->selectionStart(), 0); QCOMPARE(testWidget->selectionEnd(), 5); QCOMPARE(testWidget->selectionLength(), 5); @@ -4387,7 +4373,7 @@ void tst_QLineEdit::inputMethodSelection() QApplication::sendEvent(testWidget, &event); } - QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(selectionSpy.size(), 2); QCOMPARE(testWidget->selectionStart(), 12); QCOMPARE(testWidget->selectionEnd(), 17); QCOMPARE(testWidget->selectionLength(), 5); @@ -4400,7 +4386,7 @@ void tst_QLineEdit::inputMethodSelection() QApplication::sendEvent(testWidget, &event); } - QCOMPARE(selectionSpy.count(), 3); + QCOMPARE(selectionSpy.size(), 3); QCOMPARE(testWidget->selectionStart(), -1); QCOMPARE(testWidget->selectionEnd(), -1); QCOMPARE(testWidget->selectionLength(), 0); @@ -4427,6 +4413,33 @@ void tst_QLineEdit::inputMethodQueryImHints() QCOMPARE(static_cast<Qt::InputMethodHints>(value.toInt()), hints); } +void tst_QLineEdit::inputMethodQueryEnterKeyType() +{ + QWidget mw; + QVBoxLayout layout(&mw); + QLineEdit le1(&mw); + layout.addWidget(&le1); + mw.show(); + QVariant enterType = le1.inputMethodQuery(Qt::ImEnterKeyType); + QCOMPARE(enterType.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault); + + mw.hide(); + QLineEdit le2(&mw); + layout.addWidget(&le2); + mw.show(); + + enterType = le1.inputMethodQuery(Qt::ImEnterKeyType); +#ifdef Q_OS_ANDROID + // QTBUG-61652 + // EnterKey is changed to EnterKeyNext if the focus can be moved to widget below + QCOMPARE(enterType.value<Qt::EnterKeyType>(), Qt::EnterKeyNext); +#else + QCOMPARE(enterType.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault); +#endif + enterType = le2.inputMethodQuery(Qt::ImEnterKeyType); + QCOMPARE(enterType.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault); +} + void tst_QLineEdit::inputMethodUpdate() { if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) @@ -4563,7 +4576,6 @@ void tst_QLineEdit::clearButton() l->addWidget(listView); testWidget.move(300, 300); testWidget.show(); - qApp->setActiveWindow(&testWidget); QVERIFY(QTest::qWaitForWindowActive(&testWidget)); // Flip the clear button on,off, trying to detect crashes. filterLineEdit->setClearButtonEnabled(true); @@ -4588,11 +4600,11 @@ void tst_QLineEdit::clearButton() QSignalSpy spyEdited(filterLineEdit, &QLineEdit::textEdited); const QPoint clearButtonCenterPos = QRect(QPoint(0, 0), clearButton->size()).center(); QTest::mouseClick(clearButton, Qt::LeftButton, {}, clearButtonCenterPos); - QCOMPARE(spyEdited.count(), 1); + QCOMPARE(spyEdited.size(), 1); QTRY_COMPARE(clearButton->cursor().shape(), filterLineEdit->cursor().shape()); QTRY_COMPARE(filterModel->rowCount(), 3); QCoreApplication::processEvents(); - QCOMPARE(spyEdited.count(), 1); + QCOMPARE(spyEdited.size(), 1); filterLineEdit->setReadOnly(true); // QTBUG-34315 QVERIFY(!clearButton->isEnabled()); @@ -4674,7 +4686,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; @@ -4689,7 +4702,8 @@ void tst_QLineEdit::sideWidgets() template <class T> T *findAssociatedWidget(const QAction *a) { - foreach (QWidget *w, a->associatedWidgets()) { + const auto associatedObjects = a->associatedObjects(); + for (QObject *w : associatedObjects) { if (T *result = qobject_cast<T *>(w)) return result; } @@ -4869,7 +4883,7 @@ void tst_QLineEdit::QTBUG1266_setInputMaskEmittingTextEdited() QSignalSpy spy(&lineEdit, SIGNAL(textEdited(QString))); lineEdit.setInputMask("AAAA"); lineEdit.setInputMask(QString()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } #if QT_CONFIG(shortcut) @@ -4930,7 +4944,7 @@ void tst_QLineEdit::shortcutOverrideOnReadonlyLineEdit() } const int activationCount = shouldBeHandledByQLineEdit ? 0 : 1; - QCOMPARE(spy.count(), activationCount); + QCOMPARE(spy.size(), activationCount); } #endif // QT_CONFIG(shortcut) @@ -4963,7 +4977,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 @@ -4983,10 +4997,10 @@ void tst_QLineEdit::QTBUG_60319_setInputMaskCheckImSurroundingText() QLineEdit *testWidget = ensureTestWidget(); QString mask("+000(000)-000-00-00"); testWidget->setInputMask(mask); - testWidget->setCursorPosition(mask.length()); + testWidget->setCursorPosition(mask.size()); QString surroundingText = testWidget->inputMethodQuery(Qt::ImSurroundingText).toString(); int cursorPosition = testWidget->inputMethodQuery(Qt::ImCursorPosition).toInt(); - QCOMPARE(surroundingText.length(), cursorPosition); + QCOMPARE(surroundingText.size(), cursorPosition); } void tst_QLineEdit::testQuickSelectionWithMouse() @@ -5083,18 +5097,18 @@ void tst_QLineEdit::inputRejected() QSignalSpy spyInputRejected(testWidget, SIGNAL(inputRejected())); QTest::keyClicks(testWidget, "abcde"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); testWidget->setText("fghij"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); testWidget->insert("k"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); testWidget->clear(); testWidget->setMaxLength(5); QTest::keyClicks(testWidget, "abcde"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); QTest::keyClicks(testWidget, "fgh"); - QCOMPARE(spyInputRejected.count(), 3); + QCOMPARE(spyInputRejected.size(), 3); #if QT_CONFIG(clipboard) testWidget->clear(); spyInputRejected.clear(); @@ -5102,7 +5116,7 @@ void tst_QLineEdit::inputRejected() testWidget->paste(); // The first 5 characters are accepted, but // the last 2 are not. - QCOMPARE(spyInputRejected.count(), 1); + QCOMPARE(spyInputRejected.size(), 1); #endif testWidget->setMaxLength(INT_MAX); @@ -5111,15 +5125,15 @@ void tst_QLineEdit::inputRejected() QIntValidator intValidator(1, 100); testWidget->setValidator(&intValidator); QTest::keyClicks(testWidget, "11"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); QTest::keyClicks(testWidget, "a#"); - QCOMPARE(spyInputRejected.count(), 2); + QCOMPARE(spyInputRejected.size(), 2); #if QT_CONFIG(clipboard) testWidget->clear(); spyInputRejected.clear(); QApplication::clipboard()->setText("a#"); testWidget->paste(); - QCOMPARE(spyInputRejected.count(), 1); + QCOMPARE(spyInputRejected.size(), 1); #endif testWidget->clear(); @@ -5127,10 +5141,154 @@ void tst_QLineEdit::inputRejected() spyInputRejected.clear(); testWidget->setInputMask("999.999.999.999;_"); QTest::keyClicks(testWidget, "11"); - QCOMPARE(spyInputRejected.count(), 0); + QCOMPARE(spyInputRejected.size(), 0); QTest::keyClicks(testWidget, "a#"); - QCOMPARE(spyInputRejected.count(), 2); + 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 85ce87f764..93f94f78c7 100644 --- a/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qmainwindow/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qmainwindow.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets Qt::WidgetsPrivate diff --git a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp index f2a7981b4c..093af90d1c 100644 --- a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp +++ b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -68,13 +43,13 @@ public: } void timerEvent(QTimerEvent*) override { - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseButtonPress, QPoint(6, 7), Qt::LeftButton, {}, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(7, 8), Qt::LeftButton, Qt::LeftButton, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(27, 23), Qt::LeftButton, Qt::LeftButton, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(30, 27), Qt::LeftButton, Qt::LeftButton, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(162, 109), Qt::LeftButton, Qt::LeftButton, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(10, 4), Qt::LeftButton, Qt::LeftButton, {})); - QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseButtonRelease, QPoint(9, 4), Qt::LeftButton, {}, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseButtonPress, QPoint(6, 7), m_tb->mapToGlobal(QPoint(6, 7)), Qt::LeftButton, {}, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(7, 8), m_tb->mapToGlobal(QPoint(7, 8)), Qt::LeftButton, Qt::LeftButton, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(27, 23), m_tb->mapToGlobal(QPoint(27, 23)), Qt::LeftButton, Qt::LeftButton, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(30, 27), m_tb->mapToGlobal(QPoint(30, 27)), Qt::LeftButton, Qt::LeftButton, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(162, 109), m_tb->mapToGlobal(QPoint(162, 109)), Qt::LeftButton, Qt::LeftButton, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseMove, QPoint(10, 4), m_tb->mapToGlobal(QPoint(10, 4)), Qt::LeftButton, Qt::LeftButton, {})); + QCoreApplication::postEvent(m_tb, new QMouseEvent(QEvent::MouseButtonRelease, QPoint(9, 4), m_tb->mapToGlobal(QPoint(6, 7)), Qt::LeftButton, {}, {})); } }; @@ -92,8 +67,8 @@ public: void timerEvent(QTimerEvent*) override { - QCoreApplication::postEvent(m_w, new QMouseEvent(QEvent::MouseButtonPress, QPoint(230, 370), Qt::LeftButton, {}, {})); - QCoreApplication::postEvent(m_w, new QMouseEvent(QEvent::MouseButtonRelease, QPoint(230, 370), Qt::LeftButton, {}, {})); + QCoreApplication::postEvent(m_w, new QMouseEvent(QEvent::MouseButtonPress, QPoint(230, 370), m_w->mapToGlobal(QPoint(230, 370)), Qt::LeftButton, {}, {})); + QCoreApplication::postEvent(m_w, new QMouseEvent(QEvent::MouseButtonRelease, QPoint(230, 370), m_w->mapToGlobal(QPoint(230, 370)), Qt::LeftButton, {}, {})); } }; @@ -129,6 +104,7 @@ private slots: void restoreStateFromPreviousVersion(); void restoreStateSizeChanged_data(); void restoreStateSizeChanged(); + void restoreAndModify(); void createPopupMenu(); void hideBeforeLayout(); #ifdef QT_BUILD_INTERNAL @@ -1365,25 +1341,31 @@ void tst_QMainWindow::restoreState() dw.setObjectName(QLatin1String("dock")); mw.addDockWidget(Qt::LeftDockWidgetArea, &dw); + QWidgetPrivate *tbp = QWidgetPrivate::get(&tb); + QVERIFY(tbp->widgetItem); + QByteArray state; state = mw.saveState(); QVERIFY(mw.restoreState(state)); + QVERIFY(tbp->widgetItem); state = mw.saveState(1); QVERIFY(!mw.restoreState(state)); QVERIFY(mw.restoreState(state, 1)); + QVERIFY(tbp->widgetItem); } //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); @@ -1495,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() { { @@ -1691,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 @@ -1755,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; @@ -1768,12 +1814,12 @@ void tst_QMainWindow::saveRestore() QTextEdit centralWidget("The rain in Spain falls mainly on the plains"); mainWindow.setCentralWidget(¢ralWidget); - 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); @@ -1791,7 +1837,7 @@ void tst_QMainWindow::saveRestore() QTextEdit centralWidget("The rain in Spain falls mainly on the plains"); mainWindow.setCentralWidget(¢ralWidget); - foreach (const AddDockWidget &adw, addList) + for (const AddDockWidget &adw : addList) adw.apply(&mainWindow); mainWindow.show(); @@ -1808,7 +1854,7 @@ void tst_QMainWindow::saveRestore() QTextEdit centralWidget("The rain in Spain falls mainly on the plains"); mainWindow.setCentralWidget(¢ralWidget); - foreach (const AddDockWidget &adw, addList) + for (const AddDockWidget &adw : addList) adw.apply(&mainWindow); mainWindow.resize(size); mainWindow.restoreState(stateData); @@ -1859,11 +1905,11 @@ void tst_QMainWindow::setCursor() QVERIFY(QTest::qWaitForWindowActive(&mw)); QCOMPARE(cur.shape(), mw.cursor().shape()); - QHoverEvent enterE(QEvent::HoverEnter, QPoint(10,10), QPoint()); + QHoverEvent enterE(QEvent::HoverEnter, QPoint(10,10), QPoint(), QPoint()); mw.event(&enterE); QCOMPARE(cur.shape(), mw.cursor().shape()); - QHoverEvent leaveE(QEvent::HoverLeave, QPoint(), QPoint()); + QHoverEvent leaveE(QEvent::HoverLeave, QPoint(), QPoint(), QPoint()); mw.event(&leaveE); QCOMPARE(cur.shape(), mw.cursor().shape()); } @@ -1884,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"); @@ -2116,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); @@ -2128,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; @@ -2144,14 +2191,14 @@ void tst_QMainWindow::resizeDocks() int totalFromList = 0; int actualTotal = 0; - for (int i = 0; i < docks.count(); ++i) { + for (int i = 0; i < docks.size(); ++i) { totalFromList += sizes[i]; QSize s = list[i]->size(); actualTotal += (orientation == Qt::Horizontal) ? s.width() : s.height(); // qDebug() << list[i] << list[i]->size() << sizes[i]; } - for (int i = 0; i < docks.count(); ++i) { + for (int i = 0; i < docks.size(); ++i) { QSize s = list[i]->size(); int value = (orientation == Qt::Horizontal) ? s.width() : s.height(); QCOMPARE(value, qRound(sizes[i]*actualTotal/double(totalFromList))); 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 9586d69352..5f61dc8664 100644 --- a/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qmdiarea/CMakeLists.txt @@ -1,32 +1,38 @@ -# Generated from qmdiarea.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 DEFINES QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - INCLUDE_DIRECTORIES - . - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Widgets + Qt::WidgetsPrivate ) ## Scopes: ##################################################################### qt_internal_extend_target(tst_qmdiarea CONDITION TARGET Qt::OpenGL - PUBLIC_LIBRARIES + LIBRARIES Qt::OpenGL ) qt_internal_extend_target(tst_qmdiarea CONDITION APPLE - PUBLIC_LIBRARIES + LIBRARIES ${FWSecurity} ) diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp index 225b349f08..ef00dcaac0 100644 --- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp +++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -49,6 +24,8 @@ #endif #include <QStyleHints> +#include <QtWidgets/private/qapplication_p.h> + static const Qt::WindowFlags DefaultWindowFlags = Qt::SubWindow | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; @@ -163,7 +140,7 @@ static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const case Tiled: { // Calculate the number of rows and columns. - const int n = subWindows.count(); + const int n = subWindows.size(); const int numColumns = qMax(qCeil(qSqrt(qreal(n))), 1); const int numRows = qMax((n % numColumns) ? (n / numColumns + 1) : (n / numColumns), 1); @@ -199,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) @@ -210,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(); } @@ -283,6 +260,10 @@ private slots: void task_236750(); void qtbug92240_title_data(); void qtbug92240_title(); + void tabbedview_singleSubWindow(); + void tabbedview_activefirst(); + void tabbedview_activesecond(); + void tabbedview_activethird(); private: QMdiSubWindow *activeWindow; @@ -326,7 +307,7 @@ void tst_QMdiArea::subWindowActivated() QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow*))); connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*))); mw.show(); - qApp->setActiveWindow(&mw); + QApplicationPrivate::setActiveWindow(&mw); QFETCH( int, count ); int i; @@ -339,12 +320,12 @@ void tst_QMdiArea::subWindowActivated() widget->show(); qApp->processEvents(); QVERIFY( activeWindow == workspace->activeSubWindow() ); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); } QList<QMdiSubWindow *> windows = workspace->subWindowList(); - QCOMPARE( (int)windows.count(), count ); + QCOMPARE( (int)windows.size(), count ); for ( i = 0; i < count; ++i ) { QMdiSubWindow *window = windows.at(i); @@ -368,13 +349,13 @@ void tst_QMdiArea::subWindowActivated() workspace->activeSubWindow()->close(); qApp->processEvents(); QCOMPARE(activeWindow, workspace->activeSubWindow()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); } QVERIFY(!activeWindow); QVERIFY(!workspace->activeSubWindow()); - QCOMPARE(workspace->subWindowList().count(), 0); + QCOMPARE(workspace->subWindowList().size(), 0); { workspace->hide(); @@ -382,14 +363,14 @@ void tst_QMdiArea::subWindowActivated() widget->setAttribute(Qt::WA_DeleteOnClose); QMdiSubWindow *window = workspace->addSubWindow(widget); widget->show(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); workspace->show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY( activeWindow == window ); window->close(); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY( activeWindow == 0 ); } @@ -401,15 +382,15 @@ void tst_QMdiArea::subWindowActivated() QMdiSubWindow *window = workspace->addSubWindow(widget); widget->showMaximized(); qApp->sendPostedEvents(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); workspace->show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY( activeWindow == window ); window->close(); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY( activeWindow == 0 ); } @@ -419,13 +400,13 @@ void tst_QMdiArea::subWindowActivated() widget->setAttribute(Qt::WA_DeleteOnClose); QMdiSubWindow *window = workspace->addSubWindow(widget); widget->showMinimized(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY( activeWindow == window ); QCOMPARE(workspace->activeSubWindow(), window); window->close(); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QVERIFY(!workspace->activeSubWindow()); QVERIFY(!activeWindow); @@ -453,12 +434,12 @@ void tst_QMdiArea::subWindowActivated2() QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*))); for (int i = 0; i < 5; ++i) mdiArea.addSubWindow(new QWidget); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); mdiArea.show(); mdiArea.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&mdiArea)); - QTRY_COMPARE(spy.count(), 5); + QTRY_COMPARE(spy.size(), 5); QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().back()); spy.clear(); @@ -467,13 +448,13 @@ void tst_QMdiArea::subWindowActivated2() QMdiSubWindow *staysOnTopWindow = mdiArea.subWindowList().at(3); staysOnTopWindow->setWindowFlags(Qt::WindowStaysOnTopHint); mdiArea.setActiveSubWindow(staysOnTopWindow); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(mdiArea.activeSubWindow(), staysOnTopWindow); spy.clear(); QMdiSubWindow *activeSubWindow = mdiArea.subWindowList().at(2); mdiArea.setActiveSubWindow(activeSubWindow); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow); spy.clear(); @@ -481,7 +462,7 @@ void tst_QMdiArea::subWindowActivated2() // is unchanged after hide/show. mdiArea.hide(); QTest::qWait(100); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QVERIFY(!mdiArea.activeSubWindow()); QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow); spy.clear(); @@ -509,7 +490,7 @@ void tst_QMdiArea::subWindowActivated2() #endif if (!QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive)) QSKIP("QTBUG-25298: Unstable on some X11 window managers"); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QVERIFY(!mdiArea.activeSubWindow()); QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow); spy.clear(); @@ -519,7 +500,7 @@ void tst_QMdiArea::subWindowActivated2() mdiArea.showNormal(); mdiArea.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&mdiArea)); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow); spy.clear(); } @@ -534,7 +515,6 @@ void tst_QMdiArea::subWindowActivatedWithMinimize() QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow*))); connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*)) ); mw.show(); - qApp->setActiveWindow(&mw); QWidget *widget = new QWidget(workspace); widget->setAttribute(Qt::WA_DeleteOnClose); QMdiSubWindow *window1 = workspace->addSubWindow(widget); @@ -556,7 +536,7 @@ void tst_QMdiArea::subWindowActivatedWithMinimize() QVERIFY(!workspace->activeSubWindow()); QVERIFY(!activeWindow); - QVERIFY( workspace->subWindowList().count() == 0 ); + QVERIFY( workspace->subWindowList().size() == 0 ); } void tst_QMdiArea::showWindows() @@ -679,7 +659,6 @@ void tst_QMdiArea::changeWindowTitle() #endif mw->show(); - qApp->setActiveWindow(mw); #ifdef USE_SHOW mw->showFullScreen(); @@ -835,14 +814,14 @@ void tst_QMdiArea::fixedSize() } QList<QMdiSubWindow *> windows = ws->subWindowList(); - for (i = 0; i < (int)windows.count(); ++i) { + for (i = 0; i < (int)windows.size(); ++i) { QMdiSubWindow *child = windows.at(i); QCOMPARE(child->size(), fixed); } ws->cascadeSubWindows(); ws->resize(800, 800); - for (i = 0; i < (int)windows.count(); ++i) { + for (i = 0; i < (int)windows.size(); ++i) { QMdiSubWindow *child = windows.at(i); QCOMPARE(child->size(), fixed); } @@ -850,13 +829,13 @@ void tst_QMdiArea::fixedSize() ws->tileSubWindows(); ws->resize(800, 800); - for (i = 0; i < (int)windows.count(); ++i) { + for (i = 0; i < (int)windows.size(); ++i) { QMdiSubWindow *child = windows.at(i); QCOMPARE(child->size(), fixed); } ws->resize(500, 500); - for (i = 0; i < (int)windows.count(); ++i) { + for (i = 0; i < (int)windows.size(); ++i) { QMdiSubWindow *child = windows.at(i); delete child; } @@ -924,7 +903,7 @@ void tst_QMdiArea::setActiveSubWindow() QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*))); connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*))); - qApp->setActiveWindow(&workspace); + QApplicationPrivate::setActiveWindow(&workspace); // Activate hidden windows const int windowCount = 10; @@ -935,7 +914,7 @@ void tst_QMdiArea::setActiveSubWindow() QVERIFY(windows[i]->isHidden()); workspace.setActiveSubWindow(windows[i]); } - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); QVERIFY(!activeWindow); spy.clear(); @@ -945,7 +924,7 @@ void tst_QMdiArea::setActiveSubWindow() QVERIFY(!windows[i]->isHidden()); workspace.setActiveSubWindow(windows[i]); qApp->processEvents(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(activeWindow, windows[i]); spy.clear(); } @@ -953,7 +932,7 @@ void tst_QMdiArea::setActiveSubWindow() // Deactivate active window QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); workspace.setActiveSubWindow(0); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(!activeWindow); QVERIFY(!workspace.activeSubWindow()); @@ -983,7 +962,6 @@ void tst_QMdiArea::activeSubWindow() mainWindow.addDockWidget(Qt::LeftDockWidgetArea, dockWidget); mainWindow.show(); - qApp->setActiveWindow(&mainWindow); QVERIFY(QTest::qWaitForWindowActive(&mainWindow)); QCOMPARE(mdiArea->activeSubWindow(), subWindow); QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit); @@ -1006,15 +984,13 @@ void tst_QMdiArea::activeSubWindow() dummyTopLevel.show(); QVERIFY(QTest::qWaitForWindowExposed(&dummyTopLevel)); - qApp->setActiveWindow(&dummyTopLevel); QCOMPARE(mdiArea->activeSubWindow(), subWindow); - qApp->setActiveWindow(&mainWindow); QCOMPARE(mdiArea->activeSubWindow(), subWindow); //task 202657 dockWidgetLineEdit->setFocus(); - qApp->setActiveWindow(&mainWindow); + QApplicationPrivate::setActiveWindow(&mainWindow); QVERIFY(dockWidgetLineEdit->hasFocus()); } @@ -1027,7 +1003,7 @@ void tst_QMdiArea::currentSubWindow() for (int i = 0; i < 5; ++i) mdiArea.addSubWindow(new QLineEdit)->show(); - qApp->setActiveWindow(&mdiArea); + QApplicationPrivate::setActiveWindow(&mdiArea); QCOMPARE(qApp->activeWindow(), (QWidget *)&mdiArea); // Check that the last added window is the active and the current. @@ -1042,7 +1018,6 @@ void tst_QMdiArea::currentSubWindow() // Move focus to another top-level and check that we still // have an active window. - qApp->setActiveWindow(&dummyTopLevel); QCOMPARE(qApp->activeWindow(), (QWidget *)&dummyTopLevel); QVERIFY(mdiArea.activeSubWindow()); @@ -1055,7 +1030,7 @@ void tst_QMdiArea::currentSubWindow() QCOMPARE(mdiArea.currentSubWindow(), mdiArea.subWindowList().front()); // Activate mdi area and check that active == current. - qApp->setActiveWindow(&mdiArea); + QApplicationPrivate::setActiveWindow(&mdiArea); active = mdiArea.activeSubWindow(); QVERIFY(active); QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().front()); @@ -1064,11 +1039,9 @@ void tst_QMdiArea::currentSubWindow() QCOMPARE(mdiArea.activeSubWindow(), active); QCOMPARE(mdiArea.currentSubWindow(), active); - qApp->setActiveWindow(&dummyTopLevel); QVERIFY(mdiArea.activeSubWindow()); QCOMPARE(mdiArea.currentSubWindow(), active); - qApp->setActiveWindow(&mdiArea); active->show(); QCOMPARE(mdiArea.activeSubWindow(), active); @@ -1098,11 +1071,11 @@ void tst_QMdiArea::addAndRemoveWindows() QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); { // addSubWindow with large widget - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); QWidget *window = workspace.addSubWindow(new LargeWidget); QVERIFY(window); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); QCOMPARE(window->windowFlags(), DefaultWindowFlags); QCOMPARE(window->size(), workspace.viewport()->size()); } @@ -1113,7 +1086,7 @@ void tst_QMdiArea::addAndRemoveWindows() workspace.addSubWindow(window); QVERIFY(window); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 2); + QCOMPARE(workspace.subWindowList().size(), 2); QCOMPARE(window->windowFlags(), DefaultWindowFlags); QCOMPARE(window->size(), window->minimumSize()); } @@ -1125,7 +1098,7 @@ void tst_QMdiArea::addAndRemoveWindows() workspace.addSubWindow(window); QVERIFY(window); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 3); + QCOMPARE(workspace.subWindowList().size(), 3); QCOMPARE(window->windowFlags(), DefaultWindowFlags); QCOMPARE(window->size(), QSize(1500, 1500)); } @@ -1134,7 +1107,7 @@ void tst_QMdiArea::addAndRemoveWindows() QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget"); QWidget *window = workspace.addSubWindow(0); QVERIFY(!window); - QCOMPARE(workspace.subWindowList().count(), 3); + QCOMPARE(workspace.subWindowList().size(), 3); } { // addChildWindow @@ -1143,7 +1116,7 @@ void tst_QMdiArea::addAndRemoveWindows() qApp->processEvents(); QCOMPARE(window->windowFlags(), DefaultWindowFlags); window->setWidget(new QWidget); - QCOMPARE(workspace.subWindowList().count(), 4); + QCOMPARE(workspace.subWindowList().size(), 4); QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added"); workspace.addSubWindow(window); } @@ -1151,15 +1124,16 @@ void tst_QMdiArea::addAndRemoveWindows() { // addChildWindow with 0 pointer QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget"); workspace.addSubWindow(0); - QCOMPARE(workspace.subWindowList().count(), 4); + QCOMPARE(workspace.subWindowList().size(), 4); } // removeSubWindow - foreach (QWidget *window, workspace.subWindowList()) { + const auto subWindows = workspace.subWindowList(); + for (QWidget *window : subWindows) { workspace.removeSubWindow(window); delete window; } - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); // removeSubWindow with 0 pointer QTest::ignoreMessage(QtWarningMsg, "QMdiArea::removeSubWindow: null pointer to widget"); @@ -1167,7 +1141,7 @@ void tst_QMdiArea::addAndRemoveWindows() workspace.addSubWindow(new QPushButton(QLatin1String("Dummy to make workspace non-empty"))); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); // removeSubWindow with window not inside workspace QTest::ignoreMessage(QtWarningMsg,"QMdiArea::removeSubWindow: window is not inside workspace"); @@ -1209,20 +1183,20 @@ void tst_QMdiArea::addAndRemoveWindowsWithReparenting() // 0 because the window list contains widgets and not actual // windows. Silly, but that's the behavior. - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); window.setWidget(new QWidget); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); window.setParent(0); // Will also reset window flags - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); window.setParent(&workspace); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); QCOMPARE(window.windowFlags(), DefaultWindowFlags); QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added"); workspace.addSubWindow(&window); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); } class MySubWindow : public QMdiSubWindow @@ -1273,23 +1247,22 @@ void tst_QMdiArea::closeWindows() { QMdiArea workspace; workspace.show(); - qApp->setActiveWindow(&workspace); // Close widget QWidget *widget = new QWidget; QMdiSubWindow *subWindow = workspace.addSubWindow(widget); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); subWindow->close(); - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); // Close window QWidget *window = workspace.addSubWindow(new QWidget); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 1); + QCOMPARE(workspace.subWindowList().size(), 1); window->close(); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); const int windowCount = 10; @@ -1297,7 +1270,7 @@ void tst_QMdiArea::closeWindows() for (int i = 0; i < windowCount; ++i) workspace.addSubWindow(new QWidget)->show(); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), windowCount); + QCOMPARE(workspace.subWindowList().size(), windowCount); int activeSubWindowCount = 0; while (workspace.activeSubWindow()) { workspace.activeSubWindow()->close(); @@ -1305,19 +1278,19 @@ void tst_QMdiArea::closeWindows() ++activeSubWindowCount; } QCOMPARE(activeSubWindowCount, windowCount); - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); // Close all windows for (int i = 0; i < windowCount; ++i) workspace.addSubWindow(new QWidget)->show(); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), windowCount); + QCOMPARE(workspace.subWindowList().size(), windowCount); QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*))); connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(activeChanged(QMdiSubWindow*))); workspace.closeAllSubWindows(); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 0); - QCOMPARE(spy.count(), 1); + QCOMPARE(workspace.subWindowList().size(), 0); + QCOMPARE(spy.size(), 1); QVERIFY(!activeWindow); } @@ -1325,7 +1298,6 @@ void tst_QMdiArea::activateNextAndPreviousWindow() { QMdiArea workspace; workspace.show(); - qApp->setActiveWindow(&workspace); const int windowCount = 10; QMdiSubWindow *windows[windowCount]; @@ -1343,7 +1315,7 @@ void tst_QMdiArea::activateNextAndPreviousWindow() workspace.activateNextSubWindow(); qApp->processEvents(); QCOMPARE(workspace.activeSubWindow(), windows[i]); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); } QVERIFY(activeWindow); @@ -1355,7 +1327,7 @@ void tst_QMdiArea::activateNextAndPreviousWindow() workspace.activatePreviousSubWindow(); qApp->processEvents(); QCOMPARE(workspace.activeSubWindow(), windows[i]); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); if (i % 2 == 0) windows[i]->hide(); // 10, 8, 6, 4, 2, 0 @@ -1367,7 +1339,7 @@ void tst_QMdiArea::activateNextAndPreviousWindow() // activateNextSubWindow with every 2nd window hidden for (int i = 0; i < windowCount / 2; ++i) { workspace.activateNextSubWindow(); // 1, 3, 5, 7, 9 - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); } QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); @@ -1375,7 +1347,7 @@ void tst_QMdiArea::activateNextAndPreviousWindow() // activatePreviousSubWindow with every 2nd window hidden for (int i = 0; i < windowCount / 2; ++i) { workspace.activatePreviousSubWindow(); // 7, 5, 3, 1, 9 - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); } QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); @@ -1409,7 +1381,6 @@ void tst_QMdiArea::subWindowList() QMdiArea workspace; workspace.show(); - qApp->setActiveWindow(&workspace); QVERIFY(QTest::qWaitForWindowActive(&workspace)); QList<QMdiSubWindow *> activationOrder; @@ -1422,8 +1393,8 @@ void tst_QMdiArea::subWindowList() { QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder); - QCOMPARE(widgets.count(), windowCount); - for (int i = 0; i < widgets.count(); ++i) + QCOMPARE(widgets.size(), windowCount); + for (int i = 0; i < widgets.size(); ++i) QCOMPARE(widgets.at(i), windows[i]); } @@ -1442,9 +1413,9 @@ void tst_QMdiArea::subWindowList() } if (windowOrder == QMdiArea::StackingOrder) { - QCOMPARE(subWindows.at(subWindows.count() - 1), windows[staysOnTop1]); - QCOMPARE(subWindows.at(subWindows.count() - 2), windows[activeSubWindow]); - QCOMPARE(subWindows.count(), windowCount); + QCOMPARE(subWindows.at(subWindows.size() - 1), windows[staysOnTop1]); + QCOMPARE(subWindows.at(subWindows.size() - 2), windows[activeSubWindow]); + QCOMPARE(subWindows.size(), windowCount); } else { // ActivationHistoryOrder QCOMPARE(subWindows, activationOrder); } @@ -1459,11 +1430,11 @@ void tst_QMdiArea::subWindowList() activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1); QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder); - QCOMPARE(widgets.count(), windowCount); + QCOMPARE(widgets.size(), windowCount); if (windowOrder == QMdiArea::StackingOrder) { - QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]); - QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); - QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + QCOMPARE(widgets.at(widgets.size() - 1), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.size() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.size() - 3), windows[activeSubWindow]); } else { // ActivationHistory QCOMPARE(widgets, activationOrder); } @@ -1473,8 +1444,8 @@ void tst_QMdiArea::subWindowList() widgets = workspace.subWindowList(windowOrder); if (windowOrder == QMdiArea::StackingOrder) { - QCOMPARE(widgets.at(widgets.count() - 1), windows[activeSubWindow]); - QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.size() - 1), windows[activeSubWindow]); + QCOMPARE(widgets.at(widgets.size() - 2), windows[staysOnTop1]); QCOMPARE(widgets.at(0), windows[staysOnTop2]); } else { // ActivationHistoryOrder QCOMPARE(widgets, activationOrder); @@ -1485,9 +1456,9 @@ void tst_QMdiArea::subWindowList() widgets = workspace.subWindowList(windowOrder); if (windowOrder == QMdiArea::StackingOrder) { - QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]); - QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); - QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + QCOMPARE(widgets.at(widgets.size() - 1), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.size() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.size() - 3), windows[activeSubWindow]); } else { // ActivationHistoryOrder QCOMPARE(widgets, activationOrder); } @@ -1497,9 +1468,9 @@ void tst_QMdiArea::subWindowList() widgets = workspace.subWindowList(windowOrder); if (windowOrder == QMdiArea::StackingOrder) { - QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop1]); - QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop2]); - QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + QCOMPARE(widgets.at(widgets.size() - 1), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.size() - 2), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.size() - 3), windows[activeSubWindow]); } else { // ActivationHistoryOrder QCOMPARE(widgets, activationOrder); } @@ -1540,14 +1511,14 @@ void tst_QMdiArea::setViewport() qApp->processEvents(); QList<QMdiSubWindow *> windowsBeforeViewportChange = workspace.subWindowList(); - QCOMPARE(windowsBeforeViewportChange.count(), windowCount); + QCOMPARE(windowsBeforeViewportChange.size(), windowCount); workspace.setViewport(new QWidget); qApp->processEvents(); QVERIFY(workspace.viewport() != firstViewport); QList<QMdiSubWindow *> windowsAfterViewportChange = workspace.subWindowList(); - QCOMPARE(windowsAfterViewportChange.count(), windowCount); + QCOMPARE(windowsAfterViewportChange.size(), windowCount); QCOMPARE(windowsAfterViewportChange, windowsBeforeViewportChange); // for (int i = 0; i < windowCount; ++i) { @@ -1563,7 +1534,7 @@ void tst_QMdiArea::setViewport() delete workspace.viewport(); qApp->processEvents(); - QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(workspace.subWindowList().size(), 0); QVERIFY(!workspace.activeSubWindow()); } @@ -1705,7 +1676,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)); @@ -1803,7 +1775,7 @@ void tst_QMdiArea::cascadeAndTileSubWindows() #endif QCOMPARE(windows.at(2)->geometry().top() - windows.at(1)->geometry().top(), dy); - for (int i = 0; i < windows.count(); ++i) { + for (int i = 0; i < windows.size(); ++i) { QMdiSubWindow *window = windows.at(i); if (i % 3 == 0) { QVERIFY(window->isMinimized()); @@ -1863,7 +1835,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()); } @@ -1888,7 +1860,7 @@ void tst_QMdiArea::focusWidgetAfterAddSubWindow() mdiArea.show(); view->show(); - qApp->setActiveWindow(&mdiArea); + QApplicationPrivate::setActiveWindow(&mdiArea); QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(lineEdit2)); } @@ -1897,7 +1869,6 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() QMdiArea mdiArea; mdiArea.show(); QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); - qApp->setActiveWindow(&mdiArea); // Add one maximized window. mdiArea.addSubWindow(new QWidget)->showMaximized(); @@ -1908,16 +1879,13 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() for (int i = 0; i < 5; ++i) { QMdiSubWindow *window = mdiArea.addSubWindow(new QWidget); window->show(); -#if defined Q_OS_QNX - QEXPECT_FAIL("", "QTBUG-38231", Abort); -#endif QVERIFY(window->isMaximized()); qApp->processEvents(); } // Verify that activated windows still are maximized on activation. - QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList(); - for (int i = 0; i < subWindows.count(); ++i) { + const QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList(); + for (int i = 0; i < subWindows.size(); ++i) { mdiArea.activateNextSubWindow(); QMdiSubWindow *window = subWindows.at(i); QCOMPARE(mdiArea.activeSubWindow(), window); @@ -1928,7 +1896,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() // Restore active window and verify that other windows aren't // maximized on activation. mdiArea.activeSubWindow()->showNormal(); - for (int i = 0; i < subWindows.count(); ++i) { + for (int i = 0; i < subWindows.size(); ++i) { mdiArea.activateNextSubWindow(); QMdiSubWindow *window = subWindows.at(i); QCOMPARE(mdiArea.activeSubWindow(), window); @@ -1942,7 +1910,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() int indexOfMaximized = subWindows.indexOf(mdiArea.activeSubWindow()); // Verify that windows are not maximized on activation. - for (int i = 0; i < subWindows.count(); ++i) { + for (int i = 0; i < subWindows.size(); ++i) { mdiArea.activateNextSubWindow(); QMdiSubWindow *window = subWindows.at(i); QCOMPARE(mdiArea.activeSubWindow(), window); @@ -1953,7 +1921,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(); @@ -1964,7 +1932,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() mdiArea.activeSubWindow()->showMaximized(); // Verify that minimized windows are maximized on activation. - for (int i = 0; i < subWindows.count(); ++i) { + for (int i = 0; i < subWindows.size(); ++i) { mdiArea.activateNextSubWindow(); QMdiSubWindow *window = subWindows.at(i); QCOMPARE(mdiArea.activeSubWindow(), window); @@ -1974,7 +1942,7 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() // Verify that activated windows are maximized after closing // the active window - for (int i = 0; i < subWindows.count(); ++i) { + for (int i = 0; i < subWindows.size(); ++i) { QVERIFY(mdiArea.activeSubWindow()); QVERIFY(mdiArea.activeSubWindow()->isMaximized()); mdiArea.activeSubWindow()->close(); @@ -2226,7 +2194,7 @@ void tst_QMdiArea::setActivationOrder() mdiArea.show(); QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); - for (int i = 0; i < subWindows.count(); ++i) { + for (int i = 0; i < subWindows.size(); ++i) { mdiArea.activateNextSubWindow(); QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(i)); qApp->processEvents(); @@ -2285,12 +2253,11 @@ void tst_QMdiArea::tabBetweenSubWindows() mdiArea.show(); QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); - qApp->setActiveWindow(&mdiArea); QWidget *focusWidget = subWindows.back()->widget(); QCOMPARE(qApp->focusWidget(), focusWidget); QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*))); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // Walk through the entire list of sub windows. #ifdef Q_OS_MAC @@ -2298,7 +2265,7 @@ void tst_QMdiArea::tabBetweenSubWindows() #endif QVERIFY(tabBetweenSubWindowsIn(&mdiArea)); QCOMPARE(mdiArea.activeSubWindow(), subWindows.back()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); mdiArea.setActiveSubWindow(subWindows.front()); QCOMPARE(mdiArea.activeSubWindow(), subWindows.front()); @@ -2307,12 +2274,12 @@ void tst_QMdiArea::tabBetweenSubWindows() // Walk through the entire list of sub windows in the opposite direction (Ctrl-Shift-Tab). QVERIFY(tabBetweenSubWindowsIn(&mdiArea, -1, true)); QCOMPARE(mdiArea.activeSubWindow(), subWindows.front()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // Ctrl-Tab-Tab-Tab QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 3)); QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); mdiArea.setActiveSubWindow(subWindows.at(1)); QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(1)); @@ -2321,7 +2288,7 @@ void tst_QMdiArea::tabBetweenSubWindows() // Quick switch (Ctrl-Tab once) -> switch back to the previously active sub-window. QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 1)); QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } void tst_QMdiArea::setViewMode() @@ -2340,7 +2307,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()); @@ -2355,7 +2322,7 @@ void tst_QMdiArea::setViewMode() QVERIFY(tabBar); QVERIFY(tabBar->isVisible()); - QCOMPARE(tabBar->count(), subWindows.count()); + QCOMPARE(tabBar->count(), subWindows.size()); QVERIFY(activeSubWindow->isMaximized()); QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow)); @@ -2409,13 +2376,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). @@ -2616,8 +2582,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. @@ -2626,8 +2595,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; @@ -2648,8 +2620,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. @@ -2665,9 +2640,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() @@ -2738,6 +2716,75 @@ 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); + + auto *mdiWin1 = new QWidget(&mdiArea); + mdiWin1->setWindowTitle(QLatin1String("Sub1")); + mdiArea.addSubWindow(mdiWin1); + + auto *mdiWin2 = new QWidget(&mdiArea); + mdiWin2->setWindowTitle(QLatin1String("Sub2")); + mdiArea.addSubWindow(mdiWin2); + + auto *mdiWin3 = new QWidget(&mdiArea); + mdiWin3->setWindowTitle(QLatin1String("Sub3")); + mdiArea.addSubWindow(mdiWin3); +} + +void tst_QMdiArea::tabbedview_activefirst() +{ + QMdiArea mdiArea; + setupMdiAreaWithTabbedView(mdiArea); + + auto sub0 = mdiArea.subWindowList().at(0); + mdiArea.setActiveSubWindow(sub0); + mdiArea.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); + QCOMPARE(mdiArea.activeSubWindow(), sub0); +} + +void tst_QMdiArea::tabbedview_activesecond() +{ + QMdiArea mdiArea; + setupMdiAreaWithTabbedView(mdiArea); + + auto sub1 = mdiArea.subWindowList().at(1); + mdiArea.setActiveSubWindow(sub1); + mdiArea.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); + QCOMPARE(mdiArea.activeSubWindow(), sub1); +} + +void tst_QMdiArea::tabbedview_activethird() +{ + QMdiArea mdiArea; + setupMdiAreaWithTabbedView(mdiArea); + + auto sub2 = mdiArea.subWindowList().at(2); + mdiArea.setActiveSubWindow(sub2); + mdiArea.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); + QCOMPARE(mdiArea.activeSubWindow(), sub2); +} + + QTEST_MAIN(tst_QMdiArea) #include "tst_qmdiarea.moc" diff --git a/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt b/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt index 2c72f7d4e1..45b7b74ac4 100644 --- a/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qmdisubwindow/CMakeLists.txt @@ -1,18 +1,23 @@ -# Generated from qmdisubwindow.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 DEFINES QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - INCLUDE_DIRECTORIES - . - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets Qt::WidgetsPrivate diff --git a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp index a4283de59e..60b675b18a 100644 --- a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp +++ b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qmdisubwindow.h" #include "private/qmdisubwindow_p.h" @@ -45,10 +20,13 @@ #include <QStyleOptionTitleBar> #include <QPushButton> #include <QScreen> +#include <QScrollBar> #include <QSizeGrip> #include <QSignalSpy> #include <QList> +#include <QtWidgets/private/qapplication_p.h> + QT_BEGIN_NAMESPACE extern bool qt_tab_all_widgets(); QT_END_NAMESPACE @@ -221,6 +199,7 @@ private slots: void styleChange(); void testFullScreenState(); void testRemoveBaseWidget(); + void testRespectMinimumSize(); }; void tst_QMdiSubWindow::initTestCase() @@ -405,7 +384,6 @@ void tst_QMdiSubWindow::mainWindowSupport() mainWindow.setCentralWidget(workspace); mainWindow.show(); mainWindow.menuBar()->setVisible(true); - QApplication::setActiveWindow(&mainWindow); bool nativeMenuBar = mainWindow.menuBar()->isNativeMenuBar(); // QMainWindow's window title is empty, so on a platform which does NOT have a native menubar, @@ -494,7 +472,7 @@ void tst_QMdiSubWindow::mainWindowSupport() workspace->activateNextSubWindow(); QCoreApplication::processEvents(); - for (QMdiSubWindow *window : qAsConst(windows)) { + for (QMdiSubWindow *window : std::as_const(windows)) { QCOMPARE(workspace->activeSubWindow(), window); QVERIFY(window->isMaximized()); QVERIFY(window->maximizedButtonsWidget()); @@ -531,7 +509,6 @@ void tst_QMdiSubWindow::emittingOfSignals() workspace.setWindowTitle(QLatin1String(QTest::currentTestFunction())); workspace.show(); QCoreApplication::processEvents(); - QApplication::setActiveWindow(&workspace); QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget)); QCoreApplication::processEvents(); window->show(); @@ -551,9 +528,9 @@ void tst_QMdiSubWindow::emittingOfSignals() int count = 0; if (signal == SIGNAL(aboutToActivate())) { - count += spy.count(); + count += spy.size(); } else { - for (int i = 0; i < spy.count(); ++i) { + for (int i = 0; i < spy.size(); ++i) { Qt::WindowStates oldState = qvariant_cast<Qt::WindowStates>(spy.at(i).at(0)); Qt::WindowStates newState = qvariant_cast<Qt::WindowStates>(spy.at(i).at(1)); if (watchedState != Qt::WindowNoState) { @@ -576,7 +553,7 @@ void tst_QMdiSubWindow::emittingOfSignals() spy.clear(); triggerSignal(window, &workspace, signal); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); delete window; window = nullptr; @@ -975,6 +952,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 @@ -1002,8 +981,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); } @@ -1053,7 +1034,7 @@ void tst_QMdiSubWindow::setSystemMenu() subWindow->setSystemMenu(systemMenu); QCOMPARE(subWindow->systemMenu(), qobject_cast<QMenu *>(systemMenu)); QCOMPARE(subWindow->systemMenu()->parentWidget(), static_cast<QWidget *>(subWindow)); - QCOMPARE(subWindow->systemMenu()->actions().count(), 1); + QCOMPARE(subWindow->systemMenu()->actions().size(), 1); // Show the new system menu QVERIFY(!QApplication::activePopupWidget()); @@ -1157,7 +1138,7 @@ void tst_QMdiSubWindow::restoreFocus() topArea.show(); box->show(); - QApplication::setActiveWindow(&topArea); + QApplicationPrivate::setActiveWindow(&topArea); QMdiSubWindow *expectedFocusWindow = nestedWorkspace->subWindowList().last(); QVERIFY(expectedFocusWindow); QVERIFY(expectedFocusWindow->widget()); @@ -1249,7 +1230,6 @@ void tst_QMdiSubWindow::restoreFocusOverCreation() subWidget1->m_lineEdit2->setFocus(); subWindow1->show(); mdiArea.show(); - QApplication::setActiveWindow(&mdiArea); QVERIFY(QTest::qWaitForWindowActive(&mdiArea)); QCOMPARE(QApplication::focusWidget(), subWidget1->m_lineEdit2); @@ -1277,9 +1257,9 @@ void tst_QMdiSubWindow::changeFocusWithTab() mdiArea.setWindowTitle(QLatin1String(QTest::currentTestFunction())); mdiArea.addSubWindow(widget); mdiArea.show(); - QCOMPARE(mdiArea.subWindowList().count(), 1); + QCOMPARE(mdiArea.subWindowList().size(), 1); - QApplication::setActiveWindow(&mdiArea); + QApplicationPrivate::setActiveWindow(&mdiArea); QCOMPARE(QApplication::focusWidget(), static_cast<QWidget *>(firstLineEdit)); // Next @@ -1359,7 +1339,7 @@ void tst_QMdiSubWindow::closeEvent() QVERIFY(window->close()); QCOMPARE(closeSpy.count(), 3); - QCOMPARE(mdiArea.subWindowList().count(), 0); + QCOMPARE(mdiArea.subWindowList().size(), 0); } // There exists more tests in QMdiArea which covers window title support @@ -1394,7 +1374,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()); @@ -1567,9 +1547,6 @@ void tst_QMdiSubWindow::hideAndShow() #if !defined (Q_OS_DARWIN) QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner)); -#if defined Q_OS_QNX - QEXPECT_FAIL("", "QTBUG-38231", Abort); -#endif QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); @@ -1800,9 +1777,6 @@ void tst_QMdiSubWindow::replaceMenuBarWhileMaximized() QCoreApplication::processEvents(); -#if defined Q_OS_QNX - QEXPECT_FAIL("", "QTBUG-38231", Abort); -#endif QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar1->cornerWidget(Qt::TopLeftCorner), subWindow->maximizedSystemMenuIconWidget()); @@ -1894,7 +1868,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"))); @@ -1980,7 +1953,6 @@ void tst_QMdiSubWindow::task_182852() mainWindow.setCentralWidget(workspace); mainWindow.show(); mainWindow.menuBar()->setVisible(true); - QApplication::setActiveWindow(&mainWindow); if (mainWindow.menuBar()->isNativeMenuBar()) return; // The main window's title is not overwritten if we have a native menubar (macOS, Unity etc.) @@ -2130,7 +2102,7 @@ void tst_QMdiSubWindow::styleChange() // subWindowActivated should NOT be activated by a style change, // even if internally QMdiSubWindow un-minimizes subwindows temporarily. - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QMdiSubWindow::testFullScreenState() @@ -2169,6 +2141,36 @@ void tst_QMdiSubWindow::testRemoveBaseWidget() delete widget1; } +void tst_QMdiSubWindow::testRespectMinimumSize() // QTBUG-100494 +{ + QMdiArea mdiArea; + mdiArea.resize(400, 400); + mdiArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + mdiArea.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + auto vlay = new QVBoxLayout; + vlay->addWidget(new QPushButton(QLatin1String("btn1-1"))); + vlay->addSpacerItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding)); + vlay->addWidget(new QPushButton(QLatin1String("btn1-2"))); + auto w1 = new QWidget; + w1->setLayout(vlay); + w1->resize(300, 200); + w1->setMinimumSize(200, 150); + auto sw = new QMdiSubWindow; + sw->setWidget(w1); + sw->resize(w1->size()); + mdiArea.addSubWindow(sw); + sw->showMaximized(); + + mdiArea.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); + QVERIFY(!mdiArea.horizontalScrollBar()->isVisible()); + QVERIFY(!mdiArea.verticalScrollBar()->isVisible()); + mdiArea.resize(150, 100); + QTRY_VERIFY(mdiArea.horizontalScrollBar()->isVisible()); + QTRY_VERIFY(mdiArea.verticalScrollBar()->isVisible()); +} + QTEST_MAIN(tst_QMdiSubWindow) #include "tst_qmdisubwindow.moc" diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST index 230512769c..88484ddffa 100644 --- a/tests/auto/widgets/widgets/qmenu/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -1,10 +1,6 @@ [task258920_mouseBorder] macos -[layoutDirection] -macos # Fails when enabling synchronous expose events QTBUG-62092 -[pushButtonPopulateOnAboutToShow] -macos [tearOff] macos [submenuTearOffDontClose] @@ -20,6 +16,7 @@ android android [pushButtonPopulateOnAboutToShow] android +wayland [QTBUG8122_widgetActionCrashOnClose] android [click_while_dismissing_submenu] @@ -29,3 +26,6 @@ android [QTBUG_89082_actionTipsHide] macos ci # Can't move cursor (QTBUG-76312) windows-10 ci +# QTBUG-87424 +[transientParent] +android diff --git a/tests/auto/widgets/widgets/qmenu/CMakeLists.txt b/tests/auto/widgets/widgets/qmenu/CMakeLists.txt index 8e596a6b5b..1716ab85da 100644 --- a/tests/auto/widgets/widgets/qmenu/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qmenu/CMakeLists.txt @@ -1,17 +1,25 @@ -# Generated from qmenu.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::TestPrivate Qt::Widgets + Qt::WidgetsPrivate ) ## Scopes: @@ -20,7 +28,7 @@ qt_internal_add_test(tst_qmenu qt_internal_extend_target(tst_qmenu CONDITION MACOS SOURCES tst_qmenu_mac.mm - PUBLIC_LIBRARIES + LIBRARIES objc ) diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index 4b46c05568..57cc404fc7 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QtTest/private/qtesthelpers_p.h> @@ -52,6 +27,9 @@ #include <qpa/qplatformtheme.h> #include <qpa/qplatformintegration.h> +#include <QtWidgets/private/qapplication_p.h> +#include <QtWidgets/private/qmenu_p.h> + using namespace QTestPrivate; Q_DECLARE_METATYPE(Qt::Key); @@ -118,6 +96,7 @@ private slots: void QTBUG_89082_actionTipsHide(); void QTBUG8122_widgetActionCrashOnClose(); void widgetActionTriggerClosesMenu(); + void transientParent(); void QTBUG_10735_crashWithDialog(); #ifdef Q_OS_MAC @@ -134,6 +113,9 @@ private slots: void tearOffMenuNotDisplayed(); void QTBUG_61039_menu_shortcuts(); void screenOrientationChangedCloseMenu(); + void deleteWhenTriggered(); + + void nestedTearOffDetached(); protected slots: void onActivated(QAction*); @@ -281,11 +263,11 @@ void tst_QMenu::onStatusMessageChanged(const QString &s) void tst_QMenu::addActionsAndClear() { - QCOMPARE(menus[0]->actions().count(), 0); + QCOMPARE(menus[0]->actions().size(), 0); createActions(); - QCOMPARE(menus[0]->actions().count(), 8); + QCOMPARE(menus[0]->actions().size(), 8); menus[0]->clear(); - QCOMPARE(menus[0]->actions().count(), 0); + QCOMPARE(menus[0]->actions().size(), 0); } static void testFunction0() {} @@ -505,7 +487,7 @@ void tst_QMenu::focus() QPushButton button("Push me", &window); centerOnScreen(&window); window.show(); - qApp->setActiveWindow(&window); + QApplicationPrivate::setActiveWindow(&window); QVERIFY(button.hasFocus()); QCOMPARE(QApplication::focusWidget(), (QWidget *)&button); @@ -549,7 +531,6 @@ void tst_QMenu::overrideMenuAction() m->addAction(aQuit); w.show(); - QApplication::setActiveWindow(&w); w.setFocus(); QVERIFY(QTest::qWaitForWindowActive(&w)); QVERIFY(w.hasFocus()); @@ -917,13 +898,20 @@ private: void tst_QMenu::activeSubMenuPositionExec() { - +#ifdef Q_OS_ANDROID + // QTBUG-87424 + QSKIP("Android: This hangs. Figure out why."); +#endif SubMenuPositionExecMenu menu; menu.exec(QGuiApplication::primaryScreen()->availableGeometry().center()); } void tst_QMenu::task242454_sizeHint() { +#ifdef Q_OS_ANDROID + // QTBUG-87424 + QSKIP("Android: This hangs. Figure out why."); +#endif QMenu menu; QString s = QLatin1String("foo\nfoo\nfoo\nfoo"); menu.addAction(s); @@ -1052,12 +1040,16 @@ public: // Mouse move related signals for Windows Mobile unavailable void tst_QMenu::task258920_mouseBorder() { + const QRect screenGeometry = QGuiApplication::primaryScreen()->availableGeometry(); Menu258920 menu; + QCursor::setPos(screenGeometry.topLeft()); + if (!QTest::qWaitFor([screenGeometry]{ return QCursor::pos() == screenGeometry.topLeft(); })) + QSKIP("Can't move cursor out of the way"); // For styles which inherit from QWindowsStyle, styleHint(QStyle::SH_Menu_MouseTracking) is true. menu.setMouseTracking(true); QAction *action = menu.addAction("test"); - const QPoint center = QGuiApplication::primaryScreen()->availableGeometry().center(); + const QPoint center = screenGeometry.center(); menu.popup(center); QVERIFY(QTest::qWaitForWindowExposed(&menu)); QRect actionRect = menu.actionGeometry(action); @@ -1153,14 +1145,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())); } @@ -1275,7 +1271,7 @@ void tst_QMenu::click_while_dismissing_submenu() //the submenu must have been hidden for the bug to be triggered QVERIFY(!sub.isVisible()); QTest::mouseRelease(menuWindow, Qt::LeftButton, {}, menu.rect().center() - QPoint(0, 2), 300); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } #endif @@ -1588,6 +1584,53 @@ void tst_QMenu::widgetActionTriggerClosesMenu() QCOMPARE(actionTriggered, &widgetAction); } +void tst_QMenu::transientParent() +{ + QMainWindow window; + window.resize(480, 320); + window.menuBar()->setNativeMenuBar(false); + centerOnScreen(&window); + + QMenu *fileMenu = new QMenu("&File"); + QAction *exitAct = new QAction("Exit"); + fileMenu->addAction(exitAct); + + QMenu *editMenu = new QMenu("&Edit"); + QAction *undoAct = new QAction("Undo"); + editMenu->addAction(undoAct); + + QMenuBar *menuBar = new QMenuBar; + menuBar->addMenu(fileMenu); + menuBar->addMenu(editMenu); + window.setMenuBar(menuBar); + + // On Mac, we need to create native key events to test menu + // action activation, so skip this part of the test. +#if QT_CONFIG(shortcut) && !defined(Q_OS_DARWIN) + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QWindow *topLevel = window.windowHandle(); + QVERIFY(topLevel); + + window.setFocus(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(window.hasFocus()); + + QTest::keyPress(&window, Qt::Key_F, Qt::AltModifier); + QTRY_VERIFY(QTest::qWaitForWindowExposed(fileMenu)); + if (fileMenu->isWindow() && fileMenu->window() && fileMenu->window()->windowHandle()) + QVERIFY(fileMenu->window()->windowHandle()->transientParent()); + QTest::keyRelease(fileMenu, Qt::Key_F, Qt::AltModifier); + + QTest::keyPress(fileMenu, Qt::Key_E, Qt::AltModifier); + QTRY_VERIFY(QTest::qWaitForWindowExposed(editMenu)); + if (editMenu->isWindow() && editMenu->window() && editMenu->window()->windowHandle()) + QVERIFY(editMenu->window()->windowHandle()->transientParent()); + QTest::keyRelease(editMenu, Qt::Key_E, Qt::AltModifier); +#endif // QT_CONFIG(shortcut) && !Q_OS_DARWIN + +} + class MyMenu : public QMenu { Q_OBJECT @@ -1803,12 +1846,12 @@ void tst_QMenu::menuSize_Scrolling() private: void showEvent(QShowEvent *e) override { - QVERIFY(actions().length() == m_numItems); + QVERIFY(actions().size() == m_numItems); int hmargin = style()->pixelMetric(QStyle::PM_MenuHMargin, nullptr, this); int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, this); const QMargins cm = contentsMargins(); - QRect lastItem = actionGeometry(actions().at(actions().length() - 1)); + QRect lastItem = actionGeometry(actions().at(actions().size() - 1)); QSize s = size(); if (!QGuiApplication::platformName().compare(QLatin1String("minimal"), Qt::CaseInsensitive) || !QGuiApplication::platformName().compare(QLatin1String("offscreen"), Qt::CaseInsensitive)) { @@ -1874,7 +1917,7 @@ void tst_QMenu::menuSize_Scrolling() QVERIFY(QTest::qWaitForWindowExposed(&menu)); QList<QAction *> actions = menu.actions(); - QCOMPARE(actions.length(), numItems); + QCOMPARE(actions.size(), numItems); MenuMetrics mm(&menu); QTest::keyClick(&menu, Qt::Key_Home); @@ -1954,11 +1997,11 @@ void tst_QMenu::QTBUG_61039_menu_shortcuts() QSignalSpy actionKamenSpy(actionKamen, &QAction::triggered); QTest::keyClick(&widget, Qt::Key_K); - QTRY_COMPARE(actionKamenSpy.count(), 1); + QTRY_COMPARE(actionKamenSpy.size(), 1); QSignalSpy actionJoeSpy(actionJoe, &QAction::triggered); QTest::keyClick(&widget, Qt::Key_J, Qt::ControlModifier); - QTRY_COMPARE(actionJoeSpy.count(), 1); + QTRY_COMPARE(actionJoeSpy.size(), 1); } void tst_QMenu::screenOrientationChangedCloseMenu() @@ -1976,5 +2019,99 @@ void tst_QMenu::screenOrientationChangedCloseMenu() QTRY_COMPARE(menu.isVisible(),false); } +/* + Verify that deleting the menu in a slot connected to an + action's triggered signal doesn't crash. + QTBUG-106718 +*/ +void tst_QMenu::deleteWhenTriggered() +{ + QPointer<QMenu> menu = new QMenu; + QAction *action = menu->addAction("Action", [&menu]{ + delete menu; + }); + menu->popup(QGuiApplication::primaryScreen()->availableGeometry().center()); + menu->setActiveAction(action); + QTest::keyClick(menu, Qt::Key_Return); + 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 f90af47c19..ba76c28fd4 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu_mac.mm @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 633bda332f..516fd39f86 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -1,10 +1,5 @@ [check_menuPosition] -ubuntu-16.04 -#QTBUG-66255 -ubuntu-18.04 -ubuntu-20.04 -[activatedCount] -opensuse-42.3 +ubuntu-22.04 # QTBUG-87421 [cornerWidgets] android diff --git a/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt b/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt index 63f690a2ed..f2b1c1bec6 100644 --- a/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qmenubar/CMakeLists.txt @@ -1,16 +1,24 @@ -# Generated from qmenubar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::TestPrivate Qt::Widgets + Qt::WidgetsPrivate ) ## Scopes: @@ -19,6 +27,6 @@ qt_internal_add_test(tst_qmenubar qt_internal_extend_target(tst_qmenubar CONDITION MACOS SOURCES tst_qmenubar_mac.mm - PUBLIC_LIBRARIES + LIBRARIES ${FWAppKit} ) diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index 1b8de0b75c..06750b099b 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -40,10 +15,13 @@ #include <QVBoxLayout> #include <QLabel> #include <QPlainTextEdit> +#include <QTranslator> #include <qscreen.h> #include <qobject.h> +#include <QtWidgets/private/qapplication_p.h> + QT_FORWARD_DECLARE_CLASS(QMainWindow) #include <qmenubar.h> @@ -115,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(); @@ -144,6 +115,8 @@ private slots: #ifdef Q_OS_MACOS void taskQTBUG56275_reinsertMenuInParentlessQMenuBar(); void QTBUG_57404_existingMenuItemException(); + void defaultEditMenuItems(); + #endif void QTBUG_25669_menubarActionDoubleTriggered(); void taskQTBUG55966_subMenuRemoved(); @@ -151,6 +124,9 @@ private slots: void platformMenu(); void addActionQt5connect(); void QTBUG_65488_hiddenActionTriggered(); + void pressDragRelease_data(); + void pressDragRelease(); + protected slots: void onSimpleActivated( QAction*); void onComplexActionTriggered(); @@ -168,6 +144,7 @@ private: int m_simpleActivatedCount; int m_complexTriggerCount[int('k')]; QMenuBar* taskQTBUG53205MenuBar; + QScopedPointer<QPointingDevice> m_touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice()); }; // Testing get/set functions @@ -356,7 +333,6 @@ void tst_QMenuBar::accel() QMainWindow w; const TestMenu menu = initWindowWithSimpleMenuBar(w); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); // shortcuts won't work unless the window is active QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier ); @@ -378,7 +354,6 @@ void tst_QMenuBar::activatedCount() QFETCH( bool, forceNonNative ); initWindowWithSimpleMenuBar(w, forceNonNative); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_A, Qt::ControlModifier ); @@ -578,7 +553,6 @@ void tst_QMenuBar::check_accelKeys() QMainWindow w; initWindowWithComplexMenuBar(w); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); // start with a bogus key that shouldn't trigger anything @@ -657,7 +631,6 @@ void tst_QMenuBar::check_cursorKeys1() QMainWindow w; initWindowWithComplexMenuBar(w); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); // start with a ALT + 1 that activates the first popupmenu @@ -697,7 +670,6 @@ void tst_QMenuBar::check_cursorKeys2() QMainWindow w; initWindowWithComplexMenuBar(w); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); // select popupmenu2 @@ -736,7 +708,6 @@ void tst_QMenuBar::check_cursorKeys3() QMainWindow w; initWindowWithComplexMenuBar(w); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); // select Popupmenu 2 @@ -778,7 +749,6 @@ void tst_QMenuBar::taskQTBUG56860_focus() w.setCentralWidget(e); w.show(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QTRY_COMPARE(QApplication::focusWidget(), e); @@ -805,85 +775,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(); - QApplication::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(); - QApplication::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. @@ -900,7 +791,6 @@ void tst_QMenuBar::check_escKey() const TestMenu menu = initWindowWithComplexMenuBar(w); w.show(); w.setFocus(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QVERIFY( !menu.menus.at(0)->isActiveWindow() ); @@ -938,112 +828,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; @@ -1098,7 +882,6 @@ void tst_QMenuBar::check_altPress() initWindowWithSimpleMenuBar(w); w.show(); w.setFocus(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QTest::keyClick( &w, Qt::Key_Alt ); @@ -1128,7 +911,6 @@ void tst_QMenuBar::check_altClosePress() w.show(); w.move(QGuiApplication::primaryScreen()->availableGeometry().center()); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QTest::keyClick(&w, Qt::Key_F, Qt::AltModifier); @@ -1149,7 +931,6 @@ void tst_QMenuBar::check_shortcutPress() const TestMenu menu = initWindowWithComplexMenuBar(w); w.show(); w.setFocus(); - QApplication::setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); QCOMPARE(m_complexTriggerCount[3], 0); @@ -1206,7 +987,6 @@ void tst_QMenuBar::check_menuPosition() QAction *menu_action = w.menuBar()->addMenu(&menu); centerOnScreen(&w); w.show(); - qApp->setActiveWindow(&w); QVERIFY(QTest::qWaitForWindowActive(&w)); //the menu should be below the menubar item @@ -1290,9 +1070,9 @@ void tst_QMenuBar::task223138_triggered() //let's trigger the first action top->trigger(); - QCOMPARE(menubarSpy.count(), 1); - QCOMPARE(menuSpy.count(), 1); - QCOMPARE(submenuSpy.count(), 0); + QCOMPARE(menubarSpy.size(), 1); + QCOMPARE(menuSpy.size(), 1); + QCOMPARE(submenuSpy.size(), 0); menubarSpy.clear(); menuSpy.clear(); @@ -1300,9 +1080,9 @@ void tst_QMenuBar::task223138_triggered() //let's trigger the sub action action->trigger(); - QCOMPARE(menubarSpy.count(), 1); - QCOMPARE(menuSpy.count(), 1); - QCOMPARE(submenuSpy.count(), 1); + QCOMPARE(menubarSpy.size(), 1); + QCOMPARE(menuSpy.size(), 1); + QCOMPARE(submenuSpy.size(), 1); } void tst_QMenuBar::task256322_highlight() @@ -1325,7 +1105,6 @@ void tst_QMenuBar::task256322_highlight() centerOnScreen(&win); win.show(); - QApplication::setActiveWindow(&win); QVERIFY(QTest::qWaitForWindowActive(&win)); const QPoint filePos = menuBarActionWindowPos(win.menuBar(), file); @@ -1381,8 +1160,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); @@ -1393,7 +1172,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); @@ -1429,11 +1209,11 @@ void tst_QMenuBar::taskQTBUG4965_escapeEaten() QMenu menu("menu1"); QAction *first = menubar.addMenu(&menu); #if QT_CONFIG(shortcut) - menu.addAction("quit", &menubar, SLOT(close()), QKeySequence("ESC")); + menu.addAction("quit", QKeySequence("ESC"), &menubar, SLOT(close())); #endif centerOnScreen(&menubar); menubar.show(); - QApplication::setActiveWindow(&menubar); + QApplicationPrivate::setActiveWindow(&menubar); QVERIFY(QTest::qWaitForWindowExposed(&menubar)); menubar.setActiveAction(first); QTRY_VERIFY(menu.isVisible()); @@ -1464,7 +1244,6 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions() centerOnScreen(&menubar); menubar.show(); - QApplication::setActiveWindow(&menubar); QVERIFY(QTest::qWaitForWindowActive(&menubar)); menubar.setActiveAction(m); QCOMPARE(menubar.activeAction(), m); @@ -1495,7 +1274,6 @@ void tst_QMenuBar::closeOnSecondClickAndOpenOnThirdClick() // QTBUG-32807, menu QMenu *fileMenu = menuBar->addMenu(QStringLiteral("OpenCloseOpen")); fileMenu->addAction(QStringLiteral("Quit")); mainWindow.show(); - QApplication::setActiveWindow(&mainWindow); QVERIFY(QTest::qWaitForWindowActive(&mainWindow)); const QPoint center = menuBarActionWindowPos(mainWindow.menuBar(), fileMenu->menuAction()); @@ -1590,7 +1368,6 @@ void tst_QMenuBar::taskQTBUG53205_crashReparentNested() mainWindow.resize(300, 200); centerOnScreen(&mainWindow); const TestMenu testMenus = initWindowWithComplexMenuBar(mainWindow); - QApplication::setActiveWindow(&mainWindow); // they can't be windows QWidget hiddenParent(&mainWindow, {}); @@ -1640,12 +1417,75 @@ void tst_QMenuBar::QTBUG_65488_hiddenActionTriggered() // resize to action's size to make Action1 hidden win.resize(actRect.width() - 10, win.size().height()); win.show(); - QApplication::setActiveWindow(&win); QVERIFY(QTest::qWaitForWindowExposed(&win)); // click center of the blank area on the menubar where Action1 resided QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, win.menuBar()->geometry().center()); QCoreApplication::sendPostedEvents(); // make sure all queued events also dispatched - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); +} + +void tst_QMenuBar::pressDragRelease_data() +{ + QTest::addColumn<QPointingDevice *>("device"); + + QTest::newRow("mouse") << const_cast<QPointingDevice *>(QPointingDevice::primaryPointingDevice()); + QTest::newRow("touchscreen") << m_touchScreen.get(); +} + +void tst_QMenuBar::pressDragRelease() +{ + QFETCH(QPointingDevice *, device); + + QMainWindow w; + const TestMenu menu = initWindowWithComplexMenuBar(w); + const QMenu *firstMenu = menu.menus.first(); + QAction *hoveredAction = nullptr; + connect(firstMenu, &QMenu::hovered, firstMenu, [&hoveredAction](QAction *hov) { hoveredAction = hov; }); + w.show(); + QVERIFY(QTest::qWaitForWindowActive(&w)); + QWindow *win = w.windowHandle(); + const QPoint p1(50, w.menuBar()->geometry().height() / 2); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mousePress(win, Qt::LeftButton, {}, p1); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).press(0, p1); + break; + default: + break; + } + + QTRY_VERIFY(firstMenu->isVisible()); + const QPoint firstMenuItemPos = firstMenu->geometry().center() - QPoint(0, 2); + const QPoint firstMenuItemPosInWin = w.mapFromGlobal(firstMenuItemPos); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mouseMove(win, firstMenuItemPosInWin); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).move(0, firstMenuItemPosInWin); + break; + default: + break; + } + QVERIFY(hoveredAction); + QCOMPARE(hoveredAction, firstMenu->actionAt(firstMenu->mapFromGlobal(firstMenuItemPos))); + QSignalSpy triggeredSpy(hoveredAction, &QAction::triggered); + switch (device->type()) { + case QInputDevice::DeviceType::Mouse: + case QInputDevice::DeviceType::TouchPad: + QTest::mouseRelease(win, Qt::LeftButton, {}, firstMenuItemPosInWin); + break; + case QInputDevice::DeviceType::TouchScreen: + QTest::touchEvent(win, device).release(0, firstMenuItemPosInWin); + break; + default: + break; + } + QTRY_COMPARE(triggeredSpy.size(), 1); } // QTBUG-56526 @@ -1712,20 +1552,19 @@ void tst_QMenuBar::QTBUG_25669_menubarActionDoubleTriggered() QSignalSpy spy(win.menuBar(), &QMenuBar::triggered); win.show(); - QApplication::setActiveWindow(&win); QVERIFY(QTest::qWaitForWindowExposed(&win)); QPoint posAct1 = menuBarActionWindowPos(win.menuBar(), act1); QPoint posAct2 = menuBarActionWindowPos(win.menuBar(), act2); QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct1); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2); - QTRY_COMPARE(spy.count(), 2); + QTRY_COMPARE(spy.size(), 2); QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2); - QTRY_COMPARE(spy.count(), 3); + QTRY_COMPARE(spy.size(), 3); } void tst_QMenuBar::slotForTaskQTBUG53205() @@ -1749,7 +1588,6 @@ void tst_QMenuBar::taskQTBUG46812_doNotLeaveMenubarHighlighted() initWindowWithSimpleMenuBar(mainWindow); mainWindow.show(); - QApplication::setActiveWindow(&mainWindow); QVERIFY(QTest::qWaitForWindowActive(&mainWindow)); QVERIFY(!mainWindow.menuBar()->hasFocus()); @@ -1818,6 +1656,32 @@ void tst_QMenuBar::QTBUG_57404_existingMenuItemException() QTest::qWait(100); // No crash, all fine. Ideally, there should be only one warning. } + +void tst_QMenuBar::defaultEditMenuItems() +{ + class TestTranslator : public QTranslator + { + public: + QString translate(const char *context, const char *sourceText, + const char *disambiguation = nullptr, int n = -1) const override + { + if (QByteArrayView(context) == "QCocoaMenu" && QByteArrayView(sourceText) == "Edit") + return QString("Editieren"); + return QTranslator::translate(context, sourceText, disambiguation, n); + } + } testTranslator; + qApp->installTranslator(&testTranslator); + + QMainWindow mw; + mw.show(); + QVERIFY(QTest::qWaitForWindowActive(&mw)); + + mw.menuBar()->addMenu("Editieren")->addAction("Undo"); + + mw.hide(); + mw.show(); + // this should not crash with infinite recursion +} #endif // Q_OS_MACOS void tst_QMenuBar::taskQTBUG55966_subMenuRemoved() @@ -1835,7 +1699,6 @@ void tst_QMenuBar::taskQTBUG55966_subMenuRemoved() delete subMenu; window.show(); - QApplication::setActiveWindow(&window); QVERIFY(QTest::qWaitForWindowActive(&window)); QTest::qWait(500); } diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm index 823ca7edfa..55e983a4d1 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar_mac.mm @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// 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 ecb962d8ca..6b96499889 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST +++ b/tests/auto/widgets/widgets/qopenglwidget/BLACKLIST @@ -1,5 +1,7 @@ -[stackWidgetOpaqueChildIsVisible] -windows-10 msvc-2017 +# Temporary solution COIN-966 +ubuntu +rhel +opensuse-leap # QTBUG-87436 [clearAndGrab] diff --git a/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt index f32b547329..78cef5300a 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qopenglwidget/CMakeLists.txt @@ -1,14 +1,21 @@ -# Generated from qopenglwidget.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 # special case + LOWDPI SOURCES tst_qopenglwidget.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp index 3d7bb36f24..51f898c953 100644 --- a/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp +++ b/tests/auto/widgets/widgets/qopenglwidget/tst_qopenglwidget.cpp @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtOpenGLWidgets/QOpenGLWidget> #include <QtGui/QOpenGLFunctions> #include <QtGui/QPainter> +#include <QtGui/QBackingStore> #include <QtGui/QScreen> #include <QtGui/QStaticText> #include <QtWidgets/QGraphicsView> @@ -37,12 +13,18 @@ #include <QtWidgets/QVBoxLayout> #include <QtWidgets/QPushButton> #include <QtWidgets/QStackedWidget> +#include <QtWidgets/QTabWidget> +#include <QtWidgets/QLabel> #include <QTest> #include <QSignalSpy> #include <private/qguiapplication_p.h> #include <private/qstatictext_p.h> #include <private/qopengltextureglyphcache_p.h> #include <qpa/qplatformintegration.h> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformbackingstore.h> +#include <qpa/qplatformintegration.h> +#include <rhi/qrhi.h> class tst_QOpenGLWidget : public QObject { @@ -54,10 +36,14 @@ private slots: void clearAndGrab(); void clearAndResizeAndGrab(); void createNonTopLevel(); +#if QT_CONFIG(egl) + void deviceLoss(); +#endif void painter(); void reparentToAlreadyCreated(); void reparentToNotYetCreated(); void reparentHidden(); + void reparentTopLevel(); void asViewport(); void requestUpdate(); void fboRedirect(); @@ -66,6 +52,9 @@ private slots: void stackWidgetOpaqueChildIsVisible(); void offscreen(); void offscreenThenOnscreen(); + void paintWhileHidden(); + void widgetWindowColorFormat_data(); + void widgetWindowColorFormat(); #ifdef QT_BUILD_INTERNAL void staticTextDanglingPointer(); @@ -87,7 +76,7 @@ void tst_QOpenGLWidget::create() QSignalSpy frameSwappedSpy(w.data(), SIGNAL(frameSwapped())); w->show(); QVERIFY(QTest::qWaitForWindowExposed(w.data())); - QVERIFY(frameSwappedSpy.count() > 0); + QVERIFY(frameSwappedSpy.size() > 0); QVERIFY(w->isValid()); QVERIFY(w->context()); @@ -152,6 +141,9 @@ void tst_QOpenGLWidget::clearAndGrab() void tst_QOpenGLWidget::clearAndResizeAndGrab() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif QScopedPointer<QOpenGLWidget> w(new ClearWidget(0, 640, 480)); w->resize(640, 480); w->show(); @@ -179,7 +171,7 @@ void tst_QOpenGLWidget::createNonTopLevel() w.resize(400, 400); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); - QVERIFY(frameSwappedSpy.count() > 0); + QVERIFY(frameSwappedSpy.size() > 0); QVERIFY(glw->m_resizeCalled); glw->m_resizeCalled = false; @@ -203,10 +195,49 @@ void tst_QOpenGLWidget::createNonTopLevel() QVERIFY(QOpenGLContext::currentContext() == glw->context() && glw->context()); } +#if QT_CONFIG(egl) +void tst_QOpenGLWidget::deviceLoss() +{ + QScopedPointer<QOpenGLWidget> w(new ClearWidget(0, 640, 480)); + + w->resize(640, 480); + w->show(); + + auto rhi = w->backingStore()->handle()->rhi(w->windowHandle()); + QNativeInterface::QEGLContext *rhiContext = nullptr; + if (rhi->backend() == QRhi::OpenGLES2) { + auto rhiHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles()); + rhiContext = rhiHandles->context->nativeInterface<QNativeInterface::QEGLContext>(); + } + if (!rhiContext) + QSKIP("deviceLoss needs EGL"); + + QVERIFY(QTest::qWaitForWindowExposed(w.data())); + + QImage image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); + + rhiContext->invalidateContext(); + + w->resize(600, 600); + QSignalSpy frameSwappedSpy(w.get(), &QOpenGLWidget::resized); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + + image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); +} +#endif + class PainterWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: - PainterWidget(QWidget *parent) + PainterWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent), m_clear(false) { } void initializeGL() override { @@ -272,6 +303,9 @@ void tst_QOpenGLWidget::reparentToAlreadyCreated() void tst_QOpenGLWidget::reparentToNotYetCreated() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif QWidget w1; PainterWidget *glw = new PainterWidget(&w1); w1.resize(640, 480); @@ -320,6 +354,70 @@ void tst_QOpenGLWidget::reparentHidden() QVERIFY(originalContext != newContext); } +void tst_QOpenGLWidget::reparentTopLevel() +{ +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif + // no GL content yet, just an ordinary tab widget, top-level + QTabWidget tabWidget; + tabWidget.resize(640, 480); + tabWidget.addTab(new QLabel("Dummy page"), "Page 1"); + tabWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&tabWidget)); + + PainterWidget *glw1 = new PainterWidget; + // add child GL widget as a tab page + { + QSignalSpy frameSwappedSpy(glw1, &QOpenGLWidget::frameSwapped); + tabWidget.setCurrentIndex(tabWidget.addTab(glw1, "OpenGL widget 1")); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + } + + PainterWidget *glw2 = new PainterWidget; + // add child GL widget #2 as a tab page + { + QSignalSpy frameSwappedSpy(glw2, &QOpenGLWidget::frameSwapped); + tabWidget.setCurrentIndex(tabWidget.addTab(glw2, "OpenGL widget 2")); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + } + + QImage image = glw2->grabFramebuffer(); + QVERIFY(image.pixel(20, 10) == qRgb(0, 0, 255)); + + // now delete GL widget #2 + { + QSignalSpy frameSwappedSpy(glw1, &QOpenGLWidget::frameSwapped); + delete glw2; + QTRY_VERIFY(frameSwappedSpy.size() > 0); + } + + image = glw1->grabFramebuffer(); + QVERIFY(image.pixel(20, 10) == qRgb(0, 0, 255)); + + // make the GL widget top-level + { + QSignalSpy frameSwappedSpy(glw1, &QOpenGLWidget::frameSwapped); + glw1->setParent(nullptr); + glw1->show(); + QVERIFY(QTest::qWaitForWindowExposed(glw1)); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + } + + image = glw1->grabFramebuffer(); + QVERIFY(image.pixel(20, 10) == qRgb(0, 0, 255)); + + // back to a child widget by readding to the tab widget + { + QSignalSpy frameSwappedSpy(glw1, &QOpenGLWidget::frameSwapped); + tabWidget.setCurrentIndex(tabWidget.addTab(glw1, "Re-added OpenGL widget 1")); + QTRY_VERIFY(frameSwappedSpy.size() > 0); + } + + image = glw1->grabFramebuffer(); + QVERIFY(image.pixel(20, 10) == qRgb(0, 0, 255)); +} + class CountingGraphicsView : public QGraphicsView { public: @@ -346,6 +444,9 @@ void CountingGraphicsView::drawForeground(QPainter *, const QRectF &) void tst_QOpenGLWidget::asViewport() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif // Have a QGraphicsView with a QOpenGLWidget as its viewport. QGraphicsScene scene; scene.addItem(new QGraphicsRectItem(10, 10, 100, 100)); @@ -367,6 +468,7 @@ void tst_QOpenGLWidget::asViewport() // repainted when going from Inactive to Active. So wait for the window to be // active before we continue, so the activation doesn't happen at a random // time below. And call processEvents to have the paint events delivered right away. + widget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&widget)); qApp->processEvents(); } @@ -394,8 +496,9 @@ public: void tst_QOpenGLWidget::requestUpdate() { - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif PaintCountWidget w; w.resize(640, 480); @@ -421,6 +524,9 @@ public: void tst_QOpenGLWidget::fboRedirect() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif FboCheckWidget w; w.resize(640, 480); w.show(); @@ -436,6 +542,9 @@ void tst_QOpenGLWidget::fboRedirect() void tst_QOpenGLWidget::showHide() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif QScopedPointer<ClearWidget> w(new ClearWidget(0, 800, 600)); w->resize(800, 600); w->show(); @@ -460,41 +569,187 @@ 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() { - QScopedPointer<ClearWidget> w(new ClearWidget(0, 800, 600)); - w->resize(800, 600); - w->show(); - w->winId(); - QVERIFY(QTest::qWaitForWindowExposed(w.data())); +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif - QImage image = w->grabFramebuffer(); - QVERIFY(!image.isNull()); - QCOMPARE(image.width(), w->width()); - QCOMPARE(image.height(), w->height()); - QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); - QVERIFY(w->internalWinId()); - - // Now as a native child. - QWidget nativeParent; - nativeParent.resize(800, 600); - nativeParent.setAttribute(Qt::WA_NativeWindow); - ClearWidget *child = new ClearWidget(0, 800, 600); - child->setClearColor(0, 1, 0); - child->setParent(&nativeParent); - child->resize(400, 400); - child->move(23, 34); - nativeParent.show(); - QVERIFY(QTest::qWaitForWindowExposed(&nativeParent)); - - QVERIFY(nativeParent.internalWinId()); - QVERIFY(!child->internalWinId()); - - image = child->grabFramebuffer(); - QVERIFY(!image.isNull()); - QCOMPARE(image.width(), child->width()); - QCOMPARE(image.height(), child->height()); - QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0)); + // NB these tests do not fully verify that native child widgets are fully + // functional since there is no guarantee that the content is composed and + // 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); + w->show(); + w->winId(); + QVERIFY(QTest::qWaitForWindowExposed(w.data())); + + QImage image = w->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), w->width()); + QCOMPARE(image.height(), w->height()); + QVERIFY(image.pixel(30, 40) == qRgb(255, 0, 0)); + QVERIFY(w->internalWinId()); + } + + // 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); + + ClearWidget *child = new ClearWidget(nullptr, 800, 600); + child->setParent(&topLevel); + + // make it a native child (native window, but not top-level -> no backingstore) + child->winId(); + + child->setClearColor(0, 1, 0); + child->resize(400, 400); + child->move(23, 34); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QVERIFY(topLevel.internalWinId()); + QVERIFY(child->internalWinId()); + + QImage image = child->grabFramebuffer(); + QVERIFY(!image.isNull()); + QCOMPARE(image.width(), child->width()); + QCOMPARE(image.height(), child->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0)); + } + + // Now the same with WA_NativeWindow instead + { + QWidget topLevel; + topLevel.resize(800, 600); + + ClearWidget *child = new ClearWidget(nullptr, 800, 600); + child->setParent(&topLevel); + + // make it a native child (native window, but not top-level -> no backingstore) + child->setAttribute(Qt::WA_NativeWindow); + + child->setClearColor(0, 1, 0); + child->resize(400, 400); + child->move(23, 34); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QVERIFY(child->internalWinId()); + + QImage image = child->grabFramebuffer(); + QCOMPARE(image.width(), child->width()); + QCOMPARE(image.height(), child->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 255, 0)); + } + + // Now as a child of a native child + { + QWidget topLevel; + topLevel.resize(800, 600); + + QWidget *container = new QWidget(&topLevel); + // make it a native child (native window, but not top-level -> no backingstore) + container->winId(); + + ClearWidget *child = new ClearWidget(nullptr, 800, 600); + // set the parent separately, this is important, see next test case + child->setParent(container); + child->setClearColor(0, 0, 1); + child->resize(400, 400); + child->move(23, 34); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QVERIFY(topLevel.internalWinId()); + QVERIFY(container->internalWinId()); + QVERIFY(!child->internalWinId()); + + QImage image = child->grabFramebuffer(); + QCOMPARE(image.width(), child->width()); + QCOMPARE(image.height(), child->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255)); + } + + // Again as a child of a native child, but this time specifying the parent + // upon construction, not with an explicit setParent() call afterwards. + { + QWidget topLevel; + topLevel.resize(800, 600); + QWidget *container = new QWidget(&topLevel); + container->winId(); + // parent it right away + ClearWidget *child = new ClearWidget(container, 800, 600); + child->setClearColor(0, 0, 1); + child->resize(400, 400); + child->move(23, 34); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QVERIFY(topLevel.internalWinId()); + QVERIFY(container->internalWinId()); + QVERIFY(!child->internalWinId()); + QImage image = child->grabFramebuffer(); + QCOMPARE(image.width(), child->width()); + QCOMPARE(image.height(), child->height()); + QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255)); + } + + if (oldHandler) { + qInstallMessageHandler(oldHandler); + oldHandler = nullptr; + } } static inline QString msgRgbMismatch(unsigned actual, unsigned expected) @@ -533,50 +788,59 @@ static QPixmap grabWidgetWithoutRepaint(const QWidget *widget, QRect clipArea) bool verifyColor(const QWidget *widget, const QRect &clipArea, const QColor &color, int callerLine) { - for (int t = 0; t < 6; t++) { - const QPixmap pixmap = grabWidgetWithoutRepaint(widget, clipArea); - if (!QTest::qCompare(pixmap.size(), - clipArea.size(), - "pixmap.size()", - "rect.size()", - __FILE__, - callerLine)) - return false; - - - const QImage image = pixmap.toImage(); - QPixmap expectedPixmap(pixmap); /* ensure equal formats */ - expectedPixmap.detach(); - expectedPixmap.fill(color); - + // Create a comparison target image + QPixmap expectedPixmap(grabWidgetWithoutRepaint(widget, clipArea)); /* ensure equal formats */ + expectedPixmap.detach(); + expectedPixmap.fill(color); + const QImage expectedImage = expectedPixmap.toImage(); + + // test image size + QPixmap pixmap; + auto testSize = [&](){ + pixmap = grabWidgetWithoutRepaint(widget, clipArea); + return pixmap.size() == clipArea.size(); + }; + + // test the first pixel's color + uint firstPixel; + auto testPixel = [&](){ + const QImage image = grabWidgetWithoutRepaint(widget, clipArea).toImage(); uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; - uint firstPixel = image.pixel(0,0) | alphaCorrection; - - // Retry a couple of times. Some window managers have transparency animation, or are - // just slow to render. - if (t < 5) { - if (firstPixel == QColor(color).rgb() - && image == expectedPixmap.toImage()) - return true; - else - QTest::qWait(200); - } else { - if (!QTest::qVerify(firstPixel == QColor(color).rgb(), - "firstPixel == QColor(color).rgb()", - qPrintable(msgRgbMismatch(firstPixel, QColor(color).rgb())), - __FILE__, callerLine)) { - return false; - } - if (!QTest::qVerify(image == expectedPixmap.toImage(), - "image == expectedPixmap.toImage()", - "grabbed pixmap differs from expected pixmap", - __FILE__, callerLine)) { - return false; - } - } + firstPixel = image.pixel(0,0) | alphaCorrection; + return firstPixel == QColor(color).rgb(); + }; + + // test the rendered image + QImage image; + auto testImage = [&](){ + image = grabWidgetWithoutRepaint(widget, clipArea).toImage(); + return image == expectedImage; + }; + + // Perform checks and make test case fail if unsuccessful + if (!QTest::qWaitFor(testSize)) + return QTest::qCompare(pixmap.size(), + clipArea.size(), + "pixmap.size()", + "rect.size()", + __FILE__, + callerLine); + + if (!QTest::qWaitFor(testPixel)) { + return QTest::qVerify(firstPixel == QColor(color).rgb(), + "firstPixel == QColor(color).rgb()", + qPrintable(msgRgbMismatch(firstPixel, QColor(color).rgb())), + __FILE__, callerLine); } - return false; + if (!QTest::qWaitFor(testImage)) { + return QTest::qVerify(image == expectedImage, + "image == expectedPixmap.toImage()", + "grabbed pixmap differs from expected pixmap", + __FILE__, callerLine); + } + + return true; } void tst_QOpenGLWidget::stackWidgetOpaqueChildIsVisible() @@ -585,8 +849,11 @@ void tst_QOpenGLWidget::stackWidgetOpaqueChildIsVisible() QSKIP("QScreen::grabWindow() doesn't work properly on OSX HighDPI screen: QTBUG-46803"); return; #endif - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Platform does not support window activation"); if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive)) QSKIP("Offscreen: This fails."); @@ -606,11 +873,12 @@ void tst_QOpenGLWidget::stackWidgetOpaqueChildIsVisible() stack.resize(dimensionSize, dimensionSize); stack.show(); QVERIFY(QTest::qWaitForWindowExposed(&stack)); + stack.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&stack)); // Switch to the QOpenGLWidget. stack.setCurrentIndex(1); - QTRY_COMPARE(clearWidget->m_paintCalled, true); + QTRY_VERIFY(clearWidget->m_paintCalled); // Resize the tested region to be half size in the middle, because some OSes make the widget // have rounded corners (e.g. OSX), and the grabbed window pixmap will not coincide perfectly @@ -671,6 +939,9 @@ void tst_QOpenGLWidget::offscreen() void tst_QOpenGLWidget::offscreenThenOnscreen() { +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif QScopedPointer<ClearWidget> w(new ClearWidget(0, 800, 600)); w->resize(800, 600); @@ -694,6 +965,57 @@ void tst_QOpenGLWidget::offscreenThenOnscreen() QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255)); } +void tst_QOpenGLWidget::paintWhileHidden() +{ +#ifdef Q_OS_ANDROID + QSKIP("Crashes on Android, figure out why (QTBUG-102043)"); +#endif + QScopedPointer<QWidget> tlw(new QWidget); + tlw->resize(640, 480); + + ClearWidget *w = new ClearWidget(0, 640, 480); + w->setParent(tlw.data()); + w->setClearColor(0, 0, 1); + + tlw->show(); + QVERIFY(QTest::qWaitForWindowExposed(tlw.data())); + + // QTBUG-101620: Now make visible=false and call update and see if we get to + // paintEvent/paintGL eventually, to ensure the updating of the texture is + // not optimized permanently away even though there is no composition + // on-screen at the point when update() is called. + + w->setVisible(false); + w->m_paintCalled = false; + w->update(); + w->setVisible(true); + QTRY_VERIFY(w->m_paintCalled); +} + +void tst_QOpenGLWidget::widgetWindowColorFormat_data() +{ + QTest::addColumn<bool>("translucent"); + QTest::newRow("Translucent background disabled") << false; + QTest::newRow("Translucent background enabled") << true; +} + +void tst_QOpenGLWidget::widgetWindowColorFormat() +{ + QFETCH(bool, translucent); + + QOpenGLWidget w; + w.setAttribute(Qt::WA_TranslucentBackground, translucent); + w.setWindowTitle(QLatin1String(QTest::currentTestFunction())); + w.setFixedSize(16, 16); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QCOMPARE(w.format().redBufferSize(), ctx->format().redBufferSize()); + QCOMPARE(w.format().greenBufferSize(), ctx->format().greenBufferSize()); + QCOMPARE(w.format().blueBufferSize(), ctx->format().blueBufferSize()); +} + class StaticTextPainterWidget : public QOpenGLWidget { public: diff --git a/tests/auto/widgets/widgets/qplaintextedit/BLACKLIST b/tests/auto/widgets/widgets/qplaintextedit/BLACKLIST deleted file mode 100644 index b71f2fcc0a..0000000000 --- a/tests/auto/widgets/widgets/qplaintextedit/BLACKLIST +++ /dev/null @@ -1,15 +0,0 @@ -# QTBUG-87423 -[copyAvailable] -android -[adjustScrollbars] -android -# QTBUG-89402 -[undoAvailableAfterPaste] -android -[copyAndSelectAllInReadonly] -android -[canPaste] -android -[updateCursorPositionAfterEdit] -android - diff --git a/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt b/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt index a339b158c2..b7528498cb 100644 --- a/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qplaintextedit/CMakeLists.txt @@ -1,15 +1,22 @@ -# Generated from qplaintextedit.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 INCLUDE_DIRECTORIES .. - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Widgets @@ -20,6 +27,6 @@ qt_internal_add_test(tst_qplaintextedit ##################################################################### qt_internal_extend_target(tst_qplaintextedit CONDITION MACOS - PUBLIC_LIBRARIES + LIBRARIES ${FWAppKit} ) diff --git a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp index 297eb5ec51..ca7cc6d4b4 100644 --- a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp +++ b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -38,6 +13,7 @@ #include <qclipboard.h> #include <qtextbrowser.h> #include <private/qwidgettextcontrol_p.h> +#include <private/qplaintextedit_p.h> #include <qscrollbar.h> #include <qtextobject.h> #include <qmenu.h> @@ -143,7 +119,7 @@ private slots: void layoutAfterMultiLineRemove(); void undoCommandRemovesAndReinsertsBlock(); void taskQTBUG_43562_lineCountCrash(); -#ifndef QT_NO_CONTEXTMENU +#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD) void contextMenu(); #endif void inputMethodCursorRect(); @@ -154,6 +130,10 @@ private slots: void updateCursorPositionAfterEdit(); #endif void appendTextWhenInvisible(); + void placeholderVisibility_data(); + void placeholderVisibility(); + void scrollBarSignals(); + void dontCrashWithCss(); private: void createSelection(); @@ -415,7 +395,7 @@ void tst_QPlainTextEdit::cursorPositionChanged() spy.clear(); QTest::keyClick(ed, Qt::Key_A); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); @@ -423,23 +403,23 @@ void tst_QPlainTextEdit::cursorPositionChanged() cursor.movePosition(QTextCursor::End); spy.clear(); cursor.insertText("Test"); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); cursor.movePosition(QTextCursor::Start); spy.clear(); cursor.insertText("Test"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QTest::keyClick(ed, Qt::Key_Left); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); CursorPositionChangedRecorder spy2(ed); QVERIFY(ed->textCursor().position() > 0); ed->setPlainText("Hello World"); - QCOMPARE(spy2.cursorPositions.count(), 1); + QCOMPARE(spy2.cursorPositions.size(), 1); QCOMPARE(spy2.cursorPositions.at(0), 0); QCOMPARE(ed->textCursor().position(), 0); } @@ -456,7 +436,7 @@ void tst_QPlainTextEdit::setTextCursor() spy.clear(); ed->setTextCursor(cursor); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } #ifndef QT_NO_CLIPBOARD @@ -473,7 +453,7 @@ void tst_QPlainTextEdit::undoAvailableAfterPaste() const QString txt("Test"); QApplication::clipboard()->setText(txt); ed->paste(); - QVERIFY(spy.count() >= 1); + QVERIFY(spy.size() >= 1); QCOMPARE(ed->toPlainText(), txt); } #endif @@ -727,16 +707,16 @@ void tst_QPlainTextEdit::noPropertiesOnDefaultTextEditCharFormat() // on a text edit. Font properties instead should be taken from the // widget's font (in sync with defaultFont property in document) and the // foreground color should be taken from the palette. - QCOMPARE(ed->textCursor().charFormat().properties().count(), 0); + QCOMPARE(ed->textCursor().charFormat().properties().size(), 0); } void tst_QPlainTextEdit::setPlainTextShouldEmitTextChangedOnce() { QSignalSpy spy(ed, SIGNAL(textChanged())); ed->setPlainText("Yankee Doodle"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); ed->setPlainText(""); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); } void tst_QPlainTextEdit::overwriteMode() @@ -1016,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); @@ -1029,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") @@ -1048,8 +1027,8 @@ void tst_QPlainTextEdit::copyAvailable() //Compare spied signals QEXPECT_FAIL("Case7 T,A,A, <- + shift, <- + shift, <- + shift, ctrl + x, undo() | signals: true, false, true", "Wrong undo selection behaviour. Should be fixed in some future release. (See task: 132482)", Abort); - QCOMPARE(spyCopyAvailabe.count(), copyAvailable.count()); - for (int i=0;i<spyCopyAvailabe.count(); i++) { + QCOMPARE(spyCopyAvailabe.size(), copyAvailable.size()); + for (int i=0;i<spyCopyAvailabe.size(); i++) { QVariant variantSpyCopyAvailable = spyCopyAvailabe.at(i).at(0); QVERIFY2(variantSpyCopyAvailable.toBool() == copyAvailable.at(i), QString("Spied singnal: %1").arg(i).toLatin1()); } @@ -1085,10 +1064,10 @@ void tst_QPlainTextEdit::moveCursor() QCOMPARE(ed->textCursor().position(), 0); ed->moveCursor(QTextCursor::NextCharacter); QCOMPARE(ed->textCursor().position(), 1); - QCOMPARE(cursorMovedSpy.count(), 1); + QCOMPARE(cursorMovedSpy.size(), 1); ed->moveCursor(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(ed->textCursor().position(), 2); - QCOMPARE(cursorMovedSpy.count(), 2); + QCOMPARE(cursorMovedSpy.size(), 2); QCOMPARE(ed->textCursor().selectedText(), QString("e")); } @@ -1300,7 +1279,7 @@ void tst_QPlainTextEdit::ensureVisibleWithRtl() ed->setLayoutDirection(Qt::RightToLeft); ed->setLineWrapMode(QPlainTextEdit::NoWrap); QString txt(500, QChar(QLatin1Char('a'))); - QCOMPARE(txt.length(), 500); + QCOMPARE(txt.size(), 500); ed->setPlainText(txt); ed->resize(100, 100); ed->show(); @@ -1353,7 +1332,7 @@ void tst_QPlainTextEdit::extraSelections() ed->setExtraSelections(QList<QTextEdit::ExtraSelection>() << sel); QList<QTextEdit::ExtraSelection> selections = ed->extraSelections(); - QCOMPARE(selections.count(), 1); + QCOMPARE(selections.size(), 1); QCOMPARE(selections.at(0).cursor.position(), endPos); QCOMPARE(selections.at(0).cursor.anchor(), wordPos); } @@ -1368,7 +1347,9 @@ void tst_QPlainTextEdit::adjustScrollbars() ed->setFont(ff); ed->setMinimumSize(140, 100); ed->setMaximumSize(140, 100); - ed->show(); + // We use showNormal() here, because otherwise on Android the widget will + // be shown fullscreen, and the scrollbar will not appear. + ed->showNormal(); QLatin1String txt("\nabc def ghi jkl mno pqr stu vwx"); ed->setPlainText(txt + txt + txt + txt); @@ -1481,44 +1462,44 @@ void tst_QPlainTextEdit::selectionChanged() QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 1); - QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(selectionChangedSpy.size(), 0); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 2); - QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(selectionChangedSpy.size(), 1); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 3); - QCOMPARE(selectionChangedSpy.count(), 2); + QCOMPARE(selectionChangedSpy.size(), 2); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 4); - QCOMPARE(selectionChangedSpy.count(), 3); + QCOMPARE(selectionChangedSpy.size(), 3); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 4); - QCOMPARE(selectionChangedSpy.count(), 4); + QCOMPARE(selectionChangedSpy.size(), 4); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 5); - QCOMPARE(selectionChangedSpy.count(), 4); + QCOMPARE(selectionChangedSpy.size(), 4); } void tst_QPlainTextEdit::blockCountChanged() { QSignalSpy blockCountCpangedSpy(ed, SIGNAL(blockCountChanged(int))); ed->setPlainText("Hello"); - QCOMPARE(blockCountCpangedSpy.count(), 0); + QCOMPARE(blockCountCpangedSpy.size(), 0); ed->setPlainText("Hello World"); - QCOMPARE(blockCountCpangedSpy.count(), 0); + QCOMPARE(blockCountCpangedSpy.size(), 0); ed->setPlainText("Hello \n World \n this \n has \n more \n blocks \n than \n just \n one"); - QCOMPARE(blockCountCpangedSpy.count(), 1); + QCOMPARE(blockCountCpangedSpy.size(), 1); ed->setPlainText("One"); - QCOMPARE(blockCountCpangedSpy.count(), 2); + QCOMPARE(blockCountCpangedSpy.size(), 2); ed->setPlainText("One \n Two"); - QCOMPARE(blockCountCpangedSpy.count(), 3); + QCOMPARE(blockCountCpangedSpy.size(), 3); ed->setPlainText("Three \n Four"); - QCOMPARE(blockCountCpangedSpy.count(), 3); + QCOMPARE(blockCountCpangedSpy.size(), 3); } @@ -1696,7 +1677,7 @@ void tst_QPlainTextEdit::taskQTBUG_43562_lineCountCrash() disconnect(ed->document(), SIGNAL(contentsChange(int, int, int)), 0, 0); } -#ifndef QT_NO_CONTEXTMENU +#if !defined(QT_NO_CONTEXTMENU) && !defined(QT_NO_CLIPBOARD) void tst_QPlainTextEdit::contextMenu() { ed->appendHtml(QStringLiteral("Hello <a href='http://www.qt.io'>Qt</a>")); @@ -1719,7 +1700,7 @@ void tst_QPlainTextEdit::contextMenu() QVERIFY(!ed->findChild<QAction *>(QStringLiteral("link-copy"))); QTextCursor cursor = ed->textCursor(); - cursor.setPosition(ed->toPlainText().length() - 2); + cursor.setPosition(ed->toPlainText().size() - 2); ed->setTextCursor(cursor); menu = ed->createStandardContextMenu(ed->cursorRect().center()); @@ -1730,7 +1711,7 @@ void tst_QPlainTextEdit::contextMenu() delete menu; QVERIFY(!ed->findChild<QAction *>(QStringLiteral("link-copy"))); } -#endif // QT_NO_CONTEXTMENU +#endif // QT_NO_CONTEXTMENU && QT_NO_CLIPBOARD // QTBUG-51923: Verify that the cursor rectangle returned by the input // method query correctly reflects the viewport offset. @@ -1802,7 +1783,7 @@ void tst_QPlainTextEdit::updateCursorPositionAfterEdit() QTest::keyClick(&plaintextEdit, Qt::Key_Up); // The curser should move back to the end of the copied text - QCOMPARE(plaintextEdit.textCursor().position(), initialPosition + txt.length()); + QCOMPARE(plaintextEdit.textCursor().position(), initialPosition + txt.size()); } #endif @@ -1837,5 +1818,141 @@ void tst_QPlainTextEdit::appendTextWhenInvisible() QCOMPARE(maxAfterAppend, maxAfterSet); } +enum SetupCommand { + ClearPlaceHolder, // set empty placeholder text + SetPlaceHolder, // set a non-empty placeholder text + ClearContent, // set empty text as content + SetContent // set non-empty text as content +}; + +void tst_QPlainTextEdit::placeholderVisibility_data() +{ + QTest::addColumn<QList<SetupCommand>>("setupCommands"); + QTest::addColumn<bool>("placeholderVisible"); + QTest::addRow("no placeholder set + no text set") + << 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") + << QList<SetupCommand>{ SetContent , ClearContent } + << false; + QTest::addRow("no placeholder set + empty text set + text set") + << QList<SetupCommand>{ ClearContent, SetContent } + << false; + QTest::addRow("empty placeholder set + no text set") + << QList<SetupCommand>{ ClearPlaceHolder } << false; + QTest::addRow("empty placeholder set + text set") + << QList<SetupCommand>{ ClearPlaceHolder, SetContent } + << false; + QTest::addRow("empty placeholder set + text set + empty text set") + << QList<SetupCommand>{ ClearPlaceHolder, SetContent, ClearContent } + << false; + QTest::addRow("empty placeholder set + empty text set + text set") + << QList<SetupCommand>{ ClearPlaceHolder, ClearContent, SetContent } + << false; + QTest::addRow("placeholder set + no text set") + << QList<SetupCommand>{ SetPlaceHolder, ClearContent } + << true; + QTest::addRow("placeholder set + text set") + << QList<SetupCommand>{ SetPlaceHolder, SetContent } + << false; + QTest::addRow("placeholder set + text set + empty text set") + << QList<SetupCommand>{ SetPlaceHolder, SetContent, ClearContent } + << true; + QTest::addRow("placeholder set + empty text set + text set") + << QList<SetupCommand>{ SetPlaceHolder, ClearContent, SetContent } + << false; + QTest::addRow("placeholder set + text set + empty placeholder set") + << QList<SetupCommand>{ SetPlaceHolder, SetContent, ClearPlaceHolder} + << false; + QTest::addRow("placeholder set + empty placeholder set + text set") + << QList<SetupCommand>{ SetPlaceHolder, ClearPlaceHolder, SetContent } + << false; + QTest::addRow("placeholder set + empty placeholder set + empty text set") + << QList<SetupCommand>{ SetPlaceHolder, ClearPlaceHolder, ClearContent } + << false; + QTest::addRow("placeholder set + empty text set + empty placeholder set") + << QList<SetupCommand>{ SetPlaceHolder, ClearContent, ClearPlaceHolder } + << false; + QTest::addRow("text set + no placeholder set + empty text set") + << QList<SetupCommand>{ SetContent, ClearContent } + << false; + QTest::addRow("text set + empty placeholder set") + << QList<SetupCommand>{ SetContent, ClearPlaceHolder } + << false; + QTest::addRow("text set + placeholder set") + << QList<SetupCommand>{ SetContent, SetPlaceHolder } + << false; + QTest::addRow("text set + placeholder set + empty text set") + << QList<SetupCommand>{ SetContent, SetPlaceHolder, ClearContent } + << true; + QTest::addRow("text set + placeholder set + empty placeholder set") + << QList<SetupCommand>{ SetContent, SetPlaceHolder, ClearPlaceHolder } + << false; +} + +void tst_QPlainTextEdit::placeholderVisibility() +{ + QFETCH(QList<SetupCommand>, setupCommands); + QFETCH(bool, placeholderVisible); + + QPlainTextEdit plainTextEdit; + for (auto command : setupCommands) { + switch (command) { + case ClearPlaceHolder: + plainTextEdit.setPlaceholderText(""); + break; + case SetPlaceHolder: + plainTextEdit.setPlaceholderText("Qt is awesome !"); + break; + case ClearContent: + plainTextEdit.setPlainText(""); + break; + case SetContent: + plainTextEdit.setPlainText("PlainText..."); + break; + } + } + auto *plainTextEdit_d = static_cast<QPlainTextEditPrivate *>(qt_widget_private(&plainTextEdit)); + + plainTextEdit.show(); + QVERIFY(QTest::qWaitForWindowExposed(&plainTextEdit)); + QTRY_COMPARE(plainTextEdit_d->placeholderTextShown, placeholderVisible); +} + + +void tst_QPlainTextEdit::scrollBarSignals() +{ + QPlainTextEdit plainTextEdit; + QString longText; + for (uint i = 0; i < 500; ++i) + longText += "This is going to be a very long text for scroll signal testing.\n"; + plainTextEdit.setPlainText(longText); + QScrollBar *vbar = plainTextEdit.verticalScrollBar(); + plainTextEdit.show(); + QVERIFY(QTest::qWaitForWindowExposed(&plainTextEdit)); + QSignalSpy spy(vbar, &QScrollBar::valueChanged); + + QTest::keyClick(vbar, Qt::Key_Down); + QTRY_COMPARE(spy.count(), 1); + QTest::keyClick(vbar, Qt::Key_PageDown); + QTRY_COMPARE(spy.count(), 2); + QTest::keyClick(vbar, Qt::Key_PageDown); + QTRY_COMPARE(spy.count(), 3); + QTest::keyClick(vbar, Qt::Key_Up); + QTRY_COMPARE(spy.count(), 4); + QTest::keyClick(vbar, Qt::Key_PageUp); + 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 699ba0a2f1..61ce6c2692 100644 --- a/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qprogressbar/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qprogressbar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp index 5c08ac4e3e..4a90ed6667 100644 --- a/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp +++ b/tests/auto/widgets/widgets/qprogressbar/tst_qprogressbar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -36,6 +11,8 @@ #include <qtimer.h> #include <QStyleFactory> +#include <QtWidgets/private/qapplication_p.h> + class tst_QProgressBar : public QObject { Q_OBJECT @@ -248,7 +225,7 @@ void tst_QProgressBar::setMinMaxRepaint() pbar.setFormat("%v"); pbar.move(300, 300); pbar.show(); - qApp->setActiveWindow(&pbar); + QApplicationPrivate::setActiveWindow(&pbar); QVERIFY(QTest::qWaitForWindowActive(&pbar)); // No repaint when setting minimum to the current minimum diff --git a/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt b/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt index 0ec5c1fe09..afd052fa17 100644 --- a/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qpushbutton/CMakeLists.txt @@ -1,13 +1,22 @@ -# Generated from qpushbutton.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui + Qt::GuiPrivate Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/disabled_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/disabled_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index 8c2c08aee9..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/disabled_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Motif_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 3c455887da..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_data0.qsnap Binary files differdeleted file mode 100644 index e655b09d29..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index 8f59499d72..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setEnabled/enabled_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Motif_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Motif_data0.qsnap Binary files differdeleted file mode 100644 index a6967a17f7..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_data0.qsnap Binary files differdeleted file mode 100644 index d7c721c960..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index ae0261a22c..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setPixmap/Vpix_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Motif_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Motif_data0.qsnap Binary files differdeleted file mode 100644 index 039bdce748..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Motif_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_data0.qsnap Binary files differdeleted file mode 100644 index db40dc4726..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_win32_data0.qsnap b/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_win32_data0.qsnap Binary files differdeleted file mode 100644 index c0e1279f46..0000000000 --- a/tests/auto/widgets/widgets/qpushbutton/testdata/setText/simple_Windows_win32_data0.qsnap +++ /dev/null diff --git a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp index 8c0eb591aa..73360ae21d 100644 --- a/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp +++ b/tests/auto/widgets/widgets/qpushbutton/tst_qpushbutton.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -40,6 +15,12 @@ #include <QGridLayout> #include <QStyleFactory> #include <QTabWidget> +#include <QStyleOption> + +#include <private/qguiapplication_p.h> +#include <qpa/qplatformtheme.h> + +#include <QtWidgets/private/qapplication_p.h> class tst_QPushButton : public QObject { @@ -60,7 +41,6 @@ private slots: void setDown(); void popupCrash(); void isChecked(); - void animateClick(); void toggle(); void clicked(); void touchTap(); @@ -75,20 +55,20 @@ private slots: void hitButton(); void iconOnlyStyleSheet(); void mousePressAndMove(); + void reactToMenuClosed(); protected slots: void resetCounters(); void onClicked(); - void onToggled( bool on ); + void onToggled(bool on); void onPressed(); void onReleased(); - void helperSlotDelete(); private: - uint click_count; - uint toggle_count; - uint press_count; - uint release_count; + int click_count; + int toggle_count; + int press_count; + int release_count; QPushButton *testWidget; QPointingDevice *m_touchScreen = QTest::createTouchDevice(); @@ -103,40 +83,40 @@ void tst_QPushButton::getSetCheck() QMenu *var1 = new QMenu; obj1.setMenu(var1); QCOMPARE(var1, obj1.menu()); - obj1.setMenu((QMenu *)0); - QCOMPARE((QMenu *)0, obj1.menu()); + obj1.setMenu(nullptr); + QCOMPARE(obj1.menu(), nullptr); delete var1; } void tst_QPushButton::initTestCase() { // Create the test class - testWidget = new QPushButton( "&Start", 0 ); + testWidget = new QPushButton("&Start", 0); testWidget->setObjectName("testWidget"); - testWidget->resize( 200, 200 ); + testWidget->resize(200, 200); testWidget->show(); - connect( testWidget, SIGNAL(clicked()), this, SLOT(onClicked()) ); - connect( testWidget, SIGNAL(pressed()), this, SLOT(onPressed()) ); - connect( testWidget, SIGNAL(released()), this, SLOT(onReleased()) ); - connect( testWidget, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)) ); + connect(testWidget, SIGNAL(clicked()), this, SLOT(onClicked())); + connect(testWidget, SIGNAL(pressed()), this, SLOT(onPressed())); + connect(testWidget, SIGNAL(released()), this, SLOT(onReleased())); + connect(testWidget, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); } void tst_QPushButton::cleanupTestCase() { delete testWidget; - testWidget = 0; + testWidget = nullptr; } void tst_QPushButton::init() { - testWidget->setAutoRepeat( false ); - testWidget->setDown( false ); + testWidget->setAutoRepeat(false); + testWidget->setDown(false); testWidget->setText("Test"); - testWidget->setEnabled( true ); + testWidget->setEnabled(true); #if QT_CONFIG(shortcut) QKeySequence seq; - testWidget->setShortcut( seq ); + testWidget->setShortcut(seq); #endif resetCounters(); @@ -155,7 +135,7 @@ void tst_QPushButton::onClicked() click_count++; } -void tst_QPushButton::onToggled( bool /*on*/ ) +void tst_QPushButton::onToggled(bool /*on*/) { toggle_count++; } @@ -173,46 +153,46 @@ void tst_QPushButton::onReleased() void tst_QPushButton::autoRepeat() { // If this changes, this test must be completely revised. - QVERIFY( !testWidget->isCheckable() ); + QVERIFY(!testWidget->isCheckable()); // verify autorepeat is off by default. - QPushButton tmp( 0 ); + QPushButton tmp; tmp.setObjectName("tmp"); - QVERIFY( !tmp.autoRepeat() ); + QVERIFY(!tmp.autoRepeat()); // check if we can toggle the mode - testWidget->setAutoRepeat( true ); - QVERIFY( testWidget->autoRepeat() ); + testWidget->setAutoRepeat(true); + QVERIFY(testWidget->autoRepeat()); - testWidget->setAutoRepeat( false ); - QVERIFY( !testWidget->autoRepeat() ); + testWidget->setAutoRepeat(false); + QVERIFY(!testWidget->autoRepeat()); resetCounters(); // check that the button is down if we press space and not in autorepeat - testWidget->setDown( false ); - testWidget->setAutoRepeat( false ); - QTest::keyPress( testWidget, Qt::Key_Space ); + testWidget->setDown(false); + testWidget->setAutoRepeat(false); + QTest::keyPress(testWidget, Qt::Key_Space); - QTRY_VERIFY( testWidget->isDown() ); - QVERIFY( toggle_count == 0 ); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 0 ); - QVERIFY( click_count == 0 ); + QTRY_VERIFY(testWidget->isDown()); + QCOMPARE(toggle_count, 0); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 0); + QCOMPARE(click_count, 0); - QTest::keyRelease( testWidget, Qt::Key_Space ); + QTest::keyRelease(testWidget, Qt::Key_Space); resetCounters(); // check that the button is down if we press space while in autorepeat // we can't actually confirm how many times it is fired, more than 1 is enough. - testWidget->setDown( false ); - testWidget->setAutoRepeat( true ); - QTest::keyPress( testWidget, Qt::Key_Space ); + testWidget->setDown(false); + testWidget->setAutoRepeat(true); + QTest::keyPress(testWidget, Qt::Key_Space); QTRY_VERIFY(press_count > 3); - QVERIFY( testWidget->isDown() ); - QVERIFY( toggle_count == 0 ); - QTest::keyRelease( testWidget, Qt::Key_Space ); + QVERIFY(testWidget->isDown()); + QCOMPARE(toggle_count, 0); + QTest::keyRelease(testWidget, Qt::Key_Space); QCOMPARE(press_count, release_count); QCOMPARE(release_count, click_count); @@ -220,113 +200,128 @@ void tst_QPushButton::autoRepeat() // check that pressing ENTER has no effect resetCounters(); - testWidget->setDown( false ); - testWidget->setAutoRepeat( false ); - QTest::keyPress( testWidget, Qt::Key_Enter ); + testWidget->setDown(false); + // Skip after reset if ButtonPressKeys has Key_Enter + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + return; + } + testWidget->setAutoRepeat(false); + QTest::keyPress(testWidget, Qt::Key_Enter); - QTest::qWait( 300 ); + QTest::qWait(300); - QVERIFY( !testWidget->isDown() ); - QVERIFY( toggle_count == 0 ); - QVERIFY( press_count == 0 ); - QVERIFY( release_count == 0 ); - QVERIFY( click_count == 0 ); - QTest::keyRelease( testWidget, Qt::Key_Enter ); + QVERIFY(!testWidget->isDown()); + QCOMPARE(toggle_count, 0); + QCOMPARE(press_count, 0); + QCOMPARE(release_count, 0); + QCOMPARE(click_count, 0); + QTest::keyRelease(testWidget, Qt::Key_Enter); // check that pressing ENTER has no effect resetCounters(); - testWidget->setDown( false ); - testWidget->setAutoRepeat( true ); - QTest::keyClick( testWidget, Qt::Key_Enter ); - QTest::qWait( 300 ); - QVERIFY( !testWidget->isDown() ); - QVERIFY( toggle_count == 0 ); - QVERIFY( press_count == 0 ); - QVERIFY( release_count == 0 ); - QVERIFY( click_count == 0 ); + testWidget->setDown(false); + testWidget->setAutoRepeat(true); + QTest::keyClick(testWidget, Qt::Key_Enter); + QTest::qWait(300); + QVERIFY(!testWidget->isDown()); + QCOMPARE(toggle_count, 0); + QCOMPARE(press_count, 0); + QCOMPARE(release_count, 0); + QCOMPARE(click_count, 0); } void tst_QPushButton::pressed() { - QTest::keyPress( testWidget, ' ' ); - QCOMPARE( press_count, (uint)1 ); - QCOMPARE( release_count, (uint)0 ); - - QTest::keyRelease( testWidget, ' ' ); - QCOMPARE( press_count, (uint)1 ); - QCOMPARE( release_count, (uint)1 ); + QTest::keyPress(testWidget, ' '); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 0); + + QTest::keyRelease(testWidget, ' '); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 1); + + // Skip if ButtonPressKeys has Key_Enter + const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme() + ->themeHint(QPlatformTheme::ButtonPressKeys) + .value<QList<Qt::Key>>(); + if (buttonPressKeys.contains(Qt::Key_Enter)) { + return; + } - QTest::keyPress( testWidget,Qt::Key_Enter ); - QCOMPARE( press_count, (uint)1 ); - QCOMPARE( release_count, (uint)1 ); + QTest::keyPress(testWidget,Qt::Key_Enter); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 1); testWidget->setAutoDefault(true); - QTest::keyPress( testWidget,Qt::Key_Enter ); - QCOMPARE( press_count, (uint)2 ); - QCOMPARE( release_count, (uint)2 ); + QTest::keyPress(testWidget,Qt::Key_Enter); + QCOMPARE(press_count, 2); + QCOMPARE(release_count, 2); testWidget->setAutoDefault(false); } void tst_QPushButton::isCheckable() { - QVERIFY( !testWidget->isCheckable() ); + QVERIFY(!testWidget->isCheckable()); } void tst_QPushButton::setDown() { - testWidget->setDown( false ); - QVERIFY( !testWidget->isDown() ); + testWidget->setDown(false); + QVERIFY(!testWidget->isDown()); - testWidget->setDown( true ); - QVERIFY( testWidget->isDown() ); + testWidget->setDown(true); + QVERIFY(testWidget->isDown()); - testWidget->setDown( true ); - QTest::keyClick( testWidget, Qt::Key_Escape ); - QVERIFY( !testWidget->isDown() ); + testWidget->setDown(true); + QTest::keyClick(testWidget, Qt::Key_Escape); + QVERIFY(!testWidget->isDown()); } void tst_QPushButton::isChecked() { - testWidget->setDown( false ); - QVERIFY( !testWidget->isChecked() ); + testWidget->setDown(false); + QVERIFY(!testWidget->isChecked()); - testWidget->setDown( true ); - QVERIFY( !testWidget->isChecked() ); + testWidget->setDown(true); + QVERIFY(!testWidget->isChecked()); - testWidget->setDown( false ); + testWidget->setDown(false); testWidget->toggle(); - QVERIFY( testWidget->isChecked() == testWidget->isCheckable() ); + QCOMPARE(testWidget->isChecked(), testWidget->isCheckable()); } void tst_QPushButton::toggle() { // the pushbutton shouldn't toggle the button. testWidget->toggle(); - QVERIFY( testWidget->isChecked() == false ); + QCOMPARE(testWidget->isChecked(), false); } void tst_QPushButton::toggled() { // the pushbutton shouldn't send a toggled signal when we call the toggle slot. - QVERIFY( !testWidget->isCheckable() ); + QVERIFY(!testWidget->isCheckable()); testWidget->toggle(); - QVERIFY( toggle_count == 0 ); + QCOMPARE(toggle_count, 0); // do it again, just to be sure resetCounters(); testWidget->toggle(); - QVERIFY( toggle_count == 0 ); + QCOMPARE(toggle_count, 0); // finally check that we can toggle using the mouse resetCounters(); - QTest::mousePress( testWidget, Qt::LeftButton ); - QVERIFY( toggle_count == 0 ); - QVERIFY( click_count == 0 ); + QTest::mousePress(testWidget, Qt::LeftButton); + QCOMPARE(toggle_count, 0); + QCOMPARE(click_count, 0); - QTest::mouseRelease( testWidget, Qt::LeftButton ); - QVERIFY( click_count == 1 ); + QTest::mouseRelease(testWidget, Qt::LeftButton); + QCOMPARE(click_count, 1); } #if QT_CONFIG(shortcut) @@ -339,70 +334,55 @@ void tst_QPushButton::toggled() void tst_QPushButton::setAccel() { testWidget->setText("&AccelTest"); - QKeySequence seq( Qt::ALT | Qt::Key_A ); - testWidget->setShortcut( seq ); + QKeySequence seq(Qt::ALT | Qt::Key_A); + testWidget->setShortcut(seq); // The shortcut will not be activated unless the button is in a active // window and has focus - QApplication::setActiveWindow(testWidget); testWidget->setFocus(); QVERIFY(QTest::qWaitForWindowActive(testWidget)); - QTest::keyClick( testWidget, 'A', Qt::AltModifier ); - QTRY_VERIFY( click_count == 1 ); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 1 ); - QVERIFY( toggle_count == 0 ); + QTest::keyClick(testWidget, 'A', Qt::AltModifier); + QTRY_VERIFY(click_count == 1); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 1); + QCOMPARE(toggle_count, 0); // wait 200 ms because setAccel uses animateClick. // if we don't wait this may screw up a next test. QTest::qWait(200); - QTRY_VERIFY( !testWidget->isDown() ); + QTRY_VERIFY(!testWidget->isDown()); } #endif // QT_CONFIG(shortcut) -void tst_QPushButton::animateClick() -{ - QVERIFY( !testWidget->isDown() ); - testWidget->animateClick(); - QVERIFY( testWidget->isDown() ); - QTest::qWait( 200 ); - QVERIFY( !testWidget->isDown() ); - - QVERIFY( click_count == 1 ); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 1 ); - QVERIFY( toggle_count == 0 ); -} - void tst_QPushButton::clicked() { - QTest::mousePress( testWidget, Qt::LeftButton ); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 0 ); + QTest::mousePress(testWidget, Qt::LeftButton); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 0); - QTest::mouseRelease( testWidget, Qt::LeftButton ); - QCOMPARE( press_count, (uint)1 ); - QCOMPARE( release_count, (uint)1 ); + QTest::mouseRelease(testWidget, Qt::LeftButton); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 1); press_count = 0; release_count = 0; testWidget->setDown(false); for (uint i=0; i<10; i++) - QTest::mouseClick( testWidget, Qt::LeftButton ); - QCOMPARE( press_count, (uint)10 ); - QCOMPARE( release_count, (uint)10 ); + QTest::mouseClick(testWidget, Qt::LeftButton); + QCOMPARE(press_count, 10); + QCOMPARE(release_count, 10); } void tst_QPushButton::touchTap() { QTest::touchEvent(testWidget, m_touchScreen).press(0, QPoint(10, 10)); - QVERIFY( press_count == 1 ); - QVERIFY( release_count == 0 ); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 0); QTest::touchEvent(testWidget, m_touchScreen).release(0, QPoint(10, 10)); - QCOMPARE( press_count, (uint)1 ); - QCOMPARE( release_count, (uint)1 ); - QCOMPARE( click_count, (uint)1 ); + QCOMPARE(press_count, 1); + QCOMPARE(release_count, 1); + QCOMPARE(click_count, 1); press_count = 0; release_count = 0; @@ -412,26 +392,23 @@ void tst_QPushButton::touchTap() QTest::touchEvent(testWidget, m_touchScreen).press(0, QPoint(10, 10)); QTest::touchEvent(testWidget, m_touchScreen).release(0, QPoint(10, 10)); } - QCOMPARE( press_count, (uint)10 ); - QCOMPARE( release_count, (uint)10 ); - QCOMPARE( click_count, (uint)10 ); -} - -QPushButton *pb = 0; -void tst_QPushButton::helperSlotDelete() -{ - delete pb; - pb = 0; + QCOMPARE(press_count, 10); + QCOMPARE(release_count, 10); + QCOMPARE(click_count, 10); } void tst_QPushButton::popupCrash() { - pb = new QPushButton("foo"); + QPushButton *pb = new QPushButton("foo"); QMenu *menu = new QMenu("bar", pb); pb->setMenu(menu); - QTimer::singleShot(1000, this, SLOT(helperSlotDelete())); + QTimer::singleShot(1000, this, [&pb]{ + delete pb; + pb = nullptr; + }); pb->show(); pb->click(); + QTRY_COMPARE(pb, nullptr); } void tst_QPushButton::defaultAndAutoDefault() @@ -521,14 +498,14 @@ void tst_QPushButton::defaultAndAutoDefault() // Reparenting QVERIFY(button2.autoDefault()); - button2.setParent(0); + button2.setParent(nullptr); QVERIFY(!button2.autoDefault()); button2.setAutoDefault(false); button2.setParent(&dialog); QVERIFY(!button2.autoDefault()); button1.setAutoDefault(true); - button1.setParent(0); + button1.setParent(nullptr); QVERIFY(button1.autoDefault()); } } @@ -569,7 +546,7 @@ void tst_QPushButton::sizeHint() button->setParent(widget); button->sizeHint(); - widget->setParent(0); + widget->setParent(nullptr); delete dialog; button->setDefault(false); QCOMPARE(button->sizeHint(), initSizeHint); @@ -624,7 +601,7 @@ void tst_QPushButton::taskQTBUG_20191_shortcutWithKeypadModifer() dialog.setLayout(layout); dialog.show(); QVERIFY(QTest::qWaitForWindowExposed(&dialog)); - QApplication::setActiveWindow(&dialog); + QApplicationPrivate::setActiveWindow(&dialog); // add shortcut '5' to button1 and test with keyboard and keypad '5' keys QSignalSpy spy1(button1, SIGNAL(clicked())); @@ -633,7 +610,7 @@ void tst_QPushButton::taskQTBUG_20191_shortcutWithKeypadModifer() QTest::qWait(300); QTest::keyClick(&dialog, Qt::Key_5, Qt::KeypadModifier); QTest::qWait(300); - QCOMPARE(spy1.count(), 2); + QCOMPARE(spy1.size(), 2); // add shortcut 'keypad 5' to button2 spy1.clear(); @@ -643,8 +620,8 @@ void tst_QPushButton::taskQTBUG_20191_shortcutWithKeypadModifer() QTest::qWait(300); QTest::keyClick(&dialog, Qt::Key_5, Qt::KeypadModifier); QTest::qWait(300); - QCOMPARE(spy1.count(), 1); - QCOMPARE(spy2.count(), 1); + QCOMPARE(spy1.size(), 1); + QCOMPARE(spy2.size(), 1); // remove shortcut from button1 spy1.clear(); @@ -654,8 +631,8 @@ void tst_QPushButton::taskQTBUG_20191_shortcutWithKeypadModifer() QTest::qWait(300); QTest::keyClick(&dialog, Qt::Key_5, Qt::KeypadModifier); QTest::qWait(300); - QCOMPARE(spy1.count(), 0); - QCOMPARE(spy2.count(), 1); + QCOMPARE(spy1.size(), 0); + QCOMPARE(spy2.size(), 1); } #endif // QT_CONFIG(shortcut) @@ -671,7 +648,7 @@ void tst_QPushButton::emitReleasedAfterChange() dialog.setLayout(layout); dialog.show(); QVERIFY(QTest::qWaitForWindowExposed(&dialog)); - QApplication::setActiveWindow(&dialog); + QApplicationPrivate::setActiveWindow(&dialog); button1->setFocus(); QSignalSpy spy(button1, SIGNAL(released())); @@ -679,16 +656,16 @@ void tst_QPushButton::emitReleasedAfterChange() QVERIFY(button1->isDown()); QTest::keyClick(&dialog, Qt::Key_Tab); QVERIFY(!button1->isDown()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); button1->setFocus(); QTest::mousePress(button1, Qt::LeftButton); QVERIFY(button1->isDown()); button1->setEnabled(false); QVERIFY(!button1->isDown()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } /* @@ -766,22 +743,68 @@ void tst_QPushButton::mousePressAndMove() QSignalSpy releaseSpy(&button, &QAbstractButton::released); QTest::mousePress(&button, Qt::LeftButton); - QCOMPARE(pressSpy.count(), 1); - QCOMPARE(releaseSpy.count(), 0); + QCOMPARE(pressSpy.size(), 1); + QCOMPARE(releaseSpy.size(), 0); // mouse pressed and moving out QTest::mouseMove(&button, QPoint(100, 100)); // should emit released signal when the mouse is dragged out of boundary - QCOMPARE(pressSpy.count(), 1); - QCOMPARE(releaseSpy.count(), 1); + QCOMPARE(pressSpy.size(), 1); + QCOMPARE(releaseSpy.size(), 1); // mouse pressed and moving into QTest::mouseMove(&button, QPoint(10, 10)); // should emit pressed signal when the mouse is dragged into of boundary - QCOMPARE(pressSpy.count(), 2); - QCOMPARE(releaseSpy.count(), 1); + QCOMPARE(pressSpy.size(), 2); + 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) diff --git a/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt b/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt index 8ce8aadea8..ce016975c8 100644 --- a/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qradiobutton/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qradiobutton.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp b/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp index 8b1670ae06..144d91e9f2 100644 --- a/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp +++ b/tests/auto/widgets/widgets/qradiobutton/tst_qradiobutton.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 Binary files differnew file mode 100644 index 0000000000..40d0a296ac --- /dev/null +++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.frag.qsb 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 Binary files differnew file mode 100644 index 0000000000..5b7fd39668 --- /dev/null +++ b/tests/auto/widgets/widgets/qrhiwidget/data/simple.vert.qsb 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 a10c911286..5e84614407 100644 --- a/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qscrollarea/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qscrollarea.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp index e0fd42e95c..87a623b223 100644 --- a/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp +++ b/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 fbaba594cf..23e31327e1 100644 --- a/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qscrollbar/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qscrollbar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::TestPrivate Qt::Widgets diff --git a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp index 471a9bd3e4..fc836dec4a 100644 --- a/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp +++ b/tests/auto/widgets/widgets/qscrollbar/tst_qscrollbar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -115,7 +90,7 @@ void tst_QScrollBar::task_209492() QSignalSpy spy(verticalScrollBar, SIGNAL(actionTriggered(int))); QCOMPARE(scrollArea.scrollCount, 0); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // Simulate a mouse click on the "scroll down button". const QPoint pressPoint(verticalScrollBar->width() / 2, verticalScrollBar->height() - 10); @@ -134,7 +109,7 @@ void tst_QScrollBar::task_209492() QSKIP("The result depends on system setting and is not relevant on Mac"); #endif QCOMPARE(scrollArea.scrollCount, 1); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } #if QT_CONFIG(wheelevent) @@ -184,7 +159,7 @@ void tst_QScrollBar::QTBUG_42871() QSignalSpy spy(&scrollBarWidget, SIGNAL(actionTriggered(int))); QVERIFY(spy.isValid()); QCOMPARE(myHandler.updatesCount, 0); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // Simulate a mouse click on the "scroll down button". const QPoint pressPoint(scrollBarWidget.width() / 2, scrollBarWidget.height() - 10); @@ -192,13 +167,20 @@ void tst_QScrollBar::QTBUG_42871() QMouseEvent mousePressEvent(QEvent::MouseButtonPress, pressPoint, globalPressPoint, Qt::LeftButton, Qt::LeftButton, {}); QApplication::sendEvent(&scrollBarWidget, &mousePressEvent); + QElapsedTimer timer; + timer.start(); QTest::qWait(1); QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, pressPoint, globalPressPoint, Qt::LeftButton, Qt::LeftButton, {}); QApplication::sendEvent(&scrollBarWidget, &mouseReleaseEvent); + if (timer.elapsed() > 40) { + // took too long, we need to tolerate auto-repeat + if (myHandler.updatesCount > 1) + QEXPECT_FAIL("", "Took too long to process events, repeat timer fired", Continue); + } // Check that the action was triggered once. QCOMPARE(myHandler.updatesCount, 1); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), myHandler.updatesCount); } QTEST_MAIN(tst_QScrollBar) diff --git a/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt b/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt index c05b601d87..2de1583233 100644 --- a/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qsizegrip/CMakeLists.txt @@ -1,15 +1,20 @@ -# Generated from qsizegrip.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - INCLUDE_DIRECTORIES - . - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp b/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp index 1c69a1c8bd..a543efe44e 100644 --- a/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp +++ b/tests/auto/widgets/widgets/qsizegrip/tst_qsizegrip.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 4fe495b3c5..664e9a52af 100644 --- a/tests/auto/widgets/widgets/qslider/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qslider/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qslider.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qslider/tst_qslider.cpp b/tests/auto/widgets/widgets/qslider/tst_qslider.cpp index 3722025782..a70c8c484e 100644 --- a/tests/auto/widgets/widgets/qslider/tst_qslider.cpp +++ b/tests/auto/widgets/widgets/qslider/tst_qslider.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 adc0ee093f..826ce16d64 100644 --- a/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qspinbox/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qspinbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp index fc3412f387..27343edcde 100644 --- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp +++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qdebug.h> #include <qapplication.h> @@ -54,6 +29,8 @@ #include <QProxyStyle> #include <QScreen> +#include <QtWidgets/private/qapplication_p.h> + #if QT_CONFIG(shortcut) # include <QKeySequence> #endif @@ -950,7 +927,6 @@ void tst_QSpinBox::editingFinished() layout->addWidget(box2); testFocusWidget.show(); - QApplication::setActiveWindow(&testFocusWidget); QVERIFY(QTest::qWaitForWindowActive(&testFocusWidget)); box->activateWindow(); box->setFocus(); @@ -964,45 +940,45 @@ void tst_QSpinBox::editingFinished() QTest::keyClick(box, Qt::Key_Up); QTest::keyClick(box, Qt::Key_Up); - QCOMPARE(editingFinishedSpy1.count(), 0); - QCOMPARE(editingFinishedSpy2.count(), 0); + QCOMPARE(editingFinishedSpy1.size(), 0); + QCOMPARE(editingFinishedSpy2.size(), 0); QTest::keyClick(box2, Qt::Key_Up); QTest::keyClick(box2, Qt::Key_Up); box2->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); box->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 1); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Up); - QCOMPARE(editingFinishedSpy1.count(), 1); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Enter); - QCOMPARE(editingFinishedSpy1.count(), 2); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 2); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box, Qt::Key_Return); - QCOMPARE(editingFinishedSpy1.count(), 3); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 3); + QCOMPARE(editingFinishedSpy2.size(), 1); box2->setFocus(); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 1); QTest::keyClick(box2, Qt::Key_Enter); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 2); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 2); QTest::keyClick(box2, Qt::Key_Return); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 3); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 3); testFocusWidget.hide(); - QCOMPARE(editingFinishedSpy1.count(), 4); - QCOMPARE(editingFinishedSpy2.count(), 4); + QCOMPARE(editingFinishedSpy1.size(), 4); + QCOMPARE(editingFinishedSpy2.size(), 4); //task203285 editingFinishedSpy1.clear(); testFocusWidget.show(); QVERIFY(QTest::qWaitForWindowActive(&testFocusWidget)); box->setKeyboardTracking(false); - qApp->setActiveWindow(&testFocusWidget); + QApplicationPrivate::setActiveWindow(&testFocusWidget); testFocusWidget.activateWindow(); box->setFocus(); QTRY_VERIFY(box->hasFocus()); @@ -1012,7 +988,7 @@ void tst_QSpinBox::editingFinished() box2->setFocus(); QTRY_VERIFY(qApp->focusWidget() != box); QCOMPARE(box->text(), QLatin1String("20")); - QCOMPARE(editingFinishedSpy1.count(), 1); + QCOMPARE(editingFinishedSpy1.size(), 1); } void tst_QSpinBox::removeAll() @@ -1129,7 +1105,6 @@ void tst_QSpinBox::specialValue() spin.setValue(50); topWidget.show(); //make sure we have the focus (even if editingFinished fails) - qApp->setActiveWindow(&topWidget); topWidget.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&topWidget)); spin.setFocus(); @@ -1175,33 +1150,32 @@ public: void tst_QSpinBox::sizeHint() { - QWidget *widget = new QWidget; - QHBoxLayout *layout = new QHBoxLayout(widget); + QWidget widget; + QHBoxLayout *layout = new QHBoxLayout(&widget); + sizeHint_SpinBox *spinBox = new sizeHint_SpinBox; layout->addWidget(spinBox); - widget->show(); - QVERIFY(QTest::qWaitForWindowExposed(widget)); + // Make sure all layout requests posted by the QHBoxLayout constructor and addWidget + // are processed before the widget is shown + QCoreApplication::sendPostedEvents(&widget, QEvent::LayoutRequest); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); // Prefix spinBox->sizeHintRequests = 0; spinBox->setPrefix(QLatin1String("abcdefghij")); - qApp->processEvents(); QTRY_VERIFY(spinBox->sizeHintRequests > 0); // Suffix spinBox->sizeHintRequests = 0; spinBox->setSuffix(QLatin1String("abcdefghij")); - qApp->processEvents(); QTRY_VERIFY(spinBox->sizeHintRequests > 0); // Range spinBox->sizeHintRequests = 0; spinBox->setRange(0, 1234567890); spinBox->setValue(spinBox->maximum()); - qApp->processEvents(); QTRY_VERIFY(spinBox->sizeHintRequests > 0); - - delete widget; } void tst_QSpinBox::taskQTBUG_5008_textFromValueAndValidate() @@ -1234,7 +1208,6 @@ void tst_QSpinBox::taskQTBUG_5008_textFromValueAndValidate() spinbox.show(); spinbox.activateWindow(); spinbox.setFocus(); - QApplication::setActiveWindow(&spinbox); QVERIFY(QTest::qWaitForWindowActive(&spinbox)); QVERIFY(spinbox.hasFocus()); QTRY_COMPARE(static_cast<QWidget *>(&spinbox), QApplication::activeWindow()); @@ -1282,7 +1255,7 @@ void tst_QSpinBox::lineEditReturnPressed() QSignalSpy spyCurrentChanged(spinBox.lineEdit(), SIGNAL(returnPressed())); spinBox.show(); QTest::keyClick(&spinBox, Qt::Key_Return); - QCOMPARE(spyCurrentChanged.count(), 1); + QCOMPARE(spyCurrentChanged.size(), 1); } void tst_QSpinBox::positiveSign() @@ -1854,10 +1827,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)); @@ -1872,13 +1841,13 @@ void tst_QSpinBox::stepModifierPressAndHold() qDebug() << "QGuiApplication::focusWindow():" << QGuiApplication::focusWindow(); qDebug() << "QGuiApplication::topLevelWindows():" << QGuiApplication::topLevelWindows(); QTest::mousePress(&spin, Qt::LeftButton, modifiers, buttonRect.center()); - QTRY_VERIFY2(spy.length() >= 3, qPrintable(QString::fromLatin1( - "Expected valueChanged() to be emitted 3 or more times, but it was only emitted %1 times").arg(spy.length()))); + QTRY_VERIFY2(spy.size() >= 3, qPrintable(QString::fromLatin1( + "Expected valueChanged() to be emitted 3 or more times, but it was only emitted %1 times").arg(spy.size()))); QTest::mouseRelease(&spin, Qt::LeftButton, modifiers, buttonRect.center()); const auto value = spy.last().at(0); QVERIFY(value.metaType().id() == QMetaType::Int); - QCOMPARE(value.toInt(), spy.length() * expectedStepModifier); + QCOMPARE(value.toInt(), spy.size() * expectedStepModifier); } void tst_QSpinBox::stepSelectAll_data() diff --git a/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt b/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt index 7c13db39a2..12602328c3 100644 --- a/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qsplashscreen/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qsplashscreen.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp b/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp index c038682788..f57634152a 100644 --- a/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp +++ b/tests/auto/widgets/widgets/qsplashscreen/tst_qsplashscreen.cpp @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QSplashScreen> +#include <QTimer> class tst_QSplashScreen : public QObject { @@ -36,7 +12,7 @@ class tst_QSplashScreen : public QObject private slots: void checkCloseTime(); - void checkScreenConstructor(); + void checkConstructorAndShow(); }; class CloseEventSplash : public QSplashScreen @@ -45,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); @@ -60,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 6cbbfd3792..16244c8834 100644 --- a/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qsplitter/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qsplitter.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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") @@ -11,7 +18,7 @@ list(APPEND test_data "setSizes3.dat") qt_internal_add_test(tst_qsplitter SOURCES tst_qsplitter.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets TESTDATA ${test_data} diff --git a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp index ce7ac0a186..071e6d4cbc 100644 --- a/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp +++ b/tests/auto/widgets/widgets/qsplitter/tst_qsplitter.cpp @@ -1,33 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> +#include <QSignalSpy> + #include <qapplication.h> #include <qsplitter.h> #include <qstyle.h> @@ -81,6 +58,8 @@ private slots: void replaceWidget(); void replaceWidgetWithSplitterChild_data(); void replaceWidgetWithSplitterChild(); + void replaceWidgetWhileHidden_data(); + void replaceWidgetWhileHidden(); void handleMinimumWidth(); // task-specific tests below me: @@ -89,6 +68,7 @@ private slots: void task169702_sizes(); void taskQTBUG_4101_ensureOneNonCollapsedWidget_data(); void taskQTBUG_4101_ensureOneNonCollapsedWidget(); + void taskQTBUG_102249_moveNonPressed(); void setLayout(); void autoAdd(); @@ -851,6 +831,47 @@ void tst_QSplitter::replaceWidgetWithSplitterChild() } } +void tst_QSplitter::replaceWidgetWhileHidden_data() +{ + QTest::addColumn<bool>("splitterVisible"); + QTest::addColumn<bool>("widgetVisible"); + + QTest::addRow("visibleToVisible") << true << true; + QTest::addRow("hiddenToVisible") << true << false; + QTest::addRow("visibleToHidden") << false << true; + QTest::addRow("hiddenToHidden") << false << false; +} + +void tst_QSplitter::replaceWidgetWhileHidden() +{ + QFETCH(bool, splitterVisible); + QFETCH(bool, widgetVisible); + + MyFriendlySplitter splitter; + + splitter.addWidget(new QLabel("One")); + splitter.addWidget(new QLabel("Two")); + + if (splitterVisible) { + splitter.show(); + QVERIFY(QTest::qWaitForWindowExposed(&splitter)); + } + QWidget *newWidget = new QLabel("Three"); + if (!widgetVisible) + newWidget->hide(); + + const bool wasExplicitHide = !widgetVisible && newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide); + splitter.replaceWidget(1, newWidget); + + QCOMPARE(!widgetVisible && newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide), wasExplicitHide); + + if (!splitterVisible) { + splitter.show(); + QVERIFY(QTest::qWaitForWindowExposed(&splitter)); + } + QCOMPARE(widgetVisible, newWidget->isVisible()); +} + void tst_QSplitter::handleMinimumWidth() { MyFriendlySplitter split; @@ -887,55 +908,56 @@ void tst_QSplitter::rubberBandNotInSplitter() void tst_QSplitter::task187373_addAbstractScrollAreas_data() { - QTest::addColumn<QString>("className"); + QTest::addColumn<QByteArray>("className"); QTest::addColumn<bool>("addInConstructor"); QTest::addColumn<bool>("addOutsideConstructor"); - QStringList classNames; - classNames << QLatin1String("QGraphicsView"); - classNames << QLatin1String("QMdiArea"); - classNames << QLatin1String("QScrollArea"); - classNames << QLatin1String("QTextEdit"); - classNames << QLatin1String("QTreeView"); - - foreach (QString className, classNames) { - QTest::newRow(qPrintable(className + QLatin1String(" 1"))) << className << false << true; - QTest::newRow(qPrintable(className + QLatin1String(" 2"))) << className << true << false; - QTest::newRow(qPrintable(className + QLatin1String(" 3"))) << className << true << true; + QList<QByteArray> classNames{ + "QGraphicsView", + "QMdiArea", + "QScrollArea", + "QTextEdit", + "QTreeView" + }; + + for (const auto &className : std::as_const(classNames)) { + QTest::newRow(qPrintable(className + " 1")) << className << false << true; + QTest::newRow(qPrintable(className + " 2")) << className << true << false; + QTest::newRow(qPrintable(className + " 3")) << className << true << true; } } static QAbstractScrollArea *task187373_createScrollArea( - QSplitter *splitter, const QString &className, bool addInConstructor) + QSplitter *splitter, const QByteArray &className, bool addInConstructor) { - if (className == QLatin1String("QGraphicsView")) + if (className == "QGraphicsView") return new QGraphicsView(addInConstructor ? splitter : 0); - if (className == QLatin1String("QMdiArea")) + if (className == "QMdiArea") return new QMdiArea(addInConstructor ? splitter : 0); - if (className == QLatin1String("QScrollArea")) + if (className == "QScrollArea") return new QScrollArea(addInConstructor ? splitter : 0); - if (className == QLatin1String("QTextEdit")) + if (className == "QTextEdit") return new QTextEdit(addInConstructor ? splitter : 0); - if (className == QLatin1String("QTreeView")) + if (className == "QTreeView") return new QTreeView(addInConstructor ? splitter : 0); return 0; } void tst_QSplitter::task187373_addAbstractScrollAreas() { - QFETCH(QString, className); + QFETCH(QByteArray, className); QFETCH(bool, addInConstructor); QFETCH(bool, addOutsideConstructor); QVERIFY(addInConstructor || addOutsideConstructor); - QSplitter *splitter = new QSplitter; - splitter->show(); - QVERIFY(splitter->isVisible()); + QSplitter splitter; + splitter.show(); + QVERIFY(splitter.isVisible()); - QAbstractScrollArea *w = task187373_createScrollArea(splitter, className, addInConstructor); + QAbstractScrollArea *w = task187373_createScrollArea(&splitter, className, addInConstructor); QVERIFY(w); if (addOutsideConstructor) - splitter->addWidget(w); + splitter.addWidget(w); QTRY_VERIFY(w->isVisible()); QVERIFY(!w->isHidden()); @@ -1010,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); @@ -1026,6 +1048,24 @@ void tst_QSplitter::taskQTBUG_4101_ensureOneNonCollapsedWidget() QTRY_VERIFY(s.sizes().at(0) > 0); } +void tst_QSplitter::taskQTBUG_102249_moveNonPressed() +{ + QSplitter s; + s.setOpaqueResize(true); + s.addWidget(new QWidget()); + s.addWidget(new QWidget()); + s.show(); + + QSignalSpy spyMove(&s, &QSplitter::splitterMoved); + QPointF posOutOfWidget = QPointF(30, 30); + QMouseEvent me(QEvent::MouseMove, + posOutOfWidget, s.mapToGlobal(posOutOfWidget), + Qt::NoButton, Qt::MouseButtons(Qt::LeftButton), + Qt::NoModifier); + qApp->sendEvent(s.handle(0), &me); + QCOMPARE(spyMove.size(), 0); +} + void tst_QSplitter::setLayout() { QSplitter splitter; diff --git a/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt b/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt index 7c99df28a4..0c79cf29f4 100644 --- a/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qstackedwidget/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qstackedwidget.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp index df3b943e05..3c28ad324a 100644 --- a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp +++ b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -36,6 +11,8 @@ #include <QHBoxLayout> #include <qlineedit.h> +#include <QtWidgets/private/qapplication_p.h> + class tst_QStackedWidget : public QObject { Q_OBJECT @@ -182,7 +159,6 @@ void tst_QStackedWidget::dynamicPages() le11->setFocus(); // set focus to second widget in the page sw->resize(200, 200); sw->show(); - qApp->setActiveWindow(sw); QVERIFY(QTest::qWaitForWindowActive(sw)); QTRY_COMPARE(QApplication::focusWidget(), le11); diff --git a/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt b/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt index e4e19e230e..3bda170936 100644 --- a/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qstatusbar/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qstatusbar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp b/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp index d7079197ce..b0a53ba01a 100644 --- a/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp +++ b/tests/auto/widgets/widgets/qstatusbar/tst_qstatusbar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -48,6 +23,7 @@ private slots: void tempMessage(); void insertWidget(); void insertPermanentWidget(); + void removeWidget(); void setSizeGripEnabled(); void task194017_hiddenWidget(); void QTBUG4334_hiddenOnMaximizedWindow(); @@ -129,6 +105,49 @@ void tst_QStatusBar::insertPermanentWidget() QCOMPARE(sb.insertPermanentWidget(1, new QLabel("foo")), 6); } +void tst_QStatusBar::removeWidget() +{ + QStatusBar sb; + std::vector<std::unique_ptr<QLabel>> widgets; + std::vector<bool> states; + for (int i = 0; i < 10; ++i) { + const QString text = i > 5 ? QString("p_%1").arg(i) : QString::number(i); + widgets.push_back(std::make_unique<QLabel>(text)); + states.push_back(true); + } + + for (auto &&widget : widgets) { + if (widget->text().startsWith("p_")) + sb.addPermanentWidget(widget.get()); + else + sb.addWidget(widget.get()); + } + sb.show(); + QVERIFY(QTest::qWaitForWindowExposed(&sb)); + + auto checkStates = [&]{ + for (size_t index = 0; index < std::size(widgets); ++index) { + if (widgets.at(index)->isVisible() != states.at(index)) { + qCritical("Mismatch for widget at index %zu\n" + "\tActual : %s\n" + "\tExpected: %s", + index, widgets.at(index)->isVisible() ? "true" : "false", + states.at(index) ? "true" : "false"); + return false; + } + } + return true; + }; + + QVERIFY(checkStates()); + // remove every widget except the first to trigger unstable reference + for (size_t i = 2; i < std::size(widgets); ++i) { + sb.removeWidget(widgets[i].get()); + states[i] = false; + QVERIFY2(checkStates(), qPrintable(QString("Failure at index %1").arg(i))); + } +} + void tst_QStatusBar::setSizeGripEnabled() { if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) @@ -297,18 +316,18 @@ void tst_QStatusBar::messageChangedSignal() testWidget->showMessage("Ready", 0); QCOMPARE(testWidget->currentMessage(), QString("Ready")); QCOMPARE(testWidget->currentMessage(), currentMessage); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), currentMessage); testWidget->clearMessage(); QCOMPARE(testWidget->currentMessage(), QString()); QCOMPARE(testWidget->currentMessage(), currentMessage); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), currentMessage); testWidget->showMessage("Ready", 0); testWidget->showMessage("Ready", 0); QCOMPARE(testWidget->currentMessage(), QString("Ready")); QCOMPARE(testWidget->currentMessage(), currentMessage); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().at(0).toString(), currentMessage); } 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 edc90d3138..b79e763819 100644 --- a/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtabbar/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qtabbar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + 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 630b5c1167..03131cebe4 100644 --- a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp +++ b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QSignalSpy> @@ -36,6 +11,12 @@ #include <QStyleOptionTab> #include <QProxyStyle> #include <QTimer> +#include <QScreen> +#include <QWindow> + +#include <QtWidgets/private/qtabbar_p.h> + +using namespace Qt::StringLiterals; class TabBar; @@ -69,6 +50,7 @@ private slots: void hideTab_data(); void hideTab(); void hideAllTabs(); + void checkHiddenTab(); void setElideMode_data(); void setElideMode(); @@ -78,6 +60,7 @@ private slots: void setUsesScrollButtons(); void removeLastTab(); + void removeLastVisibleTab(); void closeButton(); @@ -103,6 +86,8 @@ private slots: void mouseWheel(); void kineticWheel_data(); void kineticWheel(); + void highResolutionWheel_data(); + void highResolutionWheel(); void scrollButtons_data(); void scrollButtons(); @@ -112,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); }; @@ -227,7 +219,7 @@ void tst_QTabBar::testCurrentChanged() QCOMPARE(tabBar.currentIndex(), 0); tabBar.setCurrentIndex(tabToSet); QCOMPARE(tabBar.currentIndex(), tabToSet); - QCOMPARE(spy.count(), expectedCount); + QCOMPARE(spy.size(), expectedCount); } class TabBar : public QTabBar @@ -301,7 +293,7 @@ void tst_QTabBar::removeTab() tabbar.setCurrentIndex(currentIndex); QSignalSpy spy(&tabbar, SIGNAL(currentChanged(int))); tabbar.removeTab(deleteIndex); - QTEST(int(spy.count()), "spyCount"); + QTEST(int(spy.size()), "spyCount"); QTEST(tabbar.currentIndex(), "finalIndex"); } @@ -332,7 +324,7 @@ void tst_QTabBar::hideTab() tabbar.setCurrentIndex(currentIndex); QSignalSpy spy(&tabbar, &QTabBar::currentChanged); tabbar.setTabVisible(hideIndex, false); - QTEST(int(spy.count()), "spyCount"); + QTEST(int(spy.size()), "spyCount"); QTEST(tabbar.currentIndex(), "finalIndex"); } @@ -378,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"); @@ -476,16 +487,49 @@ void tst_QTabBar::removeLastTab() QTabBar tabbar; QSignalSpy spy(&tabbar, SIGNAL(currentChanged(int))); int index = tabbar.addTab("foo"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toInt(), index); spy.clear(); tabbar.removeTab(index); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toInt(), -1); spy.clear(); } +void tst_QTabBar::removeLastVisibleTab() +{ + QTabBar tabbar; + tabbar.setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior::SelectRightTab); + + int invisible = tabbar.addTab("invisible"); + int visible = tabbar.addTab("visible"); + tabbar.setCurrentIndex(visible); + tabbar.adjustSize(); + + tabbar.setTabVisible(invisible, false); + { + QSignalSpy spy(&tabbar, SIGNAL(currentChanged(int))); + tabbar.removeTab(visible); + QCOMPARE(spy.size(), 1); + QCOMPARE(spy.at(0).at(0).toInt(), -1); + QCOMPARE(tabbar.currentIndex(), -1); + } + + tabbar.setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior::SelectLeftTab); + visible = tabbar.insertTab(0, "visible"); + ++invisible; + QVERIFY(!tabbar.isTabVisible(invisible)); + tabbar.setCurrentIndex(visible); + { + QSignalSpy spy(&tabbar, SIGNAL(currentChanged(int))); + tabbar.removeTab(visible); + QCOMPARE(spy.size(), 1); + QCOMPARE(spy.at(0).at(0).toInt(), -1); + QCOMPARE(tabbar.currentIndex(), -1); + } +} + void tst_QTabBar::closeButton() { QTabBar tabbar; @@ -504,7 +548,7 @@ void tst_QTabBar::closeButton() QSignalSpy spy(&tabbar, SIGNAL(tabCloseRequested(int))); button->click(); QCOMPARE(tabbar.count(), 1); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } Q_DECLARE_METATYPE(QTabBar::ButtonPosition) @@ -776,36 +820,36 @@ void tst_QTabBar::tabBarClicked() QSignalSpy clickSpy(&tabBar, SIGNAL(tabBarClicked(int))); QSignalSpy doubleClickSpy(&tabBar, SIGNAL(tabBarDoubleClicked(int))); - QCOMPARE(clickSpy.count(), 0); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(clickSpy.size(), 0); + QCOMPARE(doubleClickSpy.size(), 0); Qt::MouseButton button = Qt::LeftButton; while (button <= Qt::MaxMouseButton) { const QPoint tabPos = tabBar.tabRect(0).center(); QTest::mouseClick(&tabBar, button, {}, tabPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(doubleClickSpy.size(), 0); QTest::mouseDClick(&tabBar, button, {}, tabPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); - QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.size(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); QTest::mouseRelease(&tabBar, button, {}, tabPos); const QPoint barPos(tabBar.tabRect(0).right() + 5, tabBar.tabRect(0).center().y()); QTest::mouseClick(&tabBar, button, {}, barPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(doubleClickSpy.size(), 0); QTest::mouseDClick(&tabBar, button, {}, barPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); - QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.size(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); QTest::mouseRelease(&tabBar, button, {}, barPos); @@ -1009,8 +1053,8 @@ void tst_QTabBar::kineticWheel() window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - const auto *leftButton = tabbar.findChild<QAbstractButton*>(u"ScrollLeftButton"_qs); - const auto *rightButton = tabbar.findChild<QAbstractButton*>(u"ScrollRightButton"_qs); + const auto *leftButton = tabbar.findChild<QAbstractButton*>(u"ScrollLeftButton"_s); + const auto *rightButton = tabbar.findChild<QAbstractButton*>(u"ScrollRightButton"_s); QVERIFY(leftButton && rightButton); QVERIFY(leftButton->isEnabled() && rightButton->isEnabled()); @@ -1106,6 +1150,49 @@ void tst_QTabBar::kineticWheel() } } +void tst_QTabBar::highResolutionWheel_data() +{ + QTest::addColumn<int>("angleDelta"); + // Smallest angleDelta for a Logitech MX Master 3 with Linux/X11/Libinput + QTest::addRow("increment index") << -16; + QTest::addRow("decrement index") << 16; +} + +void tst_QTabBar::highResolutionWheel() +{ + TabBar tabbar; + TabBarScrollingProxyStyle proxyStyle; + tabbar.setStyle(&proxyStyle); + + tabbar.addTab("tab1"); + tabbar.addTab("tab2"); + QFETCH(int, angleDelta); + // Negative values increment, positive values decrement + int startIndex = angleDelta < 0 ? 0 : 1; + tabbar.setCurrentIndex(startIndex); + + const auto systemId = QPointingDevice::primaryPointingDevice()->systemId() + 1; + QPointingDevice hiResWheel( + "test high resolution wheel", systemId, QInputDevice::DeviceType::Mouse, + QPointingDevice::PointerType::Generic, + QInputDevice::Capability::Position | QInputDevice::Capability::Scroll, 1, 3); + + const QPoint wheelPoint = tabbar.rect().bottomRight(); + QWheelEvent event(wheelPoint, tabbar.mapToGlobal(wheelPoint), QPoint(), + QPoint(angleDelta, angleDelta), Qt::NoButton, Qt::NoModifier, + Qt::NoScrollPhase, false, Qt::MouseEventSynthesizedByApplication, + &hiResWheel); + + proxyStyle.scrolling = true; + for (int accumulated = 0; accumulated < QWheelEvent::DefaultDeltasPerStep; + accumulated += qAbs(angleDelta)) { + // verify that nothing has changed until the threshold has been reached + QVERIFY(tabbar.currentIndex() == startIndex); + QVERIFY(QApplication::sendEvent(&tabbar, &event)); + } + QVERIFY(tabbar.currentIndex() != startIndex); +} + #endif // QT_CONFIG(wheelevent) void tst_QTabBar::scrollButtons_data() @@ -1145,8 +1232,8 @@ void tst_QTabBar::scrollButtons() window.show(); QVERIFY(QTest::qWaitForWindowActive(&window)); - auto *leftB = tabWidget.tabBar()->findChild<QAbstractButton*>(u"ScrollLeftButton"_qs); - auto *rightB = tabWidget.tabBar()->findChild<QAbstractButton*>(u"ScrollRightButton"_qs); + auto *leftB = tabWidget.tabBar()->findChild<QAbstractButton*>(u"ScrollLeftButton"_s); + auto *rightB = tabWidget.tabBar()->findChild<QAbstractButton*>(u"ScrollRightButton"_s); QVERIFY(leftB->isVisible()); QVERIFY(!leftB->isEnabled()); @@ -1201,9 +1288,10 @@ void tst_QTabBar::currentTabLargeFont() void tst_QTabBar::hoverTab_data() { - // Since we still rely on moving the mouse via QCursor::setPos in QTest::mouseMove, + // Move the cursor away from the widget as not to interfere. // skip this test if we can't - const QPoint cursorPos = QCursor::pos() + QPoint(10, 10); + const QPoint topLeft = QGuiApplication::primaryScreen()->availableGeometry().topLeft(); + const QPoint cursorPos = topLeft + QPoint(10, 10); QCursor::setPos(cursorPos); if (!QTest::qWaitFor([cursorPos]{ return QCursor::pos() == cursorPos; }, 500)) QSKIP("Can't move mouse"); @@ -1216,7 +1304,7 @@ void tst_QTabBar::hoverTab_data() void tst_QTabBar::hoverTab() { QFETCH(bool, documentMode); - QWidget window; + QWidget topLevel; class TabBar : public QTabBar { public: @@ -1227,7 +1315,7 @@ void tst_QTabBar::hoverTab() styleOptions[tabIndex] = *option; } mutable QHash<int, QStyleOptionTab> styleOptions; - } tabbar(&window); + } tabbar(&topLevel); tabbar.setDocumentMode(documentMode); tabbar.addTab("A"); @@ -1236,7 +1324,10 @@ void tst_QTabBar::hoverTab() tabbar.addTab("D"); tabbar.move(0,0); - window.setMinimumSize(tabbar.sizeHint()); + const QSize size = tabbar.sizeHint(); + const auto center = topLevel.screen()->availableGeometry().center(); + topLevel.move(center - QPoint{size.width(), size.height()} / 2); + topLevel.setMinimumSize(size); tabbar.ensurePolished(); // some styles set those flags, some don't. If not, use a style sheet @@ -1248,21 +1339,25 @@ void tst_QTabBar::hoverTab() )"); } - window.show(); - QVERIFY(QTest::qWaitForWindowExposed(&window)); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + auto *window = topLevel.windowHandle(); - QTest::mouseMove(&tabbar, tabbar.tabRect(0).center()); + auto pos = tabbar.mapToParent(tabbar.tabRect(0).center()); + QTest::mouseMove(window, pos); QTRY_VERIFY(tabbar.styleOptions[0].state & QStyle::State_Selected); QTRY_COMPARE(tabbar.styleOptions[1].state & QStyle::State_MouseOver, QStyle::State_None); QTRY_COMPARE(tabbar.styleOptions[2].state & QStyle::State_MouseOver, QStyle::State_None); QTRY_COMPARE(tabbar.styleOptions[3].state & QStyle::State_MouseOver, QStyle::State_None); - QTest::mouseMove(&tabbar, tabbar.tabRect(1).center()); + pos = tabbar.mapToParent(tabbar.tabRect(1).center()); + QTest::mouseMove(window, pos); QTRY_COMPARE(tabbar.styleOptions[1].state & QStyle::State_MouseOver, QStyle::State_MouseOver); QCOMPARE(tabbar.styleOptions[2].state & QStyle::State_MouseOver, QStyle::State_None); QCOMPARE(tabbar.styleOptions[3].state & QStyle::State_MouseOver, QStyle::State_None); - QTest::mouseMove(&tabbar, tabbar.tabRect(2).center()); + pos = tabbar.mapToParent(tabbar.tabRect(2).center()); + QTest::mouseMove(window, pos); QTRY_COMPARE(tabbar.styleOptions[2].state & QStyle::State_MouseOver, QStyle::State_MouseOver); QCOMPARE(tabbar.styleOptions[1].state & QStyle::State_MouseOver, QStyle::State_None); QCOMPARE(tabbar.styleOptions[3].state & QStyle::State_MouseOver, QStyle::State_None); @@ -1280,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 d0689d0b66..a8b48e925c 100644 --- a/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtabwidget/CMakeLists.txt @@ -1,15 +1,22 @@ -# Generated from qtabwidget.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 INCLUDE_DIRECTORIES .. - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets Qt::WidgetsPrivate @@ -19,6 +26,6 @@ qt_internal_add_test(tst_qtabwidget ##################################################################### qt_internal_extend_target(tst_qtabwidget CONDITION WIN32 - PUBLIC_LIBRARIES + LIBRARIES user32 ) diff --git a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp index 0e7012482d..d7bfdfaad2 100644 --- a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp +++ b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -85,6 +60,7 @@ private slots: void tabPosition(); void tabEnabled(); void tabHidden(); + void checkHiddenTab(); void tabText(); void tabShape(); void tabTooltip(); @@ -104,6 +80,9 @@ private slots: void moveCurrentTab(); void autoHide(); + void setCurrentBeforeShow_data(); + void setCurrentBeforeShow(); + private: int addPage(); void removePage(int index); @@ -274,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 @@ -383,12 +388,12 @@ void tst_QTabWidget::currentIndex() QCOMPARE(tw->currentIndex(), -1); tw->setCurrentIndex(-1); QCOMPARE(tw->currentIndex(), -1); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); int firstIndex = addPage(); tw->setCurrentIndex(firstIndex); QCOMPARE(tw->currentIndex(), firstIndex); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QList<QVariant> arguments = spy.takeFirst(); QCOMPARE(arguments.at(0).toInt(), firstIndex); @@ -396,19 +401,19 @@ void tst_QTabWidget::currentIndex() QCOMPARE(tw->currentIndex(), firstIndex); tw->setCurrentIndex(index); QCOMPARE(tw->currentIndex(), index); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.at(0).toInt(), index); removePage(index); QCOMPARE(tw->currentIndex(), firstIndex); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.at(0).toInt(), firstIndex); removePage(firstIndex); QCOMPARE(tw->currentIndex(), -1); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); arguments = spy.takeFirst(); QCOMPARE(arguments.at(0).toInt(), -1); } @@ -689,8 +694,8 @@ void tst_QTabWidget::tabBarClicked() QSignalSpy clickSpy(&tabWidget, SIGNAL(tabBarClicked(int))); QSignalSpy doubleClickSpy(&tabWidget, SIGNAL(tabBarDoubleClicked(int))); - QCOMPARE(clickSpy.count(), 0); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(clickSpy.size(), 0); + QCOMPARE(doubleClickSpy.size(), 0); QTabBar &tabBar = *tabWidget.tabBar(); Qt::MouseButton button = Qt::LeftButton; @@ -698,27 +703,27 @@ void tst_QTabWidget::tabBarClicked() const QPoint tabPos = tabBar.tabRect(0).center(); QTest::mouseClick(&tabBar, button, {}, tabPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(doubleClickSpy.size(), 0); QTest::mouseDClick(&tabBar, button, {}, tabPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); - QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.size(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); const QPoint barPos(tabBar.tabRect(0).right() + 5, tabBar.tabRect(0).center().y()); QTest::mouseClick(&tabBar, button, {}, barPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); - QCOMPARE(doubleClickSpy.count(), 0); + QCOMPARE(doubleClickSpy.size(), 0); QTest::mouseDClick(&tabBar, button, {}, barPos); - QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.size(), 1); QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); - QCOMPARE(doubleClickSpy.count(), 1); + QCOMPARE(doubleClickSpy.size(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); button = Qt::MouseButton(button << 1); @@ -775,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 170ac1e139..4a80068d75 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtextbrowser/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qtextbrowser.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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} @@ -22,9 +29,10 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qtextbrowser SOURCES tst_qtextbrowser.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp index ec187a55b0..6dfab07fed 100644 --- a/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp +++ b/tests/auto/widgets/widgets/qtextbrowser/tst_qtextbrowser.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -37,12 +12,13 @@ #include <qtextbrowser.h> #include <qtextobject.h> +#include <QtWidgets/private/qapplication_p.h> + class TestBrowser : public QTextBrowser { public: inline TestBrowser() { show(); - QApplication::setActiveWindow(this); activateWindow(); setFocus(); QVERIFY(QTest::qWaitForWindowActive(this)); @@ -245,29 +221,29 @@ void tst_QTextBrowser::relativeLinks() QSignalSpy sourceChangedSpy(browser, SIGNAL(sourceChanged(QUrl))); browser->setSource(QUrl("subdir/../qtextbrowser.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("subdir/../qtextbrowser.html")); browser->setSource(QUrl("subdir/index.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("subdir/index.html")); browser->setSource(QUrl("anchor.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("anchor.html")); browser->setSource(QUrl("subdir/index.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("subdir/index.html")); // using QUrl::fromLocalFile() browser->setSource(QUrl::fromLocalFile("anchor.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("file:anchor.html")); browser->setSource(QUrl("subdir/../qtextbrowser.html")); QVERIFY(!browser->document()->isEmpty()); - QCOMPARE(sourceChangedSpy.count(), 1); + QCOMPARE(sourceChangedSpy.size(), 1); QCOMPARE(sourceChangedSpy.takeFirst()[0].toUrl(), QUrl("subdir/../qtextbrowser.html")); } @@ -299,9 +275,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->setSource(QUrl::fromLocalFile("anchor.html")); QVERIFY(!browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(!backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -310,9 +286,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->setSource(QUrl::fromLocalFile("bigpage.html")); QVERIFY(browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -321,9 +297,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->setSource(QUrl::fromLocalFile("pagewithbg.html")); QVERIFY(browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -332,9 +308,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->backward(); QVERIFY(browser->isBackwardAvailable()); QVERIFY(browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -343,9 +319,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->backward(); QVERIFY(!browser->isBackwardAvailable()); QVERIFY(browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(!backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -354,9 +330,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->forward(); QVERIFY(browser->isBackwardAvailable()); QVERIFY(browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -365,9 +341,9 @@ void tst_QTextBrowser::forwardBackwardAvailable() browser->forward(); QVERIFY(browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -385,9 +361,9 @@ void tst_QTextBrowser::clearHistory() browser->clearHistory(); QVERIFY(!browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(!backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); QVERIFY(browser->historyTitle(-1).isEmpty()); QVERIFY(browser->historyTitle(0).isEmpty()); @@ -399,9 +375,9 @@ void tst_QTextBrowser::clearHistory() browser->setSource(QUrl::fromLocalFile("anchor.html")); QVERIFY(!browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(!backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -410,9 +386,9 @@ void tst_QTextBrowser::clearHistory() browser->setSource(QUrl::fromLocalFile("bigpage.html")); QVERIFY(browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); backwardSpy.clear(); @@ -421,9 +397,9 @@ void tst_QTextBrowser::clearHistory() browser->clearHistory(); QVERIFY(!browser->isBackwardAvailable()); QVERIFY(!browser->isForwardAvailable()); - QCOMPARE(backwardSpy.count(), 1); + QCOMPARE(backwardSpy.size(), 1); QVERIFY(!backwardSpy.at(0).at(0).toBool()); - QCOMPARE(forwardSpy.count(), 1); + QCOMPARE(forwardSpy.size(), 1); QVERIFY(!forwardSpy.at(0).at(0).toBool()); QVERIFY(browser->historyTitle(-1).isEmpty()); QVERIFY(browser->historyTitle(1).isEmpty()); @@ -696,7 +672,7 @@ void tst_QTextBrowser::urlEncoding() browser->setEditFocus(true); #endif QTest::keyClick(browser, Qt::Key_Enter); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QUrl url = spy.at(0).at(0).toUrl(); QCOMPARE(url.toEncoded(), QByteArray("http://www.google.com/q=%22")); diff --git a/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt b/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt index e90b59ccb8..e406e088ca 100644 --- a/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtextedit/CMakeLists.txt @@ -1,16 +1,23 @@ -# Generated from qtextedit.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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") qt_internal_add_test(tst_qtextedit SOURCES tst_qtextedit.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate @@ -23,6 +30,6 @@ qt_internal_add_test(tst_qtextedit ##################################################################### qt_internal_extend_target(tst_qtextedit CONDITION MACOS - PUBLIC_LIBRARIES + LIBRARIES ${FWAppKit} ) diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp index 8d5716c129..ddf2bcfa85 100644 --- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -58,6 +33,10 @@ #include "../../../shared/platforminputcontext.h" #include <private/qinputmethod_p.h> +#include <QtWidgets/private/qapplication_p.h> + +Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests") + //Used in copyAvailable typedef QPair<Qt::Key, Qt::KeyboardModifier> keyPairType; typedef QList<keyPairType> pairListType; @@ -137,7 +116,13 @@ private slots: void moveCursor(); #ifndef QT_NO_CLIPBOARD void mimeDataReimplementations(); +#ifndef QT_NO_TEXTHTMLPARSER + void mimeTypesAvailableFromRichText(); #endif +#if QT_CONFIG(textmarkdownreader) + void mimeTypesAvailableFromMarkdown(); +#endif +#endif // QT_NO_CLIPBOARD void ctrlEnterShouldInsertLineSeparator_NOT(); void shiftEnterShouldInsertLineSeparator(); void selectWordsFromStringsContainingSeparators_data(); @@ -173,6 +158,7 @@ private slots: void setDocumentPreservesPalette(); #endif void pasteFromQt3RichText(); + void pasteFromMarkdown(); void noWrapBackgrounds(); void preserveCharFormatAfterUnchangingSetPosition(); void twoSameInputMethodEvents(); @@ -209,10 +195,16 @@ private slots: void preeditCharFormat_data(); void preeditCharFormat(); + void nextFormatAfterEnterPressed_data(); + void nextFormatAfterEnterPressed(); + + void dontCrashWithCss(); + private: void createSelection(); int blockCount() const; void compareWidgetAndImage(QTextEdit &widget, const QString &imageFileName); + bool isMainFontFixed(); QTextEdit *ed; qreal rootFrameMargin; @@ -529,9 +521,9 @@ void tst_QTextEdit::clearShouldClearExtraSelections() sel.cursor = ed->textCursor(); sel.format.setProperty(QTextFormat::FullWidthSelection, true); ed->setExtraSelections(QList<QTextEdit::ExtraSelection>() << sel); - QCOMPARE(ed->extraSelections().count(), 1); + QCOMPARE(ed->extraSelections().size(), 1); ed->clear(); - QCOMPARE(ed->extraSelections().count(), 0); + QCOMPARE(ed->extraSelections().size(), 0); } void tst_QTextEdit::paragSeparatorOnPlaintextAppend() @@ -731,7 +723,7 @@ void tst_QTextEdit::cursorPositionChanged() spy.clear(); QTest::keyClick(ed, Qt::Key_A); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QTextCursor cursor = ed->textCursor(); cursor.movePosition(QTextCursor::Start); @@ -739,18 +731,18 @@ void tst_QTextEdit::cursorPositionChanged() cursor.movePosition(QTextCursor::End); spy.clear(); cursor.insertText("Test"); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); cursor.movePosition(QTextCursor::End); ed->setTextCursor(cursor); cursor.movePosition(QTextCursor::Start); spy.clear(); cursor.insertText("Test"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); QTest::keyClick(ed, Qt::Key_Left); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); cursor.movePosition(QTextCursor::Start); ed->setTextCursor(cursor); @@ -759,14 +751,19 @@ void tst_QTextEdit::cursorPositionChanged() QTest::mouseDClick(ed->viewport(), Qt::LeftButton, {}, ed->cursorRect().center()); QVERIFY(ed->textCursor().hasSelection()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); CursorPositionChangedRecorder spy2(ed); QVERIFY(ed->textCursor().position() > 0); ed->setPlainText("Hello World"); - QCOMPARE(spy2.cursorPositions.count(), 1); + 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() @@ -781,7 +778,7 @@ void tst_QTextEdit::setTextCursor() spy.clear(); ed->setTextCursor(cursor); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } #ifndef QT_NO_CLIPBOARD @@ -798,7 +795,7 @@ void tst_QTextEdit::undoAvailableAfterPaste() const QString txt("Test"); QApplication::clipboard()->setText(txt); ed->paste(); - QVERIFY(spy.count() >= 1); + QVERIFY(spy.size() >= 1); QCOMPARE(ed->toPlainText(), txt); } #endif @@ -1051,7 +1048,7 @@ void tst_QTextEdit::noPropertiesOnDefaultTextEditCharFormat() // on a text edit. Font properties instead should be taken from the // widget's font (in sync with defaultFont property in document) and the // foreground color should be taken from the palette. - QCOMPARE(ed->currentCharFormat().properties().count(), 0); + QCOMPARE(ed->currentCharFormat().properties().size(), 0); } void tst_QTextEdit::setPlainTextShouldUseCurrentCharFormat() @@ -1073,9 +1070,9 @@ void tst_QTextEdit::setPlainTextShouldEmitTextChangedOnce() { QSignalSpy spy(ed, SIGNAL(textChanged())); ed->setPlainText("Yankee Doodle"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); ed->setPlainText(""); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); } void tst_QTextEdit::overwriteMode() @@ -1357,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); @@ -1370,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") @@ -1389,8 +1385,8 @@ void tst_QTextEdit::copyAvailable() //Compare spied signals QEXPECT_FAIL("Case7 T,A,A, <- + shift, <- + shift, <- + shift, ctrl + x, undo() | signals: true, false, true", "Wrong undo selection behaviour. Should be fixed in some future release. (See task: 132482)", Abort); - QCOMPARE(spyCopyAvailabe.count(), copyAvailable.count()); - for (int i=0;i<spyCopyAvailabe.count(); i++) { + QCOMPARE(spyCopyAvailabe.size(), copyAvailable.size()); + for (int i=0;i<spyCopyAvailabe.size(); i++) { QVariant variantSpyCopyAvailable = spyCopyAvailabe.at(i).at(0); QVERIFY2(variantSpyCopyAvailable.toBool() == copyAvailable.at(i), QString("Spied singnal: %1").arg(i).toLatin1()); } @@ -1426,10 +1422,10 @@ void tst_QTextEdit::moveCursor() QCOMPARE(ed->textCursor().position(), 0); ed->moveCursor(QTextCursor::NextCharacter); QCOMPARE(ed->textCursor().position(), 1); - QCOMPARE(cursorMovedSpy.count(), 1); + QCOMPARE(cursorMovedSpy.size(), 1); ed->moveCursor(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); QCOMPARE(ed->textCursor().position(), 2); - QCOMPARE(cursorMovedSpy.count(), 2); + QCOMPARE(cursorMovedSpy.size(), 2); QCOMPARE(ed->textCursor().selectedText(), QString("e")); } @@ -1500,7 +1496,63 @@ void tst_QTextEdit::mimeDataReimplementations() QCOMPARE(ed.insertCallCount, 1); #endif } + +#ifndef QT_NO_TEXTHTMLPARSER +void tst_QTextEdit::mimeTypesAvailableFromRichText() +{ + MyTextEdit ed; + ed.setHtml("<i>Hello <b>World</b></i>"); + ed.selectAll(); + ed.copy(); + const auto *mimeData = QApplication::clipboard()->mimeData(); + qCDebug(lcTests) << "available mime types" << mimeData->formats(); + QVERIFY(mimeData->formats().contains("text/plain")); +#if QT_CONFIG(textmarkdownwriter) + QVERIFY(mimeData->formats().contains("text/markdown")); + const QByteArray expectedMarkdown = "*Hello **World***\n\n"; + if (mimeData->data("text/markdown") != expectedMarkdown && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(mimeData->data("text/markdown"), expectedMarkdown); #endif +#ifndef QT_NO_TEXTHTMLPARSER + QVERIFY(mimeData->formats().contains("text/html")); + QVERIFY(mimeData->hasHtml()); +#endif +#ifndef QT_NO_TEXTODFWRITER + QVERIFY(mimeData->formats().contains("application/vnd.oasis.opendocument.text")); +#endif +} +#endif // QT_NO_TEXTHTMLPARSER + +#if QT_CONFIG(textmarkdownreader) +void tst_QTextEdit::mimeTypesAvailableFromMarkdown() +{ + MyTextEdit ed; + const QString md("# TODO\n\n- [x] Fix bugs\n- [ ] Have a beer\n"); + ed.setMarkdown(md); + ed.selectAll(); + ed.copy(); + const auto *mimeData = QApplication::clipboard()->mimeData(); + qCDebug(lcTests) << "available mime types" << mimeData->formats(); + QVERIFY(mimeData->formats().contains("text/plain")); +#if QT_CONFIG(textmarkdownwriter) + QVERIFY(mimeData->formats().contains("text/markdown")); + if (mimeData->data("text/markdown") != md && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(mimeData->data("text/markdown"), md); +#endif +#ifndef QT_NO_TEXTHTMLPARSER + QVERIFY(mimeData->formats().contains("text/html")); + QVERIFY(mimeData->hasHtml()); + QVERIFY(mimeData->html().contains("checked")); // <li class=\"checked\" ... +#endif +#ifndef QT_NO_TEXTODFWRITER + QVERIFY(mimeData->formats().contains("application/vnd.oasis.opendocument.text")); +#endif +} +#endif // textmarkdownreader + +#endif // QT_NO_CLIPBOARD void tst_QTextEdit::ctrlEnterShouldInsertLineSeparator_NOT() { @@ -1648,7 +1700,7 @@ void tst_QTextEdit::ensureVisibleWithRtl() ed->setLayoutDirection(Qt::RightToLeft); ed->setLineWrapMode(QTextEdit::NoWrap); QString txt(500, QChar(QLatin1Char('a'))); - QCOMPARE(txt.length(), 500); + QCOMPARE(txt.size(), 500); ed->setPlainText(txt); ed->resize(100, 100); ed->show(); @@ -1699,7 +1751,7 @@ void tst_QTextEdit::extraSelections() ed->setExtraSelections(QList<QTextEdit::ExtraSelection>() << sel); QList<QTextEdit::ExtraSelection> selections = ed->extraSelections(); - QCOMPARE(selections.count(), 1); + QCOMPARE(selections.size(), 1); QCOMPARE(selections.at(0).cursor.position(), endPos); QCOMPARE(selections.at(0).cursor.anchor(), wordPos); } @@ -1841,27 +1893,27 @@ void tst_QTextEdit::selectionChanged() QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 1); - QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(selectionChangedSpy.size(), 0); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 2); - QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(selectionChangedSpy.size(), 1); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 3); - QCOMPARE(selectionChangedSpy.count(), 2); + QCOMPARE(selectionChangedSpy.size(), 2); QTest::keyClick(ed, Qt::Key_Right, Qt::ShiftModifier); QCOMPARE(ed->textCursor().position(), 4); - QCOMPARE(selectionChangedSpy.count(), 3); + QCOMPARE(selectionChangedSpy.size(), 3); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 4); - QCOMPARE(selectionChangedSpy.count(), 4); + QCOMPARE(selectionChangedSpy.size(), 4); QTest::keyClick(ed, Qt::Key_Right); QCOMPARE(ed->textCursor().position(), 5); - QCOMPARE(selectionChangedSpy.count(), 4); + QCOMPARE(selectionChangedSpy.size(), 4); } #ifndef QT_NO_CLIPBOARD @@ -2153,6 +2205,18 @@ void tst_QTextEdit::compareWidgetAndImage(QTextEdit &widget, const QString &imag } } +bool tst_QTextEdit::isMainFontFixed() +{ + bool ret = QFontInfo(QGuiApplication::font()).fixedPitch(); + if (ret) { + qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks"; + qCWarning(lcTests) << "system fonts: fixed" << QFontDatabase::systemFont(QFontDatabase::FixedFont) + << "fixed?" << QFontInfo(QFontDatabase::systemFont(QFontDatabase::FixedFont)).fixedPitch() + << "general" << QFontDatabase::systemFont(QFontDatabase::GeneralFont); + } + return ret; +} + void tst_QTextEdit::cursorRect() { ed->show(); @@ -2173,9 +2237,8 @@ void tst_QTextEdit::setDocumentPreservesPalette() QWidgetTextControl *control = ed->findChild<QWidgetTextControl *>(); QVERIFY(control); - QPalette defaultPal = ed->palette(); QPalette whitePal = ed->palette(); - whitePal.setColor(QPalette::Active, QPalette::Text, "white"); + whitePal.setColor(QPalette::Active, QPalette::Text, Qt::white); QVERIFY(whitePal != ed->palette()); @@ -2220,6 +2283,24 @@ void tst_QTextEdit::pasteFromQt3RichText() QCOMPARE(ed->toPlainText(), QString::fromLatin1(" QTextEdit is an ")); } +void tst_QTextEdit::pasteFromMarkdown() +{ + QByteArray richtext("*This* text is **rich**"); + + QMimeData mimeData; + mimeData.setData("text/markdown", richtext); + + static_cast<PublicTextEdit *>(ed)->publicInsertFromMimeData(&mimeData); + + QCOMPARE(ed->toPlainText(), "This text is rich"); +#if QT_CONFIG(textmarkdownwriter) + const auto expectedMarkdown = QString::fromLatin1(richtext + "\n\n"); + if (ed->toMarkdown() != expectedMarkdown && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(ed->toMarkdown(), expectedMarkdown); +#endif +} + void tst_QTextEdit::noWrapBackgrounds() { QWidget topLevel; @@ -2292,7 +2373,8 @@ void tst_QTextEdit::taskQTBUG_7902_contextMenuCrash() w->connect(&ti, SIGNAL(timeout()), w, SLOT(deleteLater())); ti.start(200); - QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center()); + QContextMenuEvent *cme = new QContextMenuEvent(QContextMenuEvent::Mouse, w->rect().center(), + w->viewport()->mapToGlobal(w->rect().center())); qApp->postEvent(w->viewport(), cme); QTest::qWait(300); @@ -2458,12 +2540,11 @@ void tst_QTextEdit::inputMethodEvent() QInputMethodEvent event; event.setCommitString("text"); QApplication::sendEvent(ed, &event); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(ed->toPlainText(), QString("text")); // test that input method gets chance to commit preedit when removing focus ed->setText(""); - QApplication::setActiveWindow(ed); QTRY_VERIFY(QApplication::focusWindow()); QCOMPARE(qApp->focusObject(), ed); @@ -2488,7 +2569,7 @@ void tst_QTextEdit::inputMethodSelection() cursor.setPosition(5, QTextCursor::KeepAnchor); ed->setTextCursor(cursor); - QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(selectionSpy.size(), 1); QCOMPARE(ed->textCursor().selectionStart(), 0); QCOMPARE(ed->textCursor().selectionEnd(), 5); @@ -2497,7 +2578,7 @@ void tst_QTextEdit::inputMethodSelection() QInputMethodEvent event("", attributes); QApplication::sendEvent(ed, &event); - QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(selectionSpy.size(), 2); QCOMPARE(ed->textCursor().selectionStart(), 12); QCOMPARE(ed->textCursor().selectionEnd(), 17); } @@ -2512,7 +2593,7 @@ void tst_QTextEdit::inputMethodQuery() QGuiApplication::sendEvent(ed, &event); int anchor = event.value(Qt::ImAnchorPosition).toInt(); int position = event.value(Qt::ImCursorPosition).toInt(); - QCOMPARE(qAbs(position - anchor), text.length()); + QCOMPARE(qAbs(position - anchor), text.size()); QCOMPARE(event.value(Qt::ImEnabled).toBool(), true); ed->setEnabled(false); @@ -2597,7 +2678,7 @@ void tst_QTextEdit::countTextChangedOnRemove() QKeyEvent event(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); QCoreApplication::instance()->notify(&edit, &event); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } #if QT_CONFIG(regularexpression) @@ -2895,5 +2976,103 @@ void tst_QTextEdit::preeditCharFormat() delete w; } +void tst_QTextEdit::nextFormatAfterEnterPressed_data() +{ + typedef QMap<int, QVariant> pmap; + QTest::addColumn<QString>("html"); + QTest::addColumn<int>("enterKeyCount"); + QTest::addColumn<pmap>("expectedPrevBlockProps"); + QTest::addColumn<pmap>("expectedPrevCharProps"); + QTest::addColumn<pmap>("expectedNewBlockProps"); + QTest::addColumn<pmap>("expectedNewCharProps"); + + // the BlockBottomMargin on "two" will be removed: property() returns invalid QVariant + QTest::newRow("bottom margin after ordered list") << "<ol><li>one</li><li>two</li></ol>" << 1 + << pmap{{QTextFormat::BlockBottomMargin, {}}} << pmap{} + << pmap{{QTextFormat::BlockBottomMargin, 12}} << pmap{}; + QTest::newRow("double enter after list: default format") << "<ol><li>one</li><li>two</li></ol>" << 2 + << pmap{{QTextFormat::BlockBottomMargin, {}}} << pmap{} + << pmap{} << pmap{}; + QTest::newRow("continue block quote") << "<blockquote>I'll be back</blockquote>" << 1 + << pmap{{QTextFormat::BlockLeftMargin, 40}} << pmap{} + << pmap{{QTextFormat::BlockLeftMargin, 40}} << pmap{}; + QTest::newRow("double enter after block quote") << "<blockquote>I'll be back</blockquote>" << 2 + << pmap{{QTextFormat::BlockLeftMargin, 40}} << pmap{} + << pmap{{QTextFormat::BlockLeftMargin, {}}} << pmap{}; + QTest::newRow("bottom margin after bullet list") << "<ul><li>one</li><li>two</li></ul>" << 1 + << pmap{{QTextFormat::BlockBottomMargin, {}}} << pmap{} + << pmap{{QTextFormat::BlockBottomMargin, 12}} << pmap{}; + QTest::newRow("paragraph after heading") << "<h1>so big!</h1>" << 1 + << pmap{{QTextFormat::HeadingLevel, 1}} << pmap{} + << pmap{{QTextFormat::HeadingLevel, {}}} << pmap{}; + QTest::newRow("paragraph after hrule") << "<p style='font-size:18px;'>blah blah<hr/></p>" << 1 + << pmap{} << pmap{} + << pmap{{QTextFormat::BlockTrailingHorizontalRulerWidth, {}}} << pmap{}; +} + +void tst_QTextEdit::nextFormatAfterEnterPressed() +{ + typedef QMap<int, QVariant> pmap; + QFETCH(QString, html); + QFETCH(int, enterKeyCount); + QFETCH(pmap, expectedPrevBlockProps); + QFETCH(pmap, expectedPrevCharProps); + QFETCH(pmap, expectedNewBlockProps); + QFETCH(pmap, expectedNewCharProps); + + ed->setHtml(html); + QTextCursor cursor = ed->textCursor(); + cursor.movePosition(QTextCursor::End); + ed->setTextCursor(cursor); + + if (lcTests().isDebugEnabled()) { + ed->show(); + QTest::qWait(500); + } + + for (int i = 0; i < enterKeyCount; ++i) + QTest::keyClick(ed, Qt::Key_Enter); + QTest::keyClicks(ed, "foo"); + + if (lcTests().isDebugEnabled()) { + // visually see what happened when debug is enabled + QTest::qWait(500); + qCDebug(lcTests) << "new block" << Qt::hex << ed->textCursor().blockFormat().properties(); + qCDebug(lcTests) << "new char" << Qt::hex << ed->textCursor().charFormat().properties(); + } + + // if expectedNewBlockProps is empty, we expect the current block format to be the default format + if (expectedNewBlockProps.isEmpty()) + QCOMPARE(ed->textCursor().blockFormat(), QTextBlockFormat()); + // otherwise we expect to find certain property values in the current block format + else for (auto it = expectedNewBlockProps.constBegin(); it != expectedNewBlockProps.constEnd(); ++it) + QCOMPARE(ed->textCursor().blockFormat().property(it.key()), it.value()); + + // if expectedNewCharProps is empty, we expect the current char format to be the default format + if (expectedNewCharProps.isEmpty()) + QCOMPARE(ed->textCursor().charFormat(), QTextCharFormat()); + // otherwise we expect to find certain property values in the current char format + else for (auto it = expectedNewCharProps.constBegin(); it != expectedNewCharProps.constEnd(); ++it) + QCOMPARE(ed->textCursor().charFormat().property(it.key()), it.value()); + + // check the cases where QWidgetTextControlPrivate::insertParagraphSeparator() should modify + // the previous block's block format and/or char format + auto prevBlockCursor = ed->textCursor(); + prevBlockCursor.movePosition(QTextCursor::PreviousBlock); + for (auto it = expectedPrevBlockProps.constBegin(); it != expectedPrevBlockProps.constEnd(); ++it) + QCOMPARE(prevBlockCursor.blockFormat().property(it.key()), it.value()); + for (auto it = expectedPrevCharProps.constBegin(); it != expectedPrevCharProps.constEnd(); ++it) + 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 79b4816d53..e9fb01c3e8 100644 --- a/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtoolbar/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtoolbar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Widgets diff --git a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp index 8fea0dcd67..8b8c74b1e7 100644 --- a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp +++ b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -47,6 +22,8 @@ #include <qlabel.h> #include <private/qtoolbarextension_p.h> +#include <QtWidgets/private/qapplication_p.h> + QT_FORWARD_DECLARE_CLASS(QAction) class tst_QToolBar : public QObject @@ -162,12 +139,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::RightToolBarArea); QCOMPARE((int)tb.allowedAreas(), (int)Qt::RightToolBarArea); @@ -175,12 +152,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::TopToolBarArea); QCOMPARE((int)tb.allowedAreas(), (int)Qt::TopToolBarArea); @@ -188,12 +165,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::BottomToolBarArea); QCOMPARE((int)tb.allowedAreas(), (int)Qt::BottomToolBarArea); @@ -201,12 +178,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // multiple dock window areas tb.setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); @@ -215,12 +192,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea); QCOMPARE(tb.allowedAreas(), Qt::LeftToolBarArea | Qt::RightToolBarArea); @@ -228,12 +205,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea); QCOMPARE(tb.allowedAreas(), Qt::TopToolBarArea | Qt::LeftToolBarArea); @@ -241,12 +218,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(!tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setAllowedAreas(Qt::BottomToolBarArea | Qt::RightToolBarArea); QCOMPARE(tb.allowedAreas(), Qt::BottomToolBarArea | Qt::RightToolBarArea); @@ -254,12 +231,12 @@ void tst_QToolBar::allowedAreas() QVERIFY(tb.isAreaAllowed(Qt::RightToolBarArea)); QVERIFY(!tb.isAreaAllowed(Qt::TopToolBarArea)); QVERIFY(tb.isAreaAllowed(Qt::BottomToolBarArea)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::ToolBarAreas *>(spy.at(0).value(0).constData()), tb.allowedAreas()); spy.clear(); tb.setAllowedAreas(tb.allowedAreas()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QToolBar::orientation() @@ -271,48 +248,48 @@ void tst_QToolBar::orientation() tb.setOrientation(Qt::Vertical); QCOMPARE(tb.orientation(), Qt::Vertical); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()), tb.orientation()); spy.clear(); tb.setOrientation(tb.orientation()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setOrientation(Qt::Horizontal); QCOMPARE(tb.orientation(), Qt::Horizontal); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()), tb.orientation()); spy.clear(); tb.setOrientation(tb.orientation()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setOrientation(Qt::Vertical); QCOMPARE(tb.orientation(), Qt::Vertical); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()), tb.orientation()); spy.clear(); tb.setOrientation(tb.orientation()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setOrientation(Qt::Horizontal); QCOMPARE(tb.orientation(), Qt::Horizontal); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()), tb.orientation()); spy.clear(); tb.setOrientation(tb.orientation()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setOrientation(Qt::Vertical); QCOMPARE(tb.orientation(), Qt::Vertical); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(*static_cast<const Qt::Orientation *>(spy.at(0).value(0).constData()), tb.orientation()); spy.clear(); tb.setOrientation(tb.orientation()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QToolBar::addAction() @@ -322,13 +299,13 @@ void tst_QToolBar::addAction() { QAction action(0); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); tb.addAction(&action); - QCOMPARE(tb.actions().count(), 1); + QCOMPARE(tb.actions().size(), 1); QCOMPARE(tb.actions()[0], &action); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } { @@ -351,14 +328,14 @@ void tst_QToolBar::addAction() QCOMPARE(icon, action4->icon()); QCOMPARE(text, action4->text()); - QCOMPARE(tb.actions().count(), 4); + QCOMPARE(tb.actions().size(), 4); QCOMPARE(tb.actions()[0], action1); QCOMPARE(tb.actions()[1], action2); QCOMPARE(tb.actions()[2], action3); QCOMPARE(tb.actions()[3], action4); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } } @@ -387,19 +364,19 @@ void tst_QToolBar::insertAction() QAction action3(0); QAction action4(0); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); tb.insertAction(0, &action1); tb.insertAction(&action1, &action2); tb.insertAction(&action2, &action3); tb.insertAction(&action3, &action4); - QCOMPARE(tb.actions().count(), 4); + QCOMPARE(tb.actions().size(), 4); QCOMPARE(tb.actions()[0], &action4); QCOMPARE(tb.actions()[1], &action3); QCOMPARE(tb.actions()[2], &action2); QCOMPARE(tb.actions()[3], &action1); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } void tst_QToolBar::addSeparator() @@ -413,13 +390,13 @@ void tst_QToolBar::addSeparator() QAction *sep = tb.addSeparator(); tb.addAction(&action2); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], sep); QCOMPARE(tb.actions()[2], &action2); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } void tst_QToolBar::insertSeparator() @@ -433,13 +410,13 @@ void tst_QToolBar::insertSeparator() tb.addAction(&action2); QAction *sep = tb.insertSeparator(&action2); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], sep); QCOMPARE(tb.actions()[2], &action2); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } void tst_QToolBar::addWidget() @@ -454,7 +431,7 @@ void tst_QToolBar::addWidget() QAction *widget = tb.addWidget(&w); tb.addAction(&action2); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], widget); QCOMPARE(tb.actions()[2], &action2); @@ -462,18 +439,18 @@ void tst_QToolBar::addWidget() // it should be possible to reuse the action returned by // addWidget() to place the widget somewhere else in the toolbar tb.removeAction(widget); - QCOMPARE(tb.actions().count(), 2); + QCOMPARE(tb.actions().size(), 2); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], &action2); tb.addAction(widget); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], &action2); QCOMPARE(tb.actions()[2], widget); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); } void tst_QToolBar::insertWidget() @@ -488,7 +465,7 @@ void tst_QToolBar::insertWidget() tb.addAction(&action2); QAction *widget = tb.insertWidget(&action2, &w); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], widget); QCOMPARE(tb.actions()[2], &action2); @@ -496,18 +473,18 @@ void tst_QToolBar::insertWidget() // it should be possible to reuse the action returned by // addWidget() to place the widget somewhere else in the toolbar tb.removeAction(widget); - QCOMPARE(tb.actions().count(), 2); + QCOMPARE(tb.actions().size(), 2); QCOMPARE(tb.actions()[0], &action1); QCOMPARE(tb.actions()[1], &action2); tb.insertAction(&action1, widget); - QCOMPARE(tb.actions().count(), 3); + QCOMPARE(tb.actions().size(), 3); QCOMPARE(tb.actions()[0], widget); QCOMPARE(tb.actions()[1], &action1); QCOMPARE(tb.actions()[2], &action2); tb.clear(); - QCOMPARE(tb.actions().count(), 0); + QCOMPARE(tb.actions().size(), 0); { QToolBar tb; @@ -649,43 +626,43 @@ void tst_QToolBar::iconSize() QCOMPARE(tb.iconSize(), defaultIconSize); tb.setIconSize(defaultIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); tb.setIconSize(largeIconSize); QCOMPARE(tb.iconSize(), largeIconSize); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.first().first().toSize(), largeIconSize); // no-op spy.clear(); tb.setIconSize(largeIconSize); QCOMPARE(tb.iconSize(), largeIconSize); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); tb.setIconSize(defaultIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.first().first().toSize(), defaultIconSize); // no-op spy.clear(); tb.setIconSize(defaultIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); tb.setIconSize(smallIconSize); QCOMPARE(tb.iconSize(), smallIconSize); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.first().first().toSize(), smallIconSize); // no-op spy.clear(); tb.setIconSize(smallIconSize); QCOMPARE(tb.iconSize(), smallIconSize); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); // setting the icon size to an invalid QSize will reset the // iconSize property to the default @@ -713,28 +690,28 @@ void tst_QToolBar::iconSize() // explicitly set it to the default tb.setIconSize(defaultIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.addToolBar(&tb); // tb icon size should not change since it has been explicitly set QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setIconSize(largeIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setIconSize(defaultIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setIconSize(smallIconSize); QCOMPARE(tb.iconSize(), defaultIconSize); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); // resetting to the default should cause the toolbar to take // on the mainwindow's icon size @@ -757,51 +734,51 @@ void tst_QToolBar::toolButtonStyle() QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); tb.setToolButtonStyle(Qt::ToolButtonIconOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setToolButtonStyle(Qt::ToolButtonTextOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextOnly); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); // no-op tb.setToolButtonStyle(Qt::ToolButtonTextOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextOnly); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setToolButtonStyle(Qt::ToolButtonIconOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); // no-op tb.setToolButtonStyle(Qt::ToolButtonIconOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextBesideIcon); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); // no-op tb.setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextBesideIcon); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextUnderIcon); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); // no-op tb.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonTextUnderIcon); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.setToolButtonStyle(Qt::ToolButtonFollowStyle); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonFollowStyle); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); } { @@ -815,28 +792,28 @@ void tst_QToolBar::toolButtonStyle() // explicitly set the tb to the default tb.setToolButtonStyle(Qt::ToolButtonIconOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.addToolBar(&tb); // tb icon size should not change since it has been explicitly set QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setToolButtonStyle(Qt::ToolButtonIconOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setToolButtonStyle(Qt::ToolButtonTextOnly); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); mw.setToolButtonStyle(Qt::ToolButtonTextUnderIcon); QCOMPARE(tb.toolButtonStyle(), Qt::ToolButtonIconOnly); - QCOMPARE(tbSpy.count(), 0); + QCOMPARE(tbSpy.size(), 0); // note: there is no way to clear the explicitly set tool // button style... once you explicitly set it, the toolbar @@ -950,25 +927,25 @@ void tst_QToolBar::visibilityChanged() mw.addToolBar(&tb); mw.show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); tb.hide(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), false); spy.clear(); tb.hide(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); tb.show(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).at(0).toBool(), true); spy.clear(); tb.show(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QToolBar::actionOwnership() @@ -1045,12 +1022,11 @@ void tst_QToolBar::accel() QSignalSpy spy(action, SIGNAL(triggered(bool))); mw.show(); - QApplication::setActiveWindow(&mw); QVERIFY(QTest::qWaitForWindowActive(&mw)); QTest::keyClick(&mw, Qt::Key_T, Qt::AltModifier); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); #ifdef Q_OS_MAC qt_set_sequence_auto_mnemonic(false); #endif diff --git a/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt b/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt index bb50233c6e..362fba25a4 100644 --- a/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtoolbox/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtoolbox.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets ) diff --git a/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp b/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp index fc7eade9f4..fb14ceb79c 100644 --- a/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp +++ b/tests/auto/widgets/widgets/qtoolbox/tst_qtoolbox.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// 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 b27d88f503..7c8b41b5e6 100644 --- a/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt +++ b/tests/auto/widgets/widgets/qtoolbutton/CMakeLists.txt @@ -1,13 +1,21 @@ -# Generated from qtoolbutton.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## 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 - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::Widgets + Qt::WidgetsPrivate ) diff --git a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp index 12a9ec3de0..b77a9c0eec 100644 --- a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp +++ b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -40,6 +15,8 @@ #include <qscreen.h> #include <qlabel.h> +#include <QtWidgets/private/qapplication_p.h> + class tst_QToolButton : public QObject { Q_OBJECT @@ -57,6 +34,7 @@ private slots: void qtbug_26956_popupTimerDone(); void qtbug_34759_sizeHintResetWhenSettingMenu(); void defaultActionSynced(); + void deleteInHandler(); protected slots: void sendMouseClick(); @@ -143,11 +121,11 @@ void tst_QToolButton::triggered() toolButton->setDefaultAction(defaultAction); mainWidget.show(); - QApplication::setActiveWindow(&mainWidget); + QApplicationPrivate::setActiveWindow(&mainWidget); QVERIFY(QTest::qWaitForWindowActive(&mainWidget)); defaultAction->trigger(); - QCOMPARE(spy.count(),1); + QCOMPARE(spy.size(),1); QCOMPARE(qvariant_cast<QAction *>(spy.at(0).at(0)), defaultAction); m_menu = menu.data(); @@ -158,7 +136,7 @@ void tst_QToolButton::triggered() timer->start(); QTimer::singleShot(10000, &mainWidget, SLOT(close())); // Emergency bail-out toolButton->showMenu(); - QTRY_COMPARE(spy.count(),2); + QTRY_COMPARE(spy.size(),2); QCOMPARE(qvariant_cast<QAction *>(spy.at(1).at(0)), one); } @@ -204,14 +182,13 @@ void tst_QToolButton::task176137_autoRepeatOfAction() label->move(0, 50); mainWidget.show(); - QApplication::setActiveWindow(&mainWidget); QVERIFY(QTest::qWaitForWindowActive(&mainWidget)); QSignalSpy spy(&action,SIGNAL(triggered())); QTest::mousePress (toolButton, Qt::LeftButton); QTest::qWait(2000); QTest::mouseRelease (toolButton, Qt::LeftButton, {}, {}); - QCOMPARE(spy.count(),1); + QCOMPARE(spy.size(),1); // try again with auto repeat toolButton->setAutoRepeat (true); @@ -221,11 +198,11 @@ void tst_QToolButton::task176137_autoRepeatOfAction() QTest::mouseRelease (toolButton, Qt::LeftButton, {}, {}); const qreal expected = (3000 - toolButton->autoRepeatDelay()) / toolButton->autoRepeatInterval() + 1; //we check that the difference is small (on some systems timers are not super accurate) - qreal diff = (expected - repeatSpy.count()) / expected; + qreal diff = (expected - repeatSpy.size()) / expected; QVERIFY2(qAbs(diff) < 0.2, qPrintable( QString("expected: %1, actual: %2, diff (fraction): %3") .arg(expected) - .arg(repeatSpy.count()) + .arg(repeatSpy.size()) .arg(diff))); } @@ -298,21 +275,21 @@ void tst_QToolButton::defaultActionSynced() tb.setChecked(true); QVERIFY(a.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), ++aToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), ++aToggledCount); tb.setChecked(false); QVERIFY(!a.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), ++aToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), ++aToggledCount); a.setChecked(true); QVERIFY(tb.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), ++aToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), ++aToggledCount); a.setChecked(false); QVERIFY(!tb.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), ++aToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), ++aToggledCount); QAction b; QSignalSpy bSpy(&b, SIGNAL(toggled(bool))); @@ -326,17 +303,34 @@ void tst_QToolButton::defaultActionSynced() QVERIFY(!a.isChecked()); QVERIFY(b.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), aToggledCount); - QCOMPARE(bSpy.count(), ++bToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), aToggledCount); + QCOMPARE(bSpy.size(), ++bToggledCount); tb.click(); QVERIFY(!a.isChecked()); QVERIFY(!tb.isChecked()); QVERIFY(!b.isChecked()); - QCOMPARE(tbSpy.count(), ++tbToggledCount); - QCOMPARE(aSpy.count(), aToggledCount); - QCOMPARE(bSpy.count(), ++bToggledCount); + QCOMPARE(tbSpy.size(), ++tbToggledCount); + QCOMPARE(aSpy.size(), aToggledCount); + 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) |