From 89f1f14c5e9a49f25345a65d81b3518d58ecb91a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@qt.io> Date: Tue, 22 Oct 2019 10:53:54 +0200 Subject: [PATCH] Extract QGuiShortcut [ChangeLog][QtGui] Added QGuiShortcut and made the equivalent existing classes in Qt Widgets derive from them. This provides basic functionality for adding shortcut handling in QML. Fixes: QTBUG-79638 Task-number: QTBUG-76493 Change-Id: I5bbd2c8f192660e93c4690b9f894643275090e4d Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> --- src/gui/kernel/kernel.pri | 3 + src/gui/kernel/qguishortcut.cpp | 354 ++++++++++++++++++ src/gui/kernel/qguishortcut.h | 98 +++++ src/gui/kernel/qguishortcut_p.h | 92 +++++ src/widgets/kernel/qshortcut.cpp | 240 +----------- src/widgets/kernel/qshortcut.h | 39 +- tests/auto/gui/kernel/kernel.pro | 2 + .../gui/kernel/qguishortcut/qguishortcut.pro | 4 + .../kernel/qguishortcut/tst_qguishortcut.cpp | 82 ++++ 9 files changed, 659 insertions(+), 255 deletions(-) create mode 100644 src/gui/kernel/qguishortcut.cpp create mode 100644 src/gui/kernel/qguishortcut.h create mode 100644 src/gui/kernel/qguishortcut_p.h create mode 100644 tests/auto/gui/kernel/qguishortcut/qguishortcut.pro create mode 100644 tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 42bb81fa24..3784abdacc 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -169,10 +169,13 @@ qtConfig(opengl) { qtConfig(shortcut) { HEADERS += \ + kernel/qguishortcut.h \ + kernel/qguishortcut_p.h \ kernel/qshortcutmap_p.h \ kernel/qkeysequence.h \ kernel/qkeysequence_p.h SOURCES += \ + kernel/qguishortcut.cpp \ kernel/qshortcutmap.cpp \ kernel/qkeysequence.cpp } diff --git a/src/gui/kernel/qguishortcut.cpp b/src/gui/kernel/qguishortcut.cpp new file mode 100644 index 0000000000..add1dce12e --- /dev/null +++ b/src/gui/kernel/qguishortcut.cpp @@ -0,0 +1,354 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguishortcut.h" +#include "qguishortcut_p.h" + +#include <qevent.h> +#include <qguiapplication.h> +#include <qwindow.h> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformmenu.h> + +QT_BEGIN_NAMESPACE + +#define QAPP_CHECK(functionName) \ + if (Q_UNLIKELY(!qApp)) { \ + qWarning("QGuiShortcut: Initialize QGuiApplication before calling '" functionName "'."); \ + return; \ + } + +/*! + \class QGuiShortcut + \brief The QGuiShortcut class is a base class for handling keyboard shortcuts. + + \ingroup events + \inmodule QtGui + \since 6.0 + + The QGuiShortcut class is a base class for classes providing a way of + connecting keyboard shortcuts to Qt's \l{signals and slots} mechanism, + so that objects can be informed when a shortcut is executed. The shortcut + can be set up to contain all the key presses necessary to + describe a keyboard shortcut, including the states of modifier + keys such as \uicontrol Shift, \uicontrol Ctrl, and \uicontrol Alt. + + \target mnemonic + + \sa QShortcutEvent, QKeySequence, QAction +*/ + +/*! + \fn void QGuiShortcut::activated() + + This signal is emitted when the user types the shortcut's key + sequence. + + \sa activatedAmbiguously() +*/ + +/*! + \fn void QGuiShortcut::activatedAmbiguously() + + When a key sequence is being typed at the keyboard, it is said to + be ambiguous as long as it matches the start of more than one + shortcut. + + When a shortcut's key sequence is completed, + activatedAmbiguously() is emitted if the key sequence is still + ambiguous (i.e., it is the start of one or more other shortcuts). + The activated() signal is not emitted in this case. + + \sa activated() +*/ + +static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context) +{ + auto guiShortcut = qobject_cast<QGuiShortcut *>(object); + if (QGuiApplication::applicationState() != Qt::ApplicationActive || guiShortcut == nullptr) + return false; + if (context == Qt::ApplicationShortcut) + return true; + auto focusWindow = QGuiApplication::focusWindow(); + if (!focusWindow) + return false; + auto window = qobject_cast<const QWindow *>(guiShortcut->parent()); + if (!window) + return false; + if (focusWindow == window && focusWindow->isTopLevel()) + return context == Qt::WindowShortcut || context == Qt::WidgetWithChildrenShortcut; + return focusWindow->isAncestorOf(window, QWindow::ExcludeTransients); +} + +QShortcutMap::ContextMatcher QGuiShortcutPrivate::contextMatcher() const +{ + return simpleContextMatcher; +} + +void QGuiShortcutPrivate::redoGrab(QShortcutMap &map) +{ + Q_Q(QGuiShortcut); + if (Q_UNLIKELY(!parent)) { + qWarning("QGuiShortcut: No window parent defined"); + return; + } + + if (sc_id) + map.removeShortcut(sc_id, q); + if (sc_sequence.isEmpty()) + return; + sc_id = map.addShortcut(q, sc_sequence, sc_context, contextMatcher()); + if (!sc_enabled) + map.setShortcutEnabled(false, sc_id, q); + if (!sc_autorepeat) + map.setShortcutAutoRepeat(false, sc_id, q); +} + +/*! + Constructs a QGuiShortcut object for the \a parent window. Since no + shortcut key sequence is specified, the shortcut will not emit any + signals. + + \sa setKey() +*/ +QGuiShortcut::QGuiShortcut(QWindow *parent) + : QGuiShortcut(*new QGuiShortcutPrivate, parent) +{ +} + +/*! + Constructs a QGuiShortcut object for the \a parent window. The shortcut + operates on its parent, listening for \l{QShortcutEvent}s that + match the \a key sequence. Depending on the ambiguity of the + event, the shortcut will call the \a member function, or the \a + ambiguousMember function, if the key press was in the shortcut's + \a context. +*/ +QGuiShortcut::QGuiShortcut(const QKeySequence &key, QWindow *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context) + : QGuiShortcut(*new QGuiShortcutPrivate, key, parent, member, ambiguousMember, context) +{ +} + +/*! + \internal +*/ +QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_ASSERT(parent != nullptr); +} + +/*! + \internal +*/ +QGuiShortcut::QGuiShortcut(QGuiShortcutPrivate &dd, + const QKeySequence &key, QObject *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context) + : QGuiShortcut(dd, parent) +{ + QAPP_CHECK("QGuiShortcut"); + + Q_D(QGuiShortcut); + d->sc_context = context; + d->sc_sequence = key; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); + if (member) + connect(this, SIGNAL(activated()), parent, member); + if (ambiguousMember) + connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember); +} + +/*! + Destroys the shortcut. +*/ +QGuiShortcut::~QGuiShortcut() +{ + Q_D(QGuiShortcut); + if (qApp) + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this); +} + +/*! + \property QGuiShortcut::key + \brief the shortcut's key sequence + + This is a key sequence with an optional combination of Shift, Ctrl, + and Alt. The key sequence may be supplied in a number of ways: + + \snippet code/src_gui_kernel_qshortcut.cpp 1 + + By default, this property contains an empty key sequence. +*/ +void QGuiShortcut::setKey(const QKeySequence &key) +{ + Q_D(QGuiShortcut); + if (d->sc_sequence == key) + return; + QAPP_CHECK("setKey"); + d->sc_sequence = key; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); +} + +QKeySequence QGuiShortcut::key() const +{ + Q_D(const QGuiShortcut); + return d->sc_sequence; +} + +/*! + \property QGuiShortcut::enabled + \brief whether the shortcut is enabled + + An enabled shortcut emits the activated() or activatedAmbiguously() + signal when a QShortcutEvent occurs that matches the shortcut's + key() sequence. + + If the application is in \c WhatsThis mode the shortcut will not emit + the signals, but will show the "What's This?" text instead. + + By default, this property is \c true. + + \sa whatsThis +*/ +void QGuiShortcut::setEnabled(bool enable) +{ + Q_D(QGuiShortcut); + if (d->sc_enabled == enable) + return; + QAPP_CHECK("setEnabled"); + d->sc_enabled = enable; + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this); +} + +bool QGuiShortcut::isEnabled() const +{ + Q_D(const QGuiShortcut); + return d->sc_enabled; +} + +/*! + \property QGuiShortcut::context + \brief the context in which the shortcut is valid + + A shortcut's context decides in which circumstances a shortcut is + allowed to be triggered. The normal context is Qt::WindowShortcut, + which allows the shortcut to trigger if the parent (the widget + containing the shortcut) is a subwidget of the active top-level + window. + + By default, this property is set to Qt::WindowShortcut. +*/ +void QGuiShortcut::setContext(Qt::ShortcutContext context) +{ + Q_D(QGuiShortcut); + if (d->sc_context == context) + return; + QAPP_CHECK("setContext"); + d->sc_context = context; + d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); +} + +Qt::ShortcutContext QGuiShortcut::context() const +{ + Q_D(const QGuiShortcut); + return d->sc_context; +} + +/*! + \property QGuiShortcut::autoRepeat + \brief whether the shortcut can auto repeat + + If true, the shortcut will auto repeat when the keyboard shortcut + combination is held down, provided that keyboard auto repeat is + enabled on the system. + The default value is true. +*/ +void QGuiShortcut::setAutoRepeat(bool on) +{ + Q_D(QGuiShortcut); + if (d->sc_autorepeat == on) + return; + QAPP_CHECK("setAutoRepeat"); + d->sc_autorepeat = on; + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this); +} + +bool QGuiShortcut::autoRepeat() const +{ + Q_D(const QGuiShortcut); + return d->sc_autorepeat; +} + +/*! + Returns the shortcut's ID. + + \sa QShortcutEvent::shortcutId() +*/ +int QGuiShortcut::id() const +{ + Q_D(const QGuiShortcut); + return d->sc_id; +} + +/*! + \internal +*/ +bool QGuiShortcut::event(QEvent *e) +{ + Q_D(QGuiShortcut); + if (d->sc_enabled && e->type() == QEvent::Shortcut) { + auto se = static_cast<QShortcutEvent *>(e); + if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence + && !d->handleWhatsThis()) { + if (se->isAmbiguous()) + emit activatedAmbiguously(); + else + emit activated(); + return true; + } + } + return QObject::event(e); +} + +QT_END_NAMESPACE + +#include "moc_qguishortcut.cpp" diff --git a/src/gui/kernel/qguishortcut.h b/src/gui/kernel/qguishortcut.h new file mode 100644 index 0000000000..fb64f10c84 --- /dev/null +++ b/src/gui/kernel/qguishortcut.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUISHORTCUT_H +#define QGUISHORTCUT_H + +#include <QtGui/qtguiglobal.h> +#include <QtGui/qkeysequence.h> +#include <QtCore/qobject.h> + +QT_REQUIRE_CONFIG(shortcut); + +QT_BEGIN_NAMESPACE + +class QGuiShortcutPrivate; +class QWindow; + +class Q_GUI_EXPORT QGuiShortcut : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGuiShortcut) + Q_PROPERTY(QKeySequence key READ key WRITE setKey) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat) + Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext) +public: + explicit QGuiShortcut(QWindow *parent); + explicit QGuiShortcut(const QKeySequence& key, QWindow *parent, + const char *member = nullptr, const char *ambiguousMember = nullptr, + Qt::ShortcutContext context = Qt::WindowShortcut); + ~QGuiShortcut(); + + void setKey(const QKeySequence& key); + QKeySequence key() const; + + void setEnabled(bool enable); + bool isEnabled() const; + + void setContext(Qt::ShortcutContext context); + Qt::ShortcutContext context() const; + + void setAutoRepeat(bool on); + bool autoRepeat() const; + + int id() const; + +Q_SIGNALS: + void activated(); + void activatedAmbiguously(); + +protected: + QGuiShortcut(QGuiShortcutPrivate &dd, QObject *parent); + QGuiShortcut(QGuiShortcutPrivate &dd, const QKeySequence& key, QObject *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext context); + + bool event(QEvent *e) override; +}; + +QT_END_NAMESPACE + +#endif // QGUISHORTCUT_H diff --git a/src/gui/kernel/qguishortcut_p.h b/src/gui/kernel/qguishortcut_p.h new file mode 100644 index 0000000000..420b02ef1a --- /dev/null +++ b/src/gui/kernel/qguishortcut_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUISHORTCUT_P_H +#define QGUISHORTCUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qtguiglobal_p.h> +#include "qguishortcut.h" +#include <QtGui/qkeysequence.h> + +#include <QtCore/qstring.h> +#include <QtCore/private/qobject_p.h> + +#include <private/qshortcutmap_p.h> + + + +QT_BEGIN_NAMESPACE + +class QShortcutMap; + +/* + \internal + Private data accessed through d-pointer. +*/ +class Q_GUI_EXPORT QGuiShortcutPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGuiShortcut) +public: + QGuiShortcutPrivate() = default; + + virtual QShortcutMap::ContextMatcher contextMatcher() const; + virtual bool handleWhatsThis() { return false; } + + QKeySequence sc_sequence; + Qt::ShortcutContext sc_context = Qt::WindowShortcut; + bool sc_enabled = true; + bool sc_autorepeat = true; + int sc_id = 0; + void redoGrab(QShortcutMap &map); +}; + +QT_END_NAMESPACE + +#endif // QGUISHORTCUT_P_H diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp index be5708aea7..fe94f676df 100644 --- a/src/widgets/kernel/qshortcut.cpp +++ b/src/widgets/kernel/qshortcut.cpp @@ -52,6 +52,7 @@ #endif #include <qapplication.h> #include <private/qapplication_p.h> +#include "private/qguishortcut_p.h" #include <private/qshortcutmap_p.h> #if QT_CONFIG(action) # include <private/qaction_p.h> @@ -61,13 +62,6 @@ QT_BEGIN_NAMESPACE -#define QAPP_CHECK(functionName) \ - if (Q_UNLIKELY(!qApp)) { \ - qWarning("QShortcut: Initialize QApplication before calling '" functionName "'."); \ - return; \ - } - - static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window); #if QT_CONFIG(graphicsview) static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window); @@ -396,65 +390,30 @@ static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidge Returns the shortcut's parent widget. */ -/*! - \fn void QShortcut::activated() - - This signal is emitted when the user types the shortcut's key - sequence. - - \sa activatedAmbiguously() -*/ - -/*! - \fn void QShortcut::activatedAmbiguously() - - When a key sequence is being typed at the keyboard, it is said to - be ambiguous as long as it matches the start of more than one - shortcut. - - When a shortcut's key sequence is completed, - activatedAmbiguously() is emitted if the key sequence is still - ambiguous (i.e., it is the start of one or more other shortcuts). - The activated() signal is not emitted in this case. - - \sa activated() -*/ - /* \internal Private data accessed through d-pointer. */ -class QShortcutPrivate : public QObjectPrivate +class QShortcutPrivate : public QGuiShortcutPrivate { Q_DECLARE_PUBLIC(QShortcut) public: QShortcutPrivate() = default; - QKeySequence sc_sequence; - Qt::ShortcutContext sc_context = Qt::WindowShortcut; - bool sc_enabled = true; - bool sc_autorepeat = true; - int sc_id = 0; + + QShortcutMap::ContextMatcher contextMatcher() const override + { return qWidgetShortcutContextMatcher; } + + bool handleWhatsThis() override; + QString sc_whatsthis; - void redoGrab(QShortcutMap &map); }; -void QShortcutPrivate::redoGrab(QShortcutMap &map) +bool QShortcutPrivate::handleWhatsThis() { - Q_Q(QShortcut); - if (Q_UNLIKELY(!parent)) { - qWarning("QShortcut: No widget parent defined"); - return; - } - - if (sc_id) - map.removeShortcut(sc_id, q); - if (sc_sequence.isEmpty()) - return; - sc_id = map.addShortcut(q, sc_sequence, sc_context, qWidgetShortcutContextMatcher); - if (!sc_enabled) - map.setShortcutEnabled(false, sc_id, q); - if (!sc_autorepeat) - map.setShortcutAutoRepeat(false, sc_id, q); + const bool result = QWhatsThis::inWhatsThisMode(); + if (result) + QWhatsThis::showText(QCursor::pos(), sc_whatsthis); + return result; } /*! @@ -465,9 +424,8 @@ void QShortcutPrivate::redoGrab(QShortcutMap &map) \sa setKey() */ QShortcut::QShortcut(QWidget *parent) - : QObject(*new QShortcutPrivate, parent) + : QGuiShortcut(*new QShortcutPrivate, parent) { - Q_ASSERT(parent != nullptr); } /*! @@ -481,114 +439,8 @@ QShortcut::QShortcut(QWidget *parent) QShortcut::QShortcut(const QKeySequence &key, QWidget *parent, const char *member, const char *ambiguousMember, Qt::ShortcutContext context) - : QShortcut(parent) + : QGuiShortcut(*new QShortcutPrivate, key, parent, member, ambiguousMember, context) { - QAPP_CHECK("QShortcut"); - - Q_D(QShortcut); - d->sc_context = context; - d->sc_sequence = key; - d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); - if (member) - connect(this, SIGNAL(activated()), parent, member); - if (ambiguousMember) - connect(this, SIGNAL(activatedAmbiguously()), parent, ambiguousMember); -} - -/*! - Destroys the shortcut. -*/ -QShortcut::~QShortcut() -{ - Q_D(QShortcut); - if (qApp) - QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->sc_id, this); -} - -/*! - \property QShortcut::key - \brief the shortcut's key sequence - - This is a key sequence with an optional combination of Shift, Ctrl, - and Alt. The key sequence may be supplied in a number of ways: - - \snippet code/src_gui_kernel_qshortcut.cpp 1 - - By default, this property contains an empty key sequence. -*/ -void QShortcut::setKey(const QKeySequence &key) -{ - Q_D(QShortcut); - if (d->sc_sequence == key) - return; - QAPP_CHECK("setKey"); - d->sc_sequence = key; - d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); -} - -QKeySequence QShortcut::key() const -{ - Q_D(const QShortcut); - return d->sc_sequence; -} - -/*! - \property QShortcut::enabled - \brief whether the shortcut is enabled - - An enabled shortcut emits the activated() or activatedAmbiguously() - signal when a QShortcutEvent occurs that matches the shortcut's - key() sequence. - - If the application is in \c WhatsThis mode the shortcut will not emit - the signals, but will show the "What's This?" text instead. - - By default, this property is \c true. - - \sa whatsThis -*/ -void QShortcut::setEnabled(bool enable) -{ - Q_D(QShortcut); - if (d->sc_enabled == enable) - return; - QAPP_CHECK("setEnabled"); - d->sc_enabled = enable; - QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable, d->sc_id, this); -} - -bool QShortcut::isEnabled() const -{ - Q_D(const QShortcut); - return d->sc_enabled; -} - -/*! - \property QShortcut::context - \brief the context in which the shortcut is valid - - A shortcut's context decides in which circumstances a shortcut is - allowed to be triggered. The normal context is Qt::WindowShortcut, - which allows the shortcut to trigger if the parent (the widget - containing the shortcut) is a subwidget of the active top-level - window. - - By default, this property is set to Qt::WindowShortcut. -*/ -void QShortcut::setContext(Qt::ShortcutContext context) -{ - Q_D(QShortcut); - if(d->sc_context == context) - return; - QAPP_CHECK("setContext"); - d->sc_context = context; - d->redoGrab(QGuiApplicationPrivate::instance()->shortcutMap); -} - -Qt::ShortcutContext QShortcut::context() const -{ - Q_D(const QShortcut); - return d->sc_context; } /*! @@ -618,66 +470,8 @@ QString QShortcut::whatsThis() const } /*! - \property QShortcut::autoRepeat - \brief whether the shortcut can auto repeat - \since 4.2 - - If true, the shortcut will auto repeat when the keyboard shortcut - combination is held down, provided that keyboard auto repeat is - enabled on the system. - The default value is true. + Destroys the shortcut. */ -void QShortcut::setAutoRepeat(bool on) -{ - Q_D(QShortcut); - if (d->sc_autorepeat == on) - return; - QAPP_CHECK("setAutoRepeat"); - d->sc_autorepeat = on; - QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on, d->sc_id, this); -} - -bool QShortcut::autoRepeat() const -{ - Q_D(const QShortcut); - return d->sc_autorepeat; -} - -/*! - Returns the shortcut's ID. - - \sa QShortcutEvent::shortcutId() -*/ -int QShortcut::id() const -{ - Q_D(const QShortcut); - return d->sc_id; -} - -/*! - \internal -*/ -bool QShortcut::event(QEvent *e) -{ - Q_D(QShortcut); - if (d->sc_enabled && e->type() == QEvent::Shortcut) { - auto se = static_cast<QShortcutEvent *>(e); - if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence){ -#if QT_CONFIG(whatsthis) - if (QWhatsThis::inWhatsThisMode()) { - QWhatsThis::showText(QCursor::pos(), d->sc_whatsthis); - } else -#endif - if (se->isAmbiguous()) - emit activatedAmbiguously(); - else - emit activated(); - return true; - } - } - return QObject::event(e); -} +QShortcut::~QShortcut() = default; QT_END_NAMESPACE - -#include "moc_qshortcut.cpp" diff --git a/src/widgets/kernel/qshortcut.h b/src/widgets/kernel/qshortcut.h index 6334788bce..6ac9a37fe3 100644 --- a/src/widgets/kernel/qshortcut.h +++ b/src/widgets/kernel/qshortcut.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -42,55 +42,30 @@ #include <QtWidgets/qtwidgetsglobal.h> #include <QtWidgets/qwidget.h> -#include <QtGui/qkeysequence.h> +#include <QtGui/qguishortcut.h> QT_REQUIRE_CONFIG(shortcut); QT_BEGIN_NAMESPACE class QShortcutPrivate; -class Q_WIDGETS_EXPORT QShortcut : public QObject +class Q_WIDGETS_EXPORT QShortcut : public QGuiShortcut { Q_OBJECT - Q_DECLARE_PRIVATE(QShortcut) - Q_PROPERTY(QKeySequence key READ key WRITE setKey) Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) - Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat) - Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext) + Q_DECLARE_PRIVATE(QShortcut) public: explicit QShortcut(QWidget *parent); - QShortcut(const QKeySequence& key, QWidget *parent, - const char *member = nullptr, const char *ambiguousMember = nullptr, - Qt::ShortcutContext context = Qt::WindowShortcut); + explicit QShortcut(const QKeySequence& key, QWidget *parent, + const char *member = nullptr, const char *ambiguousMember = nullptr, + Qt::ShortcutContext context = Qt::WindowShortcut); ~QShortcut(); - void setKey(const QKeySequence& key); - QKeySequence key() const; - - void setEnabled(bool enable); - bool isEnabled() const; - - void setContext(Qt::ShortcutContext context); - Qt::ShortcutContext context() const; - void setWhatsThis(const QString &text); QString whatsThis() const; - void setAutoRepeat(bool on); - bool autoRepeat() const; - - int id() const; - inline QWidget *parentWidget() const { return static_cast<QWidget *>(QObject::parent()); } - -Q_SIGNALS: - void activated(); - void activatedAmbiguously(); - -protected: - bool event(QEvent *e) override; }; QT_END_NAMESPACE diff --git a/tests/auto/gui/kernel/kernel.pro b/tests/auto/gui/kernel/kernel.pro index 134aca72f1..106e9050b8 100644 --- a/tests/auto/gui/kernel/kernel.pro +++ b/tests/auto/gui/kernel/kernel.pro @@ -11,6 +11,7 @@ SUBDIRS=\ qguieventdispatcher \ qguieventloop \ qguimetatype \ + qguishortcut \ qguitimer \ qguivariant \ qhighdpiscaling \ @@ -33,6 +34,7 @@ win32:!winrt:qtHaveModule(network): SUBDIRS += noqteventloop !qtConfig(shortcut): SUBDIRS -= \ qkeysequence \ + qguishortcut \ qguimetatype \ qguivariant diff --git a/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro b/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro new file mode 100644 index 0000000000..1417dee213 --- /dev/null +++ b/tests/auto/gui/kernel/qguishortcut/qguishortcut.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qguishortcut +QT += testlib +SOURCES += tst_qguishortcut.cpp diff --git a/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp b/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp new file mode 100644 index 0000000000..bc3fb9862d --- /dev/null +++ b/tests/auto/gui/kernel/qguishortcut/tst_qguishortcut.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtGui/qguiapplication.h> +#include <QtGui/qguishortcut.h> +#include <QtGui/qpainter.h> +#include <QtGui/qrasterwindow.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> + +class tst_QGuiShortcut : public QObject +{ + Q_OBJECT +public: + +private slots: + void trigger(); +}; + +class ColoredWindow : public QRasterWindow { +public: + ColoredWindow(QColor c) : m_color(c) {} + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + const QColor m_color; +}; + +void ColoredWindow::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(QRect(QPoint(), size()), m_color); +} + +static void sendKey(QWindow *target, Qt::Key k, char c, Qt::KeyboardModifiers modifiers) +{ + QTest::sendKeyEvent(QTest::Press, target, k, c, modifiers); + QTest::sendKeyEvent(QTest::Release, target, k, c, modifiers); +} + +void tst_QGuiShortcut::trigger() +{ + ColoredWindow w(Qt::yellow); + w.setTitle(QTest::currentTestFunction()); + w.resize(QGuiApplication::primaryScreen()->size() / 4); + new QGuiShortcut(Qt::CTRL + Qt::Key_Q, &w, SLOT(close())); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + sendKey(&w, Qt::Key_Q, 'q', Qt::ControlModifier); + QTRY_VERIFY(!w.isVisible()); +} + +QTEST_MAIN(tst_QGuiShortcut) +#include "tst_qguishortcut.moc"