From a7fd83cd0cecb789006baecabfc6a49c49b7f48c Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 22 Oct 2016 07:31:37 +0200 Subject: Shortcut: add support for multiple key sequences [ChangeLog][QtQuick][Shortcut] Added support for multiple shortcut sequences. Previously it was possible to specify a single sequence that could consist of up to four key presses. Now it is possible to specify multiple sequences that can each consist of multiple key presses. Change-Id: Id12f25da2f352cc542ec776049d8e81593951d41 Reviewed-by: Robin Burchell Reviewed-by: Mitch Curtis --- src/quick/util/qquickshortcut.cpp | 149 ++++++++++++++++++++++++++++-------- src/quick/util/qquickshortcut_p.h | 27 +++++-- src/quick/util/qquickutilmodule.cpp | 2 + 3 files changed, 140 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp index 3e04161639..a0a58f2e02 100644 --- a/src/quick/util/qquickshortcut.cpp +++ b/src/quick/util/qquickshortcut.cpp @@ -70,6 +70,9 @@ } \endqml + It is also possible to set multiple shortcut \l sequences, so that the shortcut + can be \l activated via several different sequences of key presses. + \sa Keys */ @@ -121,14 +124,23 @@ Q_QUICK_PRIVATE_EXPORT void qt_quick_set_shortcut_context_matcher(ContextMatcher QT_BEGIN_NAMESPACE -QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent), m_id(0), +static QKeySequence valueToKeySequence(const QVariant &value) +{ + if (value.type() == QVariant::Int) + return QKeySequence(static_cast(value.toInt())); + return QKeySequence::fromString(value.toString()); +} + +QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent), m_enabled(true), m_completed(false), m_autorepeat(true), m_context(Qt::WindowShortcut) { } QQuickShortcut::~QQuickShortcut() { - ungrabShortcut(); + ungrabShortcut(m_shortcut); + for (Shortcut &shortcut : m_shortcuts) + ungrabShortcut(shortcut); } /*! @@ -147,30 +159,78 @@ QQuickShortcut::~QQuickShortcut() onActivated: edit.wrapMode = TextEdit.Wrap } \endqml + + \sa sequences */ QVariant QQuickShortcut::sequence() const { - return m_sequence; + return m_shortcut.userValue; } -void QQuickShortcut::setSequence(const QVariant &sequence) +void QQuickShortcut::setSequence(const QVariant &value) { - if (sequence == m_sequence) + if (value == m_shortcut.userValue) return; - QKeySequence shortcut; - if (sequence.type() == QVariant::Int) - shortcut = QKeySequence(static_cast(sequence.toInt())); - else - shortcut = QKeySequence::fromString(sequence.toString()); + QKeySequence keySequence = valueToKeySequence(value); - grabShortcut(shortcut, m_context); - - m_sequence = sequence; - m_shortcut = shortcut; + ungrabShortcut(m_shortcut); + m_shortcut.userValue = value; + m_shortcut.keySequence = keySequence; + grabShortcut(m_shortcut, m_context); emit sequenceChanged(); } +/*! + \qmlproperty list QtQuick::Shortcut::sequences + \since 5.9 + + This property holds multiple key sequences for the shortcut. The key sequences + can be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, + or they can be described with strings containing sequences of up to four key + presses that are needed to \l{Shortcut::activated}{activate} the shortcut. + + \qml + Shortcut { + sequences: [StandardKey.Cut, "Ctrl+X", "Shift+Del"] + onActivated: edit.cut() + } + \endqml +*/ +QVariantList QQuickShortcut::sequences() const +{ + QVariantList values; + for (const Shortcut &shortcut : m_shortcuts) + values += shortcut.userValue; + return values; +} + +void QQuickShortcut::setSequences(const QVariantList &values) +{ + QVector remainder = m_shortcuts.mid(values.count()); + m_shortcuts.resize(values.count()); + + bool changed = !remainder.isEmpty(); + for (int i = 0; i < values.count(); ++i) { + QVariant value = values.at(i); + Shortcut& shortcut = m_shortcuts[i]; + if (value == shortcut.userValue) + continue; + + QKeySequence keySequence = valueToKeySequence(value); + + ungrabShortcut(shortcut); + shortcut.userValue = value; + shortcut.keySequence = keySequence; + grabShortcut(shortcut, m_context); + + changed = true; + } + + if (changed) + emit sequencesChanged(); +} + /*! \qmlproperty string QtQuick::Shortcut::nativeText \since 5.6 @@ -184,7 +244,7 @@ void QQuickShortcut::setSequence(const QVariant &sequence) */ QString QQuickShortcut::nativeText() const { - return m_shortcut.toString(QKeySequence::NativeText); + return m_shortcut.keySequence.toString(QKeySequence::NativeText); } /*! @@ -199,7 +259,7 @@ QString QQuickShortcut::nativeText() const */ QString QQuickShortcut::portableText() const { - return m_shortcut.toString(QKeySequence::PortableText); + return m_shortcut.keySequence.toString(QKeySequence::PortableText); } /*! @@ -219,8 +279,9 @@ void QQuickShortcut::setEnabled(bool enabled) if (enabled == m_enabled) return; - if (m_id) - QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, m_id, this); + setEnabled(m_shortcut, enabled); + for (Shortcut &shortcut : m_shortcuts) + setEnabled(shortcut, enabled); m_enabled = enabled; emit enabledChanged(); @@ -243,8 +304,9 @@ void QQuickShortcut::setAutoRepeat(bool repeat) if (repeat == m_autorepeat) return; - if (m_id) - QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, m_id, this); + setAutoRepeat(m_shortcut, repeat); + for (Shortcut &shortcut : m_shortcuts) + setAutoRepeat(shortcut, repeat); m_autorepeat = repeat; emit autoRepeatChanged(); @@ -279,9 +341,9 @@ void QQuickShortcut::setContext(Qt::ShortcutContext context) if (context == m_context) return; - grabShortcut(m_shortcut, context); - + ungrabShortcut(m_shortcut); m_context = context; + grabShortcut(m_shortcut, context); emit contextChanged(); } @@ -293,13 +355,19 @@ void QQuickShortcut::componentComplete() { m_completed = true; grabShortcut(m_shortcut, m_context); + for (Shortcut &shortcut : m_shortcuts) + grabShortcut(shortcut, m_context); } bool QQuickShortcut::event(QEvent *event) { if (m_enabled && event->type() == QEvent::Shortcut) { QShortcutEvent *se = static_cast(event); - if (se->shortcutId() == m_id && se->key() == m_shortcut){ + bool match = m_shortcut.matches(se); + int i = 0; + while (!match && i < m_shortcuts.count()) + match |= m_shortcuts.at(i++).matches(se); + if (match) { if (se->isAmbiguous()) emit activatedAmbiguously(); else @@ -310,25 +378,40 @@ bool QQuickShortcut::event(QEvent *event) return false; } -void QQuickShortcut::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context) +bool QQuickShortcut::Shortcut::matches(QShortcutEvent *event) const { - ungrabShortcut(); + return event->shortcutId() == id && event->key() == keySequence; +} + +void QQuickShortcut::setEnabled(QQuickShortcut::Shortcut &shortcut, bool enabled) +{ + if (shortcut.id) + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, shortcut.id, this); +} - if (m_completed && !sequence.isEmpty()) { +void QQuickShortcut::setAutoRepeat(QQuickShortcut::Shortcut &shortcut, bool repeat) +{ + if (shortcut.id) + QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, shortcut.id, this); +} + +void QQuickShortcut::grabShortcut(Shortcut &shortcut, Qt::ShortcutContext context) +{ + if (m_completed && !shortcut.keySequence.isEmpty()) { QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance(); - m_id = pApp->shortcutMap.addShortcut(this, sequence, context, *ctxMatcher()); + shortcut.id = pApp->shortcutMap.addShortcut(this, shortcut.keySequence, context, *ctxMatcher()); if (!m_enabled) - pApp->shortcutMap.setShortcutEnabled(false, m_id, this); + pApp->shortcutMap.setShortcutEnabled(false, shortcut.id, this); if (!m_autorepeat) - pApp->shortcutMap.setShortcutAutoRepeat(false, m_id, this); + pApp->shortcutMap.setShortcutAutoRepeat(false, shortcut.id, this); } } -void QQuickShortcut::ungrabShortcut() +void QQuickShortcut::ungrabShortcut(Shortcut &shortcut) { - if (m_id) { - QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_id, this); - m_id = 0; + if (shortcut.id) { + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(shortcut.id, this); + shortcut.id = 0; } } diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h index b3f33a33c1..93430ad893 100644 --- a/src/quick/util/qquickshortcut_p.h +++ b/src/quick/util/qquickshortcut_p.h @@ -52,17 +52,21 @@ // #include +#include #include #include #include QT_BEGIN_NAMESPACE +class QShortcutEvent; + class QQuickShortcut : public QObject, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL) + Q_PROPERTY(QVariantList sequences READ sequences WRITE setSequences NOTIFY sequencesChanged FINAL REVISION 9) Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 1) Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 1) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) @@ -76,6 +80,9 @@ public: QVariant sequence() const; void setSequence(const QVariant &sequence); + QVariantList sequences() const; + void setSequences(const QVariantList &sequences); + QString nativeText() const; QString portableText() const; @@ -90,6 +97,7 @@ public: Q_SIGNALS: void sequenceChanged(); + Q_REVISION(9) void sequencesChanged(); void enabledChanged(); void autoRepeatChanged(); void contextChanged(); @@ -102,17 +110,26 @@ protected: void componentComplete() Q_DECL_OVERRIDE; bool event(QEvent *event) Q_DECL_OVERRIDE; - void grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context); - void ungrabShortcut(); + struct Shortcut { + bool matches(QShortcutEvent *event) const; + int id; + QVariant userValue; + QKeySequence keySequence; + }; + + void setEnabled(Shortcut &shortcut, bool enabled); + void setAutoRepeat(Shortcut &shortcut, bool repeat); + + void grabShortcut(Shortcut &shortcut, Qt::ShortcutContext context); + void ungrabShortcut(Shortcut &shortcut); private: - int m_id; bool m_enabled; bool m_completed; bool m_autorepeat; - QKeySequence m_shortcut; Qt::ShortcutContext m_context; - QVariant m_sequence; + Shortcut m_shortcut; + QVector m_shortcuts; }; QT_END_NAMESPACE diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 7e2973a78b..cb586d1565 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -123,4 +123,6 @@ void QQuickUtilModule::defineModule() qmlRegisterType("QtQuick", 2, 5, "Shortcut"); qmlRegisterType("QtQuick", 2, 6, "Shortcut"); + + qmlRegisterType("QtQuick", 2, 9, "Shortcut"); } -- cgit v1.2.3