Merge lp:~zsombi/ubuntu-ui-toolkit/swipeListItemWithActiveChild into lp:ubuntu-ui-toolkit/staging
- swipeListItemWithActiveChild
- Merge into staging
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||
Approved revision: | 1594 | ||||
Merged at revision: | 1591 | ||||
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/swipeListItemWithActiveChild | ||||
Merge into: | lp:ubuntu-ui-toolkit/staging | ||||
Diff against target: |
803 lines (+328/-157) 8 files modified
components.api (+1/-1) src/Ubuntu/Components/plugin/uclistitem.cpp (+77/-34) src/Ubuntu/Components/plugin/uclistitem_p.h (+3/-0) src/Ubuntu/Test/UbuntuTestCase.qml (+5/-5) tests/resources/listitems/ListItemTest.qml (+2/-2) tests/unit_x11/tst_components/ListItemTestCase.qml (+137/-0) tests/unit_x11/tst_components/tst_listitem.qml (+11/-115) tests/unit_x11/tst_components/tst_listitem_extras.qml (+92/-0) |
||||
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/swipeListItemWithActiveChild | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+266390@code.launchpad.net |
Commit message
Fixing swiping over active components.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1589. By Zsombor Egri
-
test added
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1589
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1590. By Zsombor Egri
-
commenting functions
- 1591. By Zsombor Egri
-
API changed
- 1592. By Zsombor Egri
-
adapting old ListItem tests to use common ListItemTestCase
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1592
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
Me thinks tests/unit_
Btw nice refactor on the listitem testing.
- 1593. By Zsombor Egri
-
stage sync
- 1594. By Zsombor Egri
-
fixing test case
Zsombor Egri (zsombi) wrote : | # |
> Me thinks tests/unit_
> that the Button click works, if clicked, not swiped - it only tests right now
> that swiping doesn't trigger it. But we should verify that clicks will be
> triggered as expected (it works in manual testing).
Clicks on the active item should not be triggered when swipe happens. Clicks on ListItem either. Click on active items are tested in tst_listitem.qml
>
> Btw nice refactor on the listitem testing.
I think it would be nice if we'd create these "CPO"s for our needs as it would help us creating tests.. of course the best would be if we wouldn't need to import UITK at all in these CPOs...
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1594
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
Indeed we should have more of these CPO's.
Thanks for fixing the test!
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2015-07-30 13:52:23 +0000 |
3 | +++ components.api 2015-08-04 20:09:32 +0000 |
4 | @@ -1352,7 +1352,7 @@ |
5 | function var findInvisibleChild(var obj, var objectName) |
6 | function var findChildWithProperty(var item, var property, var value) |
7 | function var centerOf(var item) |
8 | - function var mouseMoveSlowly(var item, var x, var y, var dx, var dy, var steps, var stepdelay) |
9 | + function var mouseMoveSlowly(var item, var x, var y, var dx, var dy, var steps, var stepdelay, var buttons) |
10 | function var flick(var item, var x, var y, var dx, var dy, var pressTimeout, var steps, var button, var modifiers, var delay) |
11 | function var mouseLongPress(var item, var x, var y, var button, var modifiers, var delay) |
12 | function var tryCompareFunction(var func, var expectedResult, var timeout) |
13 | |
14 | === modified file 'src/Ubuntu/Components/plugin/uclistitem.cpp' |
15 | --- src/Ubuntu/Components/plugin/uclistitem.cpp 2015-07-28 19:31:13 +0000 |
16 | +++ src/Ubuntu/Components/plugin/uclistitem.cpp 2015-08-04 20:09:32 +0000 |
17 | @@ -1053,6 +1053,25 @@ |
18 | return oldNode; |
19 | } |
20 | |
21 | +// grabs the left mouse button event by turning highlight on, and triggering |
22 | +// swipe events; child items should no longer get mouse events |
23 | +void UCListItemPrivate::grabLeftButtonEvents(QMouseEvent *event) |
24 | +{ |
25 | + Q_Q(UCListItem); |
26 | + button = event->button(); |
27 | + // create style instance |
28 | + loadStyleItem(); |
29 | + setHighlighted(true); |
30 | + lastPos = pressedPos = event->localPos(); |
31 | + // connect the Flickable to know when to rebound |
32 | + listenToRebind(true); |
33 | + if (swiped && parentAttached) { |
34 | + parentAttached->disableInteractive(q, true); |
35 | + } |
36 | + // stop any ongoing animation! |
37 | + swipeEvent(event->localPos(), UCSwipeEvent::Started); |
38 | +} |
39 | + |
40 | void UCListItem::mousePressEvent(QMouseEvent *event) |
41 | { |
42 | UCStyledItemBase::mousePressEvent(event); |
43 | @@ -1063,17 +1082,7 @@ |
44 | return; |
45 | } |
46 | if (d->canHighlight(event) && !d->highlighted && event->button() == Qt::LeftButton) { |
47 | - // create style instance |
48 | - d->loadStyleItem(); |
49 | - d->setHighlighted(true); |
50 | - d->lastPos = d->pressedPos = event->localPos(); |
51 | - // connect the Flickable to know when to rebound |
52 | - d->listenToRebind(true); |
53 | - if (d->swiped && d->parentAttached) { |
54 | - d->parentAttached->disableInteractive(this, true); |
55 | - } |
56 | - // stop any ongoing animation! |
57 | - d->swipeEvent(event->localPos(), UCSwipeEvent::Started); |
58 | + d->grabLeftButtonEvents(event); |
59 | } |
60 | // accept the event so we get the rest of the events as well |
61 | event->setAccepted(true); |
62 | @@ -1125,35 +1134,44 @@ |
63 | d->setHighlighted(false); |
64 | } |
65 | |
66 | -void UCListItem::mouseReleaseEvent(QMouseEvent *event) |
67 | +// ungrabs any previously grabbed left mouse button event |
68 | +void UCListItemPrivate::ungrabLeftButtonEvents(QMouseEvent *event) |
69 | { |
70 | - UCStyledItemBase::mouseReleaseEvent(event); |
71 | - Q_D(UCListItem); |
72 | - d->button = Qt::NoButton; |
73 | + Q_Q(UCListItem); |
74 | // set released |
75 | - if (d->highlighted) { |
76 | + if (highlighted) { |
77 | // unblock ascending Flickables |
78 | - d->listenToRebind(false); |
79 | - if (d->parentAttached) { |
80 | - d->parentAttached->disableInteractive(this, false); |
81 | + listenToRebind(false); |
82 | + if (parentAttached) { |
83 | + parentAttached->disableInteractive(q, false); |
84 | } |
85 | |
86 | - if (!d->suppressClick) { |
87 | + if (!suppressClick) { |
88 | // emit clicked only if not swiped |
89 | - if (!d->swiped) { |
90 | - Q_EMIT clicked(); |
91 | - if (d->mainAction) { |
92 | - Q_EMIT d->mainAction->trigger(d->index()); |
93 | + if (!swiped) { |
94 | + Q_EMIT q->clicked(); |
95 | + if (mainAction) { |
96 | + Q_EMIT mainAction->trigger(index()); |
97 | } |
98 | } |
99 | - d->snapOut(); |
100 | + snapOut(); |
101 | } else { |
102 | // inform style about mouse/touch release |
103 | - d->swipeEvent(event->localPos(), UCSwipeEvent::Finished); |
104 | - d->suppressClick = false; |
105 | - d->setHighlighted(false); |
106 | + swipeEvent(event->localPos(), UCSwipeEvent::Finished); |
107 | + suppressClick = false; |
108 | + setHighlighted(false); |
109 | } |
110 | } |
111 | + button = Qt::NoButton; |
112 | +} |
113 | + |
114 | +void UCListItem::mouseReleaseEvent(QMouseEvent *event) |
115 | +{ |
116 | + UCStyledItemBase::mouseReleaseEvent(event); |
117 | + Q_D(UCListItem); |
118 | + d->ungrabLeftButtonEvents(event); |
119 | + // make sure we ungrab the mouse! |
120 | + ungrabMouse(); |
121 | } |
122 | |
123 | void UCListItem13::mouseReleaseEvent(QMouseEvent *event) |
124 | @@ -1162,6 +1180,15 @@ |
125 | UCListItem::mouseReleaseEvent(event); |
126 | } |
127 | |
128 | +// returns true if the mouse is swiped over the threshold value |
129 | +bool UCListItemPrivate::swipedOverThreshold(const QPointF &mousePos, const QPointF relativePos) |
130 | +{ |
131 | + qreal threshold = UCUnits::instance().gu(xAxisMoveThresholdGU); |
132 | + qreal mouseX = mousePos.x(); |
133 | + qreal pressedX = relativePos.x(); |
134 | + return ((mouseX < (pressedX - threshold)) || (mouseX > (pressedX + threshold))); |
135 | +} |
136 | + |
137 | void UCListItem::mouseMoveEvent(QMouseEvent *event) |
138 | { |
139 | Q_D(UCListItem); |
140 | @@ -1177,16 +1204,14 @@ |
141 | if (d->button == Qt::LeftButton && d->highlighted && !d->swiped && (d->leadingActions || d->trailingActions)) { |
142 | // check if we can initiate the drag at all |
143 | // only X direction matters, if Y-direction leaves the threshold, but X not, the tug is not valid |
144 | - qreal threshold = UCUnits::instance().gu(d->xAxisMoveThresholdGU); |
145 | - qreal mouseX = event->localPos().x(); |
146 | - qreal pressedX = d->pressedPos.x(); |
147 | - |
148 | - if ((mouseX < (pressedX - threshold)) || (mouseX > (pressedX + threshold))) { |
149 | + if (d->swipedOverThreshold(event->localPos(), d->pressedPos)) { |
150 | // the press went out of the threshold area, enable move, if the direction allows it |
151 | d->lastPos = event->localPos(); |
152 | if (d->parentAttached) { |
153 | d->parentAttached->disableInteractive(this, true); |
154 | } |
155 | + qreal mouseX = event->localPos().x(); |
156 | + qreal pressedX = d->pressedPos.x(); |
157 | bool doSwipe = (d->leadingActions && (mouseX > pressedX)) || |
158 | (d->trailingActions && (mouseX < pressedX)); |
159 | d->setSwiped(doSwipe); |
160 | @@ -1208,20 +1233,38 @@ |
161 | bool UCListItem::childMouseEventFilter(QQuickItem *child, QEvent *event) |
162 | { |
163 | QEvent::Type type = event->type(); |
164 | + Q_D(UCListItem); |
165 | if (type == QEvent::MouseButtonPress) { |
166 | // suppress click event if pressed over an active area, except Text, which can also handle |
167 | // mouse clicks when content is an URL |
168 | QMouseEvent *mouse = static_cast<QMouseEvent*>(event); |
169 | if (child->isEnabled() && (child->acceptedMouseButtons() & mouse->button()) && !qobject_cast<QQuickText*>(child)) { |
170 | - Q_D(UCListItem); |
171 | // suppress click |
172 | d->suppressClick = true; |
173 | // listen for flickable to be able to rebind if movement started there! |
174 | d->listenToRebind(true); |
175 | + // if left button pressed, remember the position |
176 | + if (mouse->button() == Qt::LeftButton) { |
177 | + d->pressedPos = mapFromItem(child, mouse->localPos()); |
178 | + d->button = mouse->button(); |
179 | + } |
180 | } |
181 | } else if (type == QEvent::MouseButtonRelease) { |
182 | Q_D(UCListItem); |
183 | d->suppressClick = false; |
184 | + } else if (type == QEvent::MouseMove) { |
185 | + QMouseEvent *mouse = static_cast<QMouseEvent*>(event); |
186 | + const QPointF localPos = mapFromItem(child, mouse->localPos()); |
187 | + if ((mouse->buttons() & Qt::LeftButton) && d->swipedOverThreshold(localPos, d->pressedPos) && !d->highlighted) { |
188 | + // grab the event from the child, so the click doesn't happen anymore, and initiate swiping |
189 | + QMouseEvent pressed(QEvent::MouseButtonPress, localPos, mouse->windowPos(), mouse->screenPos(), |
190 | + Qt::LeftButton, mouse->buttons(), mouse->modifiers()); |
191 | + d->grabLeftButtonEvents(&pressed); |
192 | + // stop click and pressAndHold, then grab the mouse so children do not get the mouse events anymore |
193 | + d->suppressClick = true; |
194 | + d->pressAndHoldTimer.stop(); |
195 | + grabMouse(); |
196 | + } |
197 | } |
198 | return UCStyledItemBase::childMouseEventFilter(child, event); |
199 | } |
200 | |
201 | === modified file 'src/Ubuntu/Components/plugin/uclistitem_p.h' |
202 | --- src/Ubuntu/Components/plugin/uclistitem_p.h 2015-07-28 19:29:19 +0000 |
203 | +++ src/Ubuntu/Components/plugin/uclistitem_p.h 2015-08-04 20:09:32 +0000 |
204 | @@ -67,6 +67,9 @@ |
205 | void update(); |
206 | void snapOut(); |
207 | void swipeEvent(const QPointF &localPos, UCSwipeEvent::Status status); |
208 | + bool swipedOverThreshold(const QPointF &mousePos, const QPointF relativePos); |
209 | + void grabLeftButtonEvents(QMouseEvent *event); |
210 | + void ungrabLeftButtonEvents(QMouseEvent *event); |
211 | |
212 | quint16 defaultThemeVersion; |
213 | bool highlighted:1; |
214 | |
215 | === modified file 'src/Ubuntu/Test/UbuntuTestCase.qml' |
216 | --- src/Ubuntu/Test/UbuntuTestCase.qml 2015-03-20 10:34:45 +0000 |
217 | +++ src/Ubuntu/Test/UbuntuTestCase.qml 2015-08-04 20:09:32 +0000 |
218 | @@ -102,10 +102,10 @@ |
219 | } |
220 | |
221 | /*! |
222 | - Move Mouse from x,y to distance of dx, dy divided to steps with a stepdelay (ms). |
223 | + Move Mouse from x,y to distance of dx, dy divided to steps with a stepdelay (ms) and buttons. |
224 | */ |
225 | - function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay) { |
226 | - mouseMove(item, x, y); |
227 | + function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay,buttons) { |
228 | + mouseMove(item, x, y, buttons); |
229 | var abs_dx = Math.abs(dx) |
230 | var abs_dy = Math.abs(dy) |
231 | var step_dx = dx / steps; |
232 | @@ -121,7 +121,7 @@ |
233 | if (Math.abs(iy) < abs_dy) { |
234 | iy += step_dy; |
235 | } |
236 | - mouseMove(item, x + ix, y + iy, stepdelay); |
237 | + mouseMove(item, x + ix, y + iy, stepdelay, buttons); |
238 | } |
239 | } |
240 | |
241 | @@ -164,7 +164,7 @@ |
242 | wait(pressTimeout); |
243 | } |
244 | // mouse moves are all processed immediately, without delay in between events |
245 | - mouseMoveSlowly(item, x, y, dx, dy, steps, delay); |
246 | + mouseMoveSlowly(item, x, y, dx, dy, steps, delay, button); |
247 | mouseRelease(item, x + dx, y + dy, button, modifiers); |
248 | // empty event buffer |
249 | wait(200); |
250 | |
251 | === modified file 'tests/resources/listitems/ListItemTest.qml' |
252 | --- tests/resources/listitems/ListItemTest.qml 2015-07-22 18:57:58 +0000 |
253 | +++ tests/resources/listitems/ListItemTest.qml 2015-08-04 20:09:32 +0000 |
254 | @@ -15,8 +15,8 @@ |
255 | */ |
256 | |
257 | import QtQuick 2.4 |
258 | -import Ubuntu.Components 1.2 |
259 | -import Ubuntu.Components.Styles 1.2 |
260 | +import Ubuntu.Components 1.3 |
261 | +import Ubuntu.Components.Styles 1.3 |
262 | import QtQuick.Layouts 1.1 |
263 | |
264 | MainView { |
265 | |
266 | === added file 'tests/unit_x11/tst_components/ListItemTestCase.qml' |
267 | --- tests/unit_x11/tst_components/ListItemTestCase.qml 1970-01-01 00:00:00 +0000 |
268 | +++ tests/unit_x11/tst_components/ListItemTestCase.qml 2015-08-04 20:09:32 +0000 |
269 | @@ -0,0 +1,137 @@ |
270 | +/* |
271 | + * Copyright 2015 Canonical Ltd. |
272 | + * |
273 | + * This program is free software; you can redistribute it and/or modify |
274 | + * it under the terms of the GNU Lesser General Public License as published by |
275 | + * the Free Software Foundation; version 3. |
276 | + * |
277 | + * This program is distributed in the hope that it will be useful, |
278 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
279 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
280 | + * GNU Lesser General Public License for more details. |
281 | + * |
282 | + * You should have received a copy of the GNU Lesser General Public License |
283 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
284 | + */ |
285 | + |
286 | +import QtQuick 2.4 |
287 | +import QtTest 1.0 |
288 | +import Ubuntu.Test 1.0 |
289 | +import Ubuntu.Components 1.2 |
290 | + |
291 | +/* |
292 | + * Common test case functions for ListItem. A CPO for unit tests. |
293 | + */ |
294 | +UbuntuTestCase { |
295 | + when: windowShown |
296 | + |
297 | + SignalSpy { |
298 | + id: signalSpy |
299 | + } |
300 | + |
301 | + // set up the spy component for an item and a signal |
302 | + function setupSpy(item, signalName) { |
303 | + if (item.hasOwnProperty("leadingActions")) { |
304 | + signalSpy.target = item; |
305 | + signalSpy.signalName = signalName; |
306 | + } |
307 | + } |
308 | + // wait on the previosuly set up spy |
309 | + function spyWait(timeout) { |
310 | + if (timeout == undefined) { |
311 | + timeout = 500; |
312 | + } |
313 | + if (signalSpy.target) { |
314 | + signalSpy.wait(timeout); |
315 | + signalSpy.clear(); |
316 | + signalSpy.target = null; |
317 | + } else { |
318 | + wait(timeout); |
319 | + } |
320 | + } |
321 | + |
322 | + // rebounds a ListItem |
323 | + function rebound(item, watchTarget) { |
324 | + if (watchTarget === undefined) { |
325 | + watchTarget = item; |
326 | + } |
327 | + |
328 | + if (watchTarget.contentItem.x != watchTarget.contentItem.anchors.leftMargin) { |
329 | + mouseClick(item, 1, 1); |
330 | + tryCompareFunction(function() { |
331 | + return watchTarget.contentItem.x == watchTarget.contentItem.anchors.leftMargin; |
332 | + }, true, 500); |
333 | + } |
334 | + } |
335 | + |
336 | + // delayed swipe, gives few millisecond timeout between each move |
337 | + // so Repeater has time to create the panel actions in style |
338 | + function swipe(item, x, y, dx, dy) { |
339 | + setupSpy(item, "contentMovementEnded"); |
340 | + flick(item, x, y, dx, dy, 0, 0, undefined, undefined, 100); |
341 | + spyWait(); |
342 | + } |
343 | + function swipeNoWait(item, x, y, dx, dy) { |
344 | + flick(item, x, y, dx, dy, 0, 0, undefined, undefined, 100); |
345 | + } |
346 | + |
347 | + function tug(item, x, y, dx, dy) { |
348 | + setupSpy(item, "contentMovementEnded"); |
349 | + TestExtras.touchDrag(0, item, Qt.point(x, y), Qt.point(dx, dy)); |
350 | + spyWait(); |
351 | + } |
352 | + |
353 | + // returns the leading or trailing panel item |
354 | + function panelItem(item, leading) { |
355 | + return findInvisibleChild(item, (leading ? "ListItemPanelLeading" : "ListItemPanelTrailing")); |
356 | + } |
357 | + |
358 | + function toggleSelectMode(view, enabled, scrollToTop) { |
359 | + if (view.hasOwnProperty("positionViewAtBeginning") && scrollToTop) { |
360 | + // use the topmost listItem to wait for rendering completion |
361 | + view.positionViewAtBeginning(); |
362 | + } |
363 | + var listItem = findChild(view, "listItem0"); |
364 | + verify(listItem); |
365 | + view.ViewItems.selectMode = enabled; |
366 | + // waitForRendering aint seems to be reliable here, so we wait ~400 msecs |
367 | + wait(400); |
368 | + } |
369 | + |
370 | + function toggleDragMode(view, enabled) { |
371 | + // use the topmost listItem to wait for rendering completion |
372 | + view.positionViewAtBeginning(); |
373 | + var listItem = findChild(view, "listItem0"); |
374 | + verify(listItem); |
375 | + view.ViewItems.dragMode = enabled; |
376 | + // waitForRendering aint seems to be reliable here, so we wait ~400 msecs |
377 | + wait(400); |
378 | + } |
379 | + |
380 | + function drag(view, from, to) { |
381 | + var dragArea = findChild(view, "drag_area"); |
382 | + verify(dragArea, "Cannot locate drag area"); |
383 | + |
384 | + // grab the source item |
385 | + view.positionViewAtBeginning(from,ListView.Beginning); |
386 | + var panel = findChild(view, "drag_panel" + from); |
387 | + verify(panel, "Cannot locate source panel"); |
388 | + var dragPos = dragArea.mapFromItem(panel, centerOf(panel).x, centerOf(panel).y); |
389 | + // move the mouse |
390 | + var dy = Math.abs(to - from) * panel.height + units.gu(1); |
391 | + dy *= (to > from) ? 1 : -1; |
392 | + mousePress(dragArea, dragPos.x, dragPos.y); |
393 | + wait(100); |
394 | + var draggedItem = findChild(view.contentItem, "DraggedListItem"); |
395 | + if (draggedItem) { |
396 | + setupSpy(draggedItem.__styleInstance.dropAnimation, "stopped"); |
397 | + } |
398 | + // use 10 steps to be sure the move is properly detected by the drag area |
399 | + mouseMoveSlowly(dragArea, dragPos.x, dragPos.y, 0, dy, 10, 100); |
400 | + // drop it, needs two mouse releases, this generates the Drop event also |
401 | + mouseRelease(dragArea, dragPos.x, dragPos.y + dy); |
402 | + // needs one more mouse release |
403 | + mouseRelease(dragArea, dragPos.x, dragPos.y + dy); |
404 | + spyWait(); |
405 | + } |
406 | +} |
407 | |
408 | === modified file 'tests/unit_x11/tst_components/tst_listitem.qml' |
409 | --- tests/unit_x11/tst_components/tst_listitem.qml 2015-07-28 19:31:13 +0000 |
410 | +++ tests/unit_x11/tst_components/tst_listitem.qml 2015-08-04 20:09:32 +0000 |
411 | @@ -172,7 +172,7 @@ |
412 | } |
413 | } |
414 | |
415 | - UbuntuTestCase { |
416 | + ListItemTestCase { |
417 | id: testCase |
418 | name: "ListItemAPI" |
419 | when: windowShown |
420 | @@ -202,88 +202,11 @@ |
421 | signalName: "interactiveChanged" |
422 | } |
423 | |
424 | - function panelItem(item, leading) { |
425 | - return findInvisibleChild(item, (leading ? "ListItemPanelLeading" : "ListItemPanelTrailing")); |
426 | - } |
427 | - |
428 | - function rebound(item, watchTarget) { |
429 | - if (watchTarget === undefined) { |
430 | - watchTarget = item; |
431 | - } |
432 | - |
433 | - if (watchTarget.contentItem.x != watchTarget.contentItem.anchors.leftMargin) { |
434 | - mouseClick(item, centerOf(item).x, centerOf(item).y); |
435 | - tryCompareFunction(function() { |
436 | - return watchTarget.contentItem.x == watchTarget.contentItem.anchors.leftMargin; |
437 | - }, true, 500); |
438 | - } |
439 | - } |
440 | - |
441 | - // delayed swipe, gives few millisecond timeout between each move |
442 | - // so Repeater has time to create the panel actions in style |
443 | - function swipe(item, x, y, dx, dy) { |
444 | - flick(item, x, y, dx, dy, 0, 0, undefined, undefined, 100); |
445 | - } |
446 | - |
447 | SignalSpy { |
448 | id: dropSpy |
449 | signalName: "stopped" |
450 | } |
451 | |
452 | - function toggleSelectMode(view, enabled, scrollToTop) { |
453 | - if (view.hasOwnProperty("positionViewAtBeginning") && scrollToTop) { |
454 | - // use the topmost listItem to wait for rendering completion |
455 | - view.positionViewAtBeginning(); |
456 | - } |
457 | - var listItem = findChild(view, "listItem0"); |
458 | - verify(listItem); |
459 | - view.ViewItems.selectMode = enabled; |
460 | - // waitForRendering aint seems to be reliable here, so we wait ~400 msecs |
461 | - wait(400); |
462 | - } |
463 | - |
464 | - function toggleDragMode(view, enabled) { |
465 | - // use the topmost listItem to wait for rendering completion |
466 | - view.positionViewAtBeginning(); |
467 | - var listItem = findChild(view, "listItem0"); |
468 | - verify(listItem); |
469 | - view.ViewItems.dragMode = enabled; |
470 | - // waitForRendering aint seems to be reliable here, so we wait ~400 msecs |
471 | - wait(400); |
472 | - } |
473 | - |
474 | - function drag(view, from, to) { |
475 | - var dragArea = findChild(view, "drag_area"); |
476 | - verify(dragArea, "Cannot locate drag area"); |
477 | - |
478 | - // grab the source item |
479 | - view.positionViewAtBeginning(from,ListView.Beginning); |
480 | - var panel = findChild(view, "drag_panel" + from); |
481 | - verify(panel, "Cannot locate source panel"); |
482 | - var dragPos = dragArea.mapFromItem(panel, centerOf(panel).x, centerOf(panel).y); |
483 | - // move the mouse |
484 | - var dy = Math.abs(to - from) * panel.height + units.gu(1); |
485 | - dy *= (to > from) ? 1 : -1; |
486 | - mousePress(dragArea, dragPos.x, dragPos.y); |
487 | - wait(100); |
488 | - var draggedItem = findChild(view.contentItem, "DraggedListItem"); |
489 | - if (draggedItem) { |
490 | - dropSpy.target = draggedItem.__styleInstance.dropAnimation; |
491 | - } |
492 | - // use 10 steps to be sure the move is properly detected by the drag area |
493 | - mouseMoveSlowly(dragArea, dragPos.x, dragPos.y, 0, dy, 10, 100); |
494 | - // drop it, needs two mouse releases, this generates the Drop event also |
495 | - mouseRelease(dragArea, dragPos.x, dragPos.y + dy); |
496 | - // needs one more mouse release |
497 | - mouseRelease(dragArea, dragPos.x, dragPos.y + dy); |
498 | - if (dropSpy.target) { |
499 | - dropSpy.wait(); |
500 | - } else { |
501 | - // draggedItem cannot be found, we might be trying to drag a restricted item |
502 | - wait(200); |
503 | - } |
504 | - } |
505 | - |
506 | function initTestCase() { |
507 | TestExtras.registerTouchDevice(); |
508 | waitForRendering(main); |
509 | @@ -405,12 +328,10 @@ |
510 | var item = findChild(listView, "listItem0"); |
511 | clickSpy.target = item; |
512 | clickSpy.clear(); |
513 | - movingSpy.target = item; |
514 | swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0); |
515 | - movingSpy.wait(); |
516 | |
517 | // click over the contentItem |
518 | - movingSpy.clear(); |
519 | + movingSpy.target = item; |
520 | mouseClick(item.contentItem, 1, 1); |
521 | compare(clickSpy.count, 0, "No click() should be emitted on a swiped in ListItem."); |
522 | movingSpy.wait(); |
523 | @@ -420,12 +341,10 @@ |
524 | var item = findChild(listView, "listItem0"); |
525 | pressAndHoldSpy.target = item; |
526 | pressAndHoldSpy.clear(); |
527 | - movingSpy.target = item; |
528 | swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0); |
529 | - movingSpy.wait(); |
530 | |
531 | // press and hold |
532 | - movingSpy.clear(); |
533 | + movingSpy.target = item; |
534 | mouseLongPress(item.contentItem, 1, 1); |
535 | mouseRelease(item.contentItem, 1, 1); |
536 | mouseRelease(item.contentItem, 1, 1); |
537 | @@ -490,13 +409,11 @@ |
538 | } |
539 | function test_tug_actions(data) { |
540 | listView.positionViewAtBeginning(); |
541 | - movingSpy.target = data.item; |
542 | if (data.mouse) { |
543 | swipe(data.item, data.pos.x, data.pos.y, data.dx, 0); |
544 | } else { |
545 | - TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0)); |
546 | + tug(data.item, data.pos.x, data.pos.y, data.dx, 0); |
547 | } |
548 | - movingSpy.wait(); |
549 | if (data.positiveDirection) { |
550 | verify(data.item.contentItem.x > 0, data.tag + " actions did not show up"); |
551 | } else { |
552 | @@ -527,13 +444,11 @@ |
553 | } |
554 | function test_rebound_when_pressed_outside_or_clicked(data) { |
555 | listView.positionViewAtBeginning(); |
556 | - movingSpy.target = data.item; |
557 | if (data.mouse) { |
558 | swipe(data.item, data.pos.x, data.pos.y, data.dx, 0); |
559 | } else { |
560 | - TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0)); |
561 | + tug(data.item, data.pos.x, data.pos.y, data.dx, 0); |
562 | } |
563 | - movingSpy.wait(); |
564 | verify(data.item.contentItem.x != 0, "The component wasn't tugged!"); |
565 | // dismiss |
566 | rebound(data.clickOn, data.item) |
567 | @@ -553,14 +468,12 @@ |
568 | listView.positionViewAtBeginning(); |
569 | interactiveSpy.target = listView; |
570 | compare(listView.interactive, true, "ListView is not interactive"); |
571 | - movingSpy.target = data.item; |
572 | interactiveSpy.target = listView; |
573 | if (data.mouse) { |
574 | swipe(data.item, data.pos.x, data.pos.y, data.dx, data.dy); |
575 | } else { |
576 | - TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, data.dy)); |
577 | + tug(data.item, data.pos.x, data.pos.y, data.dx, data.dy); |
578 | } |
579 | - movingSpy.wait(); |
580 | // animation should no longer be running! |
581 | compare(listView.interactive, true, "The ListView is still non-interactive!"); |
582 | compare(interactiveSpy.count, 2, "Less/more times changed!"); |
583 | @@ -580,9 +493,7 @@ |
584 | ]; |
585 | } |
586 | function test_visualized_actions(data) { |
587 | - movingSpy.target = data.item; |
588 | swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.leading ? units.gu(20) : -units.gu(20), 0); |
589 | - movingSpy.wait(); |
590 | |
591 | // check if the action is visible |
592 | var panel = panelItem(data.item, data.leading); |
593 | @@ -604,9 +515,7 @@ |
594 | } |
595 | function test_listitem_margins(data) { |
596 | data.item.contentItem.anchors.margins = units.gu(1); |
597 | - movingSpy.target = data.item; |
598 | swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0); |
599 | - movingSpy.wait(); |
600 | var panel = panelItem(data.item, data.leading); |
601 | verify(panel && panel.visible, "Panel not visible."); |
602 | // cleanup |
603 | @@ -624,13 +533,11 @@ |
604 | } |
605 | function test_selecting_action_rebounds(data) { |
606 | listView.positionViewAtBeginning(); |
607 | - movingSpy.target = data.item; |
608 | if (data.mouse) { |
609 | swipe(data.item, data.pos.x, data.pos.y, data.dx, 0); |
610 | } else { |
611 | - TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0)); |
612 | + tug(data.item, data.pos.x, data.pos.y, data.dx, 0); |
613 | } |
614 | - movingSpy.wait(); |
615 | verify(data.item.contentItem.x > 0, "Not snapped in!"); |
616 | var panel = panelItem(data.item, data.leading); |
617 | verify(panel, "panelItem not found"); |
618 | @@ -638,7 +545,7 @@ |
619 | verify(selectedAction, "Cannot select action " + data.select); |
620 | |
621 | // dismiss |
622 | - movingSpy.clear(); |
623 | + movingSpy.target = data.item; |
624 | if (data.mouse) { |
625 | mouseClick(selectedAction, centerOf(selectedAction).x, centerOf(selectedAction).y); |
626 | } else { |
627 | @@ -653,7 +560,7 @@ |
628 | listView.positionViewAtBeginning(); |
629 | var item = findChild(listView, "listItem0"); |
630 | movingSpy.target = item; |
631 | - swipe(item, centerOf(item).x, centerOf(item).y, -units.gu(20), 0); |
632 | + swipeNoWait(item, centerOf(item).x, centerOf(item).y, -units.gu(20), 0); |
633 | var panel = panelItem(item, false); |
634 | verify(panel, "Panel is not visible"); |
635 | var custom = findChild(panel, "custom_delegate"); |
636 | @@ -677,11 +584,8 @@ |
637 | ]; |
638 | } |
639 | function test_snap(data) { |
640 | - movingSpy.target = data.item; |
641 | swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0); |
642 | - movingSpy.wait(); |
643 | waitForRendering(data.item.contentItem, 400); |
644 | - movingSpy.clear(); |
645 | if (data.snapIn) { |
646 | verify(data.item.contentItem.x != 0.0, "Not snapped to be visible"); |
647 | // cleanup |
648 | @@ -741,9 +645,7 @@ |
649 | } |
650 | function test_verify_action_value(data) { |
651 | // tug actions in |
652 | - movingSpy.target = data.item; |
653 | swipe(data.item, 1, centerOf(data.item).y, units.gu(40), 0); |
654 | - movingSpy.wait(); |
655 | wait(2000); |
656 | verify(data.item.contentItem.x != data.item.contentItem.anchors.leftMargin, "Not snapped in"); |
657 | |
658 | @@ -754,7 +656,7 @@ |
659 | actionSpy.target = data.item.leadingActions.actions[1]; |
660 | |
661 | // select the action |
662 | - movingSpy.clear(); |
663 | + movingSpy.target = data.item; |
664 | mouseClick(action, centerOf(action).x, centerOf(action).y); |
665 | movingSpy.wait(); |
666 | |
667 | @@ -843,10 +745,8 @@ |
668 | var listItem = findChild(nestedListView, "listItem0"); |
669 | verify(listItem, "Cannot find test item"); |
670 | interactiveSpy.target = testFlickable; |
671 | - movingSpy.target = listItem; |
672 | // tug leading |
673 | swipe(listItem, centerOf(listItem).x, centerOf(listItem).y, listItem.width / 2, 0); |
674 | - movingSpy.wait(); |
675 | // check if interactive got changed |
676 | interactiveSpy.wait(); |
677 | |
678 | @@ -963,7 +863,7 @@ |
679 | |
680 | // try to tug leading |
681 | movingSpy.clear(); |
682 | - swipe(testItem, centerOf(testItem).x, centerOf(testItem).y, units.gu(10), 0); |
683 | + swipeNoWait(testItem, centerOf(testItem).x, centerOf(testItem).y, units.gu(10), 0); |
684 | compare(movingSpy.count, 0, "No tug allowed when in selection mode"); |
685 | } |
686 | |
687 | @@ -1241,9 +1141,7 @@ |
688 | listView.LayoutMirroring.enabled = true; |
689 | waitForRendering(listView, 500); |
690 | var listItem = findChild(listView, data.item); |
691 | - movingSpy.target = listItem; |
692 | swipe(listItem, centerOf(listItem).x, centerOf(listItem).y, data.leading ? -units.gu(20) : units.gu(20), 0); |
693 | - movingSpy.wait(); |
694 | |
695 | // check if the action is visible |
696 | var panel = panelItem(listItem, data.leading); |
697 | @@ -1298,9 +1196,7 @@ |
698 | var height = testItem.height; |
699 | testItem.height = units.gu(15); |
700 | |
701 | - movingSpy.target = testItem; |
702 | swipe(testItem, centerOf(testItem).x, centerOf(testItem).y, data.dx); |
703 | - movingSpy.wait(); |
704 | |
705 | var icon = findChild(testItem, data.action); |
706 | verify(icon); |
707 | |
708 | === added file 'tests/unit_x11/tst_components/tst_listitem_extras.qml' |
709 | --- tests/unit_x11/tst_components/tst_listitem_extras.qml 1970-01-01 00:00:00 +0000 |
710 | +++ tests/unit_x11/tst_components/tst_listitem_extras.qml 2015-08-04 20:09:32 +0000 |
711 | @@ -0,0 +1,92 @@ |
712 | +/* |
713 | + * Copyright 2015 Canonical Ltd. |
714 | + * |
715 | + * This program is free software; you can redistribute it and/or modify |
716 | + * it under the terms of the GNU Lesser General Public License as published by |
717 | + * the Free Software Foundation; version 3. |
718 | + * |
719 | + * This program is distributed in the hope that it will be useful, |
720 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
721 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
722 | + * GNU Lesser General Public License for more details. |
723 | + * |
724 | + * You should have received a copy of the GNU Lesser General Public License |
725 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
726 | + */ |
727 | + |
728 | +import QtQuick 2.4 |
729 | +import QtTest 1.0 |
730 | +import Ubuntu.Test 1.0 |
731 | +import Ubuntu.Components 1.3 |
732 | + |
733 | +Item { |
734 | + id: main |
735 | + width: units.gu(50) |
736 | + height: units.gu(100) |
737 | + |
738 | + ListItemActions { |
739 | + id: trailing |
740 | + actions: [ |
741 | + Action { |
742 | + iconName: "starred" |
743 | + text: 'Bookmark' |
744 | + objectName: "leading_1" |
745 | + }, |
746 | + Action { |
747 | + iconName: "edit" |
748 | + text: 'Edit' |
749 | + objectName: "leading_2" |
750 | + onTriggered: text = 'Edit Again' |
751 | + }, |
752 | + Action { |
753 | + iconName: "camcorder" |
754 | + text: 'Record' |
755 | + objectName: "leading_3" |
756 | + } |
757 | + ] |
758 | + } |
759 | + ListItemActions { |
760 | + id: leading |
761 | + actions: Action { |
762 | + id: stockAction |
763 | + iconName: "torch-on" |
764 | + objectName: "stockAction" |
765 | + text: 'Switch lights on' |
766 | + } |
767 | + } |
768 | + |
769 | + Column { |
770 | + anchors.fill: parent |
771 | + |
772 | + ListItem { |
773 | + id: testWithActiveItem |
774 | + leadingActions: leading |
775 | + trailingActions: trailing |
776 | + Button { |
777 | + id: activeItem |
778 | + text: "pressme" |
779 | + anchors.centerIn: parent |
780 | + } |
781 | + } |
782 | + } |
783 | + |
784 | + ListItemTestCase { |
785 | + |
786 | + SignalSpy { |
787 | + id: clickSpy |
788 | + signalName: "clicked" |
789 | + } |
790 | + |
791 | + function cleanup() { |
792 | + rebound(testWithActiveItem); |
793 | + clickSpy.target = null; |
794 | + clickSpy.clear(); |
795 | + } |
796 | + |
797 | + function test_swipe_over_active_item() { |
798 | + clickSpy.target = activeItem; |
799 | + swipe(activeItem, centerOf(activeItem).x, centerOf(activeItem).y, units.gu(10)); |
800 | + compare(clickSpy.count, 0, "activeItem was clicked"); |
801 | + } |
802 | + } |
803 | +} |
PASSED: Continuous integration, rev:1588 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2074/ jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/802 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/804 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/804/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/801
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2074/ rebuild
http://