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 | */ |
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 *>(object: 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, w: gw, active_window); |
119 | #endif |
120 | |
121 | auto w = qobject_cast<QWidget *>(o: 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 *>(o: object); |
129 | while (qwindow) { |
130 | if (auto widget_window = qobject_cast<QWidgetWindow *>(object: 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 | |
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 = qobject_cast<QMenuBar *>(object: w)) { |
149 | if (auto *pmb = menuBar->platformMenuBar()) { |
150 | if (menuBar->parentWidget()) { |
151 | visible = true; |
152 | } else { |
153 | if (auto *ww = qobject_cast<QWidgetWindow *>(object: 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(widget: w, rettop: 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(o: tlw))->extra.get()) { |
182 | if (topData->proxyWidget) { |
183 | bool res = correctGraphicsWidgetContext(context, w: 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 *>(object: 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(widget: w, rettop: nullptr); |
226 | } |
227 | |
228 | #if QT_CONFIG(graphicsview) |
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(widget: view, rettop: 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 |
288 | static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window) |
289 | { |
290 | const QWidgetList &widgets = static_cast<QActionPrivate *>(QObjectPrivate::get(o: 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 = qobject_cast<QMenu *>(object: 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(o: 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, w: 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 | |
510 | void QShortcutPrivate::redoGrab(QShortcutMap &map) |
511 | { |
512 | Q_Q(QShortcut); |
513 | if (Q_UNLIKELY(!parent)) { |
514 | qWarning(msg: "QShortcut: No widget parent defined" ); |
515 | return; |
516 | } |
517 | |
518 | if (sc_id) |
519 | map.removeShortcut(id: sc_id, owner: q); |
520 | if (sc_sequence.isEmpty()) |
521 | return; |
522 | sc_id = map.addShortcut(owner: q, key: sc_sequence, context: sc_context, matcher: qWidgetShortcutContextMatcher); |
523 | if (!sc_enabled) |
524 | map.setShortcutEnabled(enable: false, id: sc_id, owner: q); |
525 | if (!sc_autorepeat) |
526 | map.setShortcutAutoRepeat(on: false, id: sc_id, owner: 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 | */ |
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 | */ |
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(map&: QGuiApplicationPrivate::instance()->shortcutMap); |
561 | if (member) |
562 | connect(sender: this, SIGNAL(activated()), receiver: parent, member); |
563 | if (ambiguousMember) |
564 | connect(sender: this, SIGNAL(activatedAmbiguously()), receiver: parent, member: ambiguousMember); |
565 | } |
566 | |
567 | /*! |
568 | Destroys the shortcut. |
569 | */ |
570 | QShortcut::~QShortcut() |
571 | { |
572 | Q_D(QShortcut); |
573 | if (qApp) |
574 | QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id: d->sc_id, owner: 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 | */ |
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(map&: QGuiApplicationPrivate::instance()->shortcutMap); |
596 | } |
597 | |
598 | 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 | */ |
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, id: d->sc_id, owner: this); |
627 | } |
628 | |
629 | 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 | */ |
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(map&: QGuiApplicationPrivate::instance()->shortcutMap); |
655 | } |
656 | |
657 | 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 | */ |
677 | void QShortcut::setWhatsThis(const QString &text) |
678 | { |
679 | Q_D(QShortcut); |
680 | d->sc_whatsthis = text; |
681 | } |
682 | |
683 | 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 | */ |
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, id: d->sc_id, owner: this); |
707 | } |
708 | |
709 | 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 | */ |
720 | int QShortcut::id() const |
721 | { |
722 | Q_D(const QShortcut); |
723 | return d->sc_id; |
724 | } |
725 | |
726 | /*! |
727 | \internal |
728 | */ |
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(pos: QCursor::pos(), text: 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(event: e); |
748 | } |
749 | #endif // QT_NO_SHORTCUT |
750 | |
751 | QT_END_NAMESPACE |
752 | |
753 | #include "moc_qshortcut.cpp" |
754 | |