aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/controls/data/tst_tumbler.qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/controls/data/tst_tumbler.qml')
-rw-r--r--tests/auto/controls/data/tst_tumbler.qml1260
1 files changed, 0 insertions, 1260 deletions
diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml
deleted file mode 100644
index 5b3ef6e3..00000000
--- a/tests/auto/controls/data/tst_tumbler.qml
+++ /dev/null
@@ -1,1260 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.12
-import QtTest 1.0
-import QtQuick.Controls 2.12
-
-TestCase {
- id: testCase
- width: 300
- height: 300
- visible: true
- when: windowShown
- name: "Tumbler"
-
- property var tumbler: null
- readonly property real implicitTumblerWidth: 60
- readonly property real implicitTumblerHeight: 200
- readonly property real defaultImplicitDelegateHeight: implicitTumblerHeight / 3
- readonly property real defaultListViewTumblerOffset: -defaultImplicitDelegateHeight
- readonly property real tumblerDelegateHeight: tumbler ? tumbler.availableHeight / tumbler.visibleItemCount : 0
- property Item tumblerView: null
-
- Component {
- id: tumblerComponent
-
- Tumbler {
- visibleItemCount: 3
- }
- }
-
- Component {
- id: itemComponent
-
- Item {
- anchors.fill: parent
- }
- }
-
- function createTumbler(args) {
- tumbler = createTemporaryObject(tumblerComponent, testCase, args);
- verify(tumbler, "Tumbler: failed to create an instance");
- tumblerView = findView(tumbler);
- verify(tumblerView);
- }
-
- function tumblerXCenter() {
- return tumbler.leftPadding + tumbler.width / 2;
- }
-
- function tumblerYCenter() {
- return tumbler.topPadding + tumbler.height / 2;
- }
-
- // visualItemIndex is from 0 to the amount of visible items.
- function itemCenterPos(visualItemIndex) {
- var halfDelegateHeight = tumblerDelegateHeight / 2;
- var yCenter = tumbler.y + tumbler.topPadding + halfDelegateHeight
- + (tumblerDelegateHeight * visualItemIndex);
- return Qt.point(tumblerXCenter(), yCenter);
- }
-
- function itemTopLeftPos(visualItemIndex) {
- return Qt.point(tumbler.leftPadding, tumbler.topPadding + (tumblerDelegateHeight * visualItemIndex));
- }
-
- function checkItemSizes() {
- var contentChildren = tumbler.wrap ? tumblerView.children : tumblerView.contentItem.children;
- verify(contentChildren.length >= tumbler.count);
- for (var i = 0; i < contentChildren.length; ++i) {
- compare(contentChildren[i].width, tumbler.availableWidth);
- compare(contentChildren[i].height, tumblerDelegateHeight);
- }
- }
-
- function findView(parent) {
- for (var i = 0; i < parent.children.length; ++i) {
- var child = parent.children[i];
- if (child.hasOwnProperty("currentIndex")) {
- return child;
- }
-
- var grandChild = findView(child);
- if (grandChild)
- return grandChild;
- }
-
- return null;
- }
-
- function findDelegateWithText(parent, text) {
- for (var i = 0; i < parent.children.length; ++i) {
- var child = parent.children[i];
- if (child.hasOwnProperty("text") && child.text === text) {
- return child;
- }
-
- var grandChild = findDelegateWithText(child, text);
- if (grandChild)
- return grandChild;
- }
-
- return null;
- }
-
- property Component noAttachedPropertiesDelegate: Text {
- text: modelData
- }
-
- function test_wrapWithoutAttachedProperties() {
- createTumbler();
- verify(tumbler.wrap);
-
- tumbler.delegate = noAttachedPropertiesDelegate;
- // Shouldn't assert.
- tumbler.wrap = false;
- verify(findView(tumbler));
- }
-
- // TODO: test that currentIndex is maintained between contentItem changes...
-// function tst_dynamicContentItemChange() {
-// }
-
- function test_currentIndex() {
- createTumbler();
- compare(tumbler.contentItem.parent, tumbler);
-
- tumbler.model = 5;
-
- compare(tumbler.currentIndex, 0);
- waitForRendering(tumbler);
-
- // Set it through user interaction.
- var pos = Qt.point(tumblerXCenter(), tumbler.height / 2);
- mouseDrag(tumbler, pos.x, pos.y, 0, tumbler.height / 3, Qt.LeftButton, Qt.NoModifier, 200);
- tryCompare(tumblerView, "offset", 1);
- compare(tumbler.currentIndex, 4);
- compare(tumblerView.currentIndex, 4);
-
- // Set it manually.
- tumbler.currentIndex = 2;
- tryCompare(tumbler, "currentIndex", 2);
- compare(tumblerView.currentIndex, 2);
-
- tumbler.model = null;
- tryCompare(tumbler, "currentIndex", -1);
- // PathView will only use 0 as the currentIndex when there are no items.
- compare(tumblerView.currentIndex, 0);
-
- tumbler.model = ["A", "B", "C"];
- tryCompare(tumbler, "currentIndex", 0);
-
- // Setting a negative current index should have no effect, because the model isn't empty.
- tumbler.currentIndex = -1;
- compare(tumbler.currentIndex, 0);
-
- tumbler.model = 1;
- compare(tumbler.currentIndex, 0);
-
- tumbler.model = 5;
- compare(tumbler.count, 5);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 5);
- tumbler.currentIndex = 4;
- compare(tumbler.currentIndex, 4);
- compare(tumblerView.currentIndex, 4);
-
- --tumbler.model;
- compare(tumbler.count, 4);
- compare(tumblerView.count, 4);
- // Removing an item from an integer-based model will cause views to reset their currentIndex to 0.
- compare(tumbler.currentIndex, 0);
- compare(tumblerView.currentIndex, 0);
-
- tumbler.model = 0;
- compare(tumbler.currentIndex, -1);
- }
-
- Component {
- id: currentIndexTumbler
-
- Tumbler {
- model: 5
- currentIndex: 2
- visibleItemCount: 3
- }
- }
-
- Component {
- id: currentIndexTumblerNoWrap
-
- Tumbler {
- model: 5
- currentIndex: 2
- wrap: false
- visibleItemCount: 3
- }
- }
-
- Component {
- id: currentIndexTumblerNoWrapReversedOrder
-
- Tumbler {
- model: 5
- wrap: false
- currentIndex: 2
- visibleItemCount: 3
- }
- }
-
- Component {
- id: negativeCurrentIndexTumblerNoWrap
-
- Tumbler {
- model: 5
- wrap: false
- currentIndex: -1
- visibleItemCount: 3
- }
- }
-
- Component {
- id: currentIndexTooLargeTumbler
-
- Tumbler {
- objectName: "currentIndexTooLargeTumbler"
- model: 10
- currentIndex: 10
- }
- }
-
-
- function test_currentIndexAtCreation_data() {
- return [
- { tag: "wrap: implicit, expected currentIndex: 2", currentIndex: 2, wrap: true, component: currentIndexTumbler },
- { tag: "wrap: false, expected currentIndex: 2", currentIndex: 2, wrap: false, component: currentIndexTumblerNoWrap },
- // Order of property assignments shouldn't matter
- { tag: "wrap: false, expected currentIndex: 2, reversed property assignment order",
- currentIndex: 2, wrap: false, component: currentIndexTumblerNoWrapReversedOrder },
- { tag: "wrap: false, expected currentIndex: 0", currentIndex: 0, wrap: false, component: negativeCurrentIndexTumblerNoWrap },
- { tag: "wrap: implicit, expected currentIndex: 0", currentIndex: 0, wrap: true, component: currentIndexTooLargeTumbler }
- ]
- }
-
- function test_currentIndexAtCreation(data) {
- // Test setting currentIndex at creation time
- tumbler = createTemporaryObject(data.component, testCase);
- verify(tumbler);
- // A "statically declared" currentIndex will be pending until the count has changed,
- // which happens when the model is set, which happens on the TumblerView's next polish.
- tryCompare(tumbler, "currentIndex", data.currentIndex);
-
- tumblerView = findView(tumbler);
- tryVerify(function() { return tumblerView.currentItem });
- compare(tumblerView.currentIndex, data.currentIndex);
- compare(tumblerView.currentItem.text, data.currentIndex.toString());
-
- if (data.wrap) {
- tryCompare(tumblerView, "offset", data.currentIndex > 0 ? tumblerView.count - data.currentIndex : 0);
- } else {
- tryCompare(tumblerView, "contentY", tumblerDelegateHeight * data.currentIndex - tumblerView.preferredHighlightBegin);
- }
- }
-
- function test_keyboardNavigation() {
- createTumbler();
-
- tumbler.model = 5;
- tumbler.forceActiveFocus();
- tumblerView.highlightMoveDuration = 0;
-
- // Navigate upwards through entire wheel.
- for (var j = 0; j < tumbler.count - 1; ++j) {
- keyClick(Qt.Key_Up, Qt.NoModifier);
- tryCompare(tumblerView, "offset", j + 1);
- compare(tumbler.currentIndex, tumbler.count - 1 - j);
- }
-
- keyClick(Qt.Key_Up, Qt.NoModifier);
- tryCompare(tumblerView, "offset", 0);
- compare(tumbler.currentIndex, 0);
-
- // Navigate downwards through entire wheel.
- for (j = 0; j < tumbler.count - 1; ++j) {
- keyClick(Qt.Key_Down, Qt.NoModifier);
- tryCompare(tumblerView, "offset", tumbler.count - 1 - j);
- compare(tumbler.currentIndex, j + 1);
- }
-
- keyClick(Qt.Key_Down, Qt.NoModifier);
- tryCompare(tumblerView, "offset", 0);
- compare(tumbler.currentIndex, 0);
- }
-
- function test_itemsCorrectlyPositioned() {
- createTumbler();
-
- tumbler.model = 4;
- tumbler.height = 120;
- compare(tumblerDelegateHeight, 40);
- checkItemSizes();
-
- wait(tumblerView.highlightMoveDuration);
- var firstItemCenterPos = itemCenterPos(1);
- var firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y);
- var actualPos = testCase.mapFromItem(firstItem, 0, 0);
- compare(actualPos.x, tumbler.leftPadding);
- compare(actualPos.y, tumbler.topPadding + 40);
-
- tumbler.forceActiveFocus();
- keyClick(Qt.Key_Down);
- tryCompare(tumblerView, "offset", 3.0);
- tryCompare(tumbler, "moving", false);
- firstItemCenterPos = itemCenterPos(0);
- firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y);
- verify(firstItem);
- // Test QTBUG-40298.
- actualPos = testCase.mapFromItem(firstItem, 0, 0);
- fuzzyCompare(actualPos.x, tumbler.leftPadding, 0.0001);
- fuzzyCompare(actualPos.y, tumbler.topPadding, 0.0001);
-
- var secondItemCenterPos = itemCenterPos(1);
- var secondItem = tumblerView.itemAt(secondItemCenterPos.x, secondItemCenterPos.y);
- verify(secondItem);
- verify(firstItem.y < secondItem.y);
-
- var thirdItemCenterPos = itemCenterPos(2);
- var thirdItem = tumblerView.itemAt(thirdItemCenterPos.x, thirdItemCenterPos.y);
- verify(thirdItem);
- verify(firstItem.y < thirdItem.y);
- verify(secondItem.y < thirdItem.y);
- }
-
- function test_focusPastTumbler() {
- tumbler = createTemporaryObject(tumblerComponent, testCase);
- verify(tumbler);
-
- var mouseArea = createTemporaryQmlObject(
- "import QtQuick 2.2; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", testCase, "");
-
- tumbler.forceActiveFocus();
- verify(tumbler.activeFocus);
-
- keyClick(Qt.Key_Tab);
- verify(!tumbler.activeFocus);
- verify(mouseArea.activeFocus);
- }
-
- function test_datePicker() {
- var component = Qt.createComponent("TumblerDatePicker.qml");
- compare(component.status, Component.Ready, component.errorString());
- tumbler = createTemporaryObject(component, testCase);
- // Should not be any warnings.
-
- tryCompare(tumbler.dayTumbler, "currentIndex", 0);
- compare(tumbler.dayTumbler.count, 31);
- compare(tumbler.monthTumbler.currentIndex, 0);
- compare(tumbler.monthTumbler.count, 12);
- compare(tumbler.yearTumbler.currentIndex, 0);
- tryCompare(tumbler.yearTumbler, "count", 100);
-
- verify(findView(tumbler.dayTumbler).children.length >= tumbler.dayTumbler.visibleItemCount);
- verify(findView(tumbler.monthTumbler).children.length >= tumbler.monthTumbler.visibleItemCount);
- // TODO: do this properly somehow
- wait(100);
- verify(findView(tumbler.yearTumbler).children.length >= tumbler.yearTumbler.visibleItemCount);
-
- // March.
- tumbler.monthTumbler.currentIndex = 2;
- tryCompare(tumbler.monthTumbler, "currentIndex", 2);
-
- // 30th of March.
- tumbler.dayTumbler.currentIndex = 29;
- tryCompare(tumbler.dayTumbler, "currentIndex", 29);
-
- // February.
- tumbler.monthTumbler.currentIndex = 1;
- tryCompare(tumbler.monthTumbler, "currentIndex", 1);
- tryCompare(tumbler.dayTumbler, "currentIndex", 27);
- }
-
- Component {
- id: timePickerComponent
-
- Row {
- property alias minuteTumbler: minuteTumbler
- property alias amPmTumbler: amPmTumbler
-
- Tumbler {
- id: minuteTumbler
- currentIndex: 6
- model: 60
- width: 50
- height: 150
- }
-
- Tumbler {
- id: amPmTumbler
- model: ["AM", "PM"]
- width: 50
- height: 150
- contentItem: ListView {
- anchors.fill: parent
- model: amPmTumbler.model
- delegate: amPmTumbler.delegate
- }
- }
- }
- }
-
- function test_listViewTimePicker() {
- var root = createTemporaryObject(timePickerComponent, testCase);
- verify(root);
-
- mouseDrag(root.minuteTumbler, root.minuteTumbler.width / 2, root.minuteTumbler.height / 2, 0, 50);
- // Shouldn't crash.
- mouseDrag(root.amPmTumbler, root.amPmTumbler.width / 2, root.amPmTumbler.height / 2, 0, 50);
- }
-
- function test_displacement_data() {
- var data = [
- // At 0 offset, the first item is current.
- { count: 6, index: 0, offset: 0, expectedDisplacement: 0 },
- { count: 6, index: 1, offset: 0, expectedDisplacement: -1 },
- { count: 6, index: 5, offset: 0, expectedDisplacement: 1 },
- // When we start to move the first item down, the second item above it starts to become current.
- { count: 6, index: 0, offset: 0.25, expectedDisplacement: -0.25 },
- { count: 6, index: 1, offset: 0.25, expectedDisplacement: -1.25 },
- { count: 6, index: 5, offset: 0.25, expectedDisplacement: 0.75 },
- { count: 6, index: 0, offset: 0.5, expectedDisplacement: -0.5 },
- { count: 6, index: 1, offset: 0.5, expectedDisplacement: -1.5 },
- { count: 6, index: 5, offset: 0.5, expectedDisplacement: 0.5 },
- // By this stage, the delegate at index 1 is destroyed, so we can't test its displacement.
- { count: 6, index: 0, offset: 0.75, expectedDisplacement: -0.75 },
- { count: 6, index: 5, offset: 0.75, expectedDisplacement: 0.25 },
- { count: 6, index: 0, offset: 4.75, expectedDisplacement: 1.25 },
- { count: 6, index: 1, offset: 4.75, expectedDisplacement: 0.25 },
- { count: 6, index: 0, offset: 4.5, expectedDisplacement: 1.5 },
- { count: 6, index: 1, offset: 4.5, expectedDisplacement: 0.5 },
- { count: 6, index: 0, offset: 4.25, expectedDisplacement: 1.75 },
- { count: 6, index: 1, offset: 4.25, expectedDisplacement: 0.75 },
- // count == visibleItemCount
- { count: 3, index: 0, offset: 0, expectedDisplacement: 0 },
- { count: 3, index: 1, offset: 0, expectedDisplacement: -1 },
- { count: 3, index: 2, offset: 0, expectedDisplacement: 1 },
- // count < visibleItemCount
- { count: 2, index: 0, offset: 0, expectedDisplacement: 0 },
- { count: 2, index: 1, offset: 0, expectedDisplacement: 1 },
- // count == 1
- { count: 1, index: 0, offset: 0, expectedDisplacement: 0 }
- ];
- for (var i = 0; i < data.length; ++i) {
- var row = data[i];
- row.tag = "delegate" + row.index + " offset=" + row.offset + " expectedDisplacement=" + row.expectedDisplacement;
- }
- return data;
- }
-
- property Component displacementDelegate: Text {
- objectName: "delegate" + index
- text: modelData
- opacity: 0.2 + Math.max(0, 1 - Math.abs(Tumbler.displacement)) * 0.8
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
-
- Text {
- text: parent.displacement.toFixed(2)
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- }
-
- property real displacement: Tumbler.displacement
- }
-
- function test_displacement(data) {
- createTumbler();
-
- // TODO: test setting these in the opposite order (delegate after model
- // doesn't seem to cause a change in delegates in PathView)
- tumbler.wrap = true;
- tumbler.delegate = displacementDelegate;
- tumbler.model = data.count;
- compare(tumbler.count, data.count);
-
- var delegate = findChild(tumblerView, "delegate" + data.index);
- verify(delegate);
-
- tumblerView.offset = data.offset;
- compare(delegate.displacement, data.expectedDisplacement);
-
- // test displacement after adding and removing items
- }
-
- function test_wrap() {
- createTumbler();
-
- tumbler.model = 5;
- compare(tumbler.count, 5);
-
- tumbler.currentIndex = 2;
- compare(tumblerView.currentIndex, 2);
-
- tumbler.wrap = false;
- tumblerView = findView(tumbler);
- compare(tumbler.count, 5);
- compare(tumbler.currentIndex, 2);
- // Tumbler's count hasn't changed (the model hasn't changed),
- // but the new view needs time to instantiate its items.
- tryCompare(tumblerView, "count", 5);
- compare(tumblerView.currentIndex, 2);
- }
-
- Component {
- id: twoItemTumbler
-
- Tumbler {
- model: 2
- }
- }
-
- Component {
- id: tenItemTumbler
-
- Tumbler {
- model: 10
- }
- }
-
- function test_countWrap() {
- tumbler = createTemporaryObject(tumblerComponent, testCase);
- verify(tumbler);
-
- // Check that a count that is less than visibleItemCount results in wrap being set to false.
- verify(2 < tumbler.visibleItemCount);
- tumbler.model = 2;
- compare(tumbler.count, 2);
- compare(tumbler.wrap, false);
- }
-
- function test_explicitlyNonwrapping() {
- // Check that explicitly setting wrap to false works even when it was implicitly false.
- var explicitlyNonWrapping = createTemporaryObject(twoItemTumbler, testCase);
- verify(explicitlyNonWrapping);
- tryCompare(explicitlyNonWrapping, "wrap", false);
-
- explicitlyNonWrapping.wrap = false;
- // wrap shouldn't be set to true now that there are more items than there are visible ones.
- verify(10 > explicitlyNonWrapping.visibleItemCount);
- explicitlyNonWrapping.model = 10;
- compare(explicitlyNonWrapping.wrap, false);
-
- // Test resetting wrap back to the default behavior.
- explicitlyNonWrapping.wrap = undefined;
- compare(explicitlyNonWrapping.wrap, true);
- }
-
- function test_explicitlyWrapping() {
- // Check that explicitly setting wrap to true works even when it was implicitly true.
- var explicitlyWrapping = createTemporaryObject(tenItemTumbler, testCase);
- verify(explicitlyWrapping);
- compare(explicitlyWrapping.wrap, true);
-
- explicitlyWrapping.wrap = true;
- // wrap shouldn't be set to false now that there are more items than there are visible ones.
- explicitlyWrapping.model = 2;
- compare(explicitlyWrapping.wrap, true);
-
- // Test resetting wrap back to the default behavior.
- explicitlyWrapping.wrap = undefined;
- compare(explicitlyWrapping.wrap, false);
- }
-
- Component {
- id: customListViewTumblerComponent
-
- Tumbler {
- id: listViewTumbler
-
- contentItem: ListView {
- anchors.fill: parent
- model: listViewTumbler.model
- delegate: listViewTumbler.delegate
-
- snapMode: ListView.SnapToItem
- highlightRangeMode: ListView.StrictlyEnforceRange
- preferredHighlightBegin: height / 2 - (height / listViewTumbler.visibleItemCount / 2)
- preferredHighlightEnd: height / 2 + (height / listViewTumbler.visibleItemCount / 2)
- clip: true
- }
- }
- }
-
- Component {
- id: customPathViewTumblerComponent
-
- Tumbler {
- id: pathViewTumbler
-
- contentItem: PathView {
- id: pathView
- model: pathViewTumbler.model
- delegate: pathViewTumbler.delegate
- clip: true
- pathItemCount: pathViewTumbler.visibleItemCount + 1
- preferredHighlightBegin: 0.5
- preferredHighlightEnd: 0.5
- dragMargin: width / 2
-
- path: Path {
- startX: pathView.width / 2
- startY: -pathView.delegateHeight / 2
- PathLine {
- x: pathView.width / 2
- y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2
- }
- }
-
- property real delegateHeight: pathViewTumbler.availableHeight / pathViewTumbler.visibleItemCount
- }
- }
- }
-
- function test_customContentItemAtConstruction_data() {
- return [
- { tag: "ListView", component: customListViewTumblerComponent },
- { tag: "PathView", component: customPathViewTumblerComponent }
- ];
- }
-
- function test_customContentItemAtConstruction(data) {
- var tumbler = createTemporaryObject(data.component, testCase);
- // Shouldn't assert.
-
- tumbler.model = 5;
- compare(tumbler.count, 5);
-
- tumbler.currentIndex = 2;
- var tumblerView = findView(tumbler);
- compare(tumblerView.currentIndex, 2);
-
- tumblerView.incrementCurrentIndex();
- compare(tumblerView.currentIndex, 3);
- compare(tumbler.currentIndex, 3);
-
- // Shouldn't have any affect.
- tumbler.wrap = false;
- compare(tumbler.count, 5);
- compare(tumblerView.currentIndex, 3);
- compare(tumbler.currentIndex, 3);
- }
-
- function findFirstDelegateWithText(view, text) {
- var delegate = null;
- var contentItem = view.hasOwnProperty("contentItem") ? view.contentItem : view;
- for (var i = 0; i < contentItem.children.length && !delegate; ++i) {
- var child = contentItem.children[i];
- if (child.hasOwnProperty("text") && child.text === text)
- delegate = child;
- }
- return delegate;
- }
-
- function test_customContentItemAfterConstruction_data() {
- return [
- { tag: "ListView", componentPath: "TumblerListView.qml" },
- { tag: "PathView", componentPath: "TumblerPathView.qml" }
- ];
- }
-
- function test_customContentItemAfterConstruction(data) {
- createTumbler();
-
- tumbler.model = 5;
- compare(tumbler.count, 5);
-
- tumbler.currentIndex = 2;
- compare(tumblerView.currentIndex, 2);
-
- var contentItemComponent = Qt.createComponent(data.componentPath);
- compare(contentItemComponent.status, Component.Ready);
-
- var customContentItem = createTemporaryObject(contentItemComponent, tumbler);
- tumbler.contentItem = customContentItem;
- compare(tumbler.count, 5);
- tumblerView = findView(tumbler);
- compare(tumblerView.currentIndex, 2);
-
- var delegate = findFirstDelegateWithText(tumblerView, "Custom2");
- verify(delegate);
- compare(delegate.height, defaultImplicitDelegateHeight);
- tryCompare(delegate.Tumbler, "displacement", 0);
-
- tumblerView.incrementCurrentIndex();
- compare(tumblerView.currentIndex, 3);
- compare(tumbler.currentIndex, 3);
- }
-
- function test_displacementListView_data() {
- var offset = defaultListViewTumblerOffset;
-
- var data = [
- // At 0 contentY, the first item is current.
- { contentY: offset, expectedDisplacements: [
- { index: 0, displacement: 0 },
- { index: 1, displacement: -1 },
- { index: 2, displacement: -2 } ]
- },
- // When we start to move the first item down, the second item above it starts to become current.
- { contentY: offset + defaultImplicitDelegateHeight * 0.25, expectedDisplacements: [
- { index: 0, displacement: 0.25 },
- { index: 1, displacement: -0.75 },
- { index: 2, displacement: -1.75 } ]
- },
- { contentY: offset + defaultImplicitDelegateHeight * 0.5, expectedDisplacements: [
- { index: 0, displacement: 0.5 },
- { index: 1, displacement: -0.5 },
- { index: 2, displacement: -1.5 } ]
- },
- { contentY: offset + defaultImplicitDelegateHeight * 0.75, expectedDisplacements: [
- { index: 0, displacement: 0.75 },
- { index: 1, displacement: -0.25 } ]
- },
- { contentY: offset + defaultImplicitDelegateHeight * 3.5, expectedDisplacements: [
- { index: 3, displacement: 0.5 },
- { index: 4, displacement: -0.5 } ]
- }
- ];
- for (var i = 0; i < data.length; ++i) {
- var row = data[i];
- row.tag = "contentY=" + row.contentY;
- }
- return data;
- }
-
- function test_displacementListView(data) {
- createTumbler();
-
- tumbler.wrap = false;
- tumbler.delegate = displacementDelegate;
- tumbler.model = 5;
- compare(tumbler.count, 5);
- // Ensure assumptions about the tumbler used in our data() function are correct.
- tumblerView = findView(tumbler);
- compare(tumblerView.contentY, -defaultImplicitDelegateHeight);
- var delegateCount = 0;
- var listView = tumblerView;
- var listViewContentItem = tumblerView.contentItem;
-
- // We use the mouse instead of setting contentY directly, otherwise the
- // items snap back into place. This doesn't seem to be an issue for
- // PathView for some reason.
- //
- // I tried lots of things to get this test to work with small changes
- // in ListView's contentY (to match the tests for a PathView-based Tumbler), but they didn't work:
- //
- // - Pressing once and then directly moving the mouse to the correct location
- // - Pressing once and interpolating the mouse position to the correct location
- // - Pressing once and doing some dragging up and down to trigger the
- // overThreshold of QQuickFlickable
- //
- // Even after the last item above, QQuickFlickable wouldn't consider it a drag.
- // It seems that overThreshold is set too late, and because the drag distance is quite small
- // to begin with, nothing changes (the displacement was always very close to 0 in the end).
-
- // Ensure that we at least cover the distance required to reach the desired contentY.
- var distanceToReachContentY = data.contentY - defaultListViewTumblerOffset;
- var distance = Math.abs(distanceToReachContentY) + tumbler.height / 2;
- // If distanceToReachContentY is 0, we're testing 0 displacement, so we don't need to do anything.
- if (distanceToReachContentY != 0) {
- mousePress(tumbler, tumblerXCenter(), tumblerYCenter());
-
- var dragDirection = distanceToReachContentY > 0 ? -1 : 1;
- for (var i = 0; i < distance && Math.floor(listView.contentY) !== Math.floor(data.contentY); ++i) {
- mouseMove(tumbler, tumblerXCenter(), tumblerYCenter() + i * dragDirection);
- wait(1); // because Flickable pays attention to velocity, we need some time between movements (qtdeclarative ebf07c3)
- }
- }
-
- for (var i = 0; i < data.expectedDisplacements.length; ++i) {
- var delegate = findChild(listViewContentItem, "delegate" + data.expectedDisplacements[i].index);
- verify(delegate);
- compare(delegate.height, defaultImplicitDelegateHeight);
- // Due to the way we must perform this test, we can't expect high precision.
- var expectedDisplacement = data.expectedDisplacements[i].displacement;
- fuzzyCompare(delegate.displacement, expectedDisplacement, 0.1,
- "Delegate of ListView-based Tumbler at index " + data.expectedDisplacements[i].index
- + " has displacement of " + delegate.displacement + " when it should be " + expectedDisplacement);
- }
-
- if (distanceToReachContentY != 0)
- mouseRelease(tumbler, tumblerXCenter(), itemCenterPos(1) + (data.contentY - defaultListViewTumblerOffset), Qt.LeftButton);
- }
-
- function test_listViewFlickAboveBounds_data() {
- // Tests that flicking above the bounds when already at the top of the
- // tumbler doesn't result in an incorrect displacement.
- var data = [];
- // Less than two items doesn't make sense. The default visibleItemCount
- // is 3, so we test a bit more than double that.
- for (var i = 2; i <= 7; ++i) {
- data.push({ tag: i + " items", model: i });
- }
- return data;
- }
-
- function test_listViewFlickAboveBounds(data) {
- createTumbler();
-
- tumbler.wrap = false;
- tumbler.delegate = displacementDelegate;
- tumbler.model = data.model;
- tumblerView = findView(tumbler);
-
- mousePress(tumbler, tumblerXCenter(), tumblerYCenter());
-
- // Ensure it's stationary.
- var listView = tumblerView;
- compare(listView.contentY, defaultListViewTumblerOffset);
-
- // We could just move up until the contentY changed, but this is safer.
- var distance = tumbler.height;
- var changed = false;
-
- for (var i = 0; i < distance && !changed; ++i) {
- mouseMove(tumbler, tumblerXCenter(), tumblerYCenter() + i, 10);
-
- // Don't test until the contentY has actually changed.
- if (Math.abs(listView.contentY) - listView.preferredHighlightBegin > 0.01) {
-
- for (var delegateIndex = 0; delegateIndex < Math.min(tumbler.count, tumbler.visibleItemCount); ++delegateIndex) {
- var delegate = findChild(listView.contentItem, "delegate" + delegateIndex);
- verify(delegate);
-
- verify(delegate.displacement <= -delegateIndex, "Delegate at index " + delegateIndex + " has a displacement of "
- + delegate.displacement + " when it should be less than or equal to " + -delegateIndex);
- verify(delegate.displacement > -delegateIndex - 0.1, "Delegate at index 0 has a displacement of "
- + delegate.displacement + " when it should be greater than ~ " + -delegateIndex - 0.1);
- }
-
- changed = true;
- }
- }
-
- // Sanity check that something was actually tested.
- verify(changed);
-
- mouseRelease(tumbler, tumblerXCenter(), tumbler.topPadding);
- }
-
- property Component objectNameDelegate: Text {
- objectName: "delegate" + index
- text: modelData
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- }
-
- function test_visibleItemCount_data() {
- var data = [
- // e.g. {0: 2} = {delegate index: y pos / delegate height}
- // Skip item at index 3, because it's out of view.
- { model: 6, visibleItemCount: 5, expectedYPositions: {0: 2, 1: 3, 2: 4, 4: 0} },
- { model: 5, visibleItemCount: 3, expectedYPositions: {0: 1, 1: 2, 4: 0} },
- // Takes up the whole view.
- { model: 2, visibleItemCount: 1, expectedYPositions: {0: 0} },
- ];
-
- for (var i = 0; i < data.length; ++i) {
- data[i].tag = "items=" + data[i].model + ", visibleItemCount=" + data[i].visibleItemCount;
- }
- return data;
- }
-
- function test_visibleItemCount(data) {
- createTumbler();
-
- tumbler.delegate = objectNameDelegate;
- tumbler.visibleItemCount = data.visibleItemCount;
-
- tumbler.model = data.model;
- compare(tumbler.count, data.model);
-
- for (var delegateIndex = 0; delegateIndex < data.visibleItemCount; ++delegateIndex) {
- if (data.expectedYPositions.hasOwnProperty(delegateIndex)) {
- var delegate = findChild(tumblerView, "delegate" + delegateIndex);
- verify(delegate, "Delegate found at index " + delegateIndex);
- var expectedYPos = data.expectedYPositions[delegateIndex] * tumblerDelegateHeight;
- compare(delegate.mapToItem(tumbler.contentItem, 0, 0).y, expectedYPos);
- }
- }
- }
-
- property Component wrongDelegateTypeComponent: QtObject {
- property real displacement: Tumbler.displacement
- }
-
- property Component noParentDelegateComponent: Item {
- property real displacement: Tumbler.displacement
- }
-
- function test_attachedProperties() {
- tumbler = createTemporaryObject(tumblerComponent, testCase);
- verify(tumbler);
-
- // TODO: crashes somewhere in QML's guts
-// tumbler.model = 5;
-// tumbler.delegate = wrongDelegateTypeComponent;
-// ignoreWarning("Attached properties of Tumbler must be accessed from within a delegate item");
-// // Cause displacement to be changed. The warning isn't triggered if we don't do this.
-// tumbler.contentItem.offset += 1;
-
- ignoreWarning("Tumbler: attached properties must be accessed through a delegate item that has a parent");
- createTemporaryObject(noParentDelegateComponent, null);
-
- ignoreWarning("Tumbler: attempting to access attached property on item without an \"index\" property");
- var object = createTemporaryObject(noParentDelegateComponent, testCase);
- verify(object);
- }
-
- property Component paddingDelegate: Text {
- objectName: "delegate" + index
- text: modelData
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
-
- Rectangle {
- anchors.fill: parent
- color: "transparent"
- border.color: "red"
- border.width: 1
- }
- }
-
- function test_padding_data() {
- var data = [];
-
- data.push({ padding: 0 });
- data.push({ padding: 10 });
- data.push({ left: 10, top: 10 });
- data.push({ right: 10, bottom: 10 });
-
- for (var i = 0; i < data.length; ++i) {
- var tag = "";
-
- if (data[i].padding !== undefined)
- tag += "padding: " + data[i].padding + " ";
- if (data[i].left !== undefined)
- tag += "left: " + data[i].left + " ";
- if (data[i].right !== undefined)
- tag += "right: " + data[i].right + " ";
- if (data[i].top !== undefined)
- tag += "top: " + data[i].top + " ";
- if (data[i].bottom !== undefined)
- tag += "bottom: " + data[i].bottom + " ";
- tag = tag.slice(0, -1);
-
- data[i].tag = tag;
- }
-
- return data;
- }
-
- function test_padding(data) {
- createTumbler();
-
- tumbler.delegate = paddingDelegate;
- tumbler.model = 5;
- compare(tumbler.padding, 0);
- compare(tumbler.leftPadding, 0);
- compare(tumbler.rightPadding, 0);
- compare(tumbler.topPadding, 0);
- compare(tumbler.bottomPadding, 0);
- compare(tumbler.contentItem.x, 0);
- compare(tumbler.contentItem.y, 0);
-
- if (data.padding !== undefined)
- tumbler.padding = data.padding;
- if (data.left !== undefined)
- tumbler.leftPadding = data.left;
- if (data.right !== undefined)
- tumbler.rightPadding = data.right;
- if (data.top !== undefined)
- tumbler.topPadding = data.top;
- if (data.bottom !== undefined)
- tumbler.bottomPadding = data.bottom;
-
- compare(tumbler.availableWidth, tumbler.implicitWidth - tumbler.leftPadding - tumbler.rightPadding);
- compare(tumbler.availableHeight, tumbler.implicitHeight - tumbler.topPadding - tumbler.bottomPadding);
- compare(tumbler.contentItem.x, tumbler.leftPadding);
- compare(tumbler.contentItem.y, tumbler.topPadding);
-
- var pathView = tumbler.contentItem;
- var expectedDelegateHeight = tumbler.availableHeight / tumbler.visibleItemCount;
- var itemIndicesInVisualOrder = [4, 0, 1];
- for (var i = 0; i < itemIndicesInVisualOrder.length; ++i) {
- var delegate = findChild(pathView, "delegate" + itemIndicesInVisualOrder[i]);
- verify(delegate, "Couldn't find delegate at index " + itemIndicesInVisualOrder[i]
- + " (iteration " + i + " out of " + (pathView.children.length - 1) + ")");
-
- compare(delegate.width, tumbler.availableWidth);
- compare(delegate.height, expectedDelegateHeight);
-
- var expectedY = tumbler.topPadding + i * expectedDelegateHeight;
- var mappedPos = delegate.mapToItem(null, delegate.width / 2, 0);
- fuzzyCompare(mappedPos.y, expectedY, 0.5,
- "Tumbler's PathView delegate at index " + itemIndicesInVisualOrder[i]
- + " should have a y pos of " + expectedY + ", but it's actually " + mappedPos.y.toFixed(20));
-
- var expectedX = tumbler.leftPadding;
- compare(delegate.mapToItem(null, 0, 0).x, expectedX,
- "Tumbler's PathView delegate at index " + itemIndicesInVisualOrder[i]
- + " should have a x pos of " + expectedX + ", but it's actually " + mappedPos.x.toFixed(20));
- }
-
- // Force new items to be created, as there was a bug where the path was correct until this happened.
- compare(tumblerView.offset, 0);
- ++tumbler.currentIndex;
- tryCompare(tumblerView, "offset", 4, tumblerView.highlightMoveDuration * 2);
- }
-
- function test_moving_data() {
- return [
- { tag: "wrap:true", wrap: true },
- { tag: "wrap:false", wrap: false }
- ]
- }
-
- function test_moving(data) {
- createTumbler({wrap: data.wrap, model: 5})
- compare(tumbler.wrap, data.wrap)
- compare(tumbler.moving, false)
-
- waitForRendering(tumbler)
-
- mousePress(tumbler, tumbler.width / 2, tumbler.height / 2, Qt.LeftButton)
- compare(tumbler.moving, false)
-
- for (var y = tumbler.height / 2; y >= tumbler.height / 4; y -= 10)
- mouseMove(tumbler, tumbler.width / 2, y, 1)
- compare(tumbler.moving, true)
-
- mouseRelease(tumbler, tumbler.width / 2, tumbler.height / 4, Qt.LeftButton)
- compare(tumbler.moving, true)
- tryCompare(tumbler, "moving", false)
- }
-
- Component {
- id: qtbug61374Component
-
- Row {
- property alias tumbler: tumbler
- property alias label: label
-
- Component.onCompleted: {
- tumbler.currentIndex = 2
- }
-
- Tumbler {
- id: tumbler
- model: 5
- // ...
- }
-
- Label {
- id: label
- text: tumbler.currentItem.text
- }
- }
- }
-
- function test_qtbug61374() {
- var row = createTemporaryObject(qtbug61374Component, testCase);
- verify(row);
-
- var tumbler = row.tumbler;
- tryCompare(tumbler, "currentIndex", 2);
-
- tumblerView = findView(tumbler);
-
- var label = row.label;
- compare(label.text, "2");
- }
-
- function test_positionViewAtIndex_data() {
- return [
- // Should be 20, 21, ... but there is a documented limitation for this in positionViewAtIndex()'s docs.
- { tag: "wrap=true, mode=Beginning", wrap: true, mode: Tumbler.Beginning, expectedVisibleIndices: [21, 22, 23, 24, 25] },
- { tag: "wrap=true, mode=Center", wrap: true, mode: Tumbler.Center, expectedVisibleIndices: [18, 19, 20, 21, 22] },
- { tag: "wrap=true, mode=End", wrap: true, mode: Tumbler.End, expectedVisibleIndices: [16, 17, 18, 19, 20] },
- // Same as Beginning; should start at 20.
- { tag: "wrap=true, mode=Contain", wrap: true, mode: Tumbler.Contain, expectedVisibleIndices: [21, 22, 23, 24, 25] },
- { tag: "wrap=true, mode=SnapPosition", wrap: true, mode: Tumbler.SnapPosition, expectedVisibleIndices: [18, 19, 20, 21, 22] },
- { tag: "wrap=false, mode=Beginning", wrap: false, mode: Tumbler.Beginning, expectedVisibleIndices: [20, 21, 22, 23, 24] },
- { tag: "wrap=false, mode=Center", wrap: false, mode: Tumbler.Center, expectedVisibleIndices: [18, 19, 20, 21, 22] },
- { tag: "wrap=false, mode=End", wrap: false, mode: Tumbler.End, expectedVisibleIndices: [16, 17, 18, 19, 20] },
- { tag: "wrap=false, mode=Visible", wrap: false, mode: Tumbler.Visible, expectedVisibleIndices: [16, 17, 18, 19, 20] },
- { tag: "wrap=false, mode=Contain", wrap: false, mode: Tumbler.Contain, expectedVisibleIndices: [16, 17, 18, 19, 20] },
- { tag: "wrap=false, mode=SnapPosition", wrap: false, mode: Tumbler.SnapPosition, expectedVisibleIndices: [18, 19, 20, 21, 22] }
- ]
- }
-
- function test_positionViewAtIndex(data) {
- createTumbler({ wrap: data.wrap, model: 40, visibleItemCount: 5 })
- compare(tumbler.wrap, data.wrap)
-
- waitForRendering(tumbler)
-
- tumbler.positionViewAtIndex(20, data.mode)
- tryCompare(tumbler, "moving", false)
-
- compare(tumbler.visibleItemCount, 5)
- for (var i = 0; i < 5; ++i) {
- // Find the item through its text, as that's easier than child/itemAt().
- var text = data.expectedVisibleIndices[i].toString()
- var item = findDelegateWithText(tumblerView, text)
- verify(item, "found no item with text \"" + text + "\"")
- compare(item.text, data.expectedVisibleIndices[i].toString())
-
- // Ensure that it's at the position we expect.
- var expectedPos = itemTopLeftPos(i)
- var actualPos = testCase.mapFromItem(item, 0, 0)
- compare(actualPos.x, expectedPos.x, "expected delegate with text " + item.text
- + " to have an x pos of " + expectedPos.x + " but it was " + actualPos.x)
- compare(actualPos.y, expectedPos.y, "expected delegate with text " + item.text
- + " to have an y pos of " + expectedPos.y + " but it was " + actualPos.y)
- }
- }
-
- Component {
- id: setCurrentIndexOnImperativeModelChangeComponent
-
- Tumbler {
- onModelChanged: currentIndex = model - 2
- }
- }
-
- function test_setCurrentIndexOnImperativeModelChange() {
- var tumbler = createTemporaryObject(setCurrentIndexOnImperativeModelChangeComponent, testCase);
- verify(tumbler);
-
- tumbler.model = 4
- compare(tumbler.count, 4);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 4);
-
- // 4 - 2 = 2
- compare(tumbler.currentIndex, 2);
-
- ++tumbler.model;
- compare(tumbler.count, 5);
- compare(tumbler.wrap, true);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 5);
- // 5 - 2 = 3
- compare(tumbler.currentIndex, 3);
- }
-
- Component {
- id: setCurrentIndexOnDeclarativeModelChangeComponent
-
- Item {
- property alias tumbler: tumbler
-
- property int setting: 4
-
- Tumbler {
- id: tumbler
- model: setting
- onModelChanged: currentIndex = model - 2
- }
- }
- }
-
- function test_setCurrentIndexOnDeclarativeModelChange() {
- var root = createTemporaryObject(setCurrentIndexOnDeclarativeModelChangeComponent, testCase);
- verify(root);
-
- var tumbler = root.tumbler;
- compare(tumbler.count, 4);
- compare(tumbler.wrap, false);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 4);
- // 4 - 2 = 2
- compare(tumbler.currentIndex, 2);
-
- ++root.setting;
- compare(tumbler.count, 5);
- compare(tumbler.wrap, true);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 5);
- // 5 - 2 = 3
- compare(tumbler.currentIndex, 3);
- }
-
- function test_displacementAfterResizing() {
- createTumbler({
- width: 200,
- wrap: false,
- delegate: displacementDelegate,
- model: 30,
- visibleItemCount: 7,
- currentIndex: 15
- })
-
- var delegate = findChild(tumblerView, "delegate15")
- verify(delegate)
-
- tryCompare(delegate, "displacement", 0)
-
- // Resizing the Tumbler shouldn't affect the displacement.
- tumbler.height *= 1.4
- tryCompare(delegate, "displacement", 0)
- }
-}