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: mp+262413@code.launchpad.net |
Commit message
Implement Action.shortcut property
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1538. By Cris Dywan
-
Fix doc comment for UCAction::shortcut
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://
Zsombor Egri (zsombi) wrote : | # |
Got some comments inline, check 'em.
- 1539. By Cris Dywan
-
More explicit type check and multi modifier test case
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.
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://
Zsombor Egri (zsombi) wrote : | # |
One more thing we forgot!
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
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://
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
Zsombor Egri (zsombi) wrote : | # |
All good now, let's get it merged.
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 | 8 | signal clicked() | 8 | signal clicked() |
6 | 9 | signal pressAndHold() | 9 | signal pressAndHold() |
7 | 10 | property bool pressed | 10 | property bool pressed |
9 | 11 | Ubuntu.Components.Action 1.0 0.1: QtObject | 11 | Ubuntu.Components.Action 1.3 1.0 0.1: QtObject |
10 | 12 | property string description | 12 | property string description |
11 | 13 | property bool enabled | 13 | property bool enabled |
12 | 14 | property string iconName | 14 | property string iconName |
13 | @@ -20,6 +20,7 @@ | |||
14 | 20 | function trigger() | 20 | function trigger() |
15 | 21 | property string name | 21 | property string name |
16 | 22 | property Type parameterType | 22 | property Type parameterType |
17 | 23 | property var shortcut | ||
18 | 23 | property string text | 24 | property string text |
19 | 24 | property bool visible | 25 | property bool visible |
20 | 25 | Ubuntu.Components.Action.Type: Enum | 26 | Ubuntu.Components.Action.Type: Enum |
21 | 26 | 27 | ||
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 | 48 | 48 | ||
27 | 49 | Button { | 49 | Button { |
28 | 50 | objectName: "button_color" | 50 | objectName: "button_color" |
31 | 51 | text: i18n.tr("Call") | 51 | width: units.gu(20) |
32 | 52 | color: UbuntuColors.green | 52 | action: Action { |
33 | 53 | text: i18n.tr("Call %1").arg(shortcut) | ||
34 | 54 | shortcut: 'Ctrl+C' | ||
35 | 55 | property bool flipped | ||
36 | 56 | onTriggered: flipped = !flipped | ||
37 | 57 | } | ||
38 | 58 | color: action.flipped ? UbuntuColors.blue : UbuntuColors.green | ||
39 | 53 | } | 59 | } |
40 | 54 | } | 60 | } |
41 | 55 | 61 | ||
42 | 56 | 62 | ||
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 | 213 | qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13); | 213 | qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13); |
48 | 214 | qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem"); | 214 | qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem"); |
49 | 215 | qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser); | 215 | qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser); |
50 | 216 | qmlRegisterType<UCAction, 1>(uri, 1, 3, "Action"); | ||
51 | 216 | } | 217 | } |
52 | 217 | 218 | ||
53 | 218 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) | 219 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
54 | 219 | 220 | ||
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 | 17 | #include "ucaction.h" | 17 | #include "ucaction.h" |
60 | 18 | 18 | ||
61 | 19 | #include <QtDebug> | 19 | #include <QtDebug> |
62 | 20 | #include <QtQml/QQmlInfo> | ||
63 | 21 | #include <QtQuick/qquickitem.h> | ||
64 | 22 | #include <QtQuick/qquickwindow.h> | ||
65 | 23 | #include <private/qguiapplication_p.h> | ||
66 | 20 | 24 | ||
67 | 21 | /*! | 25 | /*! |
68 | 22 | * \qmltype Action | 26 | * \qmltype Action |
69 | @@ -152,6 +156,7 @@ | |||
70 | 152 | , m_published(false) | 156 | , m_published(false) |
71 | 153 | , m_itemHint(0) | 157 | , m_itemHint(0) |
72 | 154 | , m_parameterType(None) | 158 | , m_parameterType(None) |
73 | 159 | , m_shortcut(0) | ||
74 | 155 | { | 160 | { |
75 | 156 | generateName(); | 161 | generateName(); |
76 | 157 | } | 162 | } |
77 | @@ -240,6 +245,67 @@ | |||
78 | 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."; |
79 | 241 | } | 246 | } |
80 | 242 | 247 | ||
81 | 248 | bool shortcutContextMatcher(QObject* object, Qt::ShortcutContext) | ||
82 | 249 | { | ||
83 | 250 | UCAction* action = static_cast<UCAction*>(object); | ||
84 | 251 | // Can't access member here because it's not public | ||
85 | 252 | if (!action->property("enabled").toBool()) | ||
86 | 253 | return false; | ||
87 | 254 | |||
88 | 255 | QObject* window = object; | ||
89 | 256 | while (window && !window->isWindowType()) { | ||
90 | 257 | window = window->parent(); | ||
91 | 258 | if (QQuickItem* item = qobject_cast<QQuickItem*>(window)) | ||
92 | 259 | window = item->window(); | ||
93 | 260 | } | ||
94 | 261 | return window && window == QGuiApplication::focusWindow(); | ||
95 | 262 | } | ||
96 | 263 | |||
97 | 264 | QKeySequence sequenceFromVariant(const QVariant& variant) { | ||
98 | 265 | if (variant.type() == QVariant::Int) | ||
99 | 266 | return static_cast<QKeySequence::StandardKey>(variant.toInt()); | ||
100 | 267 | if (variant.type() == QVariant::String) | ||
101 | 268 | return QKeySequence::fromString(variant.toString()); | ||
102 | 269 | return QKeySequence(); | ||
103 | 270 | } | ||
104 | 271 | |||
105 | 272 | /*! | ||
106 | 273 | * \qmlproperty var Action::shortcut | ||
107 | 274 | * The keyboard shortcut that can be used to trigger the action. | ||
108 | 275 | * \b StandardKey values such as \b StandardKey.Copy | ||
109 | 276 | * as well as strings in the form "Ctrl+C" are accepted values. | ||
110 | 277 | * \since 1.3 | ||
111 | 278 | */ | ||
112 | 279 | void UCAction::setShortcut(const QVariant& shortcut) | ||
113 | 280 | { | ||
114 | 281 | if (m_shortcut.isValid()) | ||
115 | 282 | QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, this, sequenceFromVariant(m_shortcut)); | ||
116 | 283 | |||
117 | 284 | QKeySequence sequence(sequenceFromVariant(shortcut)); | ||
118 | 285 | if (!sequence.toString().isEmpty()) | ||
119 | 286 | QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence, Qt::WindowShortcut, shortcutContextMatcher); | ||
120 | 287 | else | ||
121 | 288 | qmlInfo(this) << "Invalid shortcut: " << shortcut.toString(); | ||
122 | 289 | |||
123 | 290 | m_shortcut = shortcut; | ||
124 | 291 | Q_EMIT shortcutChanged(shortcut); | ||
125 | 292 | } | ||
126 | 293 | |||
127 | 294 | bool UCAction::event(QEvent *event) | ||
128 | 295 | { | ||
129 | 296 | if (event->type() != QEvent::Shortcut) | ||
130 | 297 | return false; | ||
131 | 298 | |||
132 | 299 | QShortcutEvent *shortcut_event(static_cast<QShortcutEvent*>(event)); | ||
133 | 300 | if (shortcut_event->isAmbiguous()) { | ||
134 | 301 | qmlInfo(this) << "Ambiguous shortcut: " << shortcut_event->key().toString(); | ||
135 | 302 | return false; | ||
136 | 303 | } | ||
137 | 304 | |||
138 | 305 | trigger(); | ||
139 | 306 | return true; | ||
140 | 307 | } | ||
141 | 308 | |||
142 | 243 | /*! | 309 | /*! |
143 | 244 | * \qmlmethod Action::trigger(var value) | 310 | * \qmlmethod Action::trigger(var value) |
144 | 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. |
145 | 246 | 312 | ||
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 | 40 | Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged) | 40 | Q_PROPERTY(QUrl iconSource MEMBER m_iconSource WRITE setIconSource NOTIFY iconSourceChanged) |
151 | 41 | Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged) | 41 | Q_PROPERTY(bool visible MEMBER m_visible NOTIFY visibleChanged) |
152 | 42 | Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint) | 42 | Q_PROPERTY(QQmlComponent *itemHint MEMBER m_itemHint WRITE setItemHint) |
153 | 43 | |||
154 | 44 | // QtQuickControls.Action | ||
155 | 45 | Q_PROPERTY(QVariant shortcut MEMBER m_shortcut WRITE setShortcut NOTIFY shortcutChanged REVISION 1) | ||
156 | 43 | public: | 46 | public: |
157 | 44 | enum Type { | 47 | enum Type { |
158 | 45 | None, | 48 | None, |
159 | @@ -67,6 +70,7 @@ | |||
160 | 67 | void parameterTypeChanged(); | 70 | void parameterTypeChanged(); |
161 | 68 | void iconSourceChanged(); | 71 | void iconSourceChanged(); |
162 | 69 | void visibleChanged(); | 72 | void visibleChanged(); |
163 | 73 | void shortcutChanged(const QVariant& shortcut); | ||
164 | 70 | void triggered(const QVariant &value); | 74 | void triggered(const QVariant &value); |
165 | 71 | 75 | ||
166 | 72 | public Q_SLOTS: | 76 | public Q_SLOTS: |
167 | @@ -85,6 +89,7 @@ | |||
168 | 85 | QString m_description; | 89 | QString m_description; |
169 | 86 | QString m_keywords; | 90 | QString m_keywords; |
170 | 87 | Type m_parameterType; | 91 | Type m_parameterType; |
171 | 92 | QVariant m_shortcut; | ||
172 | 88 | 93 | ||
173 | 89 | friend class UCActionContext; | 94 | friend class UCActionContext; |
174 | 90 | friend class UCListItemPrivate; | 95 | friend class UCListItemPrivate; |
175 | @@ -97,6 +102,8 @@ | |||
176 | 97 | void setIconName(const QString &name); | 102 | void setIconName(const QString &name); |
177 | 98 | void setIconSource(const QUrl &url); | 103 | void setIconSource(const QUrl &url); |
178 | 99 | void setItemHint(QQmlComponent *); | 104 | void setItemHint(QQmlComponent *); |
179 | 105 | void setShortcut(const QVariant&); | ||
180 | 106 | bool event(QEvent *event); | ||
181 | 100 | }; | 107 | }; |
182 | 101 | 108 | ||
183 | 102 | #endif // UCACTION_H | 109 | #endif // UCACTION_H |
184 | 103 | 110 | ||
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 | 1 | /* | ||
190 | 2 | * Copyright 2015 Canonical Ltd. | ||
191 | 3 | * | ||
192 | 4 | * This program is free software; you can redistribute it and/or modify | ||
193 | 5 | * it under the terms of the GNU Lesser General Public License as published by | ||
194 | 6 | * the Free Software Foundation; version 3. | ||
195 | 7 | * | ||
196 | 8 | * This program is distributed in the hope that it will be useful, | ||
197 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
198 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
199 | 11 | * GNU Lesser General Public License for more details. | ||
200 | 12 | * | ||
201 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
202 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
203 | 15 | */ | ||
204 | 16 | |||
205 | 17 | import QtQuick 2.4 | ||
206 | 18 | import QtTest 1.0 | ||
207 | 19 | import Ubuntu.Test 1.0 | ||
208 | 20 | import Ubuntu.Components 1.3 | ||
209 | 21 | |||
210 | 22 | Item { | ||
211 | 23 | id: root | ||
212 | 24 | width: 400 | ||
213 | 25 | height: 600 | ||
214 | 26 | |||
215 | 27 | Action { | ||
216 | 28 | id: action | ||
217 | 29 | } | ||
218 | 30 | Action { | ||
219 | 31 | id: other | ||
220 | 32 | shortcut: 'Ctrl+G' | ||
221 | 33 | } | ||
222 | 34 | |||
223 | 35 | TestUtil { | ||
224 | 36 | id: util | ||
225 | 37 | } | ||
226 | 38 | |||
227 | 39 | UbuntuTestCase { | ||
228 | 40 | id: testCase | ||
229 | 41 | name: "Shortcuts" | ||
230 | 42 | when: windowShown | ||
231 | 43 | |||
232 | 44 | function initTestCase() { | ||
233 | 45 | } | ||
234 | 46 | |||
235 | 47 | function init() { | ||
236 | 48 | } | ||
237 | 49 | |||
238 | 50 | SignalSpy { | ||
239 | 51 | id: spy | ||
240 | 52 | signalName: 'triggered' | ||
241 | 53 | target: action | ||
242 | 54 | } | ||
243 | 55 | |||
244 | 56 | function ignoreQMLWarning(message) { | ||
245 | 57 | ignoreWarning(util.callerFile() + message); | ||
246 | 58 | } | ||
247 | 59 | |||
248 | 60 | function test_shortcut_triggered_data() { | ||
249 | 61 | return [ | ||
250 | 62 | { tag: 'Multiple modifiers and letter', shortcut: 'Ctrl+Shift+Alt+A', key: Qt.Key_A, mod: Qt.ControlModifier + Qt.ShiftModifier + Qt.AltModifier }, | ||
251 | 63 | { tag: 'Modifier and letter', shortcut: 'Ctrl+A', key: Qt.Key_A, mod: Qt.ControlModifier }, | ||
252 | 64 | { tag: 'Single letter', shortcut: 'E', key: Qt.Key_E, mod: Qt.NoModifier }, | ||
253 | 65 | { tag: 'StandardKey', shortcut: StandardKey.Copy, key: Qt.Key_C, mod: Qt.ControlModifier } | ||
254 | 66 | ]; | ||
255 | 67 | } | ||
256 | 68 | function test_shortcut_triggered(data) { | ||
257 | 69 | action.shortcut = data.shortcut; | ||
258 | 70 | spy.clear(); | ||
259 | 71 | keyClick(data.key, data.mod); | ||
260 | 72 | spy.wait(); | ||
261 | 73 | } | ||
262 | 74 | |||
263 | 75 | function test_shortcut_invalid_data() { | ||
264 | 76 | return [ | ||
265 | 77 | { tag: 'Typo', shortcut: 'Ctr+F' }, | ||
266 | 78 | { tag: 'Number', shortcut: 1234567890 } | ||
267 | 79 | ]; | ||
268 | 80 | } | ||
269 | 81 | function test_shortcut_invalid(data) { | ||
270 | 82 | ignoreQMLWarning(':27:5: QML Action: Invalid shortcut: '); | ||
271 | 83 | action.shortcut = data; | ||
272 | 84 | } | ||
273 | 85 | |||
274 | 86 | function test_shortcut_duplicate() { | ||
275 | 87 | ignoreQMLWarning(':30:5: QML Action: Ambiguous shortcut: Ctrl+G'); | ||
276 | 88 | action.shortcut = other.shortcut; | ||
277 | 89 | keyClick(Qt.Key_G, Qt.ControlModifier); | ||
278 | 90 | } | ||
279 | 91 | } | ||
280 | 92 | } |
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://