aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/util/qquickshortcut.cpp283
-rw-r--r--src/quick/util/qquickshortcut_p.h109
-rw-r--r--src/quick/util/qquickutilmodule.cpp3
-rw-r--r--src/quick/util/util.pri6
-rw-r--r--tests/auto/quick/qquickshortcut/data/shortcuts.qml61
-rw-r--r--tests/auto/quick/qquickshortcut/qquickshortcut.pro11
-rw-r--r--tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp354
-rw-r--r--tests/auto/quick/quick.pro1
-rw-r--r--tests/manual/shorcuts/shortcuts.qml147
9 files changed, 973 insertions, 2 deletions
diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp
new file mode 100644
index 0000000000..cd7d265ed0
--- /dev/null
+++ b/src/quick/util/qquickshortcut.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickshortcut_p.h"
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Shortcut
+ \instantiates QQuickShortcut
+ \inqmlmodule QtQuick
+ \since 5.5
+ \ingroup qtquick-input
+ \brief Provides keyboard shortcuts
+
+ The Shortcut type provides a way of handling keyboard shortcuts. The shortcut can
+ be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts},
+ or it can be described with a string containing a sequence of up to four key
+ presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
+
+ \qml
+ Item {
+ id: view
+
+ property int currentIndex
+
+ Shortcut {
+ sequence: StandardKey.NextChild
+ onActivated: view.currentIndex++
+ }
+ }
+ \endqml
+
+ \sa Keys
+*/
+
+/*! \qmlsignal QtQuick::Shortcut::activated()
+
+ This signal is emitted when the shortcut is activated.
+
+ The corresponding handler is \c onActivated.
+*/
+
+/*! \qmlsignal QtQuick::Shortcut::activatedAmbiguously()
+
+ This signal is emitted when the shortcut is activated ambigously,
+ meaning that it matches the start of more than one shortcut.
+
+ The corresponding handler is \c onActivatedAmbiguously.
+*/
+
+QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent), m_id(0),
+ m_enabled(true), m_completed(false), m_autorepeat(true), m_context(Qt::WindowShortcut)
+{
+}
+
+QQuickShortcut::~QQuickShortcut()
+{
+ ungrabShortcut();
+}
+
+/*!
+ \qmlproperty keysequence QtQuick::Shortcut::sequence
+
+ This property holds the shortcut's key sequence. The key sequence can be set
+ to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or
+ it can be described with a string containing a sequence of up to four key
+ presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
+
+ The default value is an empty key sequence.
+
+ \qml
+ Shortcut {
+ sequence: "Ctrl+E,Ctrl+W"
+ onActivated: edit.wrapMode = TextEdit.Wrap
+ }
+ \endqml
+*/
+QVariant QQuickShortcut::sequence() const
+{
+ return m_sequence;
+}
+
+void QQuickShortcut::setSequence(const QVariant &sequence)
+{
+ if (sequence == m_sequence)
+ return;
+
+ QKeySequence shortcut;
+ if (sequence.type() == QVariant::Int)
+ shortcut = QKeySequence(static_cast<QKeySequence::StandardKey>(sequence.toInt()));
+ else
+ shortcut = QKeySequence::fromString(sequence.toString());
+
+ grabShortcut(shortcut, m_context);
+
+ m_sequence = sequence;
+ m_shortcut = shortcut;
+ emit sequenceChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick::Shortcut::enabled
+
+ This property holds whether the shortcut is enabled.
+
+ The default value is \c true.
+*/
+bool QQuickShortcut::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickShortcut::setEnabled(bool enabled)
+{
+ if (enabled == m_enabled)
+ return;
+
+ if (m_id)
+ QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, m_id, this);
+
+ m_enabled = enabled;
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick::Shortcut::autoRepeat
+
+ This property holds whether the shortcut can auto repeat.
+
+ The default value is \c true.
+*/
+bool QQuickShortcut::autoRepeat() const
+{
+ return m_autorepeat;
+}
+
+void QQuickShortcut::setAutoRepeat(bool repeat)
+{
+ if (repeat == m_autorepeat)
+ return;
+
+ if (m_id)
+ QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, m_id, this);
+
+ m_autorepeat = repeat;
+ emit autoRepeatChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::Shortcut::context
+
+ This property holds the \l{Qt::ShortcutContext}{shortcut context}.
+
+ Supported values are:
+ \list
+ \li \c Qt.WindowShortcut (default) - The shortcut is active when its parent item is in an active top-level window.
+ \li \c Qt.ApplicationShortcut - The shortcut is active when one of the application's windows are active.
+ \endlist
+
+ \qml
+ Shortcut {
+ sequence: StandardKey.Quit
+ context: Qt.ApplicationShortcut
+ onActivated: Qt.quit()
+ }
+ \endqml
+*/
+Qt::ShortcutContext QQuickShortcut::context() const
+{
+ return m_context;
+}
+
+void QQuickShortcut::setContext(Qt::ShortcutContext context)
+{
+ if (context == m_context)
+ return;
+
+ grabShortcut(m_shortcut, context);
+
+ m_context = context;
+ emit contextChanged();
+}
+
+void QQuickShortcut::classBegin()
+{
+}
+
+void QQuickShortcut::componentComplete()
+{
+ m_completed = true;
+ grabShortcut(m_shortcut, m_context);
+}
+
+bool QQuickShortcut::event(QEvent *event)
+{
+ if (m_enabled && event->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
+ if (se->shortcutId() == m_id && se->key() == m_shortcut){
+ if (se->isAmbiguous())
+ emit activatedAmbiguously();
+ else
+ emit activated();
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool qQuickShortcutContextMatcher(QObject *obj, Qt::ShortcutContext context)
+{
+ switch (context) {
+ case Qt::ApplicationShortcut:
+ return true;
+ case Qt::WindowShortcut:
+ while (obj && !obj->isWindowType()) {
+ obj = obj->parent();
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(obj))
+ obj = item->window();
+ }
+ return obj && obj == QGuiApplication::focusWindow();
+ default:
+ return false;
+ }
+}
+
+void QQuickShortcut::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context)
+{
+ ungrabShortcut();
+
+ if (m_completed && !sequence.isEmpty()) {
+ QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
+ m_id = pApp->shortcutMap.addShortcut(this, sequence, context, qQuickShortcutContextMatcher);
+ if (!m_enabled)
+ pApp->shortcutMap.setShortcutEnabled(false, m_id, this);
+ if (!m_autorepeat)
+ pApp->shortcutMap.setShortcutAutoRepeat(false, m_id, this);
+ }
+}
+
+void QQuickShortcut::ungrabShortcut()
+{
+ if (m_id) {
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_id, this);
+ m_id = 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h
new file mode 100644
index 0000000000..d6ca02e00b
--- /dev/null
+++ b/src/quick/util/qquickshortcut_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSHORTCUT_P_H
+#define QQUICKSHORTCUT_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 <QtCore/qobject.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qkeysequence.h>
+#include <QtQml/qqmlparserstatus.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickShortcut : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL)
+ Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL)
+
+public:
+ explicit QQuickShortcut(QObject *parent = Q_NULLPTR);
+ ~QQuickShortcut();
+
+ QVariant sequence() const;
+ void setSequence(const QVariant &sequence);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool autoRepeat() const;
+ void setAutoRepeat(bool repeat);
+
+ Qt::ShortcutContext context() const;
+ void setContext(Qt::ShortcutContext context);
+
+Q_SIGNALS:
+ void sequenceChanged();
+ void enabledChanged();
+ void autoRepeatChanged();
+ void contextChanged();
+
+ void activated();
+ void activatedAmbiguously();
+
+protected:
+ void classBegin() Q_DECL_OVERRIDE;
+ void componentComplete() Q_DECL_OVERRIDE;
+ bool event(QEvent *event) Q_DECL_OVERRIDE;
+
+ void grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context);
+ void ungrabShortcut();
+
+private:
+ int m_id;
+ bool m_enabled;
+ bool m_completed;
+ bool m_autorepeat;
+ QKeySequence m_shortcut;
+ Qt::ShortcutContext m_context;
+ QVariant m_sequence;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSHORTCUT_P_H
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index 0b42c21e8b..3c4ba9d0d8 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -48,6 +48,7 @@
#include "qquicktextmetrics_p.h"
#include "qquicktransition_p.h"
#include "qquickanimator_p.h"
+#include "qquickshortcut_p.h"
#include <qqmlinfo.h>
#include <private/qqmltypenotavailable_p.h>
#include <private/qquickanimationcontroller_p.h>
@@ -103,4 +104,6 @@ void QQuickUtilModule::defineModule()
qmlRegisterType<QQuickFontMetrics>("QtQuick", 2, 4, "FontMetrics");
qmlRegisterType<QQuickTextMetrics>("QtQuick", 2, 4, "TextMetrics");
+
+ qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut");
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index 76cf1996bc..0e0df4e751 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -28,7 +28,8 @@ SOURCES += \
$$PWD/qquickanimatorcontroller.cpp \
$$PWD/qquickprofiler.cpp \
$$PWD/qquickfontmetrics.cpp \
- $$PWD/qquicktextmetrics.cpp
+ $$PWD/qquicktextmetrics.cpp \
+ $$PWD/qquickshortcut.cpp
HEADERS += \
$$PWD/qquickapplication_p.h\
@@ -64,4 +65,5 @@ HEADERS += \
$$PWD/qquickanimatorcontroller_p.h \
$$PWD/qquickprofiler_p.h \
$$PWD/qquickfontmetrics_p.h \
- $$PWD/qquicktextmetrics_p.h
+ $$PWD/qquicktextmetrics_p.h \
+ $$PWD/qquickshortcut_p.h
diff --git a/tests/auto/quick/qquickshortcut/data/shortcuts.qml b/tests/auto/quick/qquickshortcut/data/shortcuts.qml
new file mode 100644
index 0000000000..88692c7d03
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/data/shortcuts.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Window 2.2
+
+Window {
+ id: window
+
+ width: 300
+ height: 300
+
+ property string activatedShortcut
+ property string ambiguousShortcut
+
+ property alias shortcuts: repeater.model
+
+ Repeater {
+ id: repeater
+ Item {
+ Shortcut {
+ sequence: modelData.sequence
+ enabled: modelData.enabled
+ autoRepeat: modelData.autoRepeat
+ context: modelData.context
+ onActivated: activatedShortcut = sequence
+ onActivatedAmbiguously: ambiguousShortcut = sequence
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshortcut/qquickshortcut.pro b/tests/auto/quick/qquickshortcut/qquickshortcut.pro
new file mode 100644
index 0000000000..917a7605e6
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/qquickshortcut.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_qquickshortcut
+
+SOURCES += tst_qquickshortcut.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core gui qml quick testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
new file mode 100644
index 0000000000..5adbd9ea16
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/qtest.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQml/qqmlapplicationengine.h>
+
+#include "../../shared/util.h"
+
+class tst_QQuickShortcut : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void shortcuts_data();
+ void shortcuts();
+ void sequence_data();
+ void sequence();
+ void context_data();
+ void context();
+};
+
+Q_DECLARE_METATYPE(Qt::Key)
+Q_DECLARE_METATYPE(Qt::KeyboardModifiers)
+
+static const bool EnabledShortcut = true;
+static const bool DisabledShortcut = false;
+
+static QVariant shortcutMap(const QVariant &sequence, Qt::ShortcutContext context, bool enabled = true, bool autoRepeat = true)
+{
+ QVariantMap s;
+ s["sequence"] = sequence;
+ s["enabled"] = enabled;
+ s["context"] = context;
+ s["autoRepeat"] = autoRepeat;
+ return s;
+}
+
+static QVariant shortcutMap(const QVariant &key, bool enabled = true, bool autoRepeat = true)
+{
+ return shortcutMap(key, Qt::WindowShortcut, enabled, autoRepeat);
+}
+
+void tst_QQuickShortcut::shortcuts_data()
+{
+ QTest::addColumn<QVariantList>("shortcuts");
+ QTest::addColumn<Qt::Key>("key");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
+ QTest::addColumn<QString>("activatedShortcut");
+ QTest::addColumn<QString>("ambiguousShortcut");
+
+ QVariantList shortcuts;
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << "";
+ QTest::newRow("Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << "";
+ QTest::newRow("Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << "";
+ QTest::newRow("Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << "";
+ QTest::newRow("Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << "";
+ QTest::newRow("+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << "";
+ QTest::newRow("F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << "";
+ QTest::newRow("Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << "";
+
+ // ambiguous
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("?M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "M";
+ QTest::newRow("?Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << "Alt+M";
+ QTest::newRow("?Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << "Ctrl+M";
+ QTest::newRow("?Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+M";
+ QTest::newRow("?Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << "Ctrl+Alt+M";
+ QTest::newRow("?+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "+";
+ QTest::newRow("?F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "F1";
+ QTest::newRow("?Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+F1";
+
+ // disabled
+ shortcuts.clear();
+ shortcuts << shortcutMap("M", DisabledShortcut)
+ << shortcutMap("Alt+M", DisabledShortcut)
+ << shortcutMap("Ctrl+M", DisabledShortcut)
+ << shortcutMap("Shift+M", DisabledShortcut)
+ << shortcutMap("Ctrl+Alt+M", DisabledShortcut)
+ << shortcutMap("+", DisabledShortcut)
+ << shortcutMap("F1", DisabledShortcut)
+ << shortcutMap("Shift+F1", DisabledShortcut);
+
+ QTest::newRow("!M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << "";
+ QTest::newRow("!Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << "";
+ QTest::newRow("!Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "";
+ QTest::newRow("!Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << "";
+ QTest::newRow("!+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "";
+ QTest::newRow("!Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "";
+
+ // unambigous because others disabled
+ shortcuts << shortcutMap("M")
+ << shortcutMap("Alt+M")
+ << shortcutMap("Ctrl+M")
+ << shortcutMap("Shift+M")
+ << shortcutMap("Ctrl+Alt+M")
+ << shortcutMap("+")
+ << shortcutMap("F1")
+ << shortcutMap("Shift+F1");
+
+ QTest::newRow("/M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << "";
+ QTest::newRow("/Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << "";
+ QTest::newRow("/Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << "";
+ QTest::newRow("/Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << "";
+ QTest::newRow("/Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << "";
+ QTest::newRow("/+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << "";
+ QTest::newRow("/F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << "";
+ QTest::newRow("/Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << "";
+}
+
+void tst_QQuickShortcut::shortcuts()
+{
+ QFETCH(QVariantList, shortcuts);
+ QFETCH(Qt::Key, key);
+ QFETCH(Qt::KeyboardModifiers, modifiers);
+ QFETCH(QString, activatedShortcut);
+ QFETCH(QString, ambiguousShortcut);
+
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("shortcuts.qml"));
+
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(engine.rootObjects().value(0));
+ QVERIFY(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ window->setProperty("shortcuts", shortcuts);
+
+ QTest::keyPress(window, key, modifiers);
+ QCOMPARE(window->property("activatedShortcut").toString(), activatedShortcut);
+ QCOMPARE(window->property("ambiguousShortcut").toString(), ambiguousShortcut);
+}
+
+void tst_QQuickShortcut::sequence_data()
+{
+ QTest::addColumn<QVariantList>("shortcuts");
+ QTest::addColumn<Qt::Key>("key1");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers1");
+ QTest::addColumn<Qt::Key>("key2");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers2");
+ QTest::addColumn<Qt::Key>("key3");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers3");
+ QTest::addColumn<Qt::Key>("key4");
+ QTest::addColumn<Qt::KeyboardModifiers>("modifiers4");
+ QTest::addColumn<QString>("activatedShortcut");
+ QTest::addColumn<QString>("ambiguousShortcut");
+
+ QVariantList shortcuts;
+ shortcuts << shortcutMap("Escape,W")
+ << shortcutMap("Ctrl+X,Ctrl+C")
+ << shortcutMap("Shift+Ctrl+4,Space")
+ << shortcutMap("Alt+T,Ctrl+R,Shift+J,H");
+
+ QTest::newRow("Escape,W") << shortcuts << Qt::Key_Escape << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key_W << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << "Escape,W" << "";
+
+ QTest::newRow("Ctrl+X,Ctrl+C") << shortcuts << Qt::Key_X << Qt::KeyboardModifiers(Qt::ControlModifier)
+ << Qt::Key_C << Qt::KeyboardModifiers(Qt::ControlModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << "Ctrl+X,Ctrl+C" << "";
+
+ QTest::newRow("Shift+Ctrl+4,Space") << shortcuts << Qt::Key_4 << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::ShiftModifier)
+ << Qt::Key_Space << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << Qt::Key(0) << Qt::KeyboardModifiers(Qt::NoModifier)
+ << "Shift+Ctrl+4,Space" << "";
+
+ QTest::newRow("Alt+T,Ctrl+R,Shift+J,H") << shortcuts << Qt::Key_T << Qt::KeyboardModifiers(Qt::AltModifier)
+ << Qt::Key_R << Qt::KeyboardModifiers(Qt::ControlModifier)
+ << Qt::Key_J << Qt::KeyboardModifiers(Qt::ShiftModifier)
+ << Qt::Key_H << Qt::KeyboardModifiers(Qt::NoModifier)
+ << "Alt+T,Ctrl+R,Shift+J,H" << "";
+}
+
+void tst_QQuickShortcut::sequence()
+{
+ QFETCH(QVariantList, shortcuts);
+ QFETCH(Qt::Key, key1);
+ QFETCH(Qt::KeyboardModifiers, modifiers1);
+ QFETCH(Qt::Key, key2);
+ QFETCH(Qt::KeyboardModifiers, modifiers2);
+ QFETCH(Qt::Key, key3);
+ QFETCH(Qt::KeyboardModifiers, modifiers3);
+ QFETCH(Qt::Key, key4);
+ QFETCH(Qt::KeyboardModifiers, modifiers4);
+ QFETCH(QString, activatedShortcut);
+ QFETCH(QString, ambiguousShortcut);
+
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("shortcuts.qml"));
+
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(engine.rootObjects().value(0));
+ QVERIFY(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ window->setProperty("shortcuts", shortcuts);
+
+ if (key1 != 0)
+ QTest::keyPress(window, key1, modifiers1);
+ if (key2 != 0)
+ QTest::keyPress(window, key2, modifiers2);
+ if (key3 != 0)
+ QTest::keyPress(window, key3, modifiers3);
+ if (key4 != 0)
+ QTest::keyPress(window, key4, modifiers4);
+
+ QCOMPARE(window->property("activatedShortcut").toString(), activatedShortcut);
+ QCOMPARE(window->property("ambiguousShortcut").toString(), ambiguousShortcut);
+}
+
+void tst_QQuickShortcut::context_data()
+{
+ QTest::addColumn<Qt::Key>("key");
+ QTest::addColumn<QVariantList>("activeWindowShortcuts");
+ QTest::addColumn<QVariantList>("inactiveWindowShortcuts");
+ QTest::addColumn<QString>("activeWindowActivatedShortcut");
+ QTest::addColumn<QString>("inactiveWindowActivatedShortcut");
+ QTest::addColumn<QString>("ambiguousShortcut");
+
+ // APP: F1,(F2),F3,(F4) / WND: F7,(F8),F9,(F10)
+ QVariantList activeWindowShortcuts;
+ activeWindowShortcuts << shortcutMap("F1", Qt::ApplicationShortcut, EnabledShortcut)
+ << shortcutMap("F2", Qt::ApplicationShortcut, DisabledShortcut)
+ << shortcutMap("F3", Qt::ApplicationShortcut, EnabledShortcut)
+ << shortcutMap("F4", Qt::ApplicationShortcut, DisabledShortcut)
+ << shortcutMap("F7", Qt::WindowShortcut, EnabledShortcut)
+ << shortcutMap("F8", Qt::WindowShortcut, DisabledShortcut)
+ << shortcutMap("F9", Qt::WindowShortcut, EnabledShortcut)
+ << shortcutMap("F10", Qt::WindowShortcut, DisabledShortcut);
+
+ // APP: F3,(F4),F5,(F6) / WND: F9,(F10),F11(F12)
+ QVariantList inactiveWindowShortcuts;
+ inactiveWindowShortcuts << shortcutMap("F3", Qt::ApplicationShortcut, EnabledShortcut)
+ << shortcutMap("F4", Qt::ApplicationShortcut, DisabledShortcut)
+ << shortcutMap("F5", Qt::ApplicationShortcut, EnabledShortcut)
+ << shortcutMap("F6", Qt::ApplicationShortcut, DisabledShortcut)
+ << shortcutMap("F9", Qt::WindowShortcut, EnabledShortcut)
+ << shortcutMap("F10", Qt::WindowShortcut, DisabledShortcut)
+ << shortcutMap("F11", Qt::WindowShortcut, EnabledShortcut)
+ << shortcutMap("F12", Qt::WindowShortcut, DisabledShortcut);
+
+ // APP
+ QTest::newRow("F1") << Qt::Key_F1 << activeWindowShortcuts << inactiveWindowShortcuts << "F1" << "" << "";
+ QTest::newRow("F2") << Qt::Key_F2 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+ QTest::newRow("F3") << Qt::Key_F3 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "F3";
+ QTest::newRow("F4") << Qt::Key_F4 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+ QTest::newRow("F5") << Qt::Key_F5 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "F5" << "";
+ QTest::newRow("F6") << Qt::Key_F6 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+
+ // WND
+ QTest::newRow("F7") << Qt::Key_F7 << activeWindowShortcuts << inactiveWindowShortcuts << "F7" << "" << "";
+ QTest::newRow("F8") << Qt::Key_F8 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+ QTest::newRow("F9") << Qt::Key_F9 << activeWindowShortcuts << inactiveWindowShortcuts << "F9" << "" << "";
+ QTest::newRow("F10") << Qt::Key_F10 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+ QTest::newRow("F11") << Qt::Key_F11 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+ QTest::newRow("F12") << Qt::Key_F12 << activeWindowShortcuts << inactiveWindowShortcuts << "" << "" << "";
+}
+
+void tst_QQuickShortcut::context()
+{
+ QFETCH(Qt::Key, key);
+ QFETCH(QVariantList, activeWindowShortcuts);
+ QFETCH(QVariantList, inactiveWindowShortcuts);
+ QFETCH(QString, activeWindowActivatedShortcut);
+ QFETCH(QString, inactiveWindowActivatedShortcut);
+ QFETCH(QString, ambiguousShortcut);
+
+ QQmlApplicationEngine engine;
+
+ engine.load(testFileUrl("shortcuts.qml"));
+ QQuickWindow *inactiveWindow = qobject_cast<QQuickWindow *>(engine.rootObjects().value(0));
+ QVERIFY(inactiveWindow);
+ inactiveWindow->show();
+ QVERIFY(QTest::qWaitForWindowExposed(inactiveWindow));
+ inactiveWindow->setProperty("shortcuts", inactiveWindowShortcuts);
+
+ engine.load(testFileUrl("shortcuts.qml"));
+ QQuickWindow *activeWindow = qobject_cast<QQuickWindow *>(engine.rootObjects().value(1));
+ QVERIFY(activeWindow);
+ activeWindow->show();
+ QVERIFY(QTest::qWaitForWindowExposed(activeWindow));
+ activeWindow->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(activeWindow));
+ activeWindow->setProperty("shortcuts", activeWindowShortcuts);
+
+ QTest::keyPress(activeWindow, key);
+
+ QCOMPARE(activeWindow->property("activatedShortcut").toString(), activeWindowActivatedShortcut);
+ QCOMPARE(inactiveWindow->property("activatedShortcut").toString(), inactiveWindowActivatedShortcut);
+ QVERIFY(activeWindow->property("ambiguousShortcut").toString() == ambiguousShortcut
+ || inactiveWindow->property("ambiguousShortcut").toString() == ambiguousShortcut);
+}
+
+QTEST_MAIN(tst_QQuickShortcut)
+
+#include "tst_qquickshortcut.moc"
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index e400556b67..c2b7a4cc8d 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -64,6 +64,7 @@ QUICKTESTS = \
qquickrectangle \
qquickrepeater \
qquickshadereffect \
+ qquickshortcut \
qquickspritesequence \
qquicktext \
qquicktextdocument \
diff --git a/tests/manual/shorcuts/shortcuts.qml b/tests/manual/shorcuts/shortcuts.qml
new file mode 100644
index 0000000000..43562a6062
--- /dev/null
+++ b/tests/manual/shorcuts/shortcuts.qml
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.3
+
+ApplicationWindow {
+ id: window
+
+ width: 520
+ height: 340
+ visible: true
+ title: "Shortcuts - main"
+
+ menuBar: MenuBar {
+ Menu {
+ title: "File"
+ MenuItem {
+ text: "New..."
+ shortcut: StandardKey.New
+ onTriggered: shortcutWindow.createObject(window)
+ }
+ MenuItem {
+ text: "Quit"
+ shortcut: StandardKey.Quit
+ onTriggered: Qt.quit()
+ }
+ }
+ }
+
+ Loader {
+ anchors.margins: 20
+ anchors.fill: parent
+ sourceComponent: shortcutColumn
+ }
+
+ Component {
+ id: shortcutWindow
+
+ ApplicationWindow {
+ width: 520
+ height: 300
+ visible: true
+ title: "Shortcuts - child"
+
+ Loader {
+ anchors.margins: 20
+ anchors.fill: parent
+ sourceComponent: shortcutColumn
+ }
+
+ onClosing: destroy(1)
+ }
+ }
+
+ Component {
+ id: shortcutColumn
+
+ Column {
+ spacing: 20
+
+ Repeater {
+ model: ["Esc", "Ctrl+C", "Alt+6", "Shift+F12", "Ctrl+X,Ctrl+C"]
+
+ RowLayout {
+ spacing: 20
+ width: parent.width
+
+ CheckBox {
+ id: checkbox
+ text: modelData
+ checked: index % 2 == 0
+ Layout.fillWidth: true
+ }
+
+ ComboBox {
+ id: combobox
+ enabled: checkbox.checked
+ model: ["WindowShortcut", "ApplicationShortcut"]
+ }
+
+ Shortcut {
+ id: shortcut
+
+ property int activationCount: 0
+ property int ambiguousActivationCount: 0
+
+ sequence: modelData
+ enabled: checkbox.checked
+ context: combobox.currentText
+
+ onActivated: { activationCount++; activationTimer.restart() }
+ onActivatedAmbiguously: { ambiguousActivationCount++; ambiguousActivationTimer.restart() }
+ }
+
+ Timer { id: activationTimer; interval: 500 }
+ Timer { id: ambiguousActivationTimer; interval: 500 }
+
+ Column {
+ Text {
+ font.pixelSize: 10
+ text: qsTr("Activated: %1").arg(shortcut.activationCount)
+ color: activationTimer.running ? "red" : checkbox.checked ? "black" : "gray"
+ }
+ Text {
+ font.pixelSize: 10
+ text: qsTr("Ambiguously: %1").arg(shortcut.ambiguousActivationCount)
+ color: ambiguousActivationTimer.running ? "red" : checkbox.checked ? "black" : "gray"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+