diff options
Diffstat (limited to 'tests')
5 files changed, 361 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.mjs b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.mjs new file mode 100644 index 0000000000..cfc1e1146f --- /dev/null +++ b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.mjs @@ -0,0 +1,117 @@ +/* Copyright 2020 Esri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//------------------------------------------------------------------------------ + +export const OrderAscending = 0 +export const OrderDescending = 1 + +//------------------------------------------------------------------------------ + +export function sort(model, sortKey, descending, useMove) { + + _sort(model, sortKey, descending, useMove); +} + +//------------------------------------------------------------------------------ + +function _sort(model, sortKey, descending, useMove) { + var lessThan = descending ? 1 : -1; + var greaterThan = -lessThan; + + var indices = [...new Array(model.count).keys()]; + + function getKeyValue(index) { + return model.get(index)[sortKey]; + } + + function compareKey(index1, index2) { + var value1 = getKeyValue(index1); + var value2 = getKeyValue(index2); + + return (value1 < value2) + ? lessThan + : (value1 > value2) + ? greaterThan + : 0; + } + + indices.sort(compareKey); + + + function compareFrom(i1, i2) { + return (i1.from < i2.from) + ? -1 + : (i1.from > i2.from) + ? 1 + : 0; + } + + var swapIndices = indices.map((e, i) => { return { from: e, to: i }}).sort(compareFrom).map(e => e.to); + + function clone(o) { + return JSON.parse(JSON.stringify(o)); + } + + function cloneSwap(a, b) { + var o = clone(model.get(a)); + model.set(a, model.get(b)); + model.set(b, o); + } + + function moveSwap(a, b) { + if (a < b) { + model.move(a, b, 1); + model.move(b - 1, a, 1); + } + else if (a > b) { + model.move(b, a, 1); + model.move(a - 1, b, 1); + } + } + + + var swap = useMove ? moveSwap : cloneSwap; + var swapCount = 0; + + + for (var iFrom = 0; iFrom < swapIndices.length; iFrom++) { + var iTo = swapIndices[iFrom]; + + if (iFrom === iTo) { + continue; + } + + do { + swap(iFrom, iTo); + + var t = swapIndices[iFrom]; + swapIndices[iFrom] = swapIndices[iTo] + swapIndices[iTo] = t; + + iTo = swapIndices[iFrom]; + + swapCount++; + } + while (iFrom !== iTo); + } + +} + +//------------------------------------------------------------------------------ + + + diff --git a/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.qml b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.qml new file mode 100644 index 0000000000..2679925c80 --- /dev/null +++ b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSort.qml @@ -0,0 +1,166 @@ +/* Copyright 2020 Esri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import QtQml 2.13 +import QtQml.Models 2.13 + +import QtQuick 2.13 +import QtQuick.Layouts 1.12 + +import "ListModelSort.mjs" as ListModelSort + +Item { + Component.onCompleted: { + fillModel(namesModel, "A, D, E, B, C, A"); + } + + + function verify() { + let expected = ["A", "A", "B", "C", "D", "E"] + let sorted = listView.count === 6 + for (let i = 0; i<listView.count;++i) { + sorted = sorted && (listView.itemAtIndex(i).name === expected[i]) + } + return sorted + } + + function doSort() { + sortAsync(namesModel, "name", false, false) + } + + + function random(n) { + return Math.round(Math.random(new Date().valueOf()) * n); + } + + function fillModel(model, values) { + var names = values.split(",").map(name => name.trim()).filter(name => name > ""); + + + model.clear(); + + for (const name of names) { + model.append({ + name: name, + number: random(names.length) + }); + } + } + + //-------------------------------------------------------------------------- + + ListModel { + id: namesModel + + objectName: "namesModel" + } + + //-------------------------------------------------------------------------- + ColumnLayout { + anchors { + fill: parent + margins: 10 + } + + ListView { + id: listView + + Layout.fillWidth: true + Layout.fillHeight: true + + model: namesModel + clip: true + spacing: 5 + + delegate: Text { + required property string name + required property int number + width: ListView.view.width + text: "%1 (%2)".arg(name).arg(number) + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + + add: Transition { + NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 } + NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 } + } + + addDisplaced: Transition { + NumberAnimation { properties: "x,y"; duration: 100 } + } + + move: Transition { + NumberAnimation { properties: "x,y"; duration: 100 } + } + + moveDisplaced: Transition { + NumberAnimation { properties: "x,y"; duration: 100 } + } + + displaced: Transition { + NumberAnimation { properties: "x,y"; duration: 40; easing.type: Easing.OutBounce } + } + + populate: Transition { + NumberAnimation { properties: "x,y"; duration: 100 } + } + + remove: Transition { + ParallelAnimation { + NumberAnimation { property: "opacity"; to: 0; duration: 100 } + NumberAnimation { properties: "x,y"; to: 100; duration: 100 } + } + } + + removeDisplaced: Transition { + NumberAnimation { properties: "x,y"; duration: 100 } + } + } + } + + + function sortSync(model, sortKey, descending, useMove) { + + ListModelSort.sort(model, sortKey, descending, useMove); + } + + //-------------------------------------------------------------------------- + + function sortAsync(model, sortKey, descending, useMove) { + + var params = { + debug: true, + model: model, + sortKey: sortKey, + descending: descending, + useMove: useMove + }; + + + sortWorker.sendMessage(params); + } + + WorkerScript { + id: sortWorker + + source: "ListModelSortWorker.mjs" + } + + //-------------------------------------------------------------------------- + +} + diff --git a/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSortWorker.mjs b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSortWorker.mjs new file mode 100644 index 0000000000..fa3b5c27ec --- /dev/null +++ b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/ListModelSortWorker.mjs @@ -0,0 +1,38 @@ +/* Copyright 2020 Esri + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as ListModelSort from "ListModelSort.mjs"; + +//------------------------------------------------------------------------------ + +WorkerScript.onMessage = function(params) { + + params.model.sync(); + + const debug = params.debug; + + ListModelSort.sort(params.model, params.sortKey, !!params.descending, !!params.useMove); + + params.model.sync(); + + + WorkerScript.sendMessage({ + text: "Sorted" + }); +} + +//------------------------------------------------------------------------------ + diff --git a/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/main.qml b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/main.qml new file mode 100644 index 0000000000..88a23511fa --- /dev/null +++ b/tests/auto/qml/qqmllistmodelworkerscript/data/listmodel_async_sort/main.qml @@ -0,0 +1,23 @@ +import QtQuick 2.13 +import QtQuick.Window 2.13 + +Window { + visible: true + width: 640 + height: 640 + title: qsTr("Hello World") + + ListModelSort { + id: lms + anchors.fill: parent + } + + function doSort() { + lms.doSort() + } + + function verify(): bool { + let ok = lms.verify() + return ok + } +} diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp index 85814a54fb..262ac25d6a 100644 --- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp +++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp @@ -104,6 +104,7 @@ private slots: void worker_remove_list(); void dynamic_role_data(); void dynamic_role(); + void correctMoves(); }; bool tst_qqmllistmodelworkerscript::compareVariantList(const QVariantList &testList, QVariant object) @@ -842,6 +843,22 @@ void tst_qqmllistmodelworkerscript::dynamic_role() qApp->processEvents(); } +void tst_qqmllistmodelworkerscript::correctMoves() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("listmodel_async_sort/main.qml")); + QScopedPointer<QObject> root {component.create()}; + QVERIFY2(root, qPrintable(component.errorString())); + bool ok =QMetaObject::invokeMethod(root.get(), "doSort"); + QVERIFY(ok); + auto check = [&](){ + bool success = false; + QMetaObject::invokeMethod(root.get(), "verify", Q_RETURN_ARG(bool, success)); + return success; + }; + QTRY_VERIFY(check()); +} + QTEST_MAIN(tst_qqmllistmodelworkerscript) #include "tst_qqmllistmodelworkerscript.moc" |