Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/shortcuts into lp:ubuntu-ui-toolkit/staging

Proposed by Cris Dywan
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1542
Merged at revision: 1552
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/shortcuts
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 280 lines (+176/-3)
6 files modified
components.api (+2/-1)
examples/ubuntu-ui-toolkit-gallery/Buttons.qml (+8/-2)
modules/Ubuntu/Components/plugin/plugin.cpp (+1/-0)
modules/Ubuntu/Components/plugin/ucaction.cpp (+66/-0)
modules/Ubuntu/Components/plugin/ucaction.h (+7/-0)
tests/unit_x11/tst_components/tst_shortcuts.qml (+92/-0)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/shortcuts
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+262413@code.launchpad.net

Commit message

Implement Action.shortcut property

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1538. By Cris Dywan

Fix doc comment for UCAction::shortcut

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Got some comments inline, check 'em.

review: Needs Fixing
1539. By Cris Dywan

More explicit type check and multi modifier test case

Revision history for this message
Cris Dywan (kalikiana) wrote :

> if object is expected to be a QQuickItem,
> you should cast to it and that has a window()
> that you can use to get the window context...?

No. The action itself is in fact a QObject. We're walking up the parents to find a window.

> Shouldn't we also check whether the action is enabled?

No need, trigger() has a check already.

> What about testing also Alt+Ctrl, Shift+Ctrl and Alt+Shift+Ctrl?
> Or should we just assume that Qt shortcut system works with those?

Basically yeah, I don't think we want to duplicate their tests since we don't add any functionality. But I added another one with Atl+Shift+Ctrl just to be sure we'll know if anything obvious breaks in a Qt upgrade.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

One more thing we forgot!

review: Needs Fixing
Revision history for this message
Zsombor Egri (zsombi) wrote :

To summarise what we talked on Mumble:
- actions to be grouped in ActionContext
- Action activation to be bound to ActionContext.active
- text input action context activation to be bound with activeFocus
- Page active to drive ActionContext.active

review: Needs Fixing
1540. By Cris Dywan

New shortcut property needs to go on revision 3

1541. By Cris Dywan

Register UCAction revision 1 to 1.3 and shortcut to 1

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1542. By Cris Dywan

Update components.api

Revision history for this message
Zsombor Egri (zsombi) wrote :

All good now, let's get it merged.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2015-06-22 23:24:26 +0000
+++ components.api 2015-07-07 19:08:50 +0000
@@ -8,7 +8,7 @@
8 signal clicked()8 signal clicked()
9 signal pressAndHold()9 signal pressAndHold()
10 property bool pressed10 property bool pressed
11Ubuntu.Components.Action 1.0 0.1: QtObject11Ubuntu.Components.Action 1.3 1.0 0.1: QtObject
12 property string description12 property string description
13 property bool enabled13 property bool enabled
14 property string iconName14 property string iconName
@@ -20,6 +20,7 @@
20 function trigger()20 function trigger()
21 property string name21 property string name
22 property Type parameterType22 property Type parameterType
23 property var shortcut
23 property string text24 property string text
24 property bool visible25 property bool visible
25Ubuntu.Components.Action.Type: Enum26Ubuntu.Components.Action.Type: Enum
2627
=== modified file 'examples/ubuntu-ui-toolkit-gallery/Buttons.qml'
--- examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2015-04-29 07:21:29 +0000
+++ examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2015-07-07 19:08:50 +0000
@@ -48,8 +48,14 @@
4848
49 Button {49 Button {
50 objectName: "button_color"50 objectName: "button_color"
51 text: i18n.tr("Call")51 width: units.gu(20)
52 color: UbuntuColors.green52 action: Action {
53 text: i18n.tr("Call %1").arg(shortcut)
54 shortcut: 'Ctrl+C'
55 property bool flipped
56 onTriggered: flipped = !flipped
57 }
58 color: action.flipped ? UbuntuColors.blue : UbuntuColors.green
53 }59 }
54 }60 }
5561
5662
=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
--- modules/Ubuntu/Components/plugin/plugin.cpp 2015-05-26 17:54:51 +0000
+++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-07-07 19:08:50 +0000
@@ -213,6 +213,7 @@
213 qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13);213 qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13);
214 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");214 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");
215 qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser);215 qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser);
216 qmlRegisterType<UCAction, 1>(uri, 1, 3, "Action");
216}217}
217218
218void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)219void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
219220
=== modified file 'modules/Ubuntu/Components/plugin/ucaction.cpp'
--- modules/Ubuntu/Components/plugin/ucaction.cpp 2014-11-28 13:30:05 +0000
+++ modules/Ubuntu/Components/plugin/ucaction.cpp 2015-07-07 19:08:50 +0000
@@ -17,6 +17,10 @@
17#include "ucaction.h"17#include "ucaction.h"
1818
19#include <QtDebug>19#include <QtDebug>
20#include <QtQml/QQmlInfo>
21#include <QtQuick/qquickitem.h>
22#include <QtQuick/qquickwindow.h>
23#include <private/qguiapplication_p.h>
2024
21/*!25/*!
22 * \qmltype Action26 * \qmltype Action
@@ -152,6 +156,7 @@
152 , m_published(false)156 , m_published(false)
153 , m_itemHint(0)157 , m_itemHint(0)
154 , m_parameterType(None)158 , m_parameterType(None)
159 , m_shortcut(0)
155{160{
156 generateName();161 generateName();
157}162}
@@ -240,6 +245,67 @@
240 qWarning() << "Action.itemHint is a DEPRECATED property. Use ActionItems to specify the representation of an Action.";245 qWarning() << "Action.itemHint is a DEPRECATED property. Use ActionItems to specify the representation of an Action.";
241}246}
242247
248bool shortcutContextMatcher(QObject* object, Qt::ShortcutContext)
249{
250 UCAction* action = static_cast<UCAction*>(object);
251 // Can't access member here because it's not public
252 if (!action->property("enabled").toBool())
253 return false;
254
255 QObject* window = object;
256 while (window && !window->isWindowType()) {
257 window = window->parent();
258 if (QQuickItem* item = qobject_cast<QQuickItem*>(window))
259 window = item->window();
260 }
261 return window && window == QGuiApplication::focusWindow();
262}
263
264QKeySequence sequenceFromVariant(const QVariant& variant) {
265 if (variant.type() == QVariant::Int)
266 return static_cast<QKeySequence::StandardKey>(variant.toInt());
267 if (variant.type() == QVariant::String)
268 return QKeySequence::fromString(variant.toString());
269 return QKeySequence();
270}
271
272/*!
273 * \qmlproperty var Action::shortcut
274 * The keyboard shortcut that can be used to trigger the action.
275 * \b StandardKey values such as \b StandardKey.Copy
276 * as well as strings in the form "Ctrl+C" are accepted values.
277 * \since 1.3
278 */
279void UCAction::setShortcut(const QVariant& shortcut)
280{
281 if (m_shortcut.isValid())
282 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, this, sequenceFromVariant(m_shortcut));
283
284 QKeySequence sequence(sequenceFromVariant(shortcut));
285 if (!sequence.toString().isEmpty())
286 QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence, Qt::WindowShortcut, shortcutContextMatcher);
287 else
288 qmlInfo(this) << "Invalid shortcut: " << shortcut.toString();
289
290 m_shortcut = shortcut;
291 Q_EMIT shortcutChanged(shortcut);
292}
293
294bool UCAction::event(QEvent *event)
295{
296 if (event->type() != QEvent::Shortcut)
297 return false;
298
299 QShortcutEvent *shortcut_event(static_cast<QShortcutEvent*>(event));
300 if (shortcut_event->isAmbiguous()) {
301 qmlInfo(this) << "Ambiguous shortcut: " << shortcut_event->key().toString();
302 return false;
303 }
304
305 trigger();
306 return true;
307}
308
243/*!309/*!
244 * \qmlmethod Action::trigger(var value)310 * \qmlmethod Action::trigger(var value)
245 * Checks the \c value against the action \l parameterType and triggers the action.311 * Checks the \c value against the action \l parameterType and triggers the action.
246312
=== modified file 'modules/Ubuntu/Components/plugin/ucaction.h'
--- modules/Ubuntu/Components/plugin/ucaction.h 2015-01-07 10:15:34 +0000
+++ modules/Ubuntu/Components/plugin/ucaction.h 2015-07-07 19:08:50 +0000
@@ -40,6 +40,9 @@
40 Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged)40 Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged)
41 Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged)41 Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged)
42 Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint)42 Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint)
43
44 // QtQuickControls.Action
45 Q_PROPERTY(QVariant shortcut MEMBER m_shortcut WRITE setShortcut NOTIFY shortcutChanged REVISION 1)
43public:46public:
44 enum Type {47 enum Type {
45 None,48 None,
@@ -67,6 +70,7 @@
67 void parameterTypeChanged();70 void parameterTypeChanged();
68 void iconSourceChanged();71 void iconSourceChanged();
69 void visibleChanged();72 void visibleChanged();
73 void shortcutChanged(const QVariant& shortcut);
70 void triggered(const QVariant &value);74 void triggered(const QVariant &value);
7175
72public Q_SLOTS:76public Q_SLOTS:
@@ -85,6 +89,7 @@
85 QString m_description;89 QString m_description;
86 QString m_keywords;90 QString m_keywords;
87 Type m_parameterType;91 Type m_parameterType;
92 QVariant m_shortcut;
8893
89 friend class UCActionContext;94 friend class UCActionContext;
90 friend class UCListItemPrivate;95 friend class UCListItemPrivate;
@@ -97,6 +102,8 @@
97 void setIconName(const QString &name);102 void setIconName(const QString &name);
98 void setIconSource(const QUrl &url);103 void setIconSource(const QUrl &url);
99 void setItemHint(QQmlComponent *);104 void setItemHint(QQmlComponent *);
105 void setShortcut(const QVariant&);
106 bool event(QEvent *event);
100};107};
101108
102#endif // UCACTION_H109#endif // UCACTION_H
103110
=== added file 'tests/unit_x11/tst_components/tst_shortcuts.qml'
--- tests/unit_x11/tst_components/tst_shortcuts.qml 1970-01-01 00:00:00 +0000
+++ tests/unit_x11/tst_components/tst_shortcuts.qml 2015-07-07 19:08:50 +0000
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import QtTest 1.0
19import Ubuntu.Test 1.0
20import Ubuntu.Components 1.3
21
22Item {
23 id: root
24 width: 400
25 height: 600
26
27 Action {
28 id: action
29 }
30 Action {
31 id: other
32 shortcut: 'Ctrl+G'
33 }
34
35 TestUtil {
36 id: util
37 }
38
39 UbuntuTestCase {
40 id: testCase
41 name: "Shortcuts"
42 when: windowShown
43
44 function initTestCase() {
45 }
46
47 function init() {
48 }
49
50 SignalSpy {
51 id: spy
52 signalName: 'triggered'
53 target: action
54 }
55
56 function ignoreQMLWarning(message) {
57 ignoreWarning(util.callerFile() + message);
58 }
59
60 function test_shortcut_triggered_data() {
61 return [
62 { tag: 'Multiple modifiers and letter', shortcut: 'Ctrl+Shift+Alt+A', key: Qt.Key_A, mod: Qt.ControlModifier + Qt.ShiftModifier + Qt.AltModifier },
63 { tag: 'Modifier and letter', shortcut: 'Ctrl+A', key: Qt.Key_A, mod: Qt.ControlModifier },
64 { tag: 'Single letter', shortcut: 'E', key: Qt.Key_E, mod: Qt.NoModifier },
65 { tag: 'StandardKey', shortcut: StandardKey.Copy, key: Qt.Key_C, mod: Qt.ControlModifier }
66 ];
67 }
68 function test_shortcut_triggered(data) {
69 action.shortcut = data.shortcut;
70 spy.clear();
71 keyClick(data.key, data.mod);
72 spy.wait();
73 }
74
75 function test_shortcut_invalid_data() {
76 return [
77 { tag: 'Typo', shortcut: 'Ctr+F' },
78 { tag: 'Number', shortcut: 1234567890 }
79 ];
80 }
81 function test_shortcut_invalid(data) {
82 ignoreQMLWarning(':27:5: QML Action: Invalid shortcut: ');
83 action.shortcut = data;
84 }
85
86 function test_shortcut_duplicate() {
87 ignoreQMLWarning(':30:5: QML Action: Ambiguous shortcut: Ctrl+G');
88 action.shortcut = other.shortcut;
89 keyClick(Qt.Key_G, Qt.ControlModifier);
90 }
91 }
92}

Subscribers

People subscribed via source and target branches