~zsombi/ubuntu-ui-toolkit/83-rtl-support

« back to all changes in this revision

Viewing changes to tests/unit_x11/tst_components/tst_listitem.qml

  • Committer: Zsombor Egri
  • Date: 2015-02-25 11:54:57 UTC
  • mfrom: (1352.6.93 82-dragging-mode)
  • Revision ID: zsombor.egri@canonical.com-20150225115457-sf0p7yjxbcvkzedt
prereq sync

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright 2014 Canonical Ltd.
 
2
 * Copyright 2014-2015 Canonical Ltd.
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify
5
5
 * it under the terms of the GNU Lesser General Public License as published by
14
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
15
 */
16
16
 
17
 
import QtQuick 2.0
 
17
import QtQuick 2.4
18
18
import QtTest 1.0
19
19
import Ubuntu.Test 1.0
20
20
import Ubuntu.Components 1.2
21
21
import Ubuntu.Components.Styles 1.2
 
22
import QtQml.Models 2.1
22
23
 
23
24
Item {
24
25
    id: main
56
57
    ListItemActions {
57
58
        id: actionsDefault
58
59
    }
 
60
    ListModel {
 
61
        id: objectModel
 
62
        function reset() {
 
63
            clear();
 
64
            for (var i = 0; i < 25; i++) {
 
65
                append({data: i});
 
66
            }
 
67
        }
 
68
        Component.onCompleted: reset()
 
69
    }
59
70
 
60
71
    Component {
61
72
        id: customDelegate
107
118
            width: parent.width
108
119
            height: units.gu(28)
109
120
            clip: true
110
 
            model: 10
 
121
            model: objectModel
111
122
            ViewItems.selectMode: false
112
123
            delegate: ListItem {
113
124
                objectName: "listItem" + index
114
125
                color: "lightgray"
115
 
                width: parent.width
116
126
                leadingActions: leading
117
127
                trailingActions: trailing
118
128
                Label {
119
 
                    text: "Data " + index
 
129
                    text: "Data: " + modelData + " @" + index
120
130
                }
121
131
            }
122
132
        }
123
133
        Flickable {
124
134
            id: testFlickable
125
135
            width: parent.width
126
 
            height: units.gu(28)
 
136
            height: units.gu(21)
127
137
            ListView {
128
138
                id: nestedListView
129
139
                width: parent.width
209
219
            flick(item, x, y, dx, dy, 0, 0, undefined, undefined, 100);
210
220
        }
211
221
 
 
222
        SignalSpy {
 
223
            id: dropSpy
 
224
            signalName: "stopped"
 
225
        }
 
226
 
 
227
        function toggleDragMode(view, enabled) {
 
228
            // use the topmost listItem to wait for rendering completion
 
229
            view.positionViewAtBeginning();
 
230
            var listItem = findChild(view, "listItem0");
 
231
            verify(listItem);
 
232
            view.ViewItems.dragMode = enabled;
 
233
            // waitForRendering aint seems to be reliable here, so we wait ~400 msecs
 
234
            wait(400);
 
235
        }
 
236
 
 
237
        function drag(view, from, to) {
 
238
            var dragArea = findChild(view, "drag_area");
 
239
            verify(dragArea, "Cannot locate drag area");
 
240
 
 
241
            // grab the source item
 
242
            view.positionViewAtBeginning(from,ListView.Beginning);
 
243
            var panel = findChild(view, "drag_panel" + from);
 
244
            verify(panel, "Cannot locate source panel");
 
245
            var dragPos = dragArea.mapFromItem(panel, centerOf(panel).x, centerOf(panel).y);
 
246
            // move the mouse
 
247
            var dy = Math.abs(to - from) * panel.height + units.gu(1);
 
248
            dy *= (to > from) ? 1 : -1;
 
249
            mousePress(dragArea, dragPos.x, dragPos.y);
 
250
            wait(100);
 
251
            var draggedItem = findChild(view.contentItem, "DraggedListItem");
 
252
            if (draggedItem) {
 
253
                dropSpy.target = draggedItem.__styleInstance.dropAnimation;
 
254
            }
 
255
            // use 10 steps to be sure the move is properly detected by the drag area
 
256
            mouseMoveSlowly(dragArea, dragPos.x, dragPos.y, 0, dy, 10, 100);
 
257
            // drop it, needs two mouse releases, this generates the Drop event also
 
258
            mouseRelease(dragArea, dragPos.x, dragPos.y + dy);
 
259
            // needs one more mouse release
 
260
            mouseRelease(dragArea, dragPos.x, dragPos.y + dy);
 
261
            if (dropSpy.target) {
 
262
                dropSpy.wait();
 
263
            } else {
 
264
                // draggedItem cannot be found, we might be trying to drag a restricted item
 
265
                wait(200);
 
266
            }
 
267
        }
 
268
 
212
269
        function initTestCase() {
213
270
            TestExtras.registerTouchDevice();
214
271
            waitForRendering(main);
215
272
        }
216
273
 
217
274
        function cleanup() {
 
275
            listView.model = objectModel;
218
276
            testItem.action = null;
219
277
            testItem.contentItem.anchors.margins = 0;
220
278
            testItem.selected = false;
231
289
            interactiveSpy.clear();
232
290
            listView.interactive = true;
233
291
            listView.ViewItems.selectMode = false;
 
292
            listView.ViewItems.dragMode = false;
234
293
            // make sure we collapse
235
294
            mouseClick(defaults, 0, 0)
236
295
            movingSpy.target = null;
265
324
            compare(defaults.selectMode, false, "Not selectable by default");
266
325
            compare(testColumn.ViewItems.selectMode, false, "The parent attached property is not selectable by default");
267
326
            compare(testColumn.ViewItems.selectedIndices.length, 0, "No item is selected by default");
 
327
            compare(listView.ViewItems.dragMode, false, "Drag mode is off on ListView");
268
328
 
269
329
            compare(actionsDefault.delegate, null, "ListItemActions has no delegate set by default.");
270
330
            compare(actionsDefault.actions.length, 0, "ListItemActions has no actions set.");
914
974
            wait(400);
915
975
            verify(panel, "Selection panel not found, wrong attached property target?");
916
976
        }
 
977
 
 
978
        function test_dragmode_availability_data() {
 
979
            return [
 
980
                {tag: "Attached to Column", item: testColumn, lookupOn: testItem, xfail: true},
 
981
                {tag: "Attached to ListView", item: listView, lookupOn: findChild(listView, "listItem0"), xfail: false},
 
982
            ];
 
983
        }
 
984
        function test_dragmode_availability(data) {
 
985
            if (data.xfail) {
 
986
                ignoreWarning(warningFormat(80, 5, "QML Column: dragging mode requires ListView"));
 
987
            }
 
988
            data.item.ViewItems.dragMode = true;
 
989
            wait(400);
 
990
            var panel = findChild(data.lookupOn, "drag_panel0");
 
991
            if (data.xfail) {
 
992
                expectFailContinue(data.tag, "There should be no drag handler shown!")
 
993
            }
 
994
            verify(panel, "No drag handler found!");
 
995
        }
 
996
 
 
997
        function test_drag_data() {
 
998
            return [
 
999
                {tag: "Live 0->1 OK", live: true, from: 0, to: 1, count: 1, accept: true, indices:[1,0,2,3,4]},
 
1000
                {tag: "Live 0->2 OK", live: true, from: 0, to: 2, count: 2, accept: true, indices:[1,2,0,3,4]},
 
1001
                {tag: "Live 0->3 OK", live: true, from: 0, to: 3, count: 3, accept: true, indices:[1,2,3,0,4]},
 
1002
                {tag: "Live 3->0 OK", live: true, from: 3, to: 0, count: 3, accept: true, indices:[3,0,1,2,4]},
 
1003
                        // do not accept moves
 
1004
                {tag: "Live 0->1 NOK", live: true, from: 0, to: 1, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1005
                {tag: "Live 0->2 NOK", live: true, from: 0, to: 2, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1006
                {tag: "Live 0->3 NOK", live: true, from: 0, to: 3, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1007
                {tag: "Live 3->0 NOK", live: true, from: 3, to: 0, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1008
 
 
1009
                        // non-live updates
 
1010
                {tag: "Drop 0->1 OK", live: false, from: 0, to: 1, count: 1, accept: true, indices:[1,0,2,3,4]},
 
1011
                {tag: "Drop 0->2 OK", live: false, from: 0, to: 2, count: 1, accept: true, indices:[1,2,0,3,4]},
 
1012
                {tag: "Drop 0->3 OK", live: false, from: 0, to: 3, count: 1, accept: true, indices:[1,2,3,0,4]},
 
1013
                {tag: "Drop 3->0 OK", live: false, from: 3, to: 0, count: 1, accept: true, indices:[3,0,1,2,4]},
 
1014
                        // do not accept moves
 
1015
                {tag: "Drop 0->1 NOK", live: false, from: 0, to: 1, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1016
                {tag: "Drop 0->2 NOK", live: false, from: 0, to: 2, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1017
                {tag: "Drop 0->3 NOK", live: false, from: 0, to: 3, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1018
                {tag: "Drop 3->0 NOK", live: false, from: 3, to: 0, count: 0, accept: false, indices:[0,1,2,3,4]},
 
1019
            ];
 
1020
        }
 
1021
 
 
1022
        function test_drag(data) {
 
1023
            var moveCount = 0;
 
1024
            function liveUpdate(event) {
 
1025
                if (event.status == ListItemDrag.Started) {
 
1026
                    return;
 
1027
                }
 
1028
                if (data.accept) {
 
1029
                    moveCount++;
 
1030
                    listView.model.move(event.from, event.to, 1);
 
1031
                }
 
1032
                event.accept = data.accept;
 
1033
            }
 
1034
            function singleDrop(event) {
 
1035
                if (event.status == ListItemDrag.Dropped) {
 
1036
                    if (data.accept) {
 
1037
                        moveCount++;
 
1038
                        listView.model.move(event.from, event.to, 1);
 
1039
                    }
 
1040
                    event.accept = data.accept;
 
1041
                } else if (event.status == ListItemDrag.Moving) {
 
1042
                    event.accept = false;
 
1043
                }
 
1044
            }
 
1045
 
 
1046
            objectModel.reset();
 
1047
            waitForRendering(listView);
 
1048
            listView.positionViewAtBeginning();
 
1049
            var func = data.live ? liveUpdate : singleDrop;
 
1050
            listView.ViewItems.dragUpdated.connect(func);
 
1051
 
 
1052
            // enter drag mode
 
1053
            toggleDragMode(listView, true);
 
1054
            drag(listView, data.from, data.to);
 
1055
            compare(moveCount, data.count, "Move did not happen or more than one item was moved");
 
1056
            // compare array indices
 
1057
            for (var i in data.indices) {
 
1058
                compare(listView.model.get(i).data, data.indices[i], "data at index " + i + " is not the expected one");
 
1059
            }
 
1060
 
 
1061
            // cleanup
 
1062
            listView.ViewItems.dragUpdated.disconnect(func);
 
1063
            toggleDragMode(listView, false);
 
1064
        }
 
1065
 
 
1066
        // preconditions:
 
1067
        // the first 2 items cannot be dragged anywhere, nothing can be dropped in this area
 
1068
        // the 3-> items can be interchanged in between, cannot be dragged outside
 
1069
        function test_drag_restricted_data() {
 
1070
            return [
 
1071
                {tag: "[0,1] locked, drag 0->1 NOK", from: 0, to: 1, count: 0, indices: [0,1,2,3,4]},
 
1072
                {tag: "[0,1] locked, drag 1->2 NOK", from: 1, to: 2, count: 0, indices: [0,1,2,3,4]},
 
1073
                {tag: "[0,1] locked, drag 2->1 NOK", from: 2, to: 1, count: 0, indices: [0,1,2,3,4]},
 
1074
                {tag: "[0,1] locked, drag 2->0 NOK", from: 2, to: 0, count: 0, indices: [0,1,2,3,4]},
 
1075
                        // drag
 
1076
                {tag: "[0,1] locked, drag 2->3 OK", from: 2, to: 3, count: 1, indices: [0,1,3,2,4]},
 
1077
            ];
 
1078
        }
 
1079
        function test_drag_restricted(data) {
 
1080
            var moveCount = 0;
 
1081
            function updateHandler(event) {
 
1082
                if (event.status == ListItemDrag.Started) {
 
1083
                    if (event.from < 2) {
 
1084
                        event.accept = false;
 
1085
                    } else {
 
1086
                        event.minimumIndex = 2;
 
1087
                    }
 
1088
                } else if (event.status == ListItemDrag.Moving) {
 
1089
                    listView.model.move(event.from, event.to, 1);
 
1090
                    moveCount++;
 
1091
                }
 
1092
            }
 
1093
 
 
1094
            objectModel.reset();
 
1095
            waitForRendering(listView);
 
1096
            listView.positionViewAtBeginning();
 
1097
            listView.ViewItems.dragUpdated.connect(updateHandler);
 
1098
 
 
1099
            // enter drag mode
 
1100
            toggleDragMode(listView, true);
 
1101
            drag(listView, data.from, data.to);
 
1102
            compare(moveCount, data.count, "Move did not happen or more than one item was moved");
 
1103
            // compare array indices
 
1104
            for (var i in data.indices) {
 
1105
                compare(listView.model.get(i).data, data.indices[i], "data at index " + i + " is not the expected one");
 
1106
            }
 
1107
 
 
1108
            // cleanup
 
1109
            listView.ViewItems.dragUpdated.disconnect(updateHandler);
 
1110
            toggleDragMode(listView, false);
 
1111
        }
 
1112
 
 
1113
        function test_drag_keeps_selected_indexes_data() {
 
1114
            return [
 
1115
                {tag: "[0,1,2] selected, move 0->3, live", selected: [0,1,2], from: 0, to: 3, expected: [0,1,3], live: true},
 
1116
                {tag: "[1,2] selected, move 3->2, live", selected: [1,2], from: 3, to: 2, expected: [1,3], live: true},
 
1117
                {tag: "[1,2] selected, move 0->3, live", selected: [1,2], from: 0, to: 3, expected: [0,1], live: true},
 
1118
                {tag: "[1,2] selected, move 3->0, live", selected: [1,2], from: 3, to: 0, expected: [2,3], live: true},
 
1119
                // non-live updates
 
1120
                {tag: "[0,1,2] selected, move 0->3, non-live", selected: [0,1,2], from: 0, to: 3, expected: [0,1,3], live: false},
 
1121
                {tag: "[1,2] selected, move 3->2, non-live", selected: [1,2], from: 3, to: 2, expected: [1,3], live: false},
 
1122
                {tag: "[1,2] selected, move 0->3, non-live", selected: [1,2], from: 0, to: 3, expected: [0,1], live: false},
 
1123
                {tag: "[1,2] selected, move 3->0, non-live", selected: [1,2], from: 3, to: 0, expected: [2,3], live: false},
 
1124
            ];
 
1125
        }
 
1126
        function test_drag_keeps_selected_indexes(data) {
 
1127
            function updateHandler(event) {
 
1128
                if (event.status == ListItemDrag.Started) {
 
1129
                    return;
 
1130
                }
 
1131
                if (data.live || event.status == ListItemDrag.Dropped) {
 
1132
                    listView.model.move(event.from, event.to, 1);
 
1133
                } else {
 
1134
                    event.accept = false;
 
1135
                }
 
1136
            }
 
1137
            objectModel.reset();
 
1138
            waitForRendering(listView);
 
1139
            listView.ViewItems.selectedIndices = data.selected;
 
1140
            listView.ViewItems.dragUpdated.connect(updateHandler);
 
1141
            toggleDragMode(listView, true);
 
1142
            drag(listView, data.from, data.to);
 
1143
            listView.ViewItems.dragUpdated.disconnect(updateHandler);
 
1144
            toggleDragMode(listView, false);
 
1145
 
 
1146
            // NOTE: the selected indexes order is arbitrar and cannot be predicted by the test
 
1147
            // therefore we check the selected indexes presence in the expected list.
 
1148
            compare(listView.ViewItems.selectedIndices.length, data.expected.length, "The selected indexes and expected list size differs");
 
1149
            for (var i = 0; i < listView.ViewItems.selectedIndices.length; i++) {
 
1150
                var index = data.expected.indexOf(listView.ViewItems.selectedIndices[i]);
 
1151
                verify(index >= 0, "Index " + listView.ViewItems.selectedIndices[i] + " is not expected to be selected!");
 
1152
            }
 
1153
        }
 
1154
 
 
1155
        // must run this immediately after the defaults are checked otherwise drag handler connected check will fail
 
1156
        function test_1_warn_missing_dragUpdated_signal_handler() {
 
1157
            ignoreWarning(warningFormat(116, 9, "QML ListView: ListView has no ViewItems.dragUpdated() signal handler implemented. No dragging will be possible."));
 
1158
            toggleDragMode(listView, true);
 
1159
            drag(listView, 0, 1);
 
1160
            toggleDragMode(listView, true);
 
1161
        }
 
1162
 
 
1163
        DelegateModel {
 
1164
            id: delegateModel
 
1165
            delegate: ListItem {
 
1166
                objectName: "listItem" + index
 
1167
                Label { text: modelData }
 
1168
            }
 
1169
        }
 
1170
        ObjectModel {
 
1171
            id: objectModel2
 
1172
            Repeater {
 
1173
                model: 3
 
1174
                ListItem {
 
1175
                    objectName: "listItem" + index
 
1176
                    Label { text: modelData }
 
1177
                }
 
1178
            }
 
1179
        }
 
1180
        function test_warn_model_data() {
 
1181
            var list = [1,2,3,4,5,6,7,8,9,10];
 
1182
            return [
 
1183
                {tag: "number", model: 20, warning: "not all features of dragging will be possible on this model."},
 
1184
                {tag: "list", model: list, warning: "not all features of dragging will be possible on this model."},
 
1185
                {tag: "objectModel", model: objectModel, warning: ""},
 
1186
                {tag: "DelegateModel with number", model: delegateModel, modelModel: 20, warning: "not all features of dragging will be possible on this DelegateModel.model."},
 
1187
                {tag: "DelegateModel with list", model: delegateModel, modelModel: [1,2,3,4,5,6,7,8,9,10], warning: "not all features of dragging will be possible on this DelegateModel.model."},
 
1188
                {tag: "DelegateModel with objectModel", model: delegateModel, modelModel: objectModel, warning: ""},
 
1189
                {tag: "ObjectModel", model: objectModel2, warning: ""},
 
1190
            ];
 
1191
        }
 
1192
        function test_warn_model(data) {
 
1193
            function dummyFunc() {}
 
1194
            if (data.warning !== "") {
 
1195
                ignoreWarning(warningFormat(116, 9, "QML ListView: " + data.warning));
 
1196
            }
 
1197
            listView.model = data.model;
 
1198
            if (typeof data.modelModel !== "undefined") {
 
1199
                listView.model.model = data.modelModel;
 
1200
            }
 
1201
            waitForRendering(listView, 500);
 
1202
            listView.ViewItems.dragUpdated.connect(dummyFunc);
 
1203
            toggleDragMode(listView, true);
 
1204
            toggleDragMode(listView, false);
 
1205
            listView.ViewItems.dragUpdated.disconnect(dummyFunc);
 
1206
        }
917
1207
    }
918
1208
}