diff options
Diffstat (limited to 'src/quicktemplates/qquickshortcutcontext.cpp')
-rw-r--r-- | src/quicktemplates/qquickshortcutcontext.cpp | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/quicktemplates/qquickshortcutcontext.cpp b/src/quicktemplates/qquickshortcutcontext.cpp new file mode 100644 index 0000000000..503eb270a7 --- /dev/null +++ b/src/quicktemplates/qquickshortcutcontext.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickshortcutcontext_p_p.h" +#include "qquickoverlay_p_p.h" +#include "qquicktooltip_p.h" +#include <QtQmlModels/private/qtqmlmodels-config_p.h> +#if QT_CONFIG(qml_object_model) +#include "qquickmenu_p.h" +#include "qquickmenu_p_p.h" +#endif +#include "qquickpopup_p.h" + +#include <QtCore/qloggingcategory.h> +#include <QtGui/qguiapplication.h> +#include <QtQuick/qquickrendercontrol.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcContextMatcher, "qt.quick.controls.shortcutcontext.matcher") + +static bool isBlockedByPopup(QQuickItem *item) +{ + if (!item || !item->window()) + return false; + + QQuickOverlay *overlay = QQuickOverlay::overlay(item->window()); + const auto popups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups(); + for (QQuickPopup *popup : popups) { + if (qobject_cast<QQuickToolTip *>(popup)) + continue; // ignore tooltips (QTBUG-60492) + if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape) { + qCDebug(lcContextMatcher) << popup << "is modal or has a CloseOnEscape policy;" + << "if the following are both true," << item << "will be blocked by it:" + << (item != popup->popupItem()) << !popup->popupItem()->isAncestorOf(item); + return item != popup->popupItem() && !popup->popupItem()->isAncestorOf(item); + } + } + + return false; +} + +bool QQuickShortcutContext::matcher(QObject *obj, Qt::ShortcutContext context) +{ + QQuickItem *item = nullptr; + switch (context) { + case Qt::ApplicationShortcut: + return true; + case Qt::WindowShortcut: + while (obj && !obj->isWindowType()) { + item = qobject_cast<QQuickItem *>(obj); + if (item && item->window()) { + obj = item->window(); + break; + } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(obj)) { + obj = popup->window(); + item = popup->popupItem(); + +#if QT_CONFIG(qml_object_model) + if (!obj) { + // The popup has no associated window (yet). However, sub-menus, + // unlike top-level menus, will not have an associated window + // until their parent menu is opened. So, check if this is a sub-menu + // so that actions within it can grab shortcuts. + if (auto *menu = qobject_cast<QQuickMenu *>(popup)) { + auto parentMenu = QQuickMenuPrivate::get(menu)->parentMenu; + while (!obj && parentMenu) + obj = parentMenu->window(); + } + } +#endif + break; + } + obj = obj->parent(); + } + if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow *>(obj))) + obj = renderWindow; + qCDebug(lcContextMatcher) << "obj" << obj << "item" << item << "focusWindow" << QGuiApplication::focusWindow() + << "!isBlockedByPopup(item)" << !isBlockedByPopup(item); + return obj && qobject_cast<QWindow*>(obj)->isActive() && !isBlockedByPopup(item); + default: + return false; + } +} + +QT_END_NAMESPACE |