From fa6c1c72ca18c6a450162b8c2160eb4ef8c53900 Mon Sep 17 00:00:00 2001 From: Tomi Korpipaa Date: Thu, 14 Oct 2021 09:16:37 +0300 Subject: Fix activeFocus for highest-z popup If there was no popup with active focus, giving focus to the highest-z popup failed on exiting the previous one. This is identical to the dev version, only in a different module: https://codereview.qt-project.org/c/qt/qtdeclarative/+/376653 Fixes: QTBUG-85956 Change-Id: I6f328abfd2d6379297b97940420789aa80293977 Reviewed-by: Fabian Kosmale --- src/quicktemplates2/qquickpopup.cpp | 5 +- .../auto/qquickpopup/data/activeFocusAfterExit.qml | 79 ++++++++++++++++++++++ tests/auto/qquickpopup/tst_qquickpopup.cpp | 50 ++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qquickpopup/data/activeFocusAfterExit.qml diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index ab9740ba..7bb33b43 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -513,13 +513,14 @@ void QQuickPopupPrivate::finalizeExitTransition() if (QQuickOverlay *overlay = QQuickOverlay::overlay(window)) { const auto stackingOrderPopups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups(); for (auto popup : stackingOrderPopups) { - if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition) { + if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition + && popup->hasFocus()) { nextFocusPopup = popup; break; } } } - if (nextFocusPopup && nextFocusPopup->hasFocus()) { + if (nextFocusPopup) { nextFocusPopup->forceActiveFocus(); } else { QQuickApplicationWindow *applicationWindow = qobject_cast(window); diff --git a/tests/auto/qquickpopup/data/activeFocusAfterExit.qml b/tests/auto/qquickpopup/data/activeFocusAfterExit.qml new file mode 100644 index 00000000..06b0c068 --- /dev/null +++ b/tests/auto/qquickpopup/data/activeFocusAfterExit.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup1: popup1 + property alias popup2: popup2 + property alias popup3: popup3 + + Popup { + id: popup1 + focus: true + z: 1 + } + + Popup { + id: popup2 + focus: false + z: 2 + } + + Popup { + id: popup3 + focus: true + z: 3 + } +} diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index ede3640c..17a703f0 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -73,6 +73,7 @@ private slots: void activeFocusOnClose2(); void activeFocusOnClose3(); void activeFocusOnClosingSeveralPopups(); + void activeFocusAfterExit(); void hover_data(); void hover(); void wheel_data(); @@ -728,6 +729,55 @@ void tst_QQuickPopup::activeFocusOnClosingSeveralPopups() QTRY_COMPARE(button->hasActiveFocus(), true); } +void tst_QQuickPopup::activeFocusAfterExit() +{ + // Test that after closing a popup the highest one in z-order receives it instead. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusAfterExit.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup1 = window->property("popup1").value(); + QVERIFY(popup1); + + QQuickPopup *popup2 = window->property("popup2").value(); + QVERIFY(popup2); + QSignalSpy closedSpy2(popup2, SIGNAL(closed())); + QVERIFY(closedSpy2.isValid()); + + QQuickPopup *popup3 = window->property("popup3").value(); + QVERIFY(popup3); + QSignalSpy closedSpy3(popup3, SIGNAL(closed())); + QVERIFY(closedSpy3.isValid()); + + popup1->open(); + QVERIFY(popup1->isVisible()); + QTRY_VERIFY(popup1->hasActiveFocus()); + + popup2->open(); + QVERIFY(popup2->isVisible()); + QTRY_VERIFY(!popup2->hasActiveFocus()); + + popup3->open(); + QVERIFY(popup3->isVisible()); + QTRY_VERIFY(popup3->hasActiveFocus()); + + popup3->close(); + closedSpy3.wait(); + QVERIFY(!popup3->isVisible()); + QTRY_VERIFY(!popup3->hasActiveFocus()); + QTRY_VERIFY(!popup2->hasActiveFocus()); + QTRY_VERIFY(popup1->hasActiveFocus()); + + popup2->close(); + closedSpy2.wait(); + QVERIFY(!popup2->isVisible()); + QTRY_VERIFY(!popup2->hasActiveFocus()); + QTRY_VERIFY(popup1->hasActiveFocus()); +} + void tst_QQuickPopup::hover_data() { QTest::addColumn("source"); -- cgit v1.2.3 From ff7551a09d8a1e4f10e323a4f899cd1d1c2175a4 Mon Sep 17 00:00:00 2001 From: Tomi Korpipaa Date: Fri, 15 Oct 2021 11:06:26 +0300 Subject: Give focus to popup on prepareEnter instead of finalizeEnter If focus is given on finalize, then popups that have enter transitions may end up stealing focus from popups that were opened later. Note: Qt 6.x needs a separate task, as qtquickcontrols2 is inside qtdeclarative. Otherwise the commits are identical. Dev version can be found here: https://codereview.qt-project.org/c/qt/qtdeclarative/+/376858 Fixes: QTBUG-85918 Change-Id: If58b4278edeea8673e56c25d899cd4e3c4765edc Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickpopup.cpp | 5 +- .../qquickpopup/data/activeFocusOnDelayedEnter.qml | 73 ++++++++++++++++++++++ tests/auto/qquickpopup/tst_qquickpopup.cpp | 25 ++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qquickpopup/data/activeFocusOnDelayedEnter.qml diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 7bb33b43..6015af14 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -456,6 +456,9 @@ bool QQuickPopupPrivate::prepareEnterTransition() popupItem->setVisible(true); getPositioner()->setParentItem(parentItem); emit q->visibleChanged(); + + if (focus) + popupItem->setFocus(true); } return true; } @@ -489,8 +492,6 @@ bool QQuickPopupPrivate::prepareExitTransition() void QQuickPopupPrivate::finalizeEnterTransition() { Q_Q(QQuickPopup); - if (focus) - popupItem->setFocus(true); transitionState = NoTransition; getPositioner()->reposition(); emit q->openedChanged(); diff --git a/tests/auto/qquickpopup/data/activeFocusOnDelayedEnter.qml b/tests/auto/qquickpopup/data/activeFocusOnDelayedEnter.qml new file mode 100644 index 00000000..1ceea99c --- /dev/null +++ b/tests/auto/qquickpopup/data/activeFocusOnDelayedEnter.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup1: popup1 + property alias popup2: popup2 + + Popup { + id: popup1 + focus: true + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 100 } + } + } + + Popup { + id: popup2 + focus: true + } +} diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index 17a703f0..3242e361 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -74,6 +74,7 @@ private slots: void activeFocusOnClose3(); void activeFocusOnClosingSeveralPopups(); void activeFocusAfterExit(); + void activeFocusOnDelayedEnter(); void hover_data(); void hover(); void wheel_data(); @@ -778,6 +779,30 @@ void tst_QQuickPopup::activeFocusAfterExit() QTRY_VERIFY(popup1->hasActiveFocus()); } +void tst_QQuickPopup::activeFocusOnDelayedEnter() +{ + // Test that after opening two popups, first of which has an animation, does not cause + // the first one to receive focus after the animation stops. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnDelayedEnter.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup1 = window->property("popup1").value(); + QVERIFY(popup1); + QSignalSpy openedSpy(popup1, SIGNAL(opened())); + + QQuickPopup *popup2 = window->property("popup2").value(); + QVERIFY(popup2); + + popup1->open(); + popup2->open(); + openedSpy.wait(); + QTRY_VERIFY(popup2->hasActiveFocus()); +} + void tst_QQuickPopup::hover_data() { QTest::addColumn("source"); -- cgit v1.2.3 From abd7a31dbb0165c88de84a0f5f5fece19d8bba7c Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 15 Oct 2021 22:33:36 +0200 Subject: Consider all popups in the stack to test whether an event should be blocked Since modal and modeless popups can be arbitrarily nested, it's not enough to just let the first popup in the stack handle an input event to see if it should be blocked. The first popup might be modeless and have a modal parent that then should block events to items further down. So, return true for the first popup that handled the event, otherwise continue down the stack. Fixes: QTBUG-86854 Change-Id: I04fe7833b86353f40cb047cd1330751233dc98c3 Reviewed-by: Qt CI Bot Reviewed-by: Mitch Curtis (cherry picked from commit 85be957e9f936ea2d0fd9d7ceaf5da8eb1bcac49) Reviewed-by: Volker Hilsheimer --- src/quicktemplates2/qquickoverlay.cpp | 9 +- .../qquickpopup/data/modelessOnModalOnModeless.qml | 98 ++++++++++++++++++++++ tests/auto/qquickpopup/tst_qquickpopup.cpp | 41 +++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qquickpopup/data/modelessOnModalOnModeless.qml diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index b2d13d70..c888ed09 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -471,22 +471,27 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) // background dimming OR over another popup underneath, in case the popup // does not have background dimming. if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) { + bool handled = false; switch (event->type()) { #if QT_CONFIG(quicktemplates2_multitouch) case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: - return d->handleTouchEvent(item, static_cast(event), popup); + handled = d->handleTouchEvent(item, static_cast(event), popup); + break; #endif case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: - return d->handleMouseEvent(item, static_cast(event), popup); + handled = d->handleMouseEvent(item, static_cast(event), popup); + break; default: break; } + if (handled) + return true; } } return false; diff --git a/tests/auto/qquickpopup/data/modelessOnModalOnModeless.qml b/tests/auto/qquickpopup/data/modelessOnModalOnModeless.qml new file mode 100644 index 00000000..7f05cb67 --- /dev/null +++ b/tests/auto/qquickpopup/data/modelessOnModalOnModeless.qml @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.13 +import QtQuick.Controls 2.13 + +ApplicationWindow { + width: 400 + height: 400 + + property alias modelessPopup: modelessPopup + property alias button: button + property alias modalPopup: modalPopup + property alias tooltip: tooltip + + Popup { + id: modelessPopup + modal: false + closePolicy: Popup.NoAutoClose + width: 200 + height: 200 + anchors.centerIn: parent + + Button { + id: button + checkable: true + x: 0 + y: 0 + text: "Click me" + } + + Popup { + id: modalPopup + modal: true + closePolicy: Popup.NoAutoClose + width: 100 + height: 100 + anchors.centerIn: parent + + Popup { + id: tooltip + modal: false + closePolicy: Popup.NoAutoClose + width: 50 + height: 50 + anchors.centerIn: parent + } + } + } + +} diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index 3242e361..54952d12 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -81,6 +81,7 @@ private slots: void wheel(); void parentDestroyed(); void nested(); + void modelessOnModalOnModeless(); void grabber(); void cursorShape(); void componentComplete(); @@ -990,6 +991,46 @@ void tst_QQuickPopup::nested() QCOMPARE(modalPopup->isVisible(), true); } +void tst_QQuickPopup::modelessOnModalOnModeless() +{ + QQuickApplicationHelper helper(this, QStringLiteral("modelessOnModalOnModeless.qml")); + QVERIFY2(helper.ready, helper.failureMessage()); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *modelessPopup = window->property("modelessPopup").value(); + QVERIFY(modelessPopup); + + QQuickButton *button = window->property("button").value(); + QVERIFY(button); + QQuickPopup *modalPopup = window->property("modalPopup").value(); + QVERIFY(modalPopup); + QQuickPopup *tooltip = window->property("tooltip").value(); + QVERIFY(modalPopup); + + modelessPopup->open(); + QCOMPARE(modelessPopup->isVisible(), true); + QTRY_COMPARE(modelessPopup->isOpened(), true); + const auto buttonPoint = button->mapToScene(button->boundingRect().center()).toPoint(); + // click into the button, should not be blocked + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, buttonPoint); + QVERIFY(button->isChecked()); + modalPopup->open(); + QCOMPARE(modalPopup->isVisible(), true); + QTRY_COMPARE(modalPopup->isOpened(), true); + // click into the button, should be blocked + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, buttonPoint); + QVERIFY(button->isChecked()); + + tooltip->setVisible(true); + QCOMPARE(tooltip->isVisible(), true); + QTRY_COMPARE(tooltip->isOpened(), true); + // click into the button, should be blocked + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, buttonPoint); + QVERIFY(button->isChecked()); +} + // QTBUG-56697 void tst_QQuickPopup::grabber() { -- cgit v1.2.3 From 6c0dba7efda6c39ccdd5c3269b50e8b546d63cb8 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Tue, 19 Oct 2021 17:39:11 +0200 Subject: Register the overlay with QQuickApplicationWindow QQuickApplicationWindow creates its own overlay. We must register it as a dynamic property so that the virtual keyboard can find it. In Qt 6, this is not needed. Task-number: QTBUG-97075 Change-Id: I31d832939eeaeb69e3842b3e67f19b59414d903b Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickapplicationwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index 2906412d..0b9ab1bc 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -653,6 +653,8 @@ QQuickOverlay *QQuickApplicationWindow::overlay() const if (!d->overlay) { d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); + // make the overlay discoverable by the virtual keyboard + d->q_ptr->setProperty("_q_QQuickOverlay", QVariant::fromValue(d->overlay)); d->overlay->stackAfter(QQuickApplicationWindow::contentItem()); } return d->overlay; -- cgit v1.2.3 From 07edc8b71b66e89d81563dbecdf4d3b4082d641a Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Mon, 8 Nov 2021 18:29:08 +0200 Subject: Bump version --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index da9d9a2d..6546557b 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -5,4 +5,4 @@ DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST QQC2_SOURCE_TREE = $$PWD -MODULE_VERSION = 5.15.7 +MODULE_VERSION = 5.15.8 -- cgit v1.2.3 From 1c17ea330cd29bc05c0463d1e13978ac5dd84ee9 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Fri, 12 Nov 2021 14:32:24 +0200 Subject: Fix build without accessibility Change-Id: I26e27edcb64a7b99996e0867862dded9c888bbe8 Reviewed-by: Mitch Curtis --- src/quicktemplates2/quicktemplates2.pro | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/quicktemplates2.pro b/src/quicktemplates2/quicktemplates2.pro index 5138b610..a3f778b2 100644 --- a/src/quicktemplates2/quicktemplates2.pro +++ b/src/quicktemplates2/quicktemplates2.pro @@ -14,5 +14,7 @@ SOURCES += \ $$PWD/qtquicktemplates2global.cpp include(quicktemplates2.pri) -include(accessible/accessible.pri) +qtConfig(accessibility) { + include(accessible/accessible.pri) +} load(qt_module) -- cgit v1.2.3 From 29dfaa92b9d56f5555b511756f5b8ee62aabc0bf Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Thu, 2 Dec 2021 18:45:15 +0100 Subject: RangeSlider: update handle positions when 'from' or 'to' value is changed The RangeSlider's setTo() and setFrom() implementation was not updating the positions of the handles. This patch fixes it and aligns the behavior with the basic Slider. This commit is cherry-picked from qtdeclarative repo of the dev branch, because QuickControls2 were merged into that repo in Qt 6. Fixes: QTBUG-98482 Change-Id: I482c416f91be2b97af1d922305dfe6fc1f5bd573 Reviewed-by: Mitch Curtis (cherry picked from commit 7ff266ff782b35817d3ecc1a08c3a54bd2c2aa88) --- src/quicktemplates2/qquickrangeslider.cpp | 8 ++++++ tests/auto/controls/data/tst_rangeslider.qml | 37 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp index 7aee2109..25542fcc 100644 --- a/src/quicktemplates2/qquickrangeslider.cpp +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -665,6 +665,10 @@ void QQuickRangeSlider::setFrom(qreal from) if (isComponentComplete()) { d->first->setValue(d->first->value()); d->second->setValue(d->second->value()); + auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + firstPrivate->updatePosition(true); + secondPrivate->updatePosition(); } } @@ -693,6 +697,10 @@ void QQuickRangeSlider::setTo(qreal to) if (isComponentComplete()) { d->first->setValue(d->first->value()); d->second->setValue(d->second->value()); + auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + firstPrivate->updatePosition(true); + secondPrivate->updatePosition(); } } diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml index d645ec70..42f5bad5 100644 --- a/tests/auto/controls/data/tst_rangeslider.qml +++ b/tests/auto/controls/data/tst_rangeslider.qml @@ -159,6 +159,43 @@ TestCase { compare(control.first.position, 0.5) } + function test_setToFromUpdatesHandles() { + var control = createTemporaryObject(sliderComponent, testCase, { from: 0, to: 100, "first.value": 50, "second.value": 75 }) + verify(control) + + let firstPos = control.first.position + let secondPos = control.second.position + + var firstPosChangesSpy = signalSpy.createObject(control, {target: control.first, signalName: "positionChanged"}) + verify(firstPosChangesSpy.valid) + + var secondPosChangesSpy = signalSpy.createObject(control, {target: control.second, signalName: "positionChanged"}) + verify(secondPosChangesSpy.valid) + + // Increasing the 'to' value, so the positions of the handles should be + // moved to the left (become smaller) + control.to = 200; + compare(firstPosChangesSpy.count, 1) + compare(secondPosChangesSpy.count, 1) + verify(control.first.position < firstPos) + verify(control.second.position < secondPos) + + // resetting the values + control.to = 100 + firstPosChangesSpy.clear() + secondPosChangesSpy.clear() + firstPos = control.first.position + secondPos = control.second.position + + // Decreasing the 'from' value, so the positions of the handles should + // be moved to the right (become larger) + control.from = -100 + compare(firstPosChangesSpy.count, 1) + compare(secondPosChangesSpy.count, 1) + verify(control.first.position > firstPos) + verify(control.second.position > secondPos) + } + function test_setValues() { var control = createTemporaryObject(sliderComponent, testCase) verify(control) -- cgit v1.2.3