1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickshortcutcontext_p_p.h"
5#include "qquickoverlay_p_p.h"
6#include "qquicktooltip_p.h"
7#include "qquickmenu_p.h"
8#include "qquickmenu_p_p.h"
9#include "qquickpopup_p.h"
10
11#include <QtCore/qloggingcategory.h>
12#include <QtGui/qguiapplication.h>
13#include <QtQuick/qquickrendercontrol.h>
14
15QT_BEGIN_NAMESPACE
16
17Q_LOGGING_CATEGORY(lcContextMatcher, "qt.quick.controls.shortcutcontext.matcher")
18
19static bool isBlockedByPopup(QQuickItem *item)
20{
21 if (!item || !item->window())
22 return false;
23
24 QQuickOverlay *overlay = QQuickOverlay::overlay(window: item->window());
25 const auto popups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
26 for (QQuickPopup *popup : popups) {
27 if (qobject_cast<QQuickToolTip *>(object: popup))
28 continue; // ignore tooltips (QTBUG-60492)
29 if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape) {
30 qCDebug(lcContextMatcher) << popup << "is modal or has a CloseOnEscape policy;"
31 << "if the following are both true," << item << "will be blocked by it:"
32 << (item != popup->popupItem()) << !popup->popupItem()->isAncestorOf(child: item);
33 return item != popup->popupItem() && !popup->popupItem()->isAncestorOf(child: item);
34 }
35 }
36
37 return false;
38}
39
40bool QQuickShortcutContext::matcher(QObject *obj, Qt::ShortcutContext context)
41{
42 QQuickItem *item = nullptr;
43 switch (context) {
44 case Qt::ApplicationShortcut:
45 return true;
46 case Qt::WindowShortcut:
47 while (obj && !obj->isWindowType()) {
48 item = qobject_cast<QQuickItem *>(o: obj);
49 if (item && item->window()) {
50 obj = item->window();
51 break;
52 } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(object: obj)) {
53 obj = popup->window();
54 item = popup->popupItem();
55
56 if (!obj) {
57 // The popup has no associated window (yet). However, sub-menus,
58 // unlike top-level menus, will not have an associated window
59 // until their parent menu is opened. So, check if this is a sub-menu
60 // so that actions within it can grab shortcuts.
61 if (auto *menu = qobject_cast<QQuickMenu *>(object: popup)) {
62 auto parentMenu = QQuickMenuPrivate::get(menu)->parentMenu;
63 while (!obj && parentMenu)
64 obj = parentMenu->window();
65 }
66 }
67 break;
68 }
69 obj = obj->parent();
70 }
71 if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(win: qobject_cast<QQuickWindow *>(object: obj)))
72 obj = renderWindow;
73 qCDebug(lcContextMatcher) << "obj" << obj << "item" << item << "focusWindow" << QGuiApplication::focusWindow()
74 << "!isBlockedByPopup(item)" << !isBlockedByPopup(item);
75 return obj && obj == QGuiApplication::focusWindow() && !isBlockedByPopup(item);
76 default:
77 return false;
78 }
79}
80
81QT_END_NAMESPACE
82

source code of qtdeclarative/src/quicktemplates/qquickshortcutcontext.cpp