aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2016-10-21 22:10:39 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2016-11-01 12:59:45 +0000
commitb31b4094e1728d839fef30f5128c81451ea75e4a (patch)
treed7288c7a964a1fb9f45612e9e4b98c40dc2b1a73 /src
parent281469e947e6b09a44c296a26db474db815f6238 (diff)
QQuickPopup: use QShortcutMap to grab Back & Escape keys
This makes CloseOnEscape play well together with QML Shortcut, as illustrated by the Gallery example. For example, navigate to any control page, open the options menu, and hit escape twice. First, the options menu closes, and then the stackview navigates back. Another nice example is to open the style combobox in the settings dialog, while being navigated to one of the control pages, and hit escape three times. First, the combobox closes, then the settings dialog closes, and finally, the stackview navigates back. NOTE: tst_combobox had to be updated, because it was assuming that the popup is closed when escape is released. Now that the system is based on shortcut overrides, it gets closed on press instead. Task-number: QTBUG-56562 Change-Id: I8b8901bcba7deebd82b181af42f335d95a7cb469 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quicktemplates2/qquickpopup.cpp73
-rw-r--r--src/quicktemplates2/qquickpopup_p_p.h4
-rw-r--r--src/quicktemplates2/qquickshortcutcontext.cpp10
3 files changed, 76 insertions, 11 deletions
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index 6273e4ef..518117fa 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -37,9 +37,12 @@
#include "qquickpopup_p.h"
#include "qquickpopup_p_p.h"
#include "qquickapplicationwindow_p.h"
+#include "qquickshortcutcontext_p_p.h"
#include "qquickoverlay_p_p.h"
#include "qquickcontrol_p_p.h"
+#include <QtGui/private/qshortcutmap_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquicktransition_p.h>
@@ -433,10 +436,15 @@ public:
void resolveFont() override;
+ int backId;
+ int escapeId;
QQuickPopup *popup;
};
-QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup)
+QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
+ : backId(0),
+ escapeId(0),
+ popup(popup)
{
isTabFence = true;
}
@@ -479,6 +487,47 @@ void QQuickPopupItem::updatePolish()
return QQuickPopupPrivate::get(d->popup)->reposition();
}
+void QQuickPopupItem::grabShortcut()
+{
+#ifndef QT_NO_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 // QT_NO_SHORTCUT
+}
+
+void QQuickPopupItem::ungrabShortcut()
+{
+#ifndef QT_NO_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 // QT_NO_SHORTCUT
+}
+
+bool QQuickPopupItem::event(QEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ if (event->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
+ if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) {
+ d->popup->close();
+ return true;
+ }
+ }
+ return QQuickItem::event(event);
+}
+
bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
{
Q_D(QQuickPopupItem);
@@ -912,6 +961,7 @@ QQuickPopup::~QQuickPopup()
{
Q_D(QQuickPopup);
setParentItem(nullptr);
+ d->popupItem->ungrabShortcut();
delete d->popupItem;
}
@@ -1963,6 +2013,12 @@ 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();
}
@@ -2131,12 +2187,6 @@ void QQuickPopup::keyPressEvent(QKeyEvent *event)
if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab))
QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab);
-
- if (event->key() != Qt::Key_Escape && event->key() != Qt::Key_Back)
- return;
-
- if (d->closePolicy.testFlag(CloseOnEscape))
- close();
}
void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
@@ -2233,7 +2283,7 @@ void QQuickPopup::geometryChanged(const QRectF &newGeometry, const QRectF &oldGe
void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
{
- Q_UNUSED(data);
+ Q_D(QQuickPopup);
switch (change) {
case QQuickItem::ItemActiveFocusHasChanged:
@@ -2242,6 +2292,13 @@ 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();
+ }
default:
break;
}
diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h
index d2f16e11..96ce2ca0 100644
--- a/src/quicktemplates2/qquickpopup_p_p.h
+++ b/src/quicktemplates2/qquickpopup_p_p.h
@@ -86,9 +86,13 @@ class QQuickPopupItem : public QQuickControl
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/src/quicktemplates2/qquickshortcutcontext.cpp b/src/quicktemplates2/qquickshortcutcontext.cpp
index 2a3cb68a..04aa4f4d 100644
--- a/src/quicktemplates2/qquickshortcutcontext.cpp
+++ b/src/quicktemplates2/qquickshortcutcontext.cpp
@@ -50,8 +50,8 @@ static bool isBlockedByPopup(QQuickItem *item)
QQuickOverlay *overlay = QQuickOverlay::overlay(item->window());
const auto popups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
for (QQuickPopup *popup : popups) {
- if (popup->isModal())
- return !popup->popupItem()->isAncestorOf(item);
+ if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape)
+ return item != popup->popupItem() && !popup->popupItem()->isAncestorOf(item);
}
return false;
@@ -67,8 +67,12 @@ bool QQuickShortcutContext::matcher(QObject *obj, Qt::ShortcutContext context)
while (obj && !obj->isWindowType()) {
obj = obj->parent();
item = qobject_cast<QQuickItem *>(obj);
- if (item)
+ if (item) {
obj = item->window();
+ } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(obj)) {
+ obj = popup->window();
+ item = popup->popupItem();
+ }
}
return obj && obj == QGuiApplication::focusWindow() && !isBlockedByPopup(item);
default: