diff options
Diffstat (limited to 'tests/auto/widgets/kernel')
10 files changed, 717 insertions, 54 deletions
diff --git a/tests/auto/widgets/kernel/kernel.pro b/tests/auto/widgets/kernel/kernel.pro index 20720dc928..73fd934502 100644 --- a/tests/auto/widgets/kernel/kernel.pro +++ b/tests/auto/widgets/kernel/kernel.pro @@ -6,6 +6,7 @@ SUBDIRS=\ qboxlayout \ qdesktopwidget \ qformlayout \ + qgesturerecognizer \ qgridlayout \ qlayout \ qstackedlayout \ @@ -19,4 +20,7 @@ SUBDIRS=\ qshortcut \ qsizepolicy +darwin:SUBDIRS -= \ # Uses native recognizers + qgesturerecognizer \ + SUBDIRS -= qsound diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp index 88ddb7c11d..ac0174d19a 100644 --- a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp +++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp @@ -64,6 +64,7 @@ private slots: void task229128TriggeredSignalWhenInActiongroup(); void repeat(); void setData(); + void keysequence(); // QTBUG-53381 void disableShortcutsWithBlockedWidgets_data(); void disableShortcutsWithBlockedWidgets(); @@ -280,6 +281,40 @@ void tst_QAction::alternateShortcuts() QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier); } +void tst_QAction::keysequence() +{ + MyWidget testWidget(this); + testWidget.show(); + QApplication::setActiveWindow(&testWidget); + + { + QAction act(&testWidget); + testWidget.addAction(&act); + + QKeySequence ks(QKeySequence::SelectAll); + + act.setShortcut(ks); + + QSignalSpy spy(&act, &QAction::triggered); + + act.setAutoRepeat(true); + QTest::keySequence(&testWidget, ks); + QCoreApplication::processEvents(); + QCOMPARE(spy.count(), 1); // act should have been triggered + + act.setAutoRepeat(false); + QTest::keySequence(&testWidget, ks); + QCoreApplication::processEvents(); + QCOMPARE(spy.count(), 2); //act should have been triggered a 2nd time + + // end of the scope of the action, it will be destroyed and removed from widget + // This action should also unregister its shortcuts + } + + // this tests a crash (if the action did not unregister its alternate shortcuts) + QTest::keyClick(&testWidget, Qt::Key_A, Qt::ControlModifier); +} + void tst_QAction::enabledVisibleInteraction() { MyWidget testWidget(this); diff --git a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp index 1dac242114..7262817d23 100644 --- a/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp +++ b/tests/auto/widgets/kernel/qboxlayout/tst_qboxlayout.cpp @@ -156,7 +156,7 @@ void tst_QBoxLayout::sizeHint() lay1->addLayout(lay2); window.setLayout(lay1); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); label->setText("foooooooo baaaaaaar"); QSize sh = lay1->sizeHint(); QApplication::processEvents(); @@ -177,7 +177,7 @@ void tst_QBoxLayout::sizeConstraints() lay->setSizeConstraint(QLayout::SetFixedSize); window.setLayout(lay); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QSize sh = window.sizeHint(); delete lay->takeAt(1); QVERIFY(sh.width() >= window.sizeHint().width() && @@ -224,7 +224,7 @@ void tst_QBoxLayout::setStyleShouldChangeSpacing() style1->hspacing = 6; window.setStyle(style1.data()); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); int spacing = pb2->geometry().left() - pb1->geometry().right() - 1; QCOMPARE(spacing, 6); diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/BLACKLIST b/tests/auto/widgets/kernel/qgesturerecognizer/BLACKLIST new file mode 100644 index 0000000000..7f55c2dae0 --- /dev/null +++ b/tests/auto/widgets/kernel/qgesturerecognizer/BLACKLIST @@ -0,0 +1,2 @@ +[panGesture:Two finger] +xcb diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/qgesturerecognizer.pro b/tests/auto/widgets/kernel/qgesturerecognizer/qgesturerecognizer.pro new file mode 100644 index 0000000000..7c9ddcfb03 --- /dev/null +++ b/tests/auto/widgets/kernel/qgesturerecognizer/qgesturerecognizer.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qgesturerecognizer +QT += widgets testlib gui-private core-private +SOURCES += tst_qgesturerecognizer.cpp diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp new file mode 100644 index 0000000000..c3ebb838bb --- /dev/null +++ b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <QtWidgets/QApplication> +#include <QtWidgets/QWidget> +#include <QtWidgets/QGestureEvent> +#include <QtGui/QScreen> +#include <QtGui/QTouchDevice> +#include <QtCore/QVector> +#include <QtCore/QString> +#include <QtCore/QHash> +#include <QtCore/QDebug> + +class tst_QGestureRecognizer : public QObject +{ + Q_OBJECT +public: + tst_QGestureRecognizer(); + +private Q_SLOTS: + void initTestCase(); +#ifndef QT_NO_GESTURES + void panGesture_data(); + void panGesture(); + void pinchGesture_data(); + void pinchGesture(); + void swipeGesture_data(); + void swipeGesture(); +#endif // !QT_NO_GESTURES + +private: + const int m_fingerDistance; + QTouchDevice *m_touchDevice; +}; + +tst_QGestureRecognizer::tst_QGestureRecognizer() + : m_fingerDistance(qRound(QGuiApplication::primaryScreen()->physicalDotsPerInch() / 2.0)) + , m_touchDevice(QTest::createTouchDevice()) +{ + qputenv("QT_PAN_TOUCHPOINTS", "2"); // Prevent device detection of pan touch point count. +} + +void tst_QGestureRecognizer::initTestCase() +{ +} + +#ifndef QT_NO_GESTURES + +typedef QVector<Qt::GestureType> GestureTypeVector; + +class TestWidget : public QWidget +{ +public: + explicit TestWidget(const GestureTypeVector &gestureTypes); + + bool gestureReceived(Qt::GestureType gestureType) const + { return m_receivedGestures.value(gestureType); } + +protected: + bool event(QEvent * event) Q_DECL_OVERRIDE; + +private: + typedef QHash<Qt::GestureType, bool> GestureTypeHash; + GestureTypeHash m_receivedGestures; +}; + +TestWidget::TestWidget(const GestureTypeVector &gestureTypes) +{ + setAttribute(Qt::WA_AcceptTouchEvents); + + foreach (Qt::GestureType gestureType, gestureTypes) { + grabGesture(gestureType); + m_receivedGestures.insert(gestureType, false); + } + + const QRect geometry = QGuiApplication::primaryScreen()->availableGeometry(); + const QSize size = geometry.size() / 2; + resize(size); + move(geometry.center() - QPoint(size.width() / 2, size.height() / 2)); +} + +bool TestWidget::event(QEvent * event) +{ + switch (event->type()) { + case QEvent::Gesture: { + const QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(event); + const GestureTypeHash::iterator hend = m_receivedGestures.end(); + for (GestureTypeHash::iterator it = m_receivedGestures.begin(); it != hend; ++it) { + if (const QGesture *gesture = gestureEvent->gesture(it.key())) { + if (gesture->state() == Qt::GestureFinished) + it.value() = true; + } + } + } + break; + default: + break; + } + return QWidget::event(event); +} + +static void pressSequence(QTest::QTouchEventSequence &sequence, + QVector<QPoint> &points, + QWidget *widget) +{ + const int pointCount = points.size(); + for (int p = 0; p < pointCount; ++p) + sequence.press(p, points.at(p), widget); + sequence.commit(); +} + +static void linearSequence(int n, const QPoint &delta, + QTest::QTouchEventSequence &sequence, + QVector<QPoint> &points, + QWidget *widget) +{ + const int pointCount = points.size(); + for (int s = 0; s < n; ++s) { + for (int p = 0; p < pointCount; ++p) { + points[p] += delta; + sequence.move(p, points[p], widget); + } + sequence.commit(); + } +} + +static void releaseSequence(QTest::QTouchEventSequence &sequence, + QVector<QPoint> &points, + QWidget *widget) +{ + const int pointCount = points.size(); + for (int p = 0; p < pointCount; ++p) + sequence.release(p, points[p], widget); + sequence.commit(); +} + +// --- Pan + +enum PanSubTest { + TwoFingerPanSubTest +}; + +void tst_QGestureRecognizer::panGesture_data() +{ + QTest::addColumn<int>("panSubTest"); + QTest::addColumn<bool>("gestureExpected"); + QTest::newRow("Two finger") << int(TwoFingerPanSubTest) << true; +} + +void tst_QGestureRecognizer::panGesture() +{ + QFETCH(int, panSubTest); + QFETCH(bool, gestureExpected); + + Q_UNUSED(panSubTest) // Single finger pan will be added later. + + const int panPoints = 2; + const Qt::GestureType gestureType = Qt::PanGesture; + TestWidget widget(GestureTypeVector(1, gestureType)); + widget.setWindowTitle(QTest::currentTestFunction()); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + QVector<QPoint> points; + for (int i = 0; i < panPoints; ++i) + points.append(QPoint(10 + i *20, 10 + i *20)); + + QTest::QTouchEventSequence panSequence = QTest::touchEvent(&widget, m_touchDevice); + pressSequence(panSequence, points, &widget); + linearSequence(5, QPoint(20, 20), panSequence, points, &widget); + releaseSequence(panSequence, points, &widget); + + if (gestureExpected) { + QTRY_VERIFY(widget.gestureReceived(gestureType)); + } else { + QCoreApplication::processEvents(); + QVERIFY(!widget.gestureReceived(gestureType)); + } +} + +// --- Pinch + +enum PinchSubTest { + StandardPinchSubTest +}; + +void tst_QGestureRecognizer::pinchGesture_data() +{ + QTest::addColumn<int>("pinchSubTest"); + QTest::addColumn<bool>("gestureExpected"); + QTest::newRow("Standard") << int(StandardPinchSubTest) << true; +} + +void tst_QGestureRecognizer::pinchGesture() +{ + QFETCH(int, pinchSubTest); + QFETCH(bool, gestureExpected); + + Q_UNUSED(pinchSubTest) + + const Qt::GestureType gestureType = Qt::PinchGesture; + TestWidget widget(GestureTypeVector(1, gestureType)); + widget.setWindowTitle(QTest::currentTestFunction()); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + QVector<QPoint> points; + points.append(widget.rect().center()); + points.append(points.front() + QPoint(0, 20)); + + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&widget, m_touchDevice); + pressSequence(pinchSequence, points, &widget); + + for (int s = 0; s < 5; ++s) { + points[0] += QPoint(5, 30); + pinchSequence.move(0, points[0], &widget); + points[1] += QPoint(5, -30); + pinchSequence.move(1, points[1], &widget); + pinchSequence.commit(); + } + + releaseSequence(pinchSequence, points, &widget); + + if (gestureExpected) { + QTRY_VERIFY(widget.gestureReceived(gestureType)); + } else { + QCoreApplication::processEvents(); + QVERIFY(!widget.gestureReceived(gestureType)); + } +} + +// --- Swipe + +enum SwipeSubTest { + SwipeLineSubTest, + SwipeDirectionChangeSubTest, + SwipeSmallDirectionChangeSubTest +}; + +void tst_QGestureRecognizer::swipeGesture_data() +{ + QTest::addColumn<int>("swipeSubTest"); + QTest::addColumn<bool>("gestureExpected"); + QTest::newRow("Line") << int(SwipeLineSubTest) << true; + QTest::newRow("DirectionChange") << int(SwipeDirectionChangeSubTest) << false; + QTest::newRow("SmallDirectionChange") << int(SwipeSmallDirectionChangeSubTest) << true; +} + +void tst_QGestureRecognizer::swipeGesture() +{ + enum { swipePoints = 3 }; + + QFETCH(int, swipeSubTest); + QFETCH(bool, gestureExpected); + + const Qt::GestureType gestureType = Qt::SwipeGesture; + TestWidget widget(GestureTypeVector(1, gestureType)); + widget.setWindowTitle(QTest::currentTestFunction()); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + // Start a swipe sequence with 2 points (QTBUG-15768) + const QPoint fingerDistance(m_fingerDistance, m_fingerDistance); + QVector<QPoint> points; + for (int i = 0; i < swipePoints - 1; ++i) + points.append(fingerDistance + i * fingerDistance); + + QTest::QTouchEventSequence swipeSequence = QTest::touchEvent(&widget, m_touchDevice); + pressSequence(swipeSequence, points, &widget); + + // Press point #3 + points.append(points.last() + fingerDistance); + swipeSequence.press(points.size() - 1, points.last(), &widget); + swipeSequence.commit(); + Q_ASSERT(points.size() == swipePoints); + + // Move. + const QPoint moveDelta(60, 20); + switch (swipeSubTest) { + case SwipeLineSubTest: + linearSequence(5, moveDelta, swipeSequence, points, &widget); + break; + case SwipeDirectionChangeSubTest: + linearSequence(5, moveDelta, swipeSequence, points, &widget); + linearSequence(3, QPoint(-moveDelta.x(), moveDelta.y()), swipeSequence, points, &widget); + break; + case SwipeSmallDirectionChangeSubTest: { // QTBUG-46195, small changes in direction should not cause the gesture to be canceled. + const QPoint smallChangeMoveDelta(50, 1); + linearSequence(5, smallChangeMoveDelta, swipeSequence, points, &widget); + linearSequence(1, QPoint(smallChangeMoveDelta.x(), -3), swipeSequence, points, &widget); + linearSequence(5, smallChangeMoveDelta, swipeSequence, points, &widget); + } + break; + } + + releaseSequence(swipeSequence, points, &widget); + + if (gestureExpected) { + QTRY_VERIFY(widget.gestureReceived(gestureType)); + } else { + QCoreApplication::processEvents(); + QVERIFY(!widget.gestureReceived(gestureType)); + } +} + +#endif // !QT_NO_GESTURES + +QTEST_MAIN(tst_QGestureRecognizer) + +#include "tst_qgesturerecognizer.moc" diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index a04a67e4be..0b1d7b4437 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -74,7 +74,7 @@ osx [setClearAndResizeMask] osx [setToolTip] -osx-10.9 +osx [moveInResizeEvent] ubuntu-14.04 [moveChild:right] diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.pro b/tests/auto/widgets/kernel/qwidget/qwidget.pro index 3e4e96760b..c1908af2a2 100644 --- a/tests/auto/widgets/kernel/qwidget/qwidget.pro +++ b/tests/auto/widgets/kernel/qwidget/qwidget.pro @@ -12,7 +12,7 @@ aix-g++*:QMAKE_CXXFLAGS+=-fpermissive CONFIG += x11inc mac { - LIBS += -framework Security -framework AppKit -framework Carbon + LIBS += -framework Security -framework AppKit OBJECTIVE_SOURCES += tst_qwidget_mac_helpers.mm } diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index c1bff5b00a..cf2794903e 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -50,6 +50,7 @@ #include <qcalendarwidget.h> #include <qmainwindow.h> #include <qdockwidget.h> +#include <qrandom.h> #include <qtoolbar.h> #include <qtoolbutton.h> #include <QtGui/qpaintengine.h> @@ -183,7 +184,10 @@ private slots: void mapFromAndTo(); void focusChainOnHide(); void focusChainOnReparent(); - void setTabOrder(); + void defaultTabOrder(); + void reverseTabOrder(); + void tabOrderWithProxy(); + void tabOrderWithCompoundWidgets(); #ifdef Q_OS_WIN void activation(); #endif @@ -1650,79 +1654,281 @@ public: class Composite : public QFrame { public: - Composite(QWidget* parent = 0, const char* name = 0) + Composite(QWidget* parent = 0, const QString &name = 0) : QFrame(parent) { setObjectName(name); - //QHBoxLayout* hbox = new QHBoxLayout(this, 2, 0); - //hbox->setAutoAdd(true); + + lineEdit1 = new QLineEdit; + lineEdit2 = new QLineEdit; + lineEdit3 = new QLineEdit; + lineEdit3->setEnabled(false); + QHBoxLayout* hbox = new QHBoxLayout(this); + hbox->addWidget(lineEdit1); + hbox->addWidget(lineEdit2); + hbox->addWidget(lineEdit3); + } - lineEdit = new QLineEdit(this); - hbox->addWidget(lineEdit); +public: + QLineEdit *lineEdit1; + QLineEdit *lineEdit2; + QLineEdit *lineEdit3; +}; - button = new QPushButton(this); - hbox->addWidget(button); - button->setFocusPolicy( Qt::NoFocus ); +void tst_QWidget::defaultTabOrder() +{ + const int compositeCount = 2; + Container container; + Composite *composite[compositeCount]; - setFocusProxy( lineEdit ); - setFocusPolicy( Qt::StrongFocus ); + QLineEdit *firstEdit = new QLineEdit; + container.box->addWidget(firstEdit); - setTabOrder(lineEdit, button); + for (int i = 0; i < compositeCount; i++) { + composite[i] = new Composite(); + container.box->addWidget(composite[i]); } -private: - QLineEdit* lineEdit; - QPushButton* button; -}; + QLineEdit *lastEdit = new QLineEdit(); + container.box->addWidget(lastEdit); -#define NUM_WIDGETS 4 + container.show(); + container.activateWindow(); + qApp->setActiveWindow(&container); + QVERIFY(QTest::qWaitForWindowActive(&container)); -void tst_QWidget::setTabOrder() -{ - QTest::qWait(100); + QTRY_VERIFY(firstEdit->hasFocus()); + // Check that focus moves between the line edits when we tab forward + for (int i = 0; i < compositeCount; ++i) { + container.tab(); + QVERIFY(composite[i]->lineEdit1->hasFocus()); + QVERIFY(!composite[i]->lineEdit2->hasFocus()); + container.tab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); + } + + container.tab(); + QVERIFY(lastEdit->hasFocus()); + + // Check that focus moves between the line edits in reverse + // order when we tab backwards + for (int i = compositeCount - 1; i >= 0; --i) { + container.backTab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); + + container.backTab(); + QVERIFY(composite[i]->lineEdit1->hasFocus()); + QVERIFY(!composite[i]->lineEdit2->hasFocus()); + } + + container.backTab(); + QVERIFY(firstEdit->hasFocus()); +} + +void tst_QWidget::reverseTabOrder() +{ + const int compositeCount = 2; Container container; - container.setObjectName("setTabOrder"); - container.setWindowTitle(container.objectName()); + Composite* composite[compositeCount]; + + QLineEdit *firstEdit = new QLineEdit(); + container.box->addWidget(firstEdit); + + for (int i = 0; i < compositeCount; i++) { + composite[i] = new Composite(); + container.box->addWidget(composite[i]); + } + + QLineEdit *lastEdit = new QLineEdit(); + container.box->addWidget(lastEdit); - Composite* comp[NUM_WIDGETS]; + // Reverse tab order inside each composite + for (int i = 0; i < compositeCount; ++i) + QWidget::setTabOrder(composite[i]->lineEdit2, composite[i]->lineEdit1); - QLineEdit *firstEdit = new QLineEdit(&container); + container.show(); + container.activateWindow(); + qApp->setActiveWindow(&container); + QVERIFY(QTest::qWaitForWindowActive(&container)); + + QTRY_VERIFY(firstEdit->hasFocus()); + + // Check that focus moves in reverse order when tabbing inside the composites + // (but in the correct order when tabbing between them) + for (int i = 0; i < compositeCount; ++i) { + container.tab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); + container.tab(); + QVERIFY(composite[i]->lineEdit1->hasFocus()); + QVERIFY(!composite[i]->lineEdit2->hasFocus()); + } + + container.tab(); + QVERIFY(lastEdit->hasFocus()); + + // Check that focus moves in "normal" order when tabbing backwards inside the + // composites (since backwards of reversed order cancels each other out), + // but in the reverse order when tabbing between them. + for (int i = compositeCount - 1; i >= 0; --i) { + container.backTab(); + QVERIFY(composite[i]->lineEdit1->hasFocus()); + QVERIFY(!composite[i]->lineEdit2->hasFocus()); + container.backTab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); + } + + container.backTab(); + QVERIFY(firstEdit->hasFocus()); +} + +void tst_QWidget::tabOrderWithProxy() +{ + const int compositeCount = 2; + Container container; + Composite* composite[compositeCount]; + + QLineEdit *firstEdit = new QLineEdit(); container.box->addWidget(firstEdit); - int i = 0; - for(i = 0; i < NUM_WIDGETS; i++) { - comp[i] = new Composite(&container); - container.box->addWidget(comp[i]); + for (int i = 0; i < compositeCount; i++) { + composite[i] = new Composite(); + container.box->addWidget(composite[i]); + + // Set second child as focus proxy + composite[i]->setFocusPolicy(Qt::StrongFocus); + composite[i]->setFocusProxy(composite[i]->lineEdit2); } - QLineEdit *lastEdit = new QLineEdit(&container); + QLineEdit *lastEdit = new QLineEdit(); container.box->addWidget(lastEdit); - container.setTabOrder(lastEdit, comp[NUM_WIDGETS-1]); - for(i = NUM_WIDGETS-1; i > 0; i--) { - container.setTabOrder(comp[i], comp[i-1]); + container.show(); + container.activateWindow(); + qApp->setActiveWindow(&container); + QVERIFY(QTest::qWaitForWindowActive(&container)); + + QTRY_VERIFY(firstEdit->hasFocus()); + + // Check that focus moves between the second line edits + // (the focus proxies) when we tab forward + for (int i = 0; i < compositeCount; ++i) { + container.tab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); } - container.setTabOrder(comp[0], firstEdit); - int current = NUM_WIDGETS-1; - lastEdit->setFocus(); + container.tab(); + QVERIFY(lastEdit->hasFocus()); + + // Check that focus moves between the line edits + // in reverse order when we tab backwards. + // Note that in this case, the focus proxies should not + // be taken into consideration, since they only take + // effect when tabbing forward + for (int i = compositeCount - 1; i >= 0; --i) { + container.backTab(); + QVERIFY(!composite[i]->lineEdit1->hasFocus()); + QVERIFY(composite[i]->lineEdit2->hasFocus()); + container.backTab(); + QVERIFY(composite[i]->lineEdit1->hasFocus()); + QVERIFY(!composite[i]->lineEdit2->hasFocus()); + } + + container.backTab(); + QVERIFY(firstEdit->hasFocus()); +} + +void tst_QWidget::tabOrderWithCompoundWidgets() +{ + const int compositeCount = 4; + Container container; + Composite *composite[compositeCount]; + + QLineEdit *firstEdit = new QLineEdit(); + container.box->addWidget(firstEdit); + + for (int i = 0; i < compositeCount; i++) { + composite[i] = new Composite(0, QStringLiteral("Composite: ") + QString::number(i)); + container.box->addWidget(composite[i]); + + // Let the composite handle focus, and set a child as focus proxy (use the second child, just + // to ensure that we don't just tab to the first child by coinsidence). This will make the + // composite "compound". Also enable the last line edit to have a bit more data to check when + // tabbing forwards. + composite[i]->setFocusPolicy(Qt::StrongFocus); + composite[i]->setFocusProxy(composite[i]->lineEdit2); + composite[i]->lineEdit3->setEnabled(true); + } + + QLineEdit *lastEdit = new QLineEdit(); + container.box->addWidget(lastEdit); + + // Reverse tab order between each composite + // (but not inside them), including first and last line edit. + // The result should not affect local tab order inside each + // composite, only between them. + QWidget::setTabOrder(lastEdit, composite[compositeCount - 1]); + for (int i = compositeCount - 1; i >= 1; --i) + QWidget::setTabOrder(composite[i], composite[i-1]); + QWidget::setTabOrder(composite[0], firstEdit); container.show(); container.activateWindow(); qApp->setActiveWindow(&container); QVERIFY(QTest::qWaitForWindowActive(&container)); + lastEdit->setFocus(); QTRY_VERIFY(lastEdit->hasFocus()); - container.tab(); - do { - QVERIFY(comp[current]->focusProxy()->hasFocus()); + + // Check that focus moves between the line edits in the normal + // order when tabbing inside each compound, but in the reverse + // order when tabbing between them. Since the composites have + // lineEdit2 as focus proxy, lineEdit2 will be the first with focus + // when the compound gets focus, and lineEdit1 will therefore be skipped. + for (int i = compositeCount - 1; i >= 0; --i) { + container.tab(); + Composite *c = composite[i]; + QVERIFY(!c->lineEdit1->hasFocus()); + QVERIFY(c->lineEdit2->hasFocus()); + QVERIFY(!c->lineEdit3->hasFocus()); container.tab(); - current--; - } while (current >= 0); + QVERIFY(!c->lineEdit1->hasFocus()); + QVERIFY(!c->lineEdit2->hasFocus()); + QVERIFY(c->lineEdit3->hasFocus()); + } + container.tab(); QVERIFY(firstEdit->hasFocus()); + + // Check that focus moves in reverse order when backTab inside the composites, but + // in the 'correct' order when backTab between them (since the composites are in reverse tab + // order from before, which cancels it out). Note that when we backtab into a compound, we start + // at lineEdit3 rather than the focus proxy, since that is the reverse of what happens when we tab + // forward. And this time we will also backtab to lineEdit1, since there is no focus proxy that interferes. + for (int i = 0; i < compositeCount; ++i) { + container.backTab(); + Composite *c = composite[i]; + QVERIFY(!c->lineEdit1->hasFocus()); + QVERIFY(!c->lineEdit2->hasFocus()); + QVERIFY(c->lineEdit3->hasFocus()); + container.backTab(); + QVERIFY(!c->lineEdit1->hasFocus()); + QVERIFY(c->lineEdit2->hasFocus()); + QVERIFY(!c->lineEdit3->hasFocus()); + container.backTab(); + QVERIFY(c->lineEdit1->hasFocus()); + QVERIFY(!c->lineEdit2->hasFocus()); + QVERIFY(!c->lineEdit3->hasFocus()); + } + + container.backTab(); + QVERIFY(lastEdit->hasFocus()); } #ifdef Q_OS_WIN @@ -1787,9 +1993,11 @@ void tst_QWidget::windowState() QCOMPARE(widget1.pos(), pos); QCOMPARE(widget1.size(), size); -#define VERIFY_STATE(s) QCOMPARE(int(widget1.windowState() & stateMask), int(s)) +#define VERIFY_STATE(s) \ + QCOMPARE(int(widget1.windowState() & stateMask), int(s)); \ + QCOMPARE(int(widget1.windowHandle()->windowStates() & stateMask), int(s)) - const int stateMask = Qt::WindowMaximized|Qt::WindowMinimized|Qt::WindowFullScreen; + const auto stateMask = Qt::WindowMaximized | Qt::WindowMinimized | Qt::WindowFullScreen; widget1.setWindowState(Qt::WindowMaximized); QTest::qWait(100); @@ -2079,7 +2287,7 @@ void tst_QWidget::resizeEvent() wParent.resize(200, 200); ResizeWidget wChild(&wParent); wParent.show(); - QTest::qWaitForWindowExposed(&wParent); + QVERIFY(QTest::qWaitForWindowExposed(&wParent)); QCOMPARE (wChild.m_resizeEventCount, 1); // initial resize event before paint wParent.hide(); QSize safeSize(640,480); @@ -2095,7 +2303,7 @@ void tst_QWidget::resizeEvent() ResizeWidget wTopLevel; wTopLevel.resize(200, 200); wTopLevel.show(); - QTest::qWaitForWindowExposed(&wTopLevel); + QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel)); QCOMPARE (wTopLevel.m_resizeEventCount, 1); // initial resize event before paint for toplevels wTopLevel.hide(); QSize safeSize(640,480); @@ -2104,7 +2312,7 @@ void tst_QWidget::resizeEvent() wTopLevel.resize(safeSize); QCOMPARE (wTopLevel.m_resizeEventCount, 1); wTopLevel.show(); - QTest::qWaitForWindowExposed(&wTopLevel); + QVERIFY(QTest::qWaitForWindowExposed(&wTopLevel)); QCOMPARE (wTopLevel.m_resizeEventCount, 2); } } @@ -8060,8 +8268,8 @@ void tst_QWidget::setMaskInResizeEvent() QRegion expectedParentUpdate(0, 0, 100, 10); // Old testWidget area. expectedParentUpdate += testWidget.geometry(); // New testWidget area. - QCOMPARE(w.paintedRegion, expectedParentUpdate); - QCOMPARE(testWidget.paintedRegion, testWidget.mask()); + QTRY_COMPARE(w.paintedRegion, expectedParentUpdate); + QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask()); testWidget.paintedRegion = QRegion(); // Now resize the widget again, but in the oposite direction @@ -9609,7 +9817,7 @@ void tst_QWidget::grab() for (int row = 0; row < image.height(); ++row) { QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(row)); for (int col = 0; col < image.width(); ++col) - line[col] = qRgba(rand() & 255, row, col, opaque ? 255 : 127); + line[col] = qRgba(QRandomGenerator::global()->bounded(255), row, col, opaque ? 255 : 127); } QPalette pal = widget.palette(); @@ -10489,6 +10697,8 @@ void tst_QWidget::qmlSetParentHelper() void tst_QWidget::testForOutsideWSRangeFlag() { + QSKIP("Test assumes QWindows can have 0x0 size, see QTBUG-61953"); + // QTBUG-49445 { QWidget widget; diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp index e4564a8640..b76c4d35a8 100644 --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -96,6 +96,11 @@ private slots: void QTBUG_50561_QCocoaBackingStore_paintDevice_crash(); + void setWindowState_data(); + void setWindowState(); + + void nativeShow(); + void QTBUG_56277_resize_on_showEvent(); }; @@ -842,7 +847,7 @@ void tst_QWidget_window::QTBUG_50561_QCocoaBackingStore_paintDevice_crash() QMainWindow w; w.addToolBar(new QToolBar(&w)); w.show(); - QTest::qWaitForWindowExposed(&w); + QVERIFY(QTest::qWaitForWindowExposed(&w)); // Simulate window system close QCloseEvent *e = new QCloseEvent; @@ -859,6 +864,72 @@ void tst_QWidget_window::QTBUG_50561_QCocoaBackingStore_paintDevice_crash() w.close(); } +void tst_QWidget_window::setWindowState_data() +{ + QString platformName = QGuiApplication::platformName().toLower(); + + QTest::addColumn<Qt::WindowStates>("state"); + QTest::newRow("0") << Qt::WindowStates(); + QTest::newRow("Qt::WindowMaximized") << Qt::WindowStates(Qt::WindowMaximized); + QTest::newRow("Qt::WindowMinimized") << Qt::WindowStates(Qt::WindowMinimized); + QTest::newRow("Qt::WindowFullScreen") << Qt::WindowStates(Qt::WindowFullScreen); + + if (platformName != "xcb" && platformName != "windows" && !platformName.startsWith("wayland") + && platformName != "offscreen") + return; // Combination of states is not preserved on all platforms. + if (platformName == "xcb" && qgetenv("XDG_CURRENT_DESKTOP") != "KDE" + && qgetenv("XDG_CURRENT_DESKTOP") != "Unity") + return; // Not all window managers support state combinations. + + QTest::newRow("Qt::WindowMaximized|Qt::WindowMinimized") + << (Qt::WindowMaximized | Qt::WindowMinimized); + QTest::newRow("Qt::WindowFullScreen|Qt::WindowMinimized") + << (Qt::WindowFullScreen | Qt::WindowMinimized); + QTest::newRow("Qt::WindowMaximized|Qt::WindowFullScreen") + << (Qt::WindowMaximized | Qt::WindowFullScreen); + QTest::newRow("Qt::WindowMaximized|Qt::WindowFullScreen|Qt::WindowMinimized") + << (Qt::WindowMaximized | Qt::WindowFullScreen | Qt::WindowMinimized); +} + +void tst_QWidget_window::setWindowState() +{ + QFETCH(Qt::WindowStates, state); + + // This tests make sure that the states are preserved when the window is shown. + + QWidget w; + w.setWindowState(state); + QCOMPARE(w.windowState(), state); + w.show(); + QCOMPARE(w.windowState(), state); + QCOMPARE(w.windowHandle()->windowStates(), state); + if (!(state & Qt::WindowMinimized)) + QVERIFY(QTest::qWaitForWindowExposed(&w)); + QTRY_COMPARE(w.windowState(), state); + QCOMPARE(w.windowHandle()->windowStates(), state); + + // Minimizing keeps other states + w.showMinimized(); + QCOMPARE(w.windowState(), state | Qt::WindowMinimized); + QTest::qWait(100); + QCOMPARE(w.windowState(), state | Qt::WindowMinimized); + QCOMPARE(w.windowHandle()->windowStates(), state | Qt::WindowMinimized); +} + +void tst_QWidget_window::nativeShow() +{ + // Verify that a native widget can be shown using the QWindow::setVisible() API + QWidget w; + w.winId(); + w.windowHandle()->setVisible(true); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + QVERIFY(w.isVisible()); + + // ... and that we can hide it + w.windowHandle()->setVisible(false); + QTRY_VERIFY(!w.isVisible()); +} + class ResizedOnShowEventWidget : public QWidget { public: |