Merge lp:~mzanetti/unity8/quicklists into lp:unity8
- quicklists
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michał Sawicz |
Approved revision: | 142 |
Merged at revision: | 217 |
Proposed branch: | lp:~mzanetti/unity8/quicklists |
Merge into: | lp:unity8 |
Diff against target: |
341 lines (+157/-6) 11 files modified
Launcher/Launcher.qml (+2/-2) Launcher/LauncherPanel.qml (+55/-1) plugins/Unity/Launcher/common/quicklistentry.cpp (+5/-0) plugins/Unity/Launcher/common/quicklistentry.h (+2/-0) plugins/Unity/Launcher/launcheritem.cpp (+3/-0) plugins/Unity/Launcher/quicklistmodel.cpp (+2/-0) tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+1/-3) tests/mocks/Unity/Launcher/MockLauncherModel.h (+3/-0) tests/mocks/Unity/Launcher/MockQuickListModel.cpp (+2/-0) tests/mocks/Unity/Launcher/plugin.cpp (+3/-0) tests/qmltests/Launcher/tst_Launcher.qml (+79/-0) |
To merge this branch: | bzr merge lp:~mzanetti/unity8/quicklists |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+180894@code.launchpad.net |
Commit message
initial support for quicklists
For now they support pinning and removing of items
Description of the change
- 140. By Michael Zanetti
-
remove obsolete check for non-clickable item
- 141. By Michael Zanetti
-
hasAction -> clickable to reflect changes in unity-api
- 142. By Michael Zanetti
-
remove unrelated whitespace change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:142
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:142
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) : | # |
Preview Diff
1 | === modified file 'Launcher/Launcher.qml' |
2 | --- Launcher/Launcher.qml 2013-08-15 22:41:41 +0000 |
3 | +++ Launcher/Launcher.qml 2013-08-19 15:20:54 +0000 |
4 | @@ -73,7 +73,7 @@ |
5 | id: dismissTimer |
6 | interval: 5000 |
7 | onTriggered: { |
8 | - if (!panel.moving) { |
9 | + if (!panel.preventHiding) { |
10 | root.state = "" |
11 | } else { |
12 | dismissTimer.restart() |
13 | @@ -162,7 +162,7 @@ |
14 | root.dashItemSelected(index) |
15 | } |
16 | |
17 | - onMovingChanged: { |
18 | + onPreventHidingChanged: { |
19 | if (dismissTimer.running) { |
20 | dismissTimer.restart(); |
21 | } |
22 | |
23 | === modified file 'Launcher/LauncherPanel.qml' |
24 | --- Launcher/LauncherPanel.qml 2013-08-19 11:47:29 +0000 |
25 | +++ Launcher/LauncherPanel.qml 2013-08-19 15:20:54 +0000 |
26 | @@ -19,6 +19,7 @@ |
27 | import Ubuntu.Components.ListItems 0.1 as ListItems |
28 | import Unity 0.1 |
29 | import Unity.Launcher 0.1 |
30 | +import Ubuntu.Components.Popups 0.1 |
31 | import "../Components/ListItems" |
32 | |
33 | Item { |
34 | @@ -29,7 +30,8 @@ |
35 | property var model |
36 | property bool inverted: true |
37 | property bool dragging: false |
38 | - property bool moving: launcherListView.moving || launcherListView.flicking || dndArea.draggedIndex >= 0 |
39 | + property bool moving: launcherListView.moving || launcherListView.flicking |
40 | + property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed |
41 | property int highlightIndex: -1 |
42 | |
43 | signal applicationSelected(string desktopFile) |
44 | @@ -219,6 +221,7 @@ |
45 | |
46 | MouseArea { |
47 | id: dndArea |
48 | + objectName: "dndArea" |
49 | anchors { |
50 | fill: parent |
51 | topMargin: launcherListView.topMargin |
52 | @@ -234,6 +237,7 @@ |
53 | property bool postDragging: false |
54 | property int startX |
55 | property int startY |
56 | + property var quickListPopover: null |
57 | |
58 | onPressed: { |
59 | selectedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY) |
60 | @@ -302,6 +306,13 @@ |
61 | |
62 | draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight); |
63 | |
64 | + // Opening QuickList |
65 | + var quickListModel = launcherListView.model.get(draggedIndex).quickList |
66 | + var quickListAppId = launcherListView.model.get(draggedIndex).appId |
67 | + |
68 | + quickListPopover = PopupUtils.open(popoverComponent, selectedItem, |
69 | + {model: quickListModel, appId: quickListAppId}) |
70 | + |
71 | launcherListView.interactive = false |
72 | |
73 | var yOffset = draggedIndex > 0 ? (mouseY + launcherListView.realContentY) % (draggedIndex * launcherListView.realItemHeight) : mouseY + launcherListView.realContentY |
74 | @@ -324,6 +335,7 @@ |
75 | var distance = Math.max(Math.abs(mouseX - startX), Math.abs(mouseY - startY)) |
76 | if (!preDragging && distance > units.gu(1.5)) { |
77 | preDragging = true; |
78 | + PopupUtils.close(quickListPopover) |
79 | } |
80 | if (distance > launcherListView.itemHeight) { |
81 | selectedItem.dragging = true |
82 | @@ -414,4 +426,46 @@ |
83 | } |
84 | } |
85 | } |
86 | + |
87 | + Component { |
88 | + id: popoverComponent |
89 | + |
90 | + Popover { |
91 | + id: popover |
92 | + property var model |
93 | + property string appId |
94 | + contentWidth: quickListColumn.width |
95 | + |
96 | + // FIXME: There's a bug in the Popover positioning that it covers the item in case it is rotated. |
97 | + // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1204470 |
98 | + // For now, let's move the Popover around with callerMargin. |
99 | + // Remove popupMargin once the bug is fixed. |
100 | + property int popupMargin: root.inverted ? launcherListView.itemHeight : 0; |
101 | + |
102 | + callerMargin: units.gu(1) + popupMargin |
103 | + |
104 | + Column { |
105 | + id: quickListColumn |
106 | + width: units.gu(30) |
107 | + height: childrenRect.height |
108 | + |
109 | + Repeater { |
110 | + model: popover.model |
111 | + |
112 | + ListItems.Standard { |
113 | + objectName: "quickListEntry" + index |
114 | + text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>") |
115 | + highlightWhenPressed: model.clickable |
116 | + onClicked: { |
117 | + if (!model.clickable) { |
118 | + return; |
119 | + } |
120 | + LauncherModel.quickListActionInvoked(appId, index); |
121 | + PopupUtils.close(popover); |
122 | + } |
123 | + } |
124 | + } |
125 | + } |
126 | + } |
127 | + } |
128 | } |
129 | |
130 | === modified file 'plugins/Unity/Launcher/common/quicklistentry.cpp' |
131 | --- plugins/Unity/Launcher/common/quicklistentry.cpp 2013-07-05 11:25:54 +0000 |
132 | +++ plugins/Unity/Launcher/common/quicklistentry.cpp 2013-08-19 15:20:54 +0000 |
133 | @@ -52,3 +52,8 @@ |
134 | { |
135 | m_icon = icon; |
136 | } |
137 | + |
138 | +bool QuickListEntry::clickable() const |
139 | +{ |
140 | + return !m_actionId.isEmpty(); |
141 | +} |
142 | |
143 | === modified file 'plugins/Unity/Launcher/common/quicklistentry.h' |
144 | --- plugins/Unity/Launcher/common/quicklistentry.h 2013-07-05 11:25:54 +0000 |
145 | +++ plugins/Unity/Launcher/common/quicklistentry.h 2013-08-19 15:20:54 +0000 |
146 | @@ -35,6 +35,8 @@ |
147 | QString icon() const; |
148 | void setIcon(const QString &icon); |
149 | |
150 | + bool clickable() const; |
151 | + |
152 | private: |
153 | QString m_actionId; |
154 | QString m_text; |
155 | |
156 | === modified file 'plugins/Unity/Launcher/launcheritem.cpp' |
157 | --- plugins/Unity/Launcher/launcheritem.cpp 2013-07-24 10:42:00 +0000 |
158 | +++ plugins/Unity/Launcher/launcheritem.cpp 2013-08-19 15:20:54 +0000 |
159 | @@ -33,6 +33,9 @@ |
160 | m_count(0), |
161 | m_quickList(new QuickListModel(this)) |
162 | { |
163 | + QuickListEntry nameAction; |
164 | + nameAction.setText(m_name); |
165 | + m_quickList->appendAction(nameAction); |
166 | QuickListEntry pinningAction; |
167 | pinningAction.setActionId("pin_item"); |
168 | pinningAction.setText("Pin to Launcher"); |
169 | |
170 | === modified file 'plugins/Unity/Launcher/quicklistmodel.cpp' |
171 | --- plugins/Unity/Launcher/quicklistmodel.cpp 2013-07-24 10:42:00 +0000 |
172 | +++ plugins/Unity/Launcher/quicklistmodel.cpp 2013-08-19 15:20:54 +0000 |
173 | @@ -66,6 +66,8 @@ |
174 | return m_list.at(index.row()).text(); |
175 | case RoleIcon: |
176 | return m_list.at(index.row()).icon(); |
177 | + case RoleClickable: |
178 | + return m_list.at(index.row()).clickable(); |
179 | } |
180 | return QVariant(); |
181 | } |
182 | |
183 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp' |
184 | --- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2013-08-14 23:00:28 +0000 |
185 | +++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2013-08-19 15:20:54 +0000 |
186 | @@ -131,9 +131,7 @@ |
187 | |
188 | void MockLauncherModel::quickListActionInvoked(const QString &appId, int actionIndex) |
189 | { |
190 | - Q_UNUSED(appId) |
191 | - Q_UNUSED(actionIndex) |
192 | - // Nothing to mock yet... |
193 | + Q_EMIT quickListTriggered(appId, actionIndex); |
194 | } |
195 | |
196 | int MockLauncherModel::findApp(const QString &appId) |
197 | |
198 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.h' |
199 | --- tests/mocks/Unity/Launcher/MockLauncherModel.h 2013-07-08 12:57:39 +0000 |
200 | +++ tests/mocks/Unity/Launcher/MockLauncherModel.h 2013-08-19 15:20:54 +0000 |
201 | @@ -44,6 +44,9 @@ |
202 | Q_INVOKABLE void requestRemove(const QString &appId); |
203 | Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex); |
204 | |
205 | +Q_SIGNALS: |
206 | + void quickListTriggered(const QString &appId, int index); |
207 | + |
208 | private: |
209 | int findApp(const QString &appId); |
210 | |
211 | |
212 | === modified file 'tests/mocks/Unity/Launcher/MockQuickListModel.cpp' |
213 | --- tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2013-07-05 11:25:54 +0000 |
214 | +++ tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2013-08-19 15:20:54 +0000 |
215 | @@ -35,6 +35,8 @@ |
216 | return QLatin1String("test menu entry ") + QString::number(index.row()); |
217 | case RoleIcon: |
218 | return QLatin1String("copy.png"); |
219 | + case RoleClickable: |
220 | + return index.row() == 1 ? false : true; |
221 | } |
222 | return QVariant(); |
223 | } |
224 | |
225 | === modified file 'tests/mocks/Unity/Launcher/plugin.cpp' |
226 | --- tests/mocks/Unity/Launcher/plugin.cpp 2013-07-05 11:25:54 +0000 |
227 | +++ tests/mocks/Unity/Launcher/plugin.cpp 2013-08-19 15:20:54 +0000 |
228 | @@ -20,6 +20,7 @@ |
229 | #include "plugin.h" |
230 | #include "MockLauncherModel.h" |
231 | #include "MockLauncherItem.h" |
232 | +#include "MockQuickListModel.h" |
233 | |
234 | #include <unity/shell/launcher/LauncherModelInterface.h> |
235 | #include <unity/shell/launcher/LauncherItemInterface.h> |
236 | @@ -39,7 +40,9 @@ |
237 | // @uri Unity.Launcher |
238 | qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated."); |
239 | qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated."); |
240 | + qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListModelInterface", "Abstract Interface. Cannot be instantiated."); |
241 | |
242 | qmlRegisterSingletonType<MockLauncherModel>(uri, 0, 1, "LauncherModel", modelProvider); |
243 | qmlRegisterUncreatableType<MockLauncherItem>(uri, 0, 1, "LauncherItem", "Can't create LauncherItems in QML. Get them from the LauncherModel"); |
244 | + qmlRegisterUncreatableType<MockQuickListModel>(uri, 0, 1, "QuickListModel", "Can't create QuickLists in QML. Get them from the LauncherItems"); |
245 | } |
246 | |
247 | === modified file 'tests/qmltests/Launcher/tst_Launcher.qml' |
248 | --- tests/qmltests/Launcher/tst_Launcher.qml 2013-08-16 21:57:18 +0000 |
249 | +++ tests/qmltests/Launcher/tst_Launcher.qml 2013-08-19 15:20:54 +0000 |
250 | @@ -49,6 +49,11 @@ |
251 | property int maxPanelX: 0 |
252 | } |
253 | |
254 | + SignalSpy { |
255 | + id: signalSpy |
256 | + target: LauncherModel |
257 | + } |
258 | + |
259 | Connections { |
260 | target: testCase.findChild(launcher, "launcherPanel") |
261 | |
262 | @@ -306,5 +311,79 @@ |
263 | tryCompare(draggedItem, "itemOpacity", 1) |
264 | tryCompare(fakeDragItem, "visible", false) |
265 | } |
266 | + |
267 | + function test_quicklist_dismiss() { |
268 | + revealer.dragLauncherIntoView(); |
269 | + var draggedItem = findChild(launcher, "launcherDelegate5") |
270 | + var item0 = findChild(launcher, "launcherDelegate0") |
271 | + var fakeDragItem = findChild(launcher, "fakeDragItem") |
272 | + var dndArea = findChild(launcher, "dndArea") |
273 | + |
274 | + // Initial state |
275 | + compare(dndArea.quickListPopover, null) |
276 | + |
277 | + // Doing longpress |
278 | + mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2) |
279 | + tryCompare(fakeDragItem, "visible", true) // Wait longpress happening |
280 | + verify(dndArea.quickListPopover != null) |
281 | + |
282 | + // Dragging a bit (> 1.5 gu) |
283 | + mouseMove(draggedItem, -units.gu(2), draggedItem.height / 2) |
284 | + |
285 | + // QuickList needs to be closed when a drag operation starts |
286 | + tryCompare(dndArea, "quickListPopover", null) |
287 | + |
288 | + mouseRelease(draggedItem); |
289 | + } |
290 | + |
291 | + function test_quicklist_click_data() { |
292 | + return [ |
293 | + {tag: "non-clickable", index: 1, clickable: false }, |
294 | + {tag: "clickable", index: 2, clickable: true }, |
295 | + ]; |
296 | + } |
297 | + |
298 | + function test_quicklist_click(data) { |
299 | + revealer.dragLauncherIntoView(); |
300 | + var clickedItem = findChild(launcher, "launcherDelegate5") |
301 | + var dndArea = findChild(launcher, "dndArea") |
302 | + |
303 | + // Initial state |
304 | + compare(dndArea.quickListPopover, null) |
305 | + |
306 | + // Doing longpress |
307 | + mousePress(clickedItem, clickedItem.width / 2, clickedItem.height / 2) |
308 | + tryCompare(clickedItem, "itemOpacity", 0) // Wait for longpress to happen |
309 | + verify(dndArea.quickListPopover != null) |
310 | + |
311 | + mouseRelease(clickedItem); |
312 | + |
313 | + var quickListEntry = findChild(dndArea.quickListPopover, "quickListEntry" + data.index) |
314 | + |
315 | + signalSpy.clear(); |
316 | + signalSpy.signalName = "quickListTriggered" |
317 | + |
318 | + mouseClick(quickListEntry, quickListEntry.width / 2, quickListEntry.height / 2) |
319 | + |
320 | + if (data.clickable) { |
321 | + // QuickList needs to be closed when some clickable item is clicked |
322 | + tryCompare(dndArea, "quickListPopover", null) |
323 | + |
324 | + compare(signalSpy.count, 1, "Quicklist signal wasn't triggered") |
325 | + compare(signalSpy.signalArguments[0][0], LauncherModel.get(5).appId) |
326 | + compare(signalSpy.signalArguments[0][1], 2) |
327 | + |
328 | + } else { |
329 | + |
330 | + // QuickList must not be closed when a non-clickable item is clicked |
331 | + verify(dndArea.quickListPopover != null) |
332 | + |
333 | + compare(signalSpy.count, 0, "Quicklist signal must NOT be triggered when clicking a non-clickable item") |
334 | + |
335 | + // Click somewhere in the empty space to dismiss the quicklist |
336 | + mouseClick(launcher, launcher.width - units.gu(1), units.gu(1)); |
337 | + tryCompare(dndArea, "quickListPopover", null) |
338 | + } |
339 | + } |
340 | } |
341 | } |
FAILED: Continuous integration, rev:141 jenkins. qa.ubuntu. com/job/ unity8- ci/674/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- saucy/2370 jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- saucy/1156/ console jenkins. qa.ubuntu. com/job/ unity8- saucy-armhf- ci/675 jenkins. qa.ubuntu. com/job/ unity8- saucy-armhf- ci/675/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ unity8- saucy-i386- ci/674 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy/2376 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy/2376/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner- saucy/2012
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity8- ci/674/ rebuild
http://