Merge lp:~zsombi/ubuntu-ui-toolkit/80-selection-mode into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Cris Dywan
Approved revision: 1379
Merged at revision: 1413
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/80-selection-mode
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/79b-styling-reshufled
Diff against target: 1314 lines (+640/-69)
16 files modified
components.api (+5/-0)
examples/ubuntu-ui-toolkit-gallery/ListItemWithLabel.qml (+1/-0)
examples/ubuntu-ui-toolkit-gallery/NewListItems.qml (+28/-13)
modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml (+86/-16)
modules/Ubuntu/Components/plugin/uclistitem.cpp (+128/-13)
modules/Ubuntu/Components/plugin/uclistitem.h (+17/-0)
modules/Ubuntu/Components/plugin/uclistitem_p.h (+17/-2)
modules/Ubuntu/Components/plugin/uclistitemstyle.cpp (+20/-0)
modules/Ubuntu/Components/plugin/uclistitemstyle.h (+6/-0)
modules/Ubuntu/Components/plugin/ucviewitemsattached.cpp (+83/-5)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py (+22/-0)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_uclistitem.py (+6/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.ListItemTestCase.qml (+3/-1)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.py (+12/-0)
tests/resources/listitems/ListItemTest.qml (+18/-2)
tests/unit_x11/tst_components/tst_listitem.qml (+188/-17)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/80-selection-mode
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Cris Dywan Approve
Review via email: mp+249499@code.launchpad.net

Commit message

Introducing select/multiselect mode in ListItem.

To post a comment you must log in.
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)
Revision history for this message
Cris Dywan (kalikiana) wrote :

> 747 + self.wait_select_single('QQuickItem', objectName='selection_panel0')

A proper error message in a ToolkitException is desirable here I think.

The "new list items" section in the gallery prints "qml: Highlighting list item" when tapping, overlooked debugging? More importantly I don't see selection mode demonstrated at all.

I've used tests/resources/listitems/ListItemTest.qml for testing a bit, unfortunately it doesn't scroll so I'm not sure if I can see everything in there. At the bottom there's a very narrow item with a switch.

The test_listitem.ListItemTestCase.qml has "onPressAndHold: listView.ViewItems.selectMode = true", I'm thinking this should be available in the gallery and manual test case as well.

Visual observation: the animation from toggling select mode flickers extremely. Is this expected?

> 973 - flick(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);
> 974 + swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);

Why is this? Work-around? Something to document?

> 268 + * attached property. This property is attached to each parent item of the ListItem

I don't really understand the explanation and the example doesn't demonstrate what I think it says. There's no ListView here. The Flickable has the attached property but Column supposedly won't work. I would expect Column to be the parent and have the property. Aside from clarifying the wording I'd suggest two examples because of the special case.

review: Needs Fixing
Revision history for this message
Zsombor Egri (zsombi) wrote :
Download full text (3.5 KiB)

> > 747 + self.wait_select_single('QQuickItem', objectName='selection_panel0')
>
> A proper error message in a ToolkitException is desirable here I think.

Ok, I'll add that.

>
> The "new list items" section in the gallery prints "qml: Highlighting list
> item" when tapping, overlooked debugging? More importantly I don't see
> selection mode demonstrated at all.

That is Tim's playground, he used to update that part when I have an MR bringing new features to ListItem, that's the way he used to test the new features and eventually suggest API changes, extra API. That's why I don't have anything there. The print is an expected extra for the gallery.

>
> I've used tests/resources/listitems/ListItemTest.qml for testing a bit,
> unfortunately it doesn't scroll so I'm not sure if I can see everything in
> there. At the bottom there's a very narrow item with a switch.

The whole view doesn't scroll, true. It's a bit crowded to be honest... It has a ListItem and a Flickable, testing attached behavior in both. Perhaps I should add a separate sample for select mode...

>
> The test_listitem.ListItemTestCase.qml has "onPressAndHold:
> listView.ViewItems.selectMode = true", I'm thinking this should be available
> in the gallery and manual test case as well.

Right. As said, Tim used to test the API, perhaps you can also do an MR based on this and then we submit that. It's better if someone else tries also the API to make sure it's understandable and easy to use.

>
> Visual observation: the animation from toggling select mode flickers
> extremely. Is this expected?
>
> > 973 - flick(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);
> > 974 + swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);
>
> Why is this? Work-around? Something to document?

I think the swipe() function documents it... It is intentional, as we discussed in one of the standups last week, I have to move slower than the test function otherwise does, so the Repeater can create all the elements based on the model, otherwise the swipe is not reliable.

>
> > 268 + * attached property. This property is attached to each parent item
> of the ListItem
>
> I don't really understand the explanation and the example doesn't demonstrate
> what I think it says. There's no ListView here. The Flickable has the attached
> property but Column supposedly won't work. I would expect Column to be the
> parent and have the property. Aside from clarifying the wording I'd suggest
> two examples because of the special case.

No. ListItem's parents are the Column, and that will get the ViewItems attached property. Exception is the ListView, where the contentItem would be the one to have the attached property, but the ListItem detects it and attaches top ListView.

So, ViewItems is automatically attached to the ListItem's parent exception being when used as delegate of ListView, when will be attached to the ListView itself. So Column gets it automatically, and all you set in Column it will have effect to the ListItems in Column, but the one declared in Flickable won't work. It will not give error, but won't do anything. And unfortunately we cannot drive or detect whether...

Read more...

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)
Revision history for this message
Cris Dywan (kalikiana) wrote :

So… "selectable" is now available… I expected ViewItems.selectMode to work on ListItem which isn't the case. Using "selectable" works but seems wrong because it appears to be a property of each item when it's for the whole group.

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

> So… "selectable" is now available… I expected ViewItems.selectMode to work on
> ListItem which isn't the case. Using "selectable" works but seems wrong
> because it appears to be a property of each item when it's for the whole
> group.

Expecting ViewItems.selectMode to work on ListItem would mean you would have to have it attachable to the ListItem, right? That is equivalent on having the selectable property available, which we have now. Unless you meant to be "available" through its parent, in which case that is doable by having the "if (ListView.view != null) { ListView.view.ViewItems.selectMode } else { parent.ViewItems.selectMode }" setup.

In case this setup seems miserable, we can restrict to have the ViewItems available only for ListView, in which case we lose the flexibility of the ListItem. Dragging for instance will be available only on ListView, as it cannot handle the proper rearranging of the ListItems without the displaced animation, as Repeater or Column/Row for instance does not provide any abilities to animate the position changes.

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

documentation fixed

1379. By Zsombor Egri

staging merge

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

Looking good!

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-02-18 12:40:42 +0000
+++ components.api 2015-02-19 12:17:51 +0000
@@ -935,6 +935,8 @@
935 Property { name: "contentMoving"; type: "bool"; isReadonly: true }935 Property { name: "contentMoving"; type: "bool"; isReadonly: true }
936 Property { name: "color"; type: "QColor" }936 Property { name: "color"; type: "QColor" }
937 Property { name: "highlightColor"; type: "QColor" }937 Property { name: "highlightColor"; type: "QColor" }
938 Property { name: "selected"; type: "bool" }
939 Property { name: "selectMode"; type: "bool" }
938 Property { name: "action"; type: "UCAction"; isPointer: true }940 Property { name: "action"; type: "UCAction"; isPointer: true }
939 Property { name: "listItemData"; type: "QObject"; isList: true; isReadonly: true }941 Property { name: "listItemData"; type: "QObject"; isList: true; isReadonly: true }
940 Property { name: "listItemChildren"; type: "QQuickItem"; isList: true; isReadonly: true }942 Property { name: "listItemChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
@@ -958,6 +960,7 @@
958 prototype: "QQuickItem"960 prototype: "QQuickItem"
959 exports: ["Ubuntu.Components.Styles/ListItemStyle 1.2"]961 exports: ["Ubuntu.Components.Styles/ListItemStyle 1.2"]
960 Property { name: "snapAnimation"; type: "QQuickAbstractAnimation"; isPointer: true }962 Property { name: "snapAnimation"; type: "QQuickAbstractAnimation"; isPointer: true }
963 Property { name: "animatePanels"; type: "bool"; isReadonly: true }
961 Method {964 Method {
962 name: "swipeEvent"965 name: "swipeEvent"
963 Parameter { name: "event"; type: "UCSwipeEvent"; isPointer: true }966 Parameter { name: "event"; type: "UCSwipeEvent"; isPointer: true }
@@ -1074,6 +1077,8 @@
1074 name: "UCViewItemsAttached"1077 name: "UCViewItemsAttached"
1075 prototype: "QObject"1078 prototype: "QObject"
1076 exports: ["ViewItems 1.2"]1079 exports: ["ViewItems 1.2"]
1080 Property { name: "selectMode"; type: "bool" }
1081 Property { name: "selectedIndices"; type: "QList<int>" }
1077 name: "UbuntuI18n"1082 name: "UbuntuI18n"
1078 prototype: "QObject"1083 prototype: "QObject"
1079 exports: ["i18n 0.1", "i18n 1.0"]1084 exports: ["i18n 0.1", "i18n 1.0"]
10801085
=== modified file 'examples/ubuntu-ui-toolkit-gallery/ListItemWithLabel.qml'
--- examples/ubuntu-ui-toolkit-gallery/ListItemWithLabel.qml 2015-01-05 20:34:54 +0000
+++ examples/ubuntu-ui-toolkit-gallery/ListItemWithLabel.qml 2015-02-19 12:17:51 +0000
@@ -27,4 +27,5 @@
27 verticalCenter: parent.verticalCenter27 verticalCenter: parent.verticalCenter
28 }28 }
29 }29 }
30 onPressAndHold: selectMode = !selectMode
30}31}
3132
=== modified file 'examples/ubuntu-ui-toolkit-gallery/NewListItems.qml'
--- examples/ubuntu-ui-toolkit-gallery/NewListItems.qml 2015-02-12 17:25:35 +0000
+++ examples/ubuntu-ui-toolkit-gallery/NewListItems.qml 2015-02-19 12:17:51 +0000
@@ -34,21 +34,37 @@
34 // clip the action delegates while swiping left/right34 // clip the action delegates while swiping left/right
35 clip: true35 clip: true
3636
37 ListItemWithLabel {37 ListView {
38 text: i18n.tr("Basic")38 height: units.gu(20)
39 }39 width: parent.width
40 ListItemWithLabel {40
41 text: i18n.tr("Colored divider")41 model: [ i18n.tr("Basic"), i18n.tr("Colored divider"), i18n.tr("No divider") ]
42 divider {42 delegate: ListItemWithLabel {
43 colorFrom: UbuntuColors.red43 text: modelData
44 colorTo: UbuntuColors.green44 divider {
45 colorFrom: modelData == i18n.tr("Colored divider") ? UbuntuColors.red : Qt.rgba(0.0, 0.0, 0.0, 0.0)
46 colorTo: modelData == i18n.tr("Colored divider") ? UbuntuColors.green : Qt.rgba(0.0, 0.0, 0.0, 0.0)
47 visible: modelData != i18n.tr("No divider")
48 }
45 }49 }
46 }50 }
47 ListItemWithLabel {51 }
48 text: i18n.tr("No divider")52
49 divider.visible: false53 TemplateSection {
54 className: "ListItem"
55 // no spacing between the list items in the Column
56 spacing: 0
57 Item {
58 // compensate for the spacing of 0 by adding this
59 // Item inbetween the title and the list items.
60 height: units.gu(3)
61 width: parent.width
50 }62 }
51 ListItemWithLabel {63
64 // clip the action delegates while swiping left/right
65 clip: true
66
67 ListItemWithLabel {
52 color: UbuntuColors.blue68 color: UbuntuColors.blue
53 text: i18n.tr("Colored")69 text: i18n.tr("Colored")
54 }70 }
@@ -56,7 +72,6 @@
56 text: i18n.tr("Highlight color")72 text: i18n.tr("Highlight color")
57 highlightColor: UbuntuColors.orange73 highlightColor: UbuntuColors.orange
58 // no highlight without clicked() or leading/trailing actions74 // no highlight without clicked() or leading/trailing actions
59 onClicked: print(i18n.tr("Highlighting list item"))
60 }75 }
6176
62 ListItemActions {77 ListItemActions {
6378
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml 2015-02-12 17:25:35 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml 2015-02-19 12:17:51 +0000
@@ -44,13 +44,12 @@
44 Rectangle {44 Rectangle {
45 id: panel45 id: panel
46 objectName: "ListItemPanel" + (leading ? "Leading" : "Trailing")46 objectName: "ListItemPanel" + (leading ? "Leading" : "Trailing")
47 property bool leading: false
48 readonly property real panelWidth: actionsRow.width47 readonly property real panelWidth: actionsRow.width
4948
50 // FIXME use theme palette colors once stabilized49 // FIXME use theme palette colors once stabilized
51 color: leading ? UbuntuColors.red : "white"50 color: leading ? UbuntuColors.red : "white"
52 anchors.fill: parent51 anchors.fill: parent
53 width: parent.width52 width: parent ? parent.width : 0
5453
55 readonly property ListItemActions itemActions: leading ? styledItem.leadingActions : styledItem.trailingActions54 readonly property ListItemActions itemActions: leading ? styledItem.leadingActions : styledItem.trailingActions
5655
@@ -64,7 +63,7 @@
64 leftMargin: spacing63 leftMargin: spacing
65 }64 }
6665
67 property real maxItemWidth: parent.width / itemActions.actions.length66 readonly property real maxItemWidth: parent.width / itemActions.actions.length
6867
69 Repeater {68 Repeater {
70 model: itemActions.actions69 model: itemActions.actions
@@ -124,6 +123,46 @@
124 }123 }
125 }124 }
126 }125 }
126 // the selection/multiselection panel
127 Component {
128 id: selectionDelegate
129 Item {
130 id: selectPanel
131 objectName: "selection_panel" + listItemIndex
132 anchors.fill: parent ? parent : undefined
133
134 CheckBox {
135 id: checkbox
136 opacity: 0
137 // for unit and autopilot tests
138 objectName: "listitem_select"
139 anchors.centerIn: parent
140 // for the initial value
141 checked: styledItem.selected
142 onCheckedChanged: styledItem.selected = checked;
143 }
144
145 states: State {
146 name: "enabled"
147 when: loaded && styledItem.selectMode
148 PropertyChanges {
149 target: checkbox
150 opacity: 1.0
151 }
152 }
153 transitions: Transition {
154 from: ""
155 to: "*"
156 reversible: true
157 enabled: listItemStyle.animatePanels
158 OpacityAnimator {
159 easing: UbuntuAnimation.StandardEasing
160 duration: UbuntuAnimation.FastDuration
161 }
162 }
163 }
164 }
165
127166
128 // leading panel loader167 // leading panel loader
129 Loader {168 Loader {
@@ -135,13 +174,46 @@
135 right: parent.left174 right: parent.left
136 }175 }
137 width: parent.width176 width: parent.width
138 sourceComponent: styledItem.leadingActions && styledItem.leadingActions.actions.length > 0 ?177 sourceComponent: internals.swiped && styledItem.leadingActions && styledItem.leadingActions.actions.length > 0 ?
139 panelComponent : null178 panelComponent : null
140 onItemChanged: {179 // context properties used in delegates
141 if (item) {180 readonly property bool leading: true
142 item.leading = true;181 readonly property bool loaded: status == Loader.Ready
143 }182
144 }183 // panel states
184 states: [
185 State {
186 name: "selectable"
187 when: styledItem.selectMode
188 PropertyChanges {
189 target: leadingLoader
190 sourceComponent: selectionDelegate
191 width: units.gu(5)
192 }
193 PropertyChanges {
194 target: listItemStyle
195 anchors.leftMargin: 0
196 }
197 PropertyChanges {
198 target: styledItem.contentItem
199 anchors.leftMargin: units.gu(5)
200 }
201 }
202 ]
203 transitions: [
204 Transition {
205 from: ""
206 to: "selectable"
207 reversible: true
208 enabled: listItemStyle.animatePanels
209 PropertyAnimation {
210 target: styledItem.contentItem
211 properties: "anchors.leftMargin"
212 easing: UbuntuAnimation.StandardEasing
213 duration: UbuntuAnimation.FastDuration
214 }
215 }
216 ]
145 }217 }
146 // trailing panel loader218 // trailing panel loader
147 Loader {219 Loader {
@@ -153,13 +225,10 @@
153 left: parent.right225 left: parent.right
154 }226 }
155 width: parent.width227 width: parent.width
156 sourceComponent: styledItem.trailingActions && styledItem.trailingActions.actions.length > 0 ?228 sourceComponent: internals.swiped && styledItem.trailingActions && styledItem.trailingActions.actions.length > 0 ?
157 panelComponent : null229 panelComponent : null
158 onItemChanged: {230 // context properties used in delegates
159 if (item) {231 readonly property bool leading: false
160 item.leading = false;
161 }
162 }
163 }232 }
164233
165 // internals234 // internals
@@ -168,10 +237,11 @@
168 // action triggered237 // action triggered
169 property Action selectedAction238 property Action selectedAction
170 // swipe handling239 // swipe handling
240 readonly property bool swiped: listItemStyle.x != styledItem.x && !styledItem.selectMode
171 readonly property Item swipedPanel: listItemStyle.x > 0 ? leadingLoader.item : trailingLoader.item241 readonly property Item swipedPanel: listItemStyle.x > 0 ? leadingLoader.item : trailingLoader.item
172 readonly property bool leadingPanel: listItemStyle.x > 0242 readonly property bool leadingPanel: listItemStyle.x > 0
173 readonly property real swipedOffset: leadingPanel ? listItemStyle.x : -listItemStyle.x243 readonly property real swipedOffset: leadingPanel ? listItemStyle.x : -listItemStyle.x
174 readonly property real panelWidth: swipedPanel ? swipedPanel.panelWidth : 0244 readonly property real panelWidth: swipedPanel && swipedPanel.hasOwnProperty("panelWidth") ? swipedPanel.panelWidth : 0
175 property real prevX: 0.0245 property real prevX: 0.0
176 property real snapChangerLimit: 0.0246 property real snapChangerLimit: 0.0
177 readonly property real threshold: units.gu(1.5)247 readonly property real threshold: units.gu(1.5)
178248
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.cpp'
--- modules/Ubuntu/Components/plugin/uclistitem.cpp 2015-02-19 08:31:38 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem.cpp 2015-02-19 12:17:51 +0000
@@ -305,6 +305,15 @@
305 setContentMoving(styleItem->m_snapAnimation->isRunning());305 setContentMoving(styleItem->m_snapAnimation->isRunning());
306}306}
307307
308// synchronizes selection mode, initializes the style if has not been done yet,
309// which in turn reveals the selection panels
310void UCListItemPrivate::_q_syncSelectMode()
311{
312 initStyleItem();
313 Q_Q(UCListItem);
314 Q_EMIT q->selectModeChanged();
315}
316
308/*!317/*!
309 * \qmlproperty Component ListItem::style318 * \qmlproperty Component ListItem::style
310 * Holds the style of the component defining the components visualizing the leading/319 * Holds the style of the component defining the components visualizing the leading/
@@ -375,8 +384,9 @@
375 }384 }
376}385}
377386
378// creates the style item387// creates the style item, with altered default value of the animatePanels style property
379void UCListItemPrivate::initStyleItem()388// the property is turned on after the panel initialization.
389void UCListItemPrivate::initStyleItem(bool withAnimatedPanels)
380{390{
381 if (!ready || styleItem) {391 if (!ready || styleItem) {
382 return;392 return;
@@ -411,8 +421,11 @@
411 return;421 return;
412 }422 }
413 QQml_setParent_noEvent(styleItem, q);423 QQml_setParent_noEvent(styleItem, q);
424 styleItem->setAnimatePanels(withAnimatedPanels);
414 styleItem->setParentItem(q);425 styleItem->setParentItem(q);
415 delegate->completeCreate();426 delegate->completeCreate();
427 // turn animations on
428 styleItem->setAnimatePanels(true);
416 Q_EMIT q->__styleInstanceChanged();429 Q_EMIT q->__styleInstanceChanged();
417}430}
418431
@@ -459,7 +472,8 @@
459 Q_Q(UCListItem);472 Q_Q(UCListItem);
460 QPointF myPos = q->mapToItem(contentItem, event->localPos());473 QPointF myPos = q->mapToItem(contentItem, event->localPos());
461 QQuickItem *child = contentItem->childAt(myPos.x(), myPos.y());474 QQuickItem *child = contentItem->childAt(myPos.x(), myPos.y());
462 bool activeComponent = child && (child->acceptedMouseButtons() & event->button()) && !qobject_cast<QQuickText*>(child);475 bool activeComponent = child && (child->acceptedMouseButtons() & event->button()) &&
476 child->isEnabled() && !qobject_cast<QQuickText*>(child);
463 // do highlight if not pressed above the active component, and the component has either477 // do highlight if not pressed above the active component, and the component has either
464 // action, leading or trailing actions list or at least an active child component declared478 // action, leading or trailing actions list or at least an active child component declared
465 QQuickMouseArea *ma = q->findChild<QQuickMouseArea*>();479 QQuickMouseArea *ma = q->findChild<QQuickMouseArea*>();
@@ -672,7 +686,8 @@
672 * Being an Item, all properties can be accessed or altered. However, make sure you686 * Being an Item, all properties can be accessed or altered. However, make sure you
673 * never change \c x, \c y, \c width, \c height or \c anchors properties as those are687 * never change \c x, \c y, \c width, \c height or \c anchors properties as those are
674 * controlled by the ListItem itself when leading or trailing actions are revealed688 * controlled by the ListItem itself when leading or trailing actions are revealed
675 * and thus might cause the component to misbehave. Anchors margins are free to alter.689 * or when selectable and draggable mode is turned on, and thus might cause the
690 * component to misbehave. Anchors margins are free to alter.
676 *691 *
677 * Each ListItem has a thin divider shown on the bottom of the component. This692 * Each ListItem has a thin divider shown on the bottom of the component. This
678 * divider can be configured through the \c divider grouped property, which can693 * divider can be configured through the \c divider grouped property, which can
@@ -680,7 +695,7 @@
680 * When used in \c ListView or \l UbuntuListView, the last list item will not695 * When used in \c ListView or \l UbuntuListView, the last list item will not
681 * show the divider no matter of the visible property value set.696 * show the divider no matter of the visible property value set.
682 *697 *
683 * ListItem can handle actions that can get swiped from front to back of the item.698 * ListItem can handle actions that can get swiped from front or back of the item.
684 * These actions are Action elements visualized in panels attached to the front699 * These actions are Action elements visualized in panels attached to the front
685 * or to the back of the item, and are revealed by swiping the item horizontally.700 * or to the back of the item, and are revealed by swiping the item horizontally.
686 * The swipe is started only after the mouse/touch move had passed a given threshold.701 * The swipe is started only after the mouse/touch move had passed a given threshold.
@@ -738,6 +753,48 @@
738 * of the ListItem. However not all properties are valid in all the circumstances.753 * of the ListItem. However not all properties are valid in all the circumstances.
739 *754 *
740 * The component is styled using the \l ListItemStyle style interface.755 * The component is styled using the \l ListItemStyle style interface.
756 *
757 * \section3 Selection mode
758 * The selection mode of a ListItem is controlled by the \l ViewItems::selectMode
759 * attached property. This property is attached to each parent item of the ListItem
760 * exception being when used as delegate in ListView, where the property is attached
761 * to the view itself.
762 * \qml
763 * import QtQuick 2.3
764 * import Ubuntu.Components 1.2
765 *
766 * Flickable {
767 * width: units.gu(40)
768 * height: units.gu(50)
769 *
770 * // this will not have any effect
771 * ViewItems.selectMode: true
772 * Column {
773 * // this will work
774 * ViewItems.selectMode: false
775 * width: parent.width
776 * Repeater {
777 * model: 25
778 * ListItem {
779 * Label {
780 * text: "ListItem in Flickable #" + index
781 * }
782 * }
783 * }
784 * }
785 * }
786 * \endqml
787 * The indices selected are stored in \l ViewItems::selectedIndices attached property,
788 * attached the same way as the \l ViewItems::selectMode property is. This is a
789 * read/write property, meaning that initial selected item indices can be set up.
790 * The list contains the indices added in the order of selection, not sorted in
791 * any form.
792 *
793 * \note When in selectable mode, the ListItem content is not disabled and \l clicked
794 * and \l pressAndHold signals are also emitted. The only restriction the component
795 * implies is that leading and trailing actions cannot be swiped in. \ selectable
796 * property can be used to implement different behavior when \l clicked or \l
797 * pressAndHold.
741 */798 */
742799
743/*!800/*!
@@ -746,16 +803,16 @@
746 * is set. The signal is not emitted if the ListItem content is swiped or when used in803 * is set. The signal is not emitted if the ListItem content is swiped or when used in
747 * Flickable (or ListView, GridView) and the Flickable gets moved.804 * Flickable (or ListView, GridView) and the Flickable gets moved.
748 *805 *
749 * If the ListItem contains a component which contains a MouseArea, the clicked806 * If the ListItem contains a component which contains an active MouseArea, the clicked
750 * signal will be supressed.807 * signal will be supressed when clicked over this area.
751 */808 */
752809
753/*!810/*!
754 * \qmlsignal ListItem::pressAndHold()811 * \qmlsignal ListItem::pressAndHold()
755 * The signal is emitted when the list item is long pressed.812 * The signal is emitted when the list item is long pressed.
756 *813 *
757 * If the ListItem contains a component which contains a MouseArea, the pressAndHold814 * If the ListItem contains a component which contains an active MouseArea, the pressAndHold
758 * signal will be supressed.815 * signal will be supressed when pressed over this area.
759 */816 */
760817
761UCListItem::UCListItem(QQuickItem *parent)818UCListItem::UCListItem(QQuickItem *parent)
@@ -795,6 +852,20 @@
795 this, SLOT(_q_updateIndex()), Qt::DirectConnection);852 this, SLOT(_q_updateIndex()), Qt::DirectConnection);
796 update();853 update();
797 }854 }
855
856 if (d->parentAttached) {
857 // connect selectedIndicesChanged
858 connect(d->parentAttached, &UCViewItemsAttached::selectedIndicesChanged,
859 this, &UCListItem::selectedChanged);
860 // sync selectModeChanged()
861 connect(d->parentAttached, SIGNAL(selectModeChanged()),
862 this, SLOT(_q_syncSelectMode()));
863
864 // if selection mode is on, initialize style
865 if (d->parentAttached->selectMode()) {
866 d->initStyleItem(false);
867 }
868 }
798}869}
799870
800void UCListItem::itemChange(ItemChange change, const ItemChangeData &data)871void UCListItem::itemChange(ItemChange change, const ItemChangeData &data)
@@ -830,10 +901,9 @@
830901
831 if (parentAttachee) {902 if (parentAttachee) {
832 QObject::connect(parentAttachee, SIGNAL(widthChanged()), this, SLOT(_q_updateSize()), Qt::DirectConnection);903 QObject::connect(parentAttachee, SIGNAL(widthChanged()), this, SLOT(_q_updateSize()), Qt::DirectConnection);
904 // update size
905 d->_q_updateSize();
833 }906 }
834
835 // update size
836 d->_q_updateSize();
837 }907 }
838}908}
839909
@@ -936,7 +1006,10 @@
936 Q_D(UCListItem);1006 Q_D(UCListItem);
937 UCStyledItemBase::mouseMoveEvent(event);1007 UCStyledItemBase::mouseMoveEvent(event);
9381008
939// qDebug() << "MOVE" << event->localPos();1009 if (d->selectMode()) {
1010 // no move is allowed while selectable mode is on
1011 return;
1012 }
9401013
941 // accept the tugging only if the move is within the threshold1014 // accept the tugging only if the move is within the threshold
942 if (d->highlighted && !d->swiped && (d->leadingActions || d->trailingActions)) {1015 if (d->highlighted && !d->swiped && (d->leadingActions || d->trailingActions)) {
@@ -1261,6 +1334,48 @@
1261}1334}
12621335
1263/*!1336/*!
1337 *
1338 * \qmlproperty bool ListItem::selected
1339 * The property drives whether a list item is selected or not. Defaults to false.
1340 *
1341 * \sa ListItem::selectMode, ViewItems::selectMode
1342 */
1343bool UCListItemPrivate::isSelected()
1344{
1345 Q_Q(UCListItem);
1346 return UCViewItemsAttachedPrivate::get(parentAttached)->isItemSelected(q);
1347}
1348void UCListItemPrivate::setSelected(bool value)
1349{
1350 Q_Q(UCListItem);
1351 if (value) {
1352 UCViewItemsAttachedPrivate::get(parentAttached)->addSelectedItem(q);
1353 } else {
1354 UCViewItemsAttachedPrivate::get(parentAttached)->removeSelectedItem(q);
1355 }
1356}
1357
1358/*!
1359 * \qmlproperty bool ListItem::selectMode
1360 * The property reports whether the component and the view using the component
1361 * is in selectable state. While selectable, the ListItem's leading- and trailing
1362 * panels cannot be swiped in. \l clicked and \l pressAndHold signals are also
1363 * triggered. Selectable mode can be set either through this property or through
1364 * the parent attached \l ViewItems::selectMode property.
1365 */
1366bool UCListItemPrivate::selectMode()
1367{
1368 UCViewItemsAttachedPrivate *attached = UCViewItemsAttachedPrivate::get(parentAttached);
1369 return attached ? attached->selectable : false;
1370}
1371void UCListItemPrivate::setSelectMode(bool selectable)
1372{
1373 if (parentAttached) {
1374 parentAttached->setSelectMode(selectable);
1375 }
1376}
1377
1378/*!
1264 * \qmlproperty Action ListItem::action1379 * \qmlproperty Action ListItem::action
1265 * The property holds the action which will be triggered when the ListItem is1380 * The property holds the action which will be triggered when the ListItem is
1266 * clicked. ListItem will not visualize the action, that is the responsibility1381 * clicked. ListItem will not visualize the action, that is the responsibility
12671382
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.h'
--- modules/Ubuntu/Components/plugin/uclistitem.h 2015-02-11 13:35:34 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem.h 2015-02-19 12:17:51 +0000
@@ -36,6 +36,8 @@
36 Q_PRIVATE_PROPERTY(UCListItem::d_func(), bool contentMoving READ contentMoving NOTIFY contentMovingChanged)36 Q_PRIVATE_PROPERTY(UCListItem::d_func(), bool contentMoving READ contentMoving NOTIFY contentMovingChanged)
37 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)37 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
38 Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor RESET resetHighlightColor NOTIFY highlightColorChanged)38 Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor RESET resetHighlightColor NOTIFY highlightColorChanged)
39 Q_PRIVATE_PROPERTY(UCListItem::d_func(), bool selected READ isSelected WRITE setSelected NOTIFY selectedChanged)
40 Q_PRIVATE_PROPERTY(UCListItem::d_func(), bool selectMode READ selectMode WRITE setSelectMode NOTIFY selectModeChanged)
39 Q_PRIVATE_PROPERTY(UCListItem::d_func(), UCAction *action READ action WRITE setAction NOTIFY actionChanged DESIGNABLE false)41 Q_PRIVATE_PROPERTY(UCListItem::d_func(), UCAction *action READ action WRITE setAction NOTIFY actionChanged DESIGNABLE false)
40 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQmlListProperty<QObject> listItemData READ data DESIGNABLE false)42 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQmlListProperty<QObject> listItemData READ data DESIGNABLE false)
41 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQmlListProperty<QQuickItem> listItemChildren READ children NOTIFY listItemChildrenChanged DESIGNABLE false)43 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQmlListProperty<QQuickItem> listItemChildren READ children NOTIFY listItemChildrenChanged DESIGNABLE false)
@@ -78,6 +80,8 @@
78 void contentMovingChanged();80 void contentMovingChanged();
79 void colorChanged();81 void colorChanged();
80 void highlightColorChanged();82 void highlightColorChanged();
83 void selectedChanged();
84 void selectModeChanged();
81 void actionChanged();85 void actionChanged();
82 void listItemChildrenChanged();86 void listItemChildrenChanged();
8387
@@ -100,6 +104,7 @@
100 Q_PRIVATE_SLOT(d_func(), void _q_updateSize())104 Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
101 Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())105 Q_PRIVATE_SLOT(d_func(), void _q_updateIndex())
102 Q_PRIVATE_SLOT(d_func(), void _q_contentMoving())106 Q_PRIVATE_SLOT(d_func(), void _q_contentMoving())
107 Q_PRIVATE_SLOT(d_func(), void _q_syncSelectMode())
103};108};
104109
105class UCListItemDividerPrivate;110class UCListItemDividerPrivate;
@@ -134,6 +139,8 @@
134class UCViewItemsAttached : public QObject139class UCViewItemsAttached : public QObject
135{140{
136 Q_OBJECT141 Q_OBJECT
142 Q_PROPERTY(bool selectMode READ selectMode WRITE setSelectMode NOTIFY selectModeChanged)
143 Q_PROPERTY(QList<int> selectedIndices READ selectedIndices WRITE setSelectedIndices NOTIFY selectedIndicesChanged)
137public:144public:
138 explicit UCViewItemsAttached(QObject *owner);145 explicit UCViewItemsAttached(QObject *owner);
139 ~UCViewItemsAttached();146 ~UCViewItemsAttached();
@@ -145,8 +152,18 @@
145 bool isMoving();152 bool isMoving();
146 bool isBoundTo(UCListItem *item);153 bool isBoundTo(UCListItem *item);
147154
155 // getter/setter
156 bool selectMode() const;
157 void setSelectMode(bool value);
158 QList<int> selectedIndices() const;
159 void setSelectedIndices(const QList<int> &list);
148private Q_SLOTS:160private Q_SLOTS:
149 void unbindItem();161 void unbindItem();
162
163Q_SIGNALS:
164 void selectModeChanged();
165 void selectedIndicesChanged();
166
150private:167private:
151 Q_DECLARE_PRIVATE(UCViewItemsAttached)168 Q_DECLARE_PRIVATE(UCViewItemsAttached)
152 QScopedPointer<UCViewItemsAttachedPrivate> d_ptr;169 QScopedPointer<UCViewItemsAttachedPrivate> d_ptr;
153170
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem_p.h'
--- modules/Ubuntu/Components/plugin/uclistitem_p.h 2015-02-12 17:25:35 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem_p.h 2015-02-19 12:17:51 +0000
@@ -57,6 +57,7 @@
57 void _q_updateSize();57 void _q_updateSize();
58 void _q_updateIndex();58 void _q_updateIndex();
59 void _q_contentMoving();59 void _q_contentMoving();
60 void _q_syncSelectMode();
60 int index();61 int index();
61 bool canHighlight(QMouseEvent *event);62 bool canHighlight(QMouseEvent *event);
62 void setHighlighted(bool pressed);63 void setHighlighted(bool pressed);
@@ -101,8 +102,12 @@
101 QQmlComponent *style() const;102 QQmlComponent *style() const;
102 void setStyle(QQmlComponent *delegate);103 void setStyle(QQmlComponent *delegate);
103 void resetStyle();104 void resetStyle();
104 void initStyleItem();105 void initStyleItem(bool withAnimatedPanels = true);
105 QQuickItem *styleInstance() const;106 QQuickItem *styleInstance() const;
107 bool isSelected();
108 void setSelected(bool value);
109 bool selectMode();
110 void setSelectMode(bool selectable);
106 UCAction *action() const;111 UCAction *action() const;
107 void setAction(UCAction *action);112 void setAction(UCAction *action);
108};113};
@@ -115,13 +120,23 @@
115 UCViewItemsAttachedPrivate(UCViewItemsAttached *qq);120 UCViewItemsAttachedPrivate(UCViewItemsAttached *qq);
116 ~UCViewItemsAttachedPrivate();121 ~UCViewItemsAttachedPrivate();
117122
123 static UCViewItemsAttachedPrivate *get(UCViewItemsAttached *item)
124 {
125 return item ? item->d_func() : 0;
126 }
127
118 void clearFlickablesList();128 void clearFlickablesList();
119 void buildFlickablesList();129 void buildFlickablesList();
120 void clearChangesList();130 void clearChangesList();
121 void buildChangesList(const QVariant &newValue);131 void buildChangesList(const QVariant &newValue);
132 bool addSelectedItem(UCListItem *item);
133 bool removeSelectedItem(UCListItem *item);
134 bool isItemSelected(UCListItem *item);
122135
123 UCViewItemsAttached *q_ptr;136 UCViewItemsAttached *q_ptr;
124 bool globalDisabled;137 bool globalDisabled:1;
138 bool selectable:1;
139 QSet<int> selectedList;
125 QList< QPointer<QQuickFlickable> > flickables;140 QList< QPointer<QQuickFlickable> > flickables;
126 QList< PropertyChange* > changes;141 QList< PropertyChange* > changes;
127 QPointer<UCListItem> boundItem;142 QPointer<UCListItem> boundItem;
128143
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemstyle.cpp'
--- modules/Ubuntu/Components/plugin/uclistitemstyle.cpp 2015-02-12 17:25:35 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemstyle.cpp 2015-02-19 12:17:51 +0000
@@ -38,6 +38,7 @@
38UCListItemStyle::UCListItemStyle(QQuickItem *parent)38UCListItemStyle::UCListItemStyle(QQuickItem *parent)
39 : QQuickItem(parent)39 : QQuickItem(parent)
40 , m_snapAnimation(0)40 , m_snapAnimation(0)
41 , m_animatePanels(true)
41{42{
42}43}
4344
@@ -120,3 +121,22 @@
120 * \qmlproperty Animation ListItemStyle::snapAnimation121 * \qmlproperty Animation ListItemStyle::snapAnimation
121 * Holds the behavior used in animating when snapped in or out.122 * Holds the behavior used in animating when snapped in or out.
122 */123 */
124
125/*!
126 * \qmlproperty bool ListItemStyle::animatePanels
127 * The property drives the different panel animations in the style. Panels should
128 * not be animated when created upon scrolling a view.
129 */
130bool UCListItemStyle::animatePanels() const
131{
132 return m_animatePanels;
133}
134// the setter is used by the ListItem to drive animation state
135void UCListItemStyle::setAnimatePanels(bool animate)
136{
137 if (m_animatePanels == animate) {
138 return;
139 }
140 m_animatePanels = animate;
141 Q_EMIT animatePanelsChanged();
142}
123143
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemstyle.h'
--- modules/Ubuntu/Components/plugin/uclistitemstyle.h 2015-02-12 17:25:35 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemstyle.h 2015-02-19 12:17:51 +0000
@@ -64,14 +64,18 @@
64{64{
65 Q_OBJECT65 Q_OBJECT
66 Q_PROPERTY(QQuickAbstractAnimation *snapAnimation MEMBER m_snapAnimation NOTIFY snapAnimationChanged)66 Q_PROPERTY(QQuickAbstractAnimation *snapAnimation MEMBER m_snapAnimation NOTIFY snapAnimationChanged)
67 Q_PROPERTY(bool animatePanels READ animatePanels NOTIFY animatePanelsChanged)
67public:68public:
68 explicit UCListItemStyle(QQuickItem *parent = 0);69 explicit UCListItemStyle(QQuickItem *parent = 0);
6970
70 void invokeSwipeEvent(UCSwipeEvent *event);71 void invokeSwipeEvent(UCSwipeEvent *event);
71 void invokeRebound();72 void invokeRebound();
73 bool animatePanels() const;
74 void setAnimatePanels(bool animate);
7275
73Q_SIGNALS:76Q_SIGNALS:
74 void snapAnimationChanged();77 void snapAnimationChanged();
78 void animatePanelsChanged();
7579
76public Q_SLOTS:80public Q_SLOTS:
77 void swipeEvent(UCSwipeEvent *event);81 void swipeEvent(UCSwipeEvent *event);
@@ -85,6 +89,8 @@
85 QMetaMethod m_swipeEvent;89 QMetaMethod m_swipeEvent;
86 QMetaMethod m_rebound;90 QMetaMethod m_rebound;
87 QQuickAbstractAnimation *m_snapAnimation;91 QQuickAbstractAnimation *m_snapAnimation;
92 bool m_animatePanels:1;
93
88 friend class UCListItemPrivate;94 friend class UCListItemPrivate;
89 friend class UCActionPanel;95 friend class UCActionPanel;
90 friend class ListItemAnimator;96 friend class ListItemAnimator;
9197
=== modified file 'modules/Ubuntu/Components/plugin/ucviewitemsattached.cpp'
--- modules/Ubuntu/Components/plugin/ucviewitemsattached.cpp 2015-02-10 10:27:30 +0000
+++ modules/Ubuntu/Components/plugin/ucviewitemsattached.cpp 2015-02-19 12:17:51 +0000
@@ -32,6 +32,7 @@
32UCViewItemsAttachedPrivate::UCViewItemsAttachedPrivate(UCViewItemsAttached *qq)32UCViewItemsAttachedPrivate::UCViewItemsAttachedPrivate(UCViewItemsAttached *qq)
33 : q_ptr(qq)33 : q_ptr(qq)
34 , globalDisabled(false)34 , globalDisabled(false)
35 , selectable(false)
35{36{
36}37}
3738
@@ -76,11 +77,7 @@
76void UCViewItemsAttachedPrivate::clearChangesList()77void UCViewItemsAttachedPrivate::clearChangesList()
77{78{
78 // clear property change objects79 // clear property change objects
79 Q_FOREACH(PropertyChange *change, changes) {80 qDeleteAll(changes);
80 // deleting PropertyChange will restore the saved property
81 // to its original binding/value
82 delete change;
83 }
84 changes.clear();81 changes.clear();
85}82}
8683
@@ -104,6 +101,17 @@
104 }101 }
105}102}
106103
104/*!
105 * \qmltype ViewItems
106 * \instantiates UCViewItemsAttached
107 * \inqmlmodule Ubuntu.Components 1.2
108 * \ingroup unstable-ubuntu-listitems
109 * \since Ubuntu.Components 1.2
110 * \brief A set of properties attached to the ListItem's parent item or ListView.
111 *
112 * These properties are attached to the parent item of the ListItem, or to
113 * ListView, when the component is used as delegate.
114 */
107UCViewItemsAttached::UCViewItemsAttached(QObject *owner)115UCViewItemsAttached::UCViewItemsAttached(QObject *owner)
108 : QObject(owner)116 : QObject(owner)
109 , d_ptr(new UCViewItemsAttachedPrivate(this))117 , d_ptr(new UCViewItemsAttachedPrivate(this))
@@ -205,3 +213,73 @@
205 // clear binding list213 // clear binding list
206 d->clearFlickablesList();214 d->clearFlickablesList();
207}215}
216
217/*!
218 * \qmlattachedproperty bool ViewItems::selectMode
219 * The property drives whether list items are selectable or not.
220 *
221 * When set, the ListItems of the Item the property is attached to will enter into
222 * selection state. ListItems provide a visual clue which can be used to toggle
223 * the selection state of each, which in order will be reflected in the
224 * \l {ViewItems::selectedIndices}{ViewItems.selectedIndices} list.
225 */
226bool UCViewItemsAttached::selectMode() const
227{
228 Q_D(const UCViewItemsAttached);
229 return d->selectable;
230}
231void UCViewItemsAttached::setSelectMode(bool value)
232{
233 Q_D(UCViewItemsAttached);
234 if (d->selectable == value) {
235 return;
236 }
237 d->selectable = value;
238 Q_EMIT selectModeChanged();
239}
240
241/*!
242 * \qmlattachedproperty list<int> ViewItems::selectedIndices
243 * The property contains the indexes of the ListItems marked as selected. The
244 * indexes are model indexes when used in ListView, and child indexes in other
245 * components. The property being writable, initial selection configuration
246 * can be provided for a view, and provides ability to save the selection state.
247 */
248QList<int> UCViewItemsAttached::selectedIndices() const
249{
250 Q_D(const UCViewItemsAttached);
251 return d->selectedList.toList();
252}
253void UCViewItemsAttached::setSelectedIndices(const QList<int> &list)
254{
255 Q_D(UCViewItemsAttached);
256 if (d->selectedList.toList() == list) {
257 return;
258 }
259 d->selectedList = QSet<int>::fromList(list);
260 Q_EMIT selectedIndicesChanged();
261}
262
263bool UCViewItemsAttachedPrivate::addSelectedItem(UCListItem *item)
264{
265 int index = UCListItemPrivate::get(item)->index();
266 if (!selectedList.contains(index)) {
267 selectedList.insert(index);
268 Q_EMIT q_ptr->selectedIndicesChanged();
269 return true;
270 }
271 return false;
272}
273bool UCViewItemsAttachedPrivate::removeSelectedItem(UCListItem *item)
274{
275 if (selectedList.remove(UCListItemPrivate::get(item)->index()) > 0) {
276 Q_EMIT q_ptr->selectedIndicesChanged();
277 return true;
278 }
279 return false;
280}
281
282bool UCViewItemsAttachedPrivate::isItemSelected(UCListItem *item)
283{
284 return selectedList.contains(UCListItemPrivate::get(item)->index());
285}
208286
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2014-08-21 06:29:28 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_qquicklistview.py 2015-02-19 12:17:51 +0000
@@ -85,3 +85,25 @@
85 child = self.select_single(objectName=object_name)85 child = self.select_single(objectName=object_name)
86 containers = self._get_containers()86 containers = self._get_containers()
87 return self._is_child_visible(child, containers)87 return self._is_child_visible(child, containers)
88
89 def _get_first_item(self):
90 """Returns the first item from the ListView."""
91 items = self.get_children_by_type('QQuickItem')[0].get_children()
92 items = sorted(items, key=lambda item: item.globalRect.y)
93 return items[0]
94
95 @autopilot_logging.log_action(logger.info)
96 def enable_select_mode(self):
97 """Default implementation to enable select mode. Performs a long tap
98 over the first list item in the ListView. The delegates must be
99 the new ListItem components.
100 """
101 self.swipe_to_top()
102 first_item = self._get_first_item()
103 self.pointing_device.click_object(first_item, press_duration=2)
104 try:
105 self.wait_select_single('QQuickItem',
106 objectName='selection_panel0')
107 except dbus.StateNotFoundError:
108 raise _common.ToolkitException(
109 'ListView delegate is not a ListItem or not in selectMode')
88110
=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_uclistitem.py'
--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_uclistitem.py 2015-01-07 06:42:09 +0000
+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_uclistitem.py 2015-02-19 12:17:51 +0000
@@ -86,3 +86,9 @@
86 """86 """
87 self._click_on_panel_action('trailing', action_objectName,87 self._click_on_panel_action('trailing', action_objectName,
88 wait_function)88 wait_function)
89
90 @autopilot_logging.log_action(logger.info)
91 def toggle_selected(self):
92 """Toggles selected state of the ListItem. """
93 toggle = self.select_single(objectName='listitem_select')
94 self.pointing_device.click_object(toggle)
8995
=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.ListItemTestCase.qml'
--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.ListItemTestCase.qml 2015-02-04 16:27:27 +0000
+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.ListItemTestCase.qml 2015-02-19 12:17:51 +0000
@@ -28,13 +28,15 @@
28 Page {28 Page {
29 id: testPage29 id: testPage
30 objectName: "test_page"30 objectName: "test_page"
31 title: "No action triggered"31 title: listView.ViewItems.selectMode ? "In selection mode" : "No action triggered"
32 ListView {32 ListView {
33 id: listView33 id: listView
34 objectName: "test_view"
34 anchors.fill: parent35 anchors.fill: parent
35 model: 2536 model: 25
36 delegate: ListItem {37 delegate: ListItem {
37 objectName: "listitem" + index38 objectName: "listitem" + index
39 onPressAndHold: listView.ViewItems.selectMode = true
38 leadingActions: ListItemActions {40 leadingActions: ListItemActions {
39 actions: [41 actions: [
40 Action {42 Action {
4143
=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.py'
--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.py 2014-12-08 14:37:40 +0000
+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_listitem.py 2015-02-19 12:17:51 +0000
@@ -28,6 +28,8 @@
2828
29 def setUp(self):29 def setUp(self):
30 super(ListItemTestCase, self).setUp()30 super(ListItemTestCase, self).setUp()
31 self.list_view = self.main_view.select_single(
32 ubuntuuitoolkit.QQuickListView, objectName='test_view')
31 self.test_listitem = self.main_view.select_single(33 self.test_listitem = self.main_view.select_single(
32 'UCListItem', objectName='listitem0')34 'UCListItem', objectName='listitem0')
33 self.test_page = self.main_view.select_single(35 self.test_page = self.main_view.select_single(
@@ -84,3 +86,13 @@
84 'this_action_does_not_exist')86 'this_action_does_not_exist')
85 self.assertEqual(str(error),87 self.assertEqual(str(error),
86 'The requested action not found on trailing side')88 'The requested action not found on trailing side')
89
90 def test_select_items(self):
91 self.list_view.enable_select_mode()
92 self.test_listitem.toggle_selected()
93 self.assertTrue(self.test_listitem.selected)
94 # select an other one
95 listItem3 = self.main_view.select_single(
96 'UCListItem', objectName='listitem3')
97 listItem3.toggle_selected()
98 self.assertTrue(listItem3.selected)
8799
=== modified file 'tests/resources/listitems/ListItemTest.qml'
--- tests/resources/listitems/ListItemTest.qml 2015-02-11 13:35:34 +0000
+++ tests/resources/listitems/ListItemTest.qml 2015-02-19 12:17:51 +0000
@@ -31,7 +31,10 @@
31 id: stock31 id: stock
32 iconName: "starred"32 iconName: "starred"
33 text: "Staaaar"33 text: "Staaaar"
34 onTriggered: print(iconName, "triggered", value)34 onTriggered: {
35 print(iconName, "triggered", value)
36 view.ViewItems.selectedIndices = [0, 2, 9];
37 }
35 }38 }
3639
37 ListItemActions {40 ListItemActions {
@@ -66,6 +69,7 @@
66 ]69 ]
67 }70 }
6871
72 property bool selectable: false
69 property list<Action> leadingArray: [73 property list<Action> leadingArray: [
70 Action {74 Action {
71 iconName: "delete"75 iconName: "delete"
@@ -93,6 +97,11 @@
93 right: parent.right97 right: parent.right
94 }98 }
9599
100 Button {
101 text: "Selectable " + (selectable ? "OFF" : "ON")
102 onClicked: selectable = !selectable
103 }
104
96 ListItem {105 ListItem {
97 id: testItem106 id: testItem
98 objectName: "single"107 objectName: "single"
@@ -161,6 +170,9 @@
161 height: units.gu(28)170 height: units.gu(28)
162 model: 25171 model: 25
163 pressDelay: 0172 pressDelay: 0
173 ViewItems.selectMode: main.selectable
174 ViewItems.selectedIndices: [9,3,4,1]
175 ViewItems.onSelectedIndicesChanged: print("LISTVIEW INDEXES=", ViewItems.selectedIndices)
164 delegate: ListItem {176 delegate: ListItem {
165 objectName: "ListItem" + index177 objectName: "ListItem" + index
166 id: listItem178 id: listItem
@@ -179,6 +191,10 @@
179 text: "This is one Label split in two lines.\n" +191 text: "This is one Label split in two lines.\n" +
180 "The second line - item #" + modelData192 "The second line - item #" + modelData
181 }193 }
194 Button {
195 text: "Pressme..."
196 anchors.centerIn: parent
197 }
182198
183 states: State {199 states: State {
184 name: "override"200 name: "override"
@@ -203,11 +219,11 @@
203 id: trailing219 id: trailing
204 actions: leading.actions220 actions: leading.actions
205 }221 }
206
207 Column {222 Column {
208 id: column223 id: column
209 width: flicker.width224 width: flicker.width
210 property alias count: repeater.count225 property alias count: repeater.count
226 ViewItems.selectMode: main.selectable
211 Repeater {227 Repeater {
212 id: repeater228 id: repeater
213 model: 10229 model: 10
214230
=== modified file 'tests/unit_x11/tst_components/tst_listitem.qml'
--- tests/unit_x11/tst_components/tst_listitem.qml 2015-02-19 08:31:38 +0000
+++ tests/unit_x11/tst_components/tst_listitem.qml 2015-02-19 12:17:51 +0000
@@ -67,6 +67,7 @@
67 }67 }
6868
69 Column {69 Column {
70 id: testColumn
70 width: parent.width71 width: parent.width
71 ListItem {72 ListItem {
72 id: defaults73 id: defaults
@@ -107,6 +108,7 @@
107 height: units.gu(28)108 height: units.gu(28)
108 clip: true109 clip: true
109 model: 10110 model: 10
111 ViewItems.selectMode: false
110 delegate: ListItem {112 delegate: ListItem {
111 objectName: "listItem" + index113 objectName: "listItem" + index
112 color: "lightgray"114 color: "lightgray"
@@ -134,6 +136,24 @@
134 }136 }
135 }137 }
136 }138 }
139 Flickable {
140 id: flickable
141 width: parent.width
142 height: units.gu(14)
143 clip: true
144 contentHeight: column.height
145 Column {
146 id: column
147 width: parent.width
148 Repeater {
149 model: 10
150 ListItem {
151 objectName: "listItem" + index
152 color: "lightgreen"
153 }
154 }
155 }
156 }
137 }157 }
138158
139 UbuntuTestCase {159 UbuntuTestCase {
@@ -183,6 +203,12 @@
183 }203 }
184 }204 }
185205
206 // delayed swipe, gives few millisecond timeout between each move
207 // so Repeater has time to create the panel actions in style
208 function swipe(item, x, y, dx, dy) {
209 flick(item, x, y, dx, dy, 0, 0, undefined, undefined, 100);
210 }
211
186 function initTestCase() {212 function initTestCase() {
187 TestExtras.registerTouchDevice();213 TestExtras.registerTouchDevice();
188 waitForRendering(main);214 waitForRendering(main);
@@ -191,6 +217,11 @@
191 function cleanup() {217 function cleanup() {
192 testItem.action = null;218 testItem.action = null;
193 testItem.contentItem.anchors.margins = 0;219 testItem.contentItem.anchors.margins = 0;
220 testItem.selected = false;
221 testColumn.ViewItems.selectMode = false;
222 waitForRendering(testItem.contentItem, 200);
223 controlItem.selected = false;
224 waitForRendering(controlItem.contentItem, 200);
194 movingSpy.clear();225 movingSpy.clear();
195 highlightedSpy.clear();226 highlightedSpy.clear();
196 clickSpy.clear();227 clickSpy.clear();
@@ -199,6 +230,7 @@
199 buttonSpy.clear();230 buttonSpy.clear();
200 interactiveSpy.clear();231 interactiveSpy.clear();
201 listView.interactive = true;232 listView.interactive = true;
233 listView.ViewItems.selectMode = false;
202 // make sure we collapse234 // make sure we collapse
203 mouseClick(defaults, 0, 0)235 mouseClick(defaults, 0, 0)
204 movingSpy.target = null;236 movingSpy.target = null;
@@ -229,6 +261,10 @@
229 compare(defaults.action, null, "No action by default.");261 compare(defaults.action, null, "No action by default.");
230 compare(defaults.style, null, "Style is loaded upon first use.");262 compare(defaults.style, null, "Style is loaded upon first use.");
231 compare(defaults.__styleInstance, null, "__styleInstance must be null.");263 compare(defaults.__styleInstance, null, "__styleInstance must be null.");
264 compare(defaults.selected, false, "Not selected by default");
265 compare(defaults.selectMode, false, "Not selectable by default");
266 compare(testColumn.ViewItems.selectMode, false, "The parent attached property is not selectable by default");
267 compare(testColumn.ViewItems.selectedIndices.length, 0, "No item is selected by default");
232268
233 compare(actionsDefault.delegate, null, "ListItemActions has no delegate set by default.");269 compare(actionsDefault.delegate, null, "ListItemActions has no delegate set by default.");
234 compare(actionsDefault.actions.length, 0, "ListItemActions has no actions set.");270 compare(actionsDefault.actions.length, 0, "ListItemActions has no actions set.");
@@ -277,7 +313,7 @@
277 clickSpy.target = item;313 clickSpy.target = item;
278 clickSpy.clear();314 clickSpy.clear();
279 movingSpy.target = item;315 movingSpy.target = item;
280 flick(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);316 swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);
281 movingSpy.wait();317 movingSpy.wait();
282318
283 // click over the contentItem319 // click over the contentItem
@@ -292,7 +328,7 @@
292 pressAndHoldSpy.target = item;328 pressAndHoldSpy.target = item;
293 pressAndHoldSpy.clear();329 pressAndHoldSpy.clear();
294 movingSpy.target = item;330 movingSpy.target = item;
295 flick(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);331 swipe(item, centerOf(item).x, centerOf(item).y, units.gu(20), 0);
296 movingSpy.wait();332 movingSpy.wait();
297333
298 // press and hold334 // press and hold
@@ -363,7 +399,7 @@
363 listView.positionViewAtBeginning();399 listView.positionViewAtBeginning();
364 movingSpy.target = data.item;400 movingSpy.target = data.item;
365 if (data.mouse) {401 if (data.mouse) {
366 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);402 swipe(data.item, data.pos.x, data.pos.y, data.dx, 0);
367 } else {403 } else {
368 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));404 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
369 }405 }
@@ -392,7 +428,7 @@
392 listView.positionViewAtBeginning();428 listView.positionViewAtBeginning();
393 movingSpy.target = data.item;429 movingSpy.target = data.item;
394 if (data.mouse) {430 if (data.mouse) {
395 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);431 swipe(data.item, data.pos.x, data.pos.y, data.dx, 0);
396 } else {432 } else {
397 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));433 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
398 }434 }
@@ -419,7 +455,7 @@
419 movingSpy.target = data.item;455 movingSpy.target = data.item;
420 interactiveSpy.target = listView;456 interactiveSpy.target = listView;
421 if (data.mouse) {457 if (data.mouse) {
422 flick(data.item, data.pos.x, data.pos.y, data.dx, data.dy);458 swipe(data.item, data.pos.x, data.pos.y, data.dx, data.dy);
423 } else {459 } else {
424 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, data.dy));460 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, data.dy));
425 }461 }
@@ -444,7 +480,7 @@
444 }480 }
445 function test_visualized_actions(data) {481 function test_visualized_actions(data) {
446 movingSpy.target = data.item;482 movingSpy.target = data.item;
447 flick(data.item, centerOf(data.item).x, centerOf(data.item).y, data.leading ? units.gu(20) : -units.gu(20), 0);483 swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.leading ? units.gu(20) : -units.gu(20), 0);
448 movingSpy.wait();484 movingSpy.wait();
449485
450 // check if the action is visible486 // check if the action is visible
@@ -468,7 +504,7 @@
468 function test_listitem_margins(data) {504 function test_listitem_margins(data) {
469 data.item.contentItem.anchors.margins = units.gu(1);505 data.item.contentItem.anchors.margins = units.gu(1);
470 movingSpy.target = data.item;506 movingSpy.target = data.item;
471 flick(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0);507 swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0);
472 movingSpy.wait();508 movingSpy.wait();
473 var panel = panelItem(data.item, data.leading);509 var panel = panelItem(data.item, data.leading);
474 verify(panel && panel.visible, "Panel not visible.");510 verify(panel && panel.visible, "Panel not visible.");
@@ -489,7 +525,7 @@
489 listView.positionViewAtBeginning();525 listView.positionViewAtBeginning();
490 movingSpy.target = data.item;526 movingSpy.target = data.item;
491 if (data.mouse) {527 if (data.mouse) {
492 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);528 swipe(data.item, data.pos.x, data.pos.y, data.dx, 0);
493 } else {529 } else {
494 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));530 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
495 }531 }
@@ -516,7 +552,7 @@
516 listView.positionViewAtBeginning();552 listView.positionViewAtBeginning();
517 var item = findChild(listView, "listItem0");553 var item = findChild(listView, "listItem0");
518 movingSpy.target = item;554 movingSpy.target = item;
519 flick(item, centerOf(item).x, centerOf(item).y, -units.gu(20), 0);555 swipe(item, centerOf(item).x, centerOf(item).y, -units.gu(20), 0);
520 var panel = panelItem(item, false);556 var panel = panelItem(item, false);
521 verify(panel, "Panel is not visible");557 verify(panel, "Panel is not visible");
522 var custom = findChild(panel, "custom_delegate");558 var custom = findChild(panel, "custom_delegate");
@@ -534,16 +570,16 @@
534 return [570 return [
535 // the list snaps out if the panel is dragged in > overshoot GU (hardcoded for now)571 // the list snaps out if the panel is dragged in > overshoot GU (hardcoded for now)
536 {tag: "Snap out leading", item: listItem, dx: units.gu(2), snapIn: false},572 {tag: "Snap out leading", item: listItem, dx: units.gu(2), snapIn: false},
537 {tag: "Snap in leading", item: listItem, dx: units.gu(4), snapIn: true},573 {tag: "Snap in leading", item: listItem, dx: units.gu(6), snapIn: true},
538 {tag: "Snap out trailing", item: listItem, dx: -units.gu(2), snapIn: false},574 {tag: "Snap out trailing", item: listItem, dx: -units.gu(2), snapIn: false},
539 {tag: "Snap in trailing", item: listItem, dx: -units.gu(4), snapIn: true},575 {tag: "Snap in trailing", item: listItem, dx: -units.gu(6), snapIn: true},
540 ];576 ];
541 }577 }
542 function test_snap(data) {578 function test_snap(data) {
543 movingSpy.target = data.item;579 movingSpy.target = data.item;
544 flick(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0);580 swipe(data.item, centerOf(data.item).x, centerOf(data.item).y, data.dx, 0);
545 movingSpy.wait();581 movingSpy.wait();
546 waitForRendering(data.item, 400);582 waitForRendering(data.item.contentItem, 400);
547 movingSpy.clear();583 movingSpy.clear();
548 if (data.snapIn) {584 if (data.snapIn) {
549 verify(data.item.contentItem.x != 0.0, "Not snapped to be visible");585 verify(data.item.contentItem.x != 0.0, "Not snapped to be visible");
@@ -595,8 +631,6 @@
595 listView.positionViewAtBeginning();631 listView.positionViewAtBeginning();
596 var item0 = findChild(listView, "listItem0");632 var item0 = findChild(listView, "listItem0");
597 var item1 = findChild(listView, "listItem1");633 var item1 = findChild(listView, "listItem1");
598 var item2 = findChild(listView, "listItem2");
599 var item3 = findChild(listView, "listItem3");
600 return [634 return [
601 // testItem is the child item @index 3 in the topmost Column.635 // testItem is the child item @index 3 in the topmost Column.
602 {tag: "Standalone item, child index 3", item: testItem, result: 3},636 {tag: "Standalone item, child index 3", item: testItem, result: 3},
@@ -607,8 +641,9 @@
607 function test_verify_action_value(data) {641 function test_verify_action_value(data) {
608 // tug actions in642 // tug actions in
609 movingSpy.target = data.item;643 movingSpy.target = data.item;
610 flick(data.item, centerOf(data.item).x, centerOf(data.item).y, units.gu(20), 0);644 swipe(data.item, 1, centerOf(data.item).y, units.gu(40), 0);
611 movingSpy.wait();645 movingSpy.wait();
646 wait(2000);
612 verify(data.item.contentItem.x != data.item.contentItem.anchors.leftMargin, "Not snapped in");647 verify(data.item.contentItem.x != data.item.contentItem.anchors.leftMargin, "Not snapped in");
613648
614 var panel = panelItem(data.item, "Leading");649 var panel = panelItem(data.item, "Leading");
@@ -709,7 +744,7 @@
709 interactiveSpy.target = testFlickable;744 interactiveSpy.target = testFlickable;
710 movingSpy.target = listItem;745 movingSpy.target = listItem;
711 // tug leading746 // tug leading
712 flick(listItem, centerOf(listItem).x, centerOf(listItem).y, listItem.width / 2, 0);747 swipe(listItem, centerOf(listItem).x, centerOf(listItem).y, listItem.width / 2, 0);
713 movingSpy.wait();748 movingSpy.wait();
714 // check if interactive got changed749 // check if interactive got changed
715 interactiveSpy.wait();750 interactiveSpy.wait();
@@ -743,5 +778,141 @@
743 compare(clickSpy.count, 0, "Click must be suppressed.");778 compare(clickSpy.count, 0, "Click must be suppressed.");
744 compare(actionSpy.count, 0, "Action triggered must be suppressed");779 compare(actionSpy.count, 0, "Action triggered must be suppressed");
745 }780 }
781
782 function test_select_indices_updates_selected_items() {
783 listView.ViewItems.selectedIndices = [0,1,2];
784 listView.ViewItems.selectMode = true;
785 waitForRendering(listView, 500);
786 for (var i in listView.ViewItems.selectedIndices) {
787 var index = listView.ViewItems.selectedIndices[i];
788 var listItem = findChild(listView, "listItem" + index);
789 compare(listItem.selected, true, "ListItem at index " + index + " is not selected!");
790 }
791 listView.ViewItems.selectMode = false;
792 listView.ViewItems.selectedIndices = [];
793 waitForRendering(listView, 500);
794 }
795
796 function test_toggle_selectMode_data() {
797 return [
798 {tag: "When not selected", index: 0, selected: false},
799 {tag: "When selected", index: 0, selected: true},
800 ]
801 }
802 function test_toggle_selectMode(data) {
803 var listItem = findChild(listView, "listItem" + data.index)
804 verify(listItem, "Cannot get test item");
805 listItem.selected = data.selected;
806 listView.ViewItems.selectMode = true;
807 // wait few milliseconds
808 wait(400);
809 // testItem is the 4th child, so index is 3
810 verify(findChild(listItem, "selection_panel" + data.index), "Cannot find selection panel");
811 compare(listItem.contentItem.enabled, true, "contentItem is not disabled.");
812 }
813
814 SignalSpy {
815 id: selectedSpy
816 signalName: "selectedChanged"
817 }
818
819 function test_toggle_selected_data() {
820 return [
821 // item = <test-item>, clickOk: <item-to-click-on>, offsetX|Y: <clickOn offset clicked>
822 {tag: "Click over selection", selectableHolder: testColumn, item: controlItem, clickOn: "listitem_select", offsetX: units.gu(0.5), offsetY: units.gu(0.5), xfail: false},
823 {tag: "Click over contentItem", selectableHolder: testColumn, item: controlItem, clickOn: "ListItemHolder", offsetX: units.gu(0.5), offsetY: units.gu(0.5), xfail: true},
824 {tag: "Click over control", selectableHolder: testColumn, item: controlItem, clickOn: "button_in_list", offsetX: units.gu(0.5), offsetY: units.gu(0.5), xfail: true},
825 ];
826 }
827 function test_toggle_selected(data) {
828 // make test item selectable first, so the panel is created
829 data.selectableHolder.ViewItems.selectMode = true;
830 wait(400);
831 // get the control to click on
832 var clickOn = findChild(data.item, data.clickOn);
833 verify(clickOn, "control to be clicked on not found");
834 // click on the selection and check selected changed
835 selectedSpy.target = data.item;
836 selectedSpy.clear();
837 mouseClick(clickOn, data.offsetX, data.offsetY);
838 if (data.xfail) {
839 expectFail(data.tag, "Clicking anywhere else but selection panel should not toggle selection state!");
840 }
841 selectedSpy.wait();
842 }
843
844 SignalSpy {
845 id: selectedIndicesSpy
846 signalName: "selectedIndicesChanged"
847 target: listView.ViewItems
848 }
849
850 function test_selectedIndices_change() {
851 // move to the end of the view
852 listView.positionViewAtEnd();
853 var listItem = findChild(listView, "listItem" + (listView.count - 1));
854 verify(listItem, "Cannot get tested list item");
855 listView.ViewItems.selectMode = true;
856 waitForRendering(listItem);
857 selectedSpy.target = listItem;
858 selectedSpy.clear();
859
860 listItem.selected = true;
861 selectedSpy.wait();
862 selectedIndicesSpy.wait();
863 }
864
865 function test_no_tug_when_selectable() {
866 movingSpy.target = testItem;
867 testColumn.ViewItems.selectMode = true;
868 // wait till animation to selection mode ends
869 waitForRendering(testItem.contentItem);
870
871 // try to tug leading
872 movingSpy.clear();
873 swipe(testItem, centerOf(testItem).x, centerOf(testItem).y, units.gu(10), 0);
874 compare(movingSpy.count, 0, "No tug allowed when in selection mode");
875 }
876
877 function test_selectable_and_click() {
878 testColumn.ViewItems.selectMode = true;
879 // wait till animation to selection mode ends
880 waitForRendering(testItem.contentItem);
881
882 clickSpy.target = testItem;
883 mouseClick(testItem, centerOf(testItem).x, centerOf(testItem).y);
884 clickSpy.wait();
885 }
886
887 function test_selectable_and_pressandhold() {
888 testColumn.ViewItems.selectMode = true;
889 // wait till animation to selection mode ends
890 waitForRendering(testItem.contentItem);
891
892 pressAndHoldSpy.target = testItem;
893 mouseLongPress(testItem, centerOf(testItem).x, centerOf(testItem).y);
894 mouseRelease(testItem, centerOf(testItem).x, centerOf(testItem).y);
895 pressAndHoldSpy.wait();
896 }
897
898 function test_proper_attached_properties_data() {
899 return [
900 {tag: "Attached to ListView", item: listView},
901 {tag: "Attached to Column in Flickable", item: column},
902 ];
903 }
904 function test_proper_attached_properties(data) {
905 var listItem = findChild(data.item, "listItem0");
906 verify(listItem, "ListItem not found!");
907 data.item.ViewItems.selectMode = true;
908 // wait few milliseconds to get the selection panel opened
909 wait(400);
910 // check if the selection mode was activated by looking after the first selection panel
911 var panel = findChild(listItem, "selection_panel0");
912 // turn off selection mode so we have a proper cleanup
913 data.item.ViewItems.selectMode = false;
914 wait(400);
915 verify(panel, "Selection panel not found, wrong attached property target?");
916 }
746 }917 }
747}918}

Subscribers

People subscribed via source and target branches