aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2022-02-25 15:38:53 +0800
committerMitch Curtis <mitch.curtis@qt.io>2022-05-25 19:51:20 +0800
commit1c680287ff448ee3e196179cd6a586c9be0c012b (patch)
tree83cf76f90193a7fd79ab7c4e1129e4630286d5f5
parent7b535d22d67d696b6f3e134a9937fd035990ab86 (diff)
Use regular key events for cancelling popups
We should avoid creating shortcuts for special keys like Cancel (Back/Escape), as it can interfere with the user's own shortcuts by e.g. requiring use of Keys.shortcutOverride, which itself can only be sent to items with active focus, preventing users from overriding Qt's global shortcuts in some cases. [ChangeLog][Controls][Important Behavior Changes] Popups no longer handle the Escape and Back keys by grabbing them as shortcuts, instead they are treated as regular events. This also means that popups that should be closable with the Escape or Back keys must have focus. Task-number: QTBUG-79280 Change-Id: Iaf7249226d5766b2ab101630de5590b9524c56dd Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp78
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h1
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h4
-rw-r--r--src/quicktemplates2/qquickpopup.cpp63
-rw-r--r--src/quicktemplates2/qquickpopupitem.cpp53
-rw-r--r--src/quicktemplates2/qquickpopupitem_p_p.h4
-rw-r--r--tests/auto/quickcontrols2/controls/basic/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/data/tst_combobox.qml9
-rw-r--r--tests/auto/quickcontrols2/controls/fusion/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/imagine/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/ios/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/macos/BLACKLIST2
-rw-r--r--tests/auto/quickcontrols2/controls/material/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/universal/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/controls/windows/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/data/activeFocusOnClose3.qml12
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/data/closeOnEscapeWithVisiblePopup.qml1
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/data/destroyDuringExitTransition.qml1
-rw-r--r--tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp45
20 files changed, 133 insertions, 164 deletions
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp
index d2bc38d297..b0580c943f 100644
--- a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp
@@ -367,29 +367,11 @@ void QQuickFolderBreadcrumbBarPrivate::textFieldActiveFocusChanged()
void QQuickFolderBreadcrumbBarPrivate::handleTextFieldShown()
{
#if QT_CONFIG(shortcut)
- Q_Q(QQuickFolderBreadcrumbBar);
if (editPathToggleShortcutId == 0)
return;
- QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
- qCDebug(lcShortcuts) << "text field was shown; grabbing/ungrabbing relevant shortcuts...";
-
- // Disable the back/escape shortcuts for QQuickPopup so that the TextField can get them.
- auto popupItem = qobject_cast<QQuickPopupItem*>(dialog->popupItem());
- popupItem->ungrabShortcut();
-
- appPrivate->shortcutMap.removeShortcut(editPathToggleShortcutId, q);
- editPathToggleShortcutId = 0;
-
- editPathBackShortcutId = appPrivate->shortcutMap.addShortcut(
- q, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher);
- editPathEscapeShortcutId = appPrivate->shortcutMap.addShortcut(
- q, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher);
-
- qCDebug(lcShortcuts).nospace() << "... shortcut IDs:"
- << " editPathToggleShortcutId=" << editPathToggleShortcutId
- << " editPathBackShortcutId=" << editPathBackShortcutId
- << " editPathEscapeShortcutId=" << editPathEscapeShortcutId;
+ qCDebug(lcShortcuts) << "text field was shown; ungrabbing edit path shortcut";
+ ungrabEditPathShortcut();
#endif
}
@@ -405,56 +387,26 @@ void QQuickFolderBreadcrumbBarPrivate::handleTextFieldHidden()
Q_Q(QQuickFolderBreadcrumbBar);
QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
- qCDebug(lcShortcuts) << "text field was hidden; grabbing/ungrabbing relevant shortcuts...";
+ qCDebug(lcShortcuts) << "text field was hidden; grabbing edit path shortcut";
if (editPathToggleShortcutId == 0) {
editPathToggleShortcutId = appPrivate->shortcutMap.addShortcut(
q, Qt::CTRL | Qt::Key_L, Qt::WindowShortcut, QQuickShortcutContext::matcher);
}
- // When the bar is first completed, this function is called, since the text field starts off hidden.
- // If removeShortcut is called with a zero id, all shortcuts for the given object will be removed,
- // and we don't want that.
- if (editPathBackShortcutId != 0) {
- appPrivate->shortcutMap.removeShortcut(editPathBackShortcutId, q);
- editPathBackShortcutId = 0;
- }
- if (editPathEscapeShortcutId != 0) {
- appPrivate->shortcutMap.removeShortcut(editPathEscapeShortcutId, q);
- editPathEscapeShortcutId = 0;
- }
-
- // Re-enable the back/escape shortcuts for QQuickPopup now that TextField no longer needs them.
- auto popupItem = qobject_cast<QQuickPopupItem*>(dialog->popupItem());
- if (popupItem)
- popupItem->grabShortcut();
-
- qCDebug(lcShortcuts).nospace() << "... shortcut IDs: "
- << " editPathToggleShortcutId=" << editPathToggleShortcutId
- << " editPathBackShortcutId=" << editPathBackShortcutId
- << " editPathEscapeShortcutId=" << editPathEscapeShortcutId;
+ qCDebug(lcShortcuts).nospace() << "... editPathToggleShortcutId=" << editPathToggleShortcutId;
#endif
}
-void QQuickFolderBreadcrumbBarPrivate::ungrabEditPathShortcuts()
+void QQuickFolderBreadcrumbBarPrivate::ungrabEditPathShortcut()
{
#if QT_CONFIG(shortcut)
Q_Q(QQuickFolderBreadcrumbBar);
QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
- qCDebug(lcShortcuts) << "ungrabbing all edit path shortcuts";
-
if (editPathToggleShortcutId != 0) {
appPrivate->shortcutMap.removeShortcut(editPathToggleShortcutId, q);
editPathToggleShortcutId = 0;
}
- if (editPathBackShortcutId != 0) {
- appPrivate->shortcutMap.removeShortcut(editPathBackShortcutId, q);
- editPathBackShortcutId = 0;
- }
- if (editPathEscapeShortcutId != 0) {
- appPrivate->shortcutMap.removeShortcut(editPathEscapeShortcutId, q);
- editPathEscapeShortcutId = 0;
- }
#endif
}
@@ -756,9 +708,7 @@ bool QQuickFolderBreadcrumbBar::event(QEvent *event)
Q_D(QQuickFolderBreadcrumbBar);
if (event->type() == QEvent::Shortcut) {
QShortcutEvent *shortcutEvent = static_cast<QShortcutEvent *>(event);
- if (shortcutEvent->shortcutId() == d->editPathToggleShortcutId
- || shortcutEvent->shortcutId() == d->editPathBackShortcutId
- || shortcutEvent->shortcutId() == d->editPathEscapeShortcutId) {
+ if (shortcutEvent->shortcutId() == d->editPathToggleShortcutId) {
d->toggleTextFieldVisibility();
return true;
} else if (shortcutEvent->shortcutId() == d->goUpShortcutId) {
@@ -769,6 +719,18 @@ bool QQuickFolderBreadcrumbBar::event(QEvent *event)
return QQuickItem::event(event);
}
+void QQuickFolderBreadcrumbBar::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+
+ if (event->matches(QKeySequence::Cancel) && d->textField->isVisible()) {
+ d->toggleTextFieldVisibility();
+ event->accept();
+ } else {
+ QQuickContainer::keyPressEvent(event);
+ }
+}
+
void QQuickFolderBreadcrumbBar::componentComplete()
{
Q_D(QQuickFolderBreadcrumbBar);
@@ -804,8 +766,8 @@ void QQuickFolderBreadcrumbBar::itemChange(QQuickItem::ItemChange change, const
if (d->contentItem)
d->contentItem->setVisible(true);
- // We also need to ungrab all shortcuts when we're not visible.
- d->ungrabEditPathShortcuts();
+ // We also need to ungrab the edit path shortcut when we're not visible.
+ d->ungrabEditPathShortcut();
if (d->goUpShortcutId != 0) {
QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->goUpShortcutId, this);
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h
index 1cfc0ac267..322b246f5f 100644
--- a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h
@@ -104,6 +104,7 @@ Q_SIGNALS:
protected:
bool event(QEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
void componentComplete() override;
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h
index 61007f9a54..08aebd59f8 100644
--- a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h
@@ -88,7 +88,7 @@ public:
void textFieldActiveFocusChanged();
void handleTextFieldShown();
void handleTextFieldHidden();
- void ungrabEditPathShortcuts();
+ void ungrabEditPathShortcut();
QQuickFileDialogImpl *asFileDialog() const;
QQuickFolderDialogImpl *asFolderDialog() const;
@@ -112,8 +112,6 @@ private:
QQuickDeferredPointer<QQuickAbstractButton> upButton;
QQuickDeferredPointer<QQuickTextField> textField;
int editPathToggleShortcutId = 0;
- int editPathBackShortcutId = 0;
- int editPathEscapeShortcutId = 0;
int goUpShortcutId = 0;
int upButtonSpacing = 0;
bool repopulating = false;
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index fa84580777..ae491ac5af 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -237,15 +237,22 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
\section1 Back/Escape Event Handling
- By default, a Popup will close if the Escape or Back keys are pressed. This
- can be problematic for popups which contain items that want to handle those
- events themselves. There are two solutions to this:
+ By default, a Popup will close if:
+ \list
+ \li It has \l activeFocus,
+ \li Its \l closePolicy is \c {Popup.CloseOnEscape}, and
+ \li The user presses the key sequence for QKeySequence::Cancel (typically
+ the Escape key)
+ \endlist
+
+ To prevent this from happening, either:
\list
- \li Set Popup's \l closePolicy to a value that does not include
+ \li Don't give the popup \l focus.
+ \li Set the popup's \l closePolicy to a value that does not include
\c {Popup.CloseOnEscape}.
- \li Handle \l {Keys}' \l {Keys::}{shortcutOverride} signal and accept the
- event before Popup can.
+ \li Handle \l {Keys}' \l {Keys::}{escapePressed} signal in a child item of
+ the popup so that it gets the event before the Popup.
\endlist
\sa {Popup Controls}, {Customizing Popup}, ApplicationWindow
@@ -906,7 +913,6 @@ QQuickPopup::~QQuickPopup()
{
Q_D(QQuickPopup);
setParentItem(nullptr);
- d->popupItem->ungrabShortcut();
// If the popup is destroyed before the exit transition finishes,
// the necessary cleanup (removing modal dimmers that block mouse events,
@@ -2066,8 +2072,6 @@ void QQuickPopup::setScale(qreal scale)
not result in the first closing.
The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}.
- This default value may interfere with existing shortcuts in the application
- that makes use of the \e Escape key.
\note There is a known limitation that the \c Popup.CloseOnReleaseOutside
and \c Popup.CloseOnReleaseOutsideParent policies only work with
@@ -2086,12 +2090,6 @@ void QQuickPopup::setClosePolicy(ClosePolicy policy)
if (d->closePolicy == policy)
return;
d->closePolicy = policy;
- if (isVisible()) {
- if (policy & QQuickPopup::CloseOnEscape)
- d->popupItem->grabShortcut();
- else
- d->popupItem->ungrabShortcut();
- }
emit closePolicyChanged();
}
@@ -2501,13 +2499,6 @@ void QQuickPopup::componentComplete()
d->complete = true;
d->popupItem->componentComplete();
-
- if (isVisible()) {
- if (d->closePolicy & QQuickPopup::CloseOnEscape)
- d->popupItem->grabShortcut();
- else
- d->popupItem->ungrabShortcut();
- }
}
bool QQuickPopup::isComponentComplete() const
@@ -2536,10 +2527,22 @@ void QQuickPopup::focusOutEvent(QFocusEvent *event)
void QQuickPopup::keyPressEvent(QKeyEvent *event)
{
Q_D(QQuickPopup);
- event->accept();
+ if (!hasActiveFocus())
+ return;
- if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab))
+#if QT_CONFIG(shortcut)
+ if (d->closePolicy.testFlag(QQuickPopup::CloseOnEscape) && event->matches(QKeySequence::Cancel)) {
+ event->accept();
+ if (d->interactive)
+ d->closeOrReject();
+ return;
+ }
+#endif
+
+ if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) {
+ event->accept();
QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab);
+ }
}
void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
@@ -2666,10 +2669,8 @@ void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeo
}
}
-void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &)
{
- Q_D(QQuickPopup);
-
switch (change) {
case QQuickItem::ItemActiveFocusHasChanged:
emit activeFocusChanged();
@@ -2677,14 +2678,6 @@ void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::It
case QQuickItem::ItemOpacityHasChanged:
emit opacityChanged();
break;
- case QQuickItem::ItemVisibleHasChanged:
- if (isComponentComplete() && d->closePolicy & CloseOnEscape) {
- if (data.boolValue)
- d->popupItem->grabShortcut();
- else
- d->popupItem->ungrabShortcut();
- }
- break;
default:
break;
}
diff --git a/src/quicktemplates2/qquickpopupitem.cpp b/src/quicktemplates2/qquickpopupitem.cpp
index 0d86a859e9..fb1664d522 100644
--- a/src/quicktemplates2/qquickpopupitem.cpp
+++ b/src/quicktemplates2/qquickpopupitem.cpp
@@ -39,18 +39,11 @@
#include "qquickpopupitem_p_p.h"
#include "qquickapplicationwindow_p.h"
-#include "qquickshortcutcontext_p_p.h"
#include "qquickpage_p_p.h"
#include "qquickcontentitem_p.h"
#include "qquickpopup_p_p.h"
#include "qquickdeferredexecute_p_p.h"
-#include <QtCore/qloggingcategory.h>
-#if QT_CONFIG(shortcut)
-# include <QtGui/private/qshortcutmap_p.h>
-#endif
-#include <QtGui/private/qguiapplication_p.h>
-
#if QT_CONFIG(accessibility)
#include <QtQuick/private/qquickaccessibleattached_p.h>
#endif
@@ -156,34 +149,6 @@ QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup)
#endif
}
-void QQuickPopupItem::grabShortcut()
-{
-#if QT_CONFIG(shortcut)
- Q_D(QQuickPopupItem);
- QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
- if (!d->backId)
- d->backId = pApp->shortcutMap.addShortcut(this, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher);
- if (!d->escapeId)
- d->escapeId = pApp->shortcutMap.addShortcut(this, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher);
-#endif
-}
-
-void QQuickPopupItem::ungrabShortcut()
-{
-#if QT_CONFIG(shortcut)
- Q_D(QQuickPopupItem);
- QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
- if (d->backId) {
- pApp->shortcutMap.removeShortcut(d->backId, this);
- d->backId = 0;
- }
- if (d->escapeId) {
- pApp->shortcutMap.removeShortcut(d->escapeId, this);
- d->escapeId = 0;
- }
-#endif
-}
-
QQuickPalette *QQuickPopupItemPrivate::palette() const
{
return QQuickPopupPrivate::get(popup)->palette();
@@ -220,24 +185,6 @@ void QQuickPopupItem::updatePolish()
return QQuickPopupPrivate::get(d->popup)->reposition();
}
-bool QQuickPopupItem::event(QEvent *event)
-{
-#if QT_CONFIG(shortcut)
- Q_D(QQuickPopupItem);
- if (event->type() == QEvent::Shortcut) {
- QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
- if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) {
- QQuickPopupPrivate *p = QQuickPopupPrivate::get(d->popup);
- if (p->interactive) {
- p->closeOrReject();
- return true;
- }
- }
- }
-#endif
- return QQuickItem::event(event);
-}
-
bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
{
Q_D(QQuickPopupItem);
diff --git a/src/quicktemplates2/qquickpopupitem_p_p.h b/src/quicktemplates2/qquickpopupitem_p_p.h
index b9b0c33440..d5d1537c05 100644
--- a/src/quicktemplates2/qquickpopupitem_p_p.h
+++ b/src/quicktemplates2/qquickpopupitem_p_p.h
@@ -66,13 +66,9 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupItem : public QQuickPage
public:
explicit QQuickPopupItem(QQuickPopup *popup);
- void grabShortcut();
- void ungrabShortcut();
-
protected:
void updatePolish() override;
- bool event(QEvent *event) override;
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
diff --git a/tests/auto/quickcontrols2/controls/basic/BLACKLIST b/tests/auto/quickcontrols2/controls/basic/BLACKLIST
index bdb2af0b46..b643dd1d9c 100644
--- a/tests/auto/quickcontrols2/controls/basic/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/basic/BLACKLIST
@@ -8,3 +8,6 @@
[RangeSlider::test_overlappingHandles]
b2qt
qnx
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/data/tst_combobox.qml b/tests/auto/quickcontrols2/controls/data/tst_combobox.qml
index 0e896ddb2d..6de1c81595 100644
--- a/tests/auto/quickcontrols2/controls/data/tst_combobox.qml
+++ b/tests/auto/quickcontrols2/controls/data/tst_combobox.qml
@@ -1870,8 +1870,8 @@ TestCase {
width: 200
height: 200
- Keys.onPressed: { ++pressedKeys; lastPressedKey = event.key }
- Keys.onReleased: { ++releasedKeys; lastReleasedKey = event.key }
+ Keys.onPressed: (event) => { ++pressedKeys; lastPressedKey = event.key }
+ Keys.onReleased: (event) => { ++releasedKeys; lastReleasedKey = event.key }
ComboBox {
id: comboBox
@@ -1918,11 +1918,6 @@ TestCase {
compare(container.pressedKeys, pressedKeys)
keyRelease(data.key)
- // Popup receives the key release event if it has an exit transition, but
- // not if it has been immediately closed on press, without a transition.
- // ### TODO: Should Popup somehow always block the key release event?
- if (!control.popup.exit)
- ++releasedKeys
compare(container.releasedKeys, releasedKeys)
tryCompare(control.popup, "visible", false)
diff --git a/tests/auto/quickcontrols2/controls/fusion/BLACKLIST b/tests/auto/quickcontrols2/controls/fusion/BLACKLIST
index bdb2af0b46..b643dd1d9c 100644
--- a/tests/auto/quickcontrols2/controls/fusion/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/fusion/BLACKLIST
@@ -8,3 +8,6 @@
[RangeSlider::test_overlappingHandles]
b2qt
qnx
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/imagine/BLACKLIST b/tests/auto/quickcontrols2/controls/imagine/BLACKLIST
index 72eebcd21d..c3865e0006 100644
--- a/tests/auto/quickcontrols2/controls/imagine/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/imagine/BLACKLIST
@@ -12,3 +12,6 @@ qnx
# QTBUG-101704
[ToolTip::test_attachedSizeBug]
*
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/ios/BLACKLIST b/tests/auto/quickcontrols2/controls/ios/BLACKLIST
index 68b52a8ccc..e5d8e9bcab 100644
--- a/tests/auto/quickcontrols2/controls/ios/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/ios/BLACKLIST
@@ -2,3 +2,6 @@
[ScrollView::test_textArea]
*
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/macos/BLACKLIST b/tests/auto/quickcontrols2/controls/macos/BLACKLIST
index 0e48b148d8..1e751af957 100644
--- a/tests/auto/quickcontrols2/controls/macos/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/macos/BLACKLIST
@@ -1,2 +1,4 @@
# See qtbase/src/testlib/qtestblacklist.cpp for format
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/material/BLACKLIST b/tests/auto/quickcontrols2/controls/material/BLACKLIST
index bdb2af0b46..b643dd1d9c 100644
--- a/tests/auto/quickcontrols2/controls/material/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/material/BLACKLIST
@@ -8,3 +8,6 @@
[RangeSlider::test_overlappingHandles]
b2qt
qnx
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/universal/BLACKLIST b/tests/auto/quickcontrols2/controls/universal/BLACKLIST
index bdb2af0b46..b643dd1d9c 100644
--- a/tests/auto/quickcontrols2/controls/universal/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/universal/BLACKLIST
@@ -8,3 +8,6 @@
[RangeSlider::test_overlappingHandles]
b2qt
qnx
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/controls/windows/BLACKLIST b/tests/auto/quickcontrols2/controls/windows/BLACKLIST
index 476340700a..8230d5eb4e 100644
--- a/tests/auto/quickcontrols2/controls/windows/BLACKLIST
+++ b/tests/auto/quickcontrols2/controls/windows/BLACKLIST
@@ -3,3 +3,6 @@
# QTBUG-70597
[Tumbler::test_itemsCorrectlyPositioned]
*
+
+[ComboBox::test_keyClose]
+macos arm ci # QTBUG-102817
diff --git a/tests/auto/quickcontrols2/qquickpopup/BLACKLIST b/tests/auto/quickcontrols2/qquickpopup/BLACKLIST
index 4aa2bfeb6e..aa31440328 100644
--- a/tests/auto/quickcontrols2/qquickpopup/BLACKLIST
+++ b/tests/auto/quickcontrols2/qquickpopup/BLACKLIST
@@ -6,9 +6,6 @@ macos # QTBUG-89938
[zOrder]
macos # QTBUG-89938
-[closePolicy]
-macos # QTBUG-89938
-
# QTBUG-94251
[closePolicy]
opensuse-leap
diff --git a/tests/auto/quickcontrols2/qquickpopup/data/activeFocusOnClose3.qml b/tests/auto/quickcontrols2/qquickpopup/data/activeFocusOnClose3.qml
index 8a68246853..a6dcf637d9 100644
--- a/tests/auto/quickcontrols2/qquickpopup/data/activeFocusOnClose3.qml
+++ b/tests/auto/quickcontrols2/qquickpopup/data/activeFocusOnClose3.qml
@@ -64,15 +64,27 @@ ApplicationWindow {
Popup {
id: popup1
+ objectName: "popup1"
focus: true
enter: Transition { PauseAnimation { duration: 200 } }
exit: Transition { PauseAnimation { duration: 200 } }
+
+ Label {
+ text: popup1.objectName
+ anchors.centerIn: parent
+ }
}
Popup {
id: popup2
+ objectName: "popup2"
focus: true
enter: Transition { PauseAnimation { duration: 100 } }
exit: Transition { PauseAnimation { duration: 100 } }
+
+ Label {
+ text: popup2.objectName
+ anchors.centerIn: parent
+ }
}
}
diff --git a/tests/auto/quickcontrols2/qquickpopup/data/closeOnEscapeWithVisiblePopup.qml b/tests/auto/quickcontrols2/qquickpopup/data/closeOnEscapeWithVisiblePopup.qml
index b65e4ec0c0..b1d7413e9b 100644
--- a/tests/auto/quickcontrols2/qquickpopup/data/closeOnEscapeWithVisiblePopup.qml
+++ b/tests/auto/quickcontrols2/qquickpopup/data/closeOnEscapeWithVisiblePopup.qml
@@ -11,6 +11,7 @@ Window {
width: 200
height: 200
anchors.centerIn: parent
+ focus: true
closePolicy: Popup.CloseOnEscape
}
}
diff --git a/tests/auto/quickcontrols2/qquickpopup/data/destroyDuringExitTransition.qml b/tests/auto/quickcontrols2/qquickpopup/data/destroyDuringExitTransition.qml
index 67fca2e78e..084af64e16 100644
--- a/tests/auto/quickcontrols2/qquickpopup/data/destroyDuringExitTransition.qml
+++ b/tests/auto/quickcontrols2/qquickpopup/data/destroyDuringExitTransition.qml
@@ -89,6 +89,7 @@ ApplicationWindow {
Dialog {
dim: true
modal: true
+ focus: true
closePolicy: Popup.CloseOnEscape
visible: true
diff --git a/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
index a1412d5ddd..e7e7acd4af 100644
--- a/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
@@ -39,6 +39,7 @@
#include <QtQuickTemplates2/private/qquickcombobox_p.h>
#include <QtQuickTemplates2/private/qquickdialog_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
+#include <QtQuickTemplates2/private/qquickoverlay_p_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p.h>
#include <QtQuickTemplates2/private/qquickpopupitem_p_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
@@ -79,6 +80,7 @@ private slots:
void activeFocusOnClosingSeveralPopups();
void activeFocusAfterExit();
void activeFocusOnDelayedEnter();
+ void activeFocusDespiteLowerStackingOrder();
void hover_data();
void hover();
void wheel_data();
@@ -861,6 +863,47 @@ void tst_QQuickPopup::activeFocusOnDelayedEnter()
QTRY_VERIFY(popup2->hasActiveFocus());
}
+// Test that a popup (popup1) with a lower stacking order than another popup (popup2) gets
+// key events due to having active focus.
+void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder()
+{
+ QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickPopup *popup1 = window->property("popup1").value<QQuickPopup *>();
+ QVERIFY(popup1);
+ popup1->open();
+ QTRY_VERIFY(popup1->isOpened());
+
+ QQuickPopup *popup2 = window->property("popup2").value<QQuickPopup *>();
+ QVERIFY(popup2);
+ popup2->open();
+ QTRY_VERIFY(popup2->isOpened());
+ popup2->setX(popup1->width() / 2);
+ popup2->setY(popup1->height() / 2);
+
+ // Both popups have no explicitly assigned Z value, so they should be the same.
+ // Items (QQuickPopupItem in this case) with identical Z values are rendered according
+ // to their order in the childItems container in the parent QQuickItem (see
+ // paintOrderChildItems(), which is what stackingOrderPopups() uses).
+ QCOMPARE(popup1->z(), popup2->z());
+
+ // Give popup1 active focus. Even though it's stacked under popup2,
+ // it should still receive key events.
+ popup1->forceActiveFocus();
+
+ // Press Escape to close popup1.
+ QTest::keyClick(window, Qt::Key_Escape);
+ QVERIFY(!popup1->isOpened());
+ QVERIFY(popup2->isOpened());
+ QTRY_VERIFY(!popup1->isVisible());
+ QVERIFY(!popup1->hasActiveFocus());
+}
+
void tst_QQuickPopup::hover_data()
{
QTest::addColumn<QString>("source");
@@ -1283,7 +1326,7 @@ void tst_QQuickPopup::closeOnEscapeWithVisiblePopup()
QVERIFY(popup);
QTRY_VERIFY(popup->isOpened());
- QTRY_VERIFY(window->activeFocusItem());
+ QTRY_VERIFY(popup->hasActiveFocus());
QTest::keyClick(window, Qt::Key_Escape);
QTRY_VERIFY(!popup->isVisible());
}