1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qshortcut.h"
41 #include "private/qwidget_p.h"
42 
43 #ifndef QT_NO_SHORTCUT
44 #include <qevent.h>
45 #if QT_CONFIG(whatsthis)
46 #include <qwhatsthis.h>
47 #endif
48 #if QT_CONFIG(menu)
49 #include <qmenu.h>
50 #endif
51 #if QT_CONFIG(menubar)
52 #include <qmenubar.h>
53 #endif
54 #include <qapplication.h>
55 #include <private/qapplication_p.h>
56 #include <private/qshortcutmap_p.h>
57 #include <private/qaction_p.h>
58 #include <private/qwidgetwindow_p.h>
59 #include <qpa/qplatformmenu.h>
60 
61 QT_BEGIN_NAMESPACE
62 
63 #define QAPP_CHECK(functionName) \
64     if (Q_UNLIKELY(!qApp)) {                                            \
65         qWarning("QShortcut: Initialize QApplication before calling '" functionName "'."); \
66         return; \
67     }
68 
69 
70 static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window);
71 #if QT_CONFIG(graphicsview)
72 static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window);
73 #endif
74 #ifndef QT_NO_ACTION
75 static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window);
76 #endif
77 
78 
79 /*! \internal
80     Returns \c true if the widget \a w is a logical sub window of the current
81     top-level widget.
82 */
qWidgetShortcutContextMatcher(QObject * object,Qt::ShortcutContext context)83 bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context)
84 {
85     Q_ASSERT_X(object, "QShortcutMap", "Shortcut has no owner. Illegal map state!");
86 
87     QWidget *active_window = QApplication::activeWindow();
88 
89     // popups do not become the active window,
90     // so we fake it here to get the correct context
91     // for the shortcut system.
92     if (QApplication::activePopupWidget())
93         active_window = QApplication::activePopupWidget();
94 
95     if (!active_window) {
96         QWindow *qwindow = QGuiApplication::focusWindow();
97         if (qwindow && qwindow->isActive()) {
98             while (qwindow) {
99                 if (auto widgetWindow = qobject_cast<QWidgetWindow *>(qwindow)) {
100                     active_window = widgetWindow->widget();
101                     break;
102                 }
103                 qwindow = qwindow->parent();
104             }
105         }
106     }
107 
108     if (!active_window)
109         return false;
110 
111 #ifndef QT_NO_ACTION
112     if (auto a = qobject_cast<QAction *>(object))
113         return correctActionContext(context, a, active_window);
114 #endif
115 
116 #if QT_CONFIG(graphicsview)
117     if (auto gw = qobject_cast<QGraphicsWidget *>(object))
118         return correctGraphicsWidgetContext(context, gw, active_window);
119 #endif
120 
121     auto w = qobject_cast<QWidget *>(object);
122     if (!w) {
123         if (auto s = qobject_cast<QShortcut *>(object))
124             w = s->parentWidget();
125     }
126 
127     if (!w) {
128         auto qwindow = qobject_cast<QWindow *>(object);
129         while (qwindow) {
130             if (auto widget_window = qobject_cast<QWidgetWindow *>(qwindow)) {
131                 w = widget_window->widget();
132                 break;
133             }
134             qwindow = qwindow->parent();
135         }
136     }
137 
138     if (!w)
139         return false;
140 
141     return correctWidgetContext(context, w, active_window);
142 }
143 
correctWidgetContext(Qt::ShortcutContext context,QWidget * w,QWidget * active_window)144 static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window)
145 {
146     bool visible = w->isVisible();
147 #if QT_CONFIG(menubar)
148     if (auto menuBar = qobject_cast<QMenuBar *>(w)) {
149         if (auto *pmb = menuBar->platformMenuBar()) {
150             if (menuBar->parentWidget()) {
151                 visible = true;
152             } else {
153                 if (auto *ww = qobject_cast<QWidgetWindow *>(pmb->parentWindow()))
154                     w = ww->widget(); // Good enough since we only care about the window
155                 else
156                     return false; // This is not a QWidget window. We won't deliver
157             }
158         }
159     }
160 #endif
161 
162     if (!visible || !w->isEnabled())
163         return false;
164 
165     if (context == Qt::ApplicationShortcut)
166         return QApplicationPrivate::tryModalHelper(w, nullptr); // true, unless w is shadowed by a modal dialog
167 
168     if (context == Qt::WidgetShortcut)
169         return w == QApplication::focusWidget();
170 
171     if (context == Qt::WidgetWithChildrenShortcut) {
172         const QWidget *tw = QApplication::focusWidget();
173         while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup || tw->windowType() == Qt::SubWindow))
174             tw = tw->parentWidget();
175         return tw == w;
176     }
177 
178     // Below is Qt::WindowShortcut context
179     QWidget *tlw = w->window();
180 #if QT_CONFIG(graphicsview)
181     if (auto topData = static_cast<QWidgetPrivate *>(QObjectPrivate::get(tlw))->extra.get()) {
182         if (topData->proxyWidget) {
183             bool res = correctGraphicsWidgetContext(context, topData->proxyWidget, active_window);
184             return res;
185         }
186     }
187 #endif
188 
189     if (active_window && active_window != tlw) {
190         /* if a floating tool window is active, keep shortcuts on the parent working.
191          * and if a popup window is active (f.ex a completer), keep shortcuts on the
192          * focus proxy working */
193         if (active_window->windowType() == Qt::Tool && active_window->parentWidget()) {
194             active_window = active_window->parentWidget()->window();
195         } else if (active_window->windowType() == Qt::Popup && active_window->focusProxy()) {
196             active_window = active_window->focusProxy()->window();
197         }
198     }
199 
200     if (active_window != tlw) {
201 #if QT_CONFIG(menubar)
202         // If the tlw is a QMenuBar then we allow it to proceed as this indicates that
203         // the QMenuBar is a parentless one and is therefore used for multiple top level
204         // windows in the application. This is common on macOS platforms for example.
205         if (!qobject_cast<QMenuBar *>(tlw))
206 #endif
207         return false;
208     }
209 
210     /* if we live in a MDI subwindow, ignore the event if we are
211        not the active document window */
212     const QWidget* sw = w;
213     while (sw && !(sw->windowType() == Qt::SubWindow) && !sw->isWindow())
214         sw = sw->parentWidget();
215     if (sw && (sw->windowType() == Qt::SubWindow)) {
216         QWidget *focus_widget = QApplication::focusWidget();
217         while (focus_widget && focus_widget != sw)
218             focus_widget = focus_widget->parentWidget();
219         return sw == focus_widget;
220     }
221 
222 #if defined(DEBUG_QSHORTCUTMAP)
223     qDebug().nospace() << "..true [Pass-through]";
224 #endif
225     return QApplicationPrivate::tryModalHelper(w, nullptr);
226 }
227 
228 #if QT_CONFIG(graphicsview)
correctGraphicsWidgetContext(Qt::ShortcutContext context,QGraphicsWidget * w,QWidget * active_window)229 static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window)
230 {
231     bool visible = w->isVisible();
232 #if defined(Q_OS_DARWIN) && QT_CONFIG(menubar)
233     if (!QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast<QMenuBar *>(w))
234         visible = true;
235 #endif
236 
237     if (!visible || !w->isEnabled() || !w->scene())
238         return false;
239 
240     if (context == Qt::ApplicationShortcut) {
241         // Applicationwide shortcuts are always reachable unless their owner
242         // is shadowed by modality. In QGV there's no modality concept, but we
243         // must still check if all views are shadowed.
244         const auto &views = w->scene()->views();
245         for (auto view : views) {
246             if (QApplicationPrivate::tryModalHelper(view, nullptr))
247                 return true;
248         }
249         return false;
250     }
251 
252     if (context == Qt::WidgetShortcut)
253         return static_cast<QGraphicsItem *>(w) == w->scene()->focusItem();
254 
255     if (context == Qt::WidgetWithChildrenShortcut) {
256         const QGraphicsItem *ti = w->scene()->focusItem();
257         if (ti && ti->isWidget()) {
258             const auto *tw = static_cast<const QGraphicsWidget *>(ti);
259             while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup))
260                 tw = tw->parentWidget();
261             return tw == w;
262         }
263         return false;
264     }
265 
266     // Below is Qt::WindowShortcut context
267 
268     // Find the active view (if any).
269     const auto &views = w->scene()->views();
270     QGraphicsView *activeView = nullptr;
271     for (auto view : views) {
272         if (view->window() == active_window) {
273             activeView = view;
274             break;
275         }
276     }
277     if (!activeView)
278         return false;
279 
280     // The shortcut is reachable if owned by a windowless widget, or if the
281     // widget's window is the same as the focus item's window.
282     QGraphicsWidget *a = w->scene()->activeWindow();
283     return !w->window() || a == w->window();
284 }
285 #endif
286 
287 #ifndef QT_NO_ACTION
correctActionContext(Qt::ShortcutContext context,QAction * a,QWidget * active_window)288 static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window)
289 {
290     const QWidgetList &widgets = static_cast<QActionPrivate *>(QObjectPrivate::get(a))->widgets;
291 #if defined(DEBUG_QSHORTCUTMAP)
292     if (widgets.isEmpty())
293         qDebug() << a << "not connected to any widgets; won't trigger";
294 #endif
295     for (auto w : widgets) {
296 #if QT_CONFIG(menu)
297         if (auto menu = qobject_cast<QMenu *>(w)) {
298 #ifdef Q_OS_DARWIN
299             // On Mac, menu item shortcuts are processed before reaching any window.
300             // That means that if a menu action shortcut has not been already processed
301             // (and reaches this point), then the menu item itself has been disabled.
302             // This occurs at the QPA level on Mac, where we disable all the Cocoa menus
303             // when showing a modal window. (Notice that only the QPA menu is disabled,
304             // not the QMenu.) Since we can also reach this code by climbing the menu
305             // hierarchy (see below), or when the shortcut is not a key-equivalent, we
306             // need to check whether the QPA menu is actually disabled.
307             // When there is no QPA menu, there will be no QCocoaMenuDelegate checking
308             // for the actual shortcuts. We can then fallback to our own logic.
309             QPlatformMenu *pm = menu->platformMenu();
310             if (pm && !pm->isEnabled())
311                 continue;
312 #endif
313             QAction *a = menu->menuAction();
314             if (correctActionContext(context, a, active_window))
315                 return true;
316         } else
317 #endif
318             if (correctWidgetContext(context, w, active_window))
319                 return true;
320     }
321 
322 #if QT_CONFIG(graphicsview)
323     const auto &graphicsWidgets = static_cast<QActionPrivate *>(QObjectPrivate::get(a))->graphicsWidgets;
324 #if defined(DEBUG_QSHORTCUTMAP)
325     if (graphicsWidgets.isEmpty())
326         qDebug() << a << "not connected to any widgets; won't trigger";
327 #endif
328     for (auto graphicsWidget : graphicsWidgets) {
329         if (correctGraphicsWidgetContext(context, graphicsWidget, active_window))
330             return true;
331     }
332 #endif
333     return false;
334 }
335 #endif // QT_NO_ACTION
336 
337 
338 /*!
339     \class QShortcut
340     \brief The QShortcut class is used to create keyboard shortcuts.
341 
342     \ingroup events
343     \inmodule QtWidgets
344 
345     The QShortcut class provides a way of connecting keyboard
346     shortcuts to Qt's \l{signals and slots} mechanism, so that
347     objects can be informed when a shortcut is executed. The shortcut
348     can be set up to contain all the key presses necessary to
349     describe a keyboard shortcut, including the states of modifier
350     keys such as \uicontrol Shift, \uicontrol Ctrl, and \uicontrol Alt.
351 
352     \target mnemonic
353 
354     On certain widgets, using '&' in front of a character will
355     automatically create a mnemonic (a shortcut) for that character,
356     e.g. "E&xit" will create the shortcut \uicontrol Alt+X (use '&&' to
357     display an actual ampersand). The widget might consume and perform
358     an action on a given shortcut. On X11 the ampersand will not be
359     shown and the character will be underlined. On Windows, shortcuts
360     are normally not displayed until the user presses the \uicontrol Alt
361     key, but this is a setting the user can change. On Mac, shortcuts
362     are disabled by default. Call \l qt_set_sequence_auto_mnemonic() to
363     enable them. However, because mnemonic shortcuts do not fit in
364     with Aqua's guidelines, Qt will not show the shortcut character
365     underlined.
366 
367     For applications that use menus, it may be more convenient to
368     use the convenience functions provided in the QMenu class to
369     assign keyboard shortcuts to menu items as they are created.
370     Alternatively, shortcuts may be associated with other types of
371     actions in the QAction class.
372 
373     The simplest way to create a shortcut for a particular widget is
374     to construct the shortcut with a key sequence. For example:
375 
376     \snippet code/src_gui_kernel_qshortcut.cpp 0
377 
378     When the user types the \l{QKeySequence}{key sequence}
379     for a given shortcut, the shortcut's activated() signal is
380     emitted. (In the case of ambiguity, the activatedAmbiguously()
381     signal is emitted.) A shortcut is "listened for" by Qt's event
382     loop when the shortcut's parent widget is receiving events.
383 
384     A shortcut's key sequence can be set with setKey() and retrieved
385     with key(). A shortcut can be enabled or disabled with
386     setEnabled(), and can have "What's This?" help text set with
387     setWhatsThis().
388 
389     \sa QShortcutEvent, QKeySequence, QAction
390 */
391 
392 /*!
393     \fn QWidget *QShortcut::parentWidget() const
394 
395     Returns the shortcut's parent widget.
396 */
397 
398 /*!
399     \fn void QShortcut::activated()
400 
401     This signal is emitted when the user types the shortcut's key
402     sequence.
403 
404     \sa activatedAmbiguously()
405 */
406 
407 /*!
408     \fn void QShortcut::activatedAmbiguously()
409 
410     When a key sequence is being typed at the keyboard, it is said to
411     be ambiguous as long as it matches the start of more than one
412     shortcut.
413 
414     When a shortcut's key sequence is completed,
415     activatedAmbiguously() is emitted if the key sequence is still
416     ambiguous (i.e., it is the start of one or more other shortcuts).
417     The activated() signal is not emitted in this case.
418 
419     \sa activated()
420 */
421 
422 /*!
423     \fn template<typename Functor>
424         QShortcut(const QKeySequence &key, QWidget *parent,
425                   Functor functor,
426                   Qt::ShortcutContext shortcutContext = Qt::WindowShortcut);
427     \since 5.15
428     \overload
429 
430     This is a QShortcut convenience constructor which connects the shortcut's
431     \l{QShortcut::activated()}{activated()} signal to the \a functor.
432 */
433 /*!
434     \fn template<typename Functor>
435         QShortcut(const QKeySequence &key, QWidget *parent,
436                   const QObject *context, Functor functor,
437                   Qt::ShortcutContext shortcutContext = Qt::WindowShortcut);
438     \since 5.15
439     \overload
440 
441     This is a QShortcut convenience constructor which connects the shortcut's
442     \l{QShortcut::activated()}{activated()} signal to the \a functor.
443 
444     The \a functor can be a pointer to a member function of the \a context object.
445 
446     If the \a context object is destroyed, the \a functor will not be called.
447 */
448 /*!
449     \fn template<typename Functor, typename FunctorAmbiguous>
450         QShortcut(const QKeySequence &key, QWidget *parent,
451                   const QObject *context1, Functor functor,
452                   FunctorAmbiguous functorAmbiguous,
453                   Qt::ShortcutContext shortcutContext = Qt::WindowShortcut);
454     \since 5.15
455     \overload
456 
457     This is a QShortcut convenience constructor which connects the shortcut's
458     \l{QShortcut::activated()}{activated()} signal to the \a functor and
459     \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
460     signal to the \a FunctorAmbiguous.
461 
462     The \a functor and \a FunctorAmbiguous can be a pointer to a member
463     function of the \a context object.
464 
465     If the \a context object is destroyed, the \a functor and
466     \a FunctorAmbiguous will not be called.
467 */
468 /*!
469     \fn template<typename Functor, typename FunctorAmbiguous>
470         QShortcut(const QKeySequence &key, QWidget *parent,
471                   const QObject *context1, Functor functor,
472                   const QObject *context2, FunctorAmbiguous functorAmbiguous,
473                   Qt::ShortcutContext shortcutContext = Qt::WindowShortcut);
474     \since 5.15
475     \overload
476 
477     This is a QShortcut convenience constructor which connects the shortcut's
478     \l{QShortcut::activated()}{activated()} signal to the \a functor and
479     \l{QShortcut::activatedAmbiguously()}{activatedAmbiguously()}
480     signal to the \a FunctorAmbiguous.
481 
482     The \a functor can be a pointer to a member function of the
483     \a context1 object.
484     The \a FunctorAmbiguous can be a pointer to a member function of the
485     \a context2 object.
486 
487     If the \a context1 object is destroyed, the \a functor will not be called.
488     If the \a context2 object is destroyed, the \a FunctorAmbiguous
489     will not be called.
490 */
491 
492 /*
493     \internal
494     Private data accessed through d-pointer.
495 */
496 class QShortcutPrivate : public QObjectPrivate
497 {
498     Q_DECLARE_PUBLIC(QShortcut)
499 public:
500     QShortcutPrivate() = default;
501     QKeySequence sc_sequence;
502     Qt::ShortcutContext sc_context = Qt::WindowShortcut;
503     bool sc_enabled = true;
504     bool sc_autorepeat = true;
505     int sc_id = 0;
506     QString sc_whatsthis;
507     void redoGrab(QShortcutMap &map);
508 };
509 
redoGrab(QShortcutMap & map)510 void QShortcutPrivate::redoGrab(QShortcutMap &map)
511 {
512     Q_Q(QShortcut);
513     if (Q_UNLIKELY(!parent)) {
514         qWarning("QShortcut: No widget parent defined");
515         return;
516     }
517 
518     if (sc_id)
519         map.removeShortcut(sc_id, q);
520     if (sc_sequence.isEmpty())
521         return;
522     sc_id = map.addShortcut(q, sc_sequence, sc_context, qWidgetShortcutContextMatcher);
523     if (!sc_enabled)
524         map.setShortcutEnabled(false, sc_id, q);
525     if (!sc_autorepeat)
526         map.setShortcutAutoRepeat(false, sc_id, q);
527 }
528 
529 /*!
530     Constructs a QShortcut object for the \a parent widget. Since no
531     shortcut key sequence is specified, the shortcut will not emit any
532     signals.
533 
534     \sa setKey()
535 */
QShortcut(QWidget * parent)536 QShortcut::QShortcut(QWidget *parent)
537     : QObject(*new QShortcutPrivate, parent)
538 {
539     Q_ASSERT(parent != nullptr);
540 }
541 
542 /*!
543     Constructs a QShortcut object for the \a parent widget. The shortcut
544     operates on its parent, listening for \l{QShortcutEvent}s that
545     match the \a key sequence. Depending on the ambiguity of the
546     event, the shortcut will call the \a member function, or the \a
547     ambiguousMember function, if the key press was in the shortcut's
548     \a shortcutContext.
549 */
QShortcut(const QKeySequence & key,QWidget * parent,const char * member,const char * ambiguousMember,Qt::ShortcutContext shortcutContext)550 QShortcut::QShortcut(const QKeySequence &key, QWidget *parent,
551                      const char *member, const char *ambiguousMember,
552                      Qt::ShortcutContext shortcutContext)
553     : QShortcut(parent)
554 {
555     QAPP_CHECK("QShortcut");
556 
557     Q_D(QShortcut);
558     d->sc_context = shortcutContext;
559     d->sc_sequence = key;
560     d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
561     if (member)
562         connect(this, SIGNAL(activated()), parent, member);
563     if (ambiguousMember)
564         connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember);
565 }
566 
567 /*!
568     Destroys the shortcut.
569 */
~QShortcut()570 QShortcut::~QShortcut()
571 {
572     Q_D(QShortcut);
573     if (qApp)
574         QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this);
575 }
576 
577 /*!
578     \property QShortcut::key
579     \brief the shortcut's key sequence
580 
581     This is a key sequence with an optional combination of Shift, Ctrl,
582     and Alt. The key sequence may be supplied in a number of ways:
583 
584     \snippet code/src_gui_kernel_qshortcut.cpp 1
585 
586     By default, this property contains an empty key sequence.
587 */
setKey(const QKeySequence & key)588 void QShortcut::setKey(const QKeySequence &key)
589 {
590     Q_D(QShortcut);
591     if (d->sc_sequence == key)
592         return;
593     QAPP_CHECK("setKey");
594     d->sc_sequence = key;
595     d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
596 }
597 
key() const598 QKeySequence QShortcut::key() const
599 {
600     Q_D(const QShortcut);
601     return d->sc_sequence;
602 }
603 
604 /*!
605     \property QShortcut::enabled
606     \brief whether the shortcut is enabled
607 
608     An enabled shortcut emits the activated() or activatedAmbiguously()
609     signal when a QShortcutEvent occurs that matches the shortcut's
610     key() sequence.
611 
612     If the application is in \c WhatsThis mode the shortcut will not emit
613     the signals, but will show the "What's This?" text instead.
614 
615     By default, this property is \c true.
616 
617     \sa whatsThis
618 */
setEnabled(bool enable)619 void QShortcut::setEnabled(bool enable)
620 {
621     Q_D(QShortcut);
622     if (d->sc_enabled == enable)
623         return;
624     QAPP_CHECK("setEnabled");
625     d->sc_enabled = enable;
626     QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this);
627 }
628 
isEnabled() const629 bool QShortcut::isEnabled() const
630 {
631     Q_D(const QShortcut);
632     return d->sc_enabled;
633 }
634 
635 /*!
636     \property QShortcut::context
637     \brief the context in which the shortcut is valid
638 
639     A shortcut's context decides in which circumstances a shortcut is
640     allowed to be triggered. The normal context is Qt::WindowShortcut,
641     which allows the shortcut to trigger if the parent (the widget
642     containing the shortcut) is a subwidget of the active top-level
643     window.
644 
645     By default, this property is set to Qt::WindowShortcut.
646 */
setContext(Qt::ShortcutContext context)647 void QShortcut::setContext(Qt::ShortcutContext context)
648 {
649     Q_D(QShortcut);
650     if(d->sc_context == context)
651         return;
652     QAPP_CHECK("setContext");
653     d->sc_context = context;
654     d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap);
655 }
656 
context() const657 Qt::ShortcutContext QShortcut::context() const
658 {
659     Q_D(const QShortcut);
660     return d->sc_context;
661 }
662 
663 /*!
664     \property QShortcut::whatsThis
665     \brief the shortcut's "What's This?" help text
666 
667     The text will be shown when the application is in "What's
668     This?" mode and the user types the shortcut key() sequence.
669 
670     To set "What's This?" help on a menu item (with or without a
671     shortcut key), set the help on the item's action.
672 
673     By default, this property contains an empty string.
674 
675     \sa QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis()
676 */
setWhatsThis(const QString & text)677 void QShortcut::setWhatsThis(const QString &text)
678 {
679     Q_D(QShortcut);
680     d->sc_whatsthis = text;
681 }
682 
whatsThis() const683 QString QShortcut::whatsThis() const
684 {
685     Q_D(const QShortcut);
686     return d->sc_whatsthis;
687 }
688 
689 /*!
690     \property QShortcut::autoRepeat
691     \brief whether the shortcut can auto repeat
692     \since 4.2
693 
694     If true, the shortcut will auto repeat when the keyboard shortcut
695     combination is held down, provided that keyboard auto repeat is
696     enabled on the system.
697     The default value is true.
698 */
setAutoRepeat(bool on)699 void QShortcut::setAutoRepeat(bool on)
700 {
701     Q_D(QShortcut);
702     if (d->sc_autorepeat == on)
703         return;
704     QAPP_CHECK("setAutoRepeat");
705     d->sc_autorepeat = on;
706     QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this);
707 }
708 
autoRepeat() const709 bool QShortcut::autoRepeat() const
710 {
711     Q_D(const QShortcut);
712     return d->sc_autorepeat;
713 }
714 
715 /*!
716     Returns the shortcut's ID.
717 
718     \sa QShortcutEvent::shortcutId()
719 */
id() const720 int QShortcut::id() const
721 {
722     Q_D(const QShortcut);
723     return d->sc_id;
724 }
725 
726 /*!
727     \internal
728 */
event(QEvent * e)729 bool QShortcut::event(QEvent *e)
730 {
731     Q_D(QShortcut);
732     if (d->sc_enabled && e->type() == QEvent::Shortcut) {
733         auto se = static_cast<QShortcutEvent *>(e);
734         if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence){
735 #if QT_CONFIG(whatsthis)
736             if (QWhatsThis::inWhatsThisMode()) {
737                 QWhatsThis::showText(QCursor::pos(), d->sc_whatsthis);
738             } else
739 #endif
740             if (se->isAmbiguous())
741                 emit activatedAmbiguously();
742             else
743                 emit activated();
744             return true;
745         }
746     }
747     return QObject::event(e);
748 }
749 #endif // QT_NO_SHORTCUT
750 
751 QT_END_NAMESPACE
752 
753 #include "moc_qshortcut.cpp"
754