Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/shortcuts into lp:ubuntu-ui-toolkit/staging
- shortcuts
- Merge into staging
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Zsombor Egri | Approve | ||
Review via email:
|
Commit message
Implement Action.shortcut property
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1538. By Cris Dywan
-
Fix doc comment for UCAction::shortcut
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1538
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Zsombor Egri (zsombi) wrote : | # |
Got some comments inline, check 'em.
- 1539. By Cris Dywan
-
More explicit type check and multi modifier test case
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1539
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Zsombor Egri (zsombi) wrote : | # |
One more thing we forgot!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Zsombor Egri (zsombi) wrote : | # |
To summarise what we talked on Mumble:
- actions to be grouped in ActionContext
- Action activation to be bound to ActionContext.
- text input action context activation to be bound with activeFocus
- Page active to drive ActionContext.
- 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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1540
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1541
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1542. By Cris Dywan
-
Update components.api
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Zsombor Egri (zsombi) wrote : | # |
All good now, let's get it merged.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2015-06-22 23:24:26 +0000 |
3 | +++ components.api 2015-07-07 19:08:50 +0000 |
4 | @@ -8,7 +8,7 @@ |
5 | signal clicked() |
6 | signal pressAndHold() |
7 | property bool pressed |
8 | -Ubuntu.Components.Action 1.0 0.1: QtObject |
9 | +Ubuntu.Components.Action 1.3 1.0 0.1: QtObject |
10 | property string description |
11 | property bool enabled |
12 | property string iconName |
13 | @@ -20,6 +20,7 @@ |
14 | function trigger() |
15 | property string name |
16 | property Type parameterType |
17 | + property var shortcut |
18 | property string text |
19 | property bool visible |
20 | Ubuntu.Components.Action.Type: Enum |
21 | |
22 | === modified file 'examples/ubuntu-ui-toolkit-gallery/Buttons.qml' |
23 | --- examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2015-04-29 07:21:29 +0000 |
24 | +++ examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2015-07-07 19:08:50 +0000 |
25 | @@ -48,8 +48,14 @@ |
26 | |
27 | Button { |
28 | objectName: "button_color" |
29 | - text: i18n.tr("Call") |
30 | - color: UbuntuColors.green |
31 | + width: units.gu(20) |
32 | + action: Action { |
33 | + text: i18n.tr("Call %1").arg(shortcut) |
34 | + shortcut: 'Ctrl+C' |
35 | + property bool flipped |
36 | + onTriggered: flipped = !flipped |
37 | + } |
38 | + color: action.flipped ? UbuntuColors.blue : UbuntuColors.green |
39 | } |
40 | } |
41 | |
42 | |
43 | === modified file 'modules/Ubuntu/Components/plugin/plugin.cpp' |
44 | --- modules/Ubuntu/Components/plugin/plugin.cpp 2015-05-26 17:54:51 +0000 |
45 | +++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-07-07 19:08:50 +0000 |
46 | @@ -213,6 +213,7 @@ |
47 | qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13); |
48 | qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem"); |
49 | qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser); |
50 | + qmlRegisterType<UCAction, 1>(uri, 1, 3, "Action"); |
51 | } |
52 | |
53 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
54 | |
55 | === modified file 'modules/Ubuntu/Components/plugin/ucaction.cpp' |
56 | --- modules/Ubuntu/Components/plugin/ucaction.cpp 2014-11-28 13:30:05 +0000 |
57 | +++ modules/Ubuntu/Components/plugin/ucaction.cpp 2015-07-07 19:08:50 +0000 |
58 | @@ -17,6 +17,10 @@ |
59 | #include "ucaction.h" |
60 | |
61 | #include <QtDebug> |
62 | +#include <QtQml/QQmlInfo> |
63 | +#include <QtQuick/qquickitem.h> |
64 | +#include <QtQuick/qquickwindow.h> |
65 | +#include <private/qguiapplication_p.h> |
66 | |
67 | /*! |
68 | * \qmltype Action |
69 | @@ -152,6 +156,7 @@ |
70 | , m_published(false) |
71 | , m_itemHint(0) |
72 | , m_parameterType(None) |
73 | + , m_shortcut(0) |
74 | { |
75 | generateName(); |
76 | } |
77 | @@ -240,6 +245,67 @@ |
78 | qWarning() << "Action.itemHint is a DEPRECATED property. Use ActionItems to specify the representation of an Action."; |
79 | } |
80 | |
81 | +bool shortcutContextMatcher(QObject* object, Qt::ShortcutContext) |
82 | +{ |
83 | + UCAction* action = static_cast<UCAction*>(object); |
84 | + // Can't access member here because it's not public |
85 | + if (!action->property("enabled").toBool()) |
86 | + return false; |
87 | + |
88 | + QObject* window = object; |
89 | + while (window && !window->isWindowType()) { |
90 | + window = window->parent(); |
91 | + if (QQuickItem* item = qobject_cast<QQuickItem*>(window)) |
92 | + window = item->window(); |
93 | + } |
94 | + return window && window == QGuiApplication::focusWindow(); |
95 | +} |
96 | + |
97 | +QKeySequence sequenceFromVariant(const QVariant& variant) { |
98 | + if (variant.type() == QVariant::Int) |
99 | + return static_cast<QKeySequence::StandardKey>(variant.toInt()); |
100 | + if (variant.type() == QVariant::String) |
101 | + return QKeySequence::fromString(variant.toString()); |
102 | + return QKeySequence(); |
103 | +} |
104 | + |
105 | +/*! |
106 | + * \qmlproperty var Action::shortcut |
107 | + * The keyboard shortcut that can be used to trigger the action. |
108 | + * \b StandardKey values such as \b StandardKey.Copy |
109 | + * as well as strings in the form "Ctrl+C" are accepted values. |
110 | + * \since 1.3 |
111 | + */ |
112 | +void UCAction::setShortcut(const QVariant& shortcut) |
113 | +{ |
114 | + if (m_shortcut.isValid()) |
115 | + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, this, sequenceFromVariant(m_shortcut)); |
116 | + |
117 | + QKeySequence sequence(sequenceFromVariant(shortcut)); |
118 | + if (!sequence.toString().isEmpty()) |
119 | + QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence, Qt::WindowShortcut, shortcutContextMatcher); |
120 | + else |
121 | + qmlInfo(this) << "Invalid shortcut: " << shortcut.toString(); |
122 | + |
123 | + m_shortcut = shortcut; |
124 | + Q_EMIT shortcutChanged(shortcut); |
125 | +} |
126 | + |
127 | +bool UCAction::event(QEvent *event) |
128 | +{ |
129 | + if (event->type() != QEvent::Shortcut) |
130 | + return false; |
131 | + |
132 | + QShortcutEvent *shortcut_event(static_cast<QShortcutEvent*>(event)); |
133 | + if (shortcut_event->isAmbiguous()) { |
134 | + qmlInfo(this) << "Ambiguous shortcut: " << shortcut_event->key().toString(); |
135 | + return false; |
136 | + } |
137 | + |
138 | + trigger(); |
139 | + return true; |
140 | +} |
141 | + |
142 | /*! |
143 | * \qmlmethod Action::trigger(var value) |
144 | * Checks the \c value against the action \l parameterType and triggers the action. |
145 | |
146 | === modified file 'modules/Ubuntu/Components/plugin/ucaction.h' |
147 | --- modules/Ubuntu/Components/plugin/ucaction.h 2015-01-07 10:15:34 +0000 |
148 | +++ modules/Ubuntu/Components/plugin/ucaction.h 2015-07-07 19:08:50 +0000 |
149 | @@ -40,6 +40,9 @@ |
150 | Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged) |
151 | Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged) |
152 | Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint) |
153 | + |
154 | + // QtQuickControls.Action |
155 | + Q_PROPERTY(QVariant shortcut MEMBER m_shortcut WRITE setShortcut NOTIFY shortcutChanged REVISION 1) |
156 | public: |
157 | enum Type { |
158 | None, |
159 | @@ -67,6 +70,7 @@ |
160 | void parameterTypeChanged(); |
161 | void iconSourceChanged(); |
162 | void visibleChanged(); |
163 | + void shortcutChanged(const QVariant& shortcut); |
164 | void triggered(const QVariant &value); |
165 | |
166 | public Q_SLOTS: |
167 | @@ -85,6 +89,7 @@ |
168 | QString m_description; |
169 | QString m_keywords; |
170 | Type m_parameterType; |
171 | + QVariant m_shortcut; |
172 | |
173 | friend class UCActionContext; |
174 | friend class UCListItemPrivate; |
175 | @@ -97,6 +102,8 @@ |
176 | void setIconName(const QString &name); |
177 | void setIconSource(const QUrl &url); |
178 | void setItemHint(QQmlComponent *); |
179 | + void setShortcut(const QVariant&); |
180 | + bool event(QEvent *event); |
181 | }; |
182 | |
183 | #endif // UCACTION_H |
184 | |
185 | === added file 'tests/unit_x11/tst_components/tst_shortcuts.qml' |
186 | --- tests/unit_x11/tst_components/tst_shortcuts.qml 1970-01-01 00:00:00 +0000 |
187 | +++ tests/unit_x11/tst_components/tst_shortcuts.qml 2015-07-07 19:08:50 +0000 |
188 | @@ -0,0 +1,92 @@ |
189 | +/* |
190 | + * Copyright 2015 Canonical Ltd. |
191 | + * |
192 | + * This program is free software; you can redistribute it and/or modify |
193 | + * it under the terms of the GNU Lesser General Public License as published by |
194 | + * the Free Software Foundation; version 3. |
195 | + * |
196 | + * This program is distributed in the hope that it will be useful, |
197 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
198 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
199 | + * GNU Lesser General Public License for more details. |
200 | + * |
201 | + * You should have received a copy of the GNU Lesser General Public License |
202 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
203 | + */ |
204 | + |
205 | +import QtQuick 2.4 |
206 | +import QtTest 1.0 |
207 | +import Ubuntu.Test 1.0 |
208 | +import Ubuntu.Components 1.3 |
209 | + |
210 | +Item { |
211 | + id: root |
212 | + width: 400 |
213 | + height: 600 |
214 | + |
215 | + Action { |
216 | + id: action |
217 | + } |
218 | + Action { |
219 | + id: other |
220 | + shortcut: 'Ctrl+G' |
221 | + } |
222 | + |
223 | + TestUtil { |
224 | + id: util |
225 | + } |
226 | + |
227 | + UbuntuTestCase { |
228 | + id: testCase |
229 | + name: "Shortcuts" |
230 | + when: windowShown |
231 | + |
232 | + function initTestCase() { |
233 | + } |
234 | + |
235 | + function init() { |
236 | + } |
237 | + |
238 | + SignalSpy { |
239 | + id: spy |
240 | + signalName: 'triggered' |
241 | + target: action |
242 | + } |
243 | + |
244 | + function ignoreQMLWarning(message) { |
245 | + ignoreWarning(util.callerFile() + message); |
246 | + } |
247 | + |
248 | + function test_shortcut_triggered_data() { |
249 | + return [ |
250 | + { tag: 'Multiple modifiers and letter', shortcut: 'Ctrl+Shift+Alt+A', key: Qt.Key_A, mod: Qt.ControlModifier + Qt.ShiftModifier + Qt.AltModifier }, |
251 | + { tag: 'Modifier and letter', shortcut: 'Ctrl+A', key: Qt.Key_A, mod: Qt.ControlModifier }, |
252 | + { tag: 'Single letter', shortcut: 'E', key: Qt.Key_E, mod: Qt.NoModifier }, |
253 | + { tag: 'StandardKey', shortcut: StandardKey.Copy, key: Qt.Key_C, mod: Qt.ControlModifier } |
254 | + ]; |
255 | + } |
256 | + function test_shortcut_triggered(data) { |
257 | + action.shortcut = data.shortcut; |
258 | + spy.clear(); |
259 | + keyClick(data.key, data.mod); |
260 | + spy.wait(); |
261 | + } |
262 | + |
263 | + function test_shortcut_invalid_data() { |
264 | + return [ |
265 | + { tag: 'Typo', shortcut: 'Ctr+F' }, |
266 | + { tag: 'Number', shortcut: 1234567890 } |
267 | + ]; |
268 | + } |
269 | + function test_shortcut_invalid(data) { |
270 | + ignoreQMLWarning(':27:5: QML Action: Invalid shortcut: '); |
271 | + action.shortcut = data; |
272 | + } |
273 | + |
274 | + function test_shortcut_duplicate() { |
275 | + ignoreQMLWarning(':30:5: QML Action: Ambiguous shortcut: Ctrl+G'); |
276 | + action.shortcut = other.shortcut; |
277 | + keyClick(Qt.Key_G, Qt.ControlModifier); |
278 | + } |
279 | + } |
280 | +} |
FAILED: Continuous integration, rev:1537 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1925/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 3259/console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/653/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/655/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/652/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 3257/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1925/ rebuild
http://