aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qtquick2/qquickpathview
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qtquick2/qquickpathview')
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/ComponentView.qml17
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/asyncloader.qml71
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/closedPath.qml24
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/creationContext.qml5
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/datamodel.qml38
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/displaypath.qml59
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/dragpath.qml19
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/emptymodel.qml5
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/missingPercent.qml9
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/openPath.qml10
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathUpdate.qml18
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathUpdateOnStartChanged.qml38
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathline.qml48
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathtest.qml14
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathview0.qml85
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathview1.qml4
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathview2.qml57
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathview3.qml59
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/pathview_package.qml88
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/propertychanges.qml116
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/treemodel.qml19
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/undefinedpath.qml17
-rw-r--r--tests/auto/qtquick2/qquickpathview/data/vdm.qml28
-rw-r--r--tests/auto/qtquick2/qquickpathview/qquickpathview.pro12
-rw-r--r--tests/auto/qtquick2/qquickpathview/tst_qquickpathview.cpp1629
25 files changed, 2489 insertions, 0 deletions
diff --git a/tests/auto/qtquick2/qquickpathview/data/ComponentView.qml b/tests/auto/qtquick2/qquickpathview/data/ComponentView.qml
new file mode 100644
index 0000000000..b61033d375
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/ComponentView.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+PathView {
+ id: view
+
+ property string title
+
+ width: 100; height: 100;
+
+ model: 1
+ delegate: Text { objectName: "listItem"; text: view.title }
+
+ path: Path {
+ startX: 25; startY: 25;
+ PathLine { x: 75; y: 75 }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/asyncloader.qml b/tests/auto/qtquick2/qquickpathview/data/asyncloader.qml
new file mode 100644
index 0000000000..94f560f3e7
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/asyncloader.qml
@@ -0,0 +1,71 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property real delegateWidth: 60
+ property real delegateHeight: 20
+ property real delegateScale: 1.0
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Loader {
+ asynchronous: true
+ sourceComponent: viewComponent
+ anchors.fill: parent
+ }
+
+ Component {
+ id: adelegate
+ Rectangle {
+ objectName: "wrapper"
+ property bool onPath: PathView.onPath
+ height: root.delegateHeight
+ width: root.delegateWidth
+ scale: root.delegateScale
+ color: PathView.isCurrentItem ? "lightsteelblue" : "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ }
+ }
+ Component {
+ id: viewComponent
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: 5
+ delegate: adelegate
+ highlight: Rectangle {
+ width: 60
+ height: 20
+ color: "yellow"
+ }
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 0
+ control2X: 200
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/closedPath.qml b/tests/auto/qtquick2/qquickpathview/data/closedPath.qml
new file mode 100644
index 0000000000..3ca34056c8
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/closedPath.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/creationContext.qml b/tests/auto/qtquick2/qquickpathview/data/creationContext.qml
new file mode 100644
index 0000000000..79a682788b
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/creationContext.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+ComponentView {
+ title: "Hello!"
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/datamodel.qml b/tests/auto/qtquick2/qquickpathview/data/datamodel.qml
new file mode 100644
index 0000000000..44f2aecc0a
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/datamodel.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathview
+ property int viewCount: count
+ objectName: "pathview"
+ width: 240; height: 320
+ pathItemCount: testObject.pathItemCount
+
+ function checkProperties() {
+ testObject.error = false;
+ if (testObject.useModel && pathview.model != testData) {
+ console.log("model property incorrect");
+ testObject.error = true;
+ }
+ }
+
+ model: testObject.useModel ? testData : 0
+
+ delegate: Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ property bool onPath: PathView.onPath
+ width: 20; height: 20; color: name
+ Text {
+ objectName: "myText"
+ text: name
+ }
+ }
+ }
+
+ path: Path {
+ startX: 120; startY: 20;
+ PathLine { x: 120; y: 300 }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/displaypath.qml b/tests/auto/qtquick2/qquickpathview/data/displaypath.qml
new file mode 100644
index 0000000000..af0f381fc4
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/displaypath.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: delegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 60
+ color: "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ Text {
+ x: 20
+ id: displayText
+ objectName: "displayText"
+ text: display
+ }
+ }
+ }
+ ]
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: delegate
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/dragpath.qml b/tests/auto/qtquick2/qquickpathview/data/dragpath.qml
new file mode 100644
index 0000000000..f9c6615b04
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/dragpath.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+PathView {
+ width: 400
+ height: 200
+ model: 100
+ pathItemCount: 20
+ path: Path {
+ startX: 0; startY: 100
+ PathLine { x: 400; y: 100 }
+ }
+ delegate: Rectangle { objectName: "wrapper"; height: 100; width: 2; color: PathView.isCurrentItem?"red" : "black" }
+ dragMargin: 100
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ Text {
+ text: "current index: " + parent.currentIndex
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/emptymodel.qml b/tests/auto/qtquick2/qquickpathview/data/emptymodel.qml
new file mode 100644
index 0000000000..eb4d3006f4
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/emptymodel.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+PathView {
+ model: emptyModel
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/missingPercent.qml b/tests/auto/qtquick2/qquickpathview/data/missingPercent.qml
new file mode 100644
index 0000000000..97af8e8982
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/missingPercent.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Path {
+ startY: 0
+ startX: 0
+ PathLine { x: 0; y: 50 }
+ PathPercent { value: .5 }
+ PathLine { x: 50; y: 50 }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/openPath.qml b/tests/auto/qtquick2/qquickpathview/data/openPath.qml
new file mode 100644
index 0000000000..1bd8375d9e
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/openPath.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Path {
+ startY: 120
+ startX: 160
+ PathLine {
+ y: 160
+ x: 20
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathUpdate.qml b/tests/auto/qtquick2/qquickpathview/data/pathUpdate.qml
new file mode 100644
index 0000000000..e729291025
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathUpdate.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ PathView {
+ id: view
+ objectName: "pathView"
+ anchors.fill: parent
+ model: 10
+ delegate: Rectangle { objectName: "wrapper"; color: "green"; width: 100; height: 100 }
+ path: Path {
+ startX: view.width/2; startY: 0
+ PathLine { x: view.width/2; y: view.height }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathUpdateOnStartChanged.qml b/tests/auto/qtquick2/qquickpathview/data/pathUpdateOnStartChanged.qml
new file mode 100644
index 0000000000..89084b2a37
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathUpdateOnStartChanged.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 800
+ height: 480
+ color: "black"
+ resources: [
+ ListModel {
+ id: appModel
+ ListElement { color: "green" }
+ },
+ Component {
+ id: appDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ color: "green"
+ width: 100
+ height: 100
+ }
+ }
+ ]
+ PathView {
+ id: pathView
+ objectName: "pathView"
+ model: appModel
+ anchors.fill: parent
+
+ transformOrigin: "Top"
+ delegate: appDelegate
+ path: Path {
+ objectName: "path"
+ startX: pathView.width / 2 // startX: 400 <- this works as expected
+ startY: 300
+ PathLine { x: 400; y: 120 }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathline.qml b/tests/auto/qtquick2/qquickpathview/data/pathline.qml
new file mode 100644
index 0000000000..4c1c785bce
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathline.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: app
+ width: 360
+ height: 360
+
+ PathView {
+ id: pathView
+ objectName: "view"
+ x: (app.width-pathView.width)/2
+ y: 100
+ width: 240
+ height: 100
+
+ model: testModel
+
+ Rectangle {
+ anchors.fill: parent
+ color: "white"
+ border.color: "black"
+ }
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+
+ delegate: Rectangle {
+ objectName: "wrapper"
+ width: 100
+ height: 100
+ color: PathView.isCurrentItem ? "red" : "yellow"
+ Text {
+ text: index
+ anchors.centerIn: parent
+ }
+ z: (PathView.isCurrentItem?1:0)
+ }
+ path: Path {
+ id: path
+ startX: -100+pathView.width/2
+ startY: pathView.height/2
+ PathLine {
+ id: line
+ x: 100+pathView.width/2
+ y: pathView.height/2
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathtest.qml b/tests/auto/qtquick2/qquickpathview/data/pathtest.qml
new file mode 100644
index 0000000000..736d58d2a9
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathtest.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Path {
+ startX: 120; startY: 100
+
+ PathAttribute { name: "scale"; value: 1.0 }
+ PathQuad { x: 120; y: 25; controlX: 260; controlY: 75 }
+ PathPercent { value: 0.3 }
+ PathLine { x: 120; y: 100 }
+ PathCubic {
+ x: 180; y: 0; control1X: -10; control1Y: 90
+ control2X: 210; control2Y: 90
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathview0.qml b/tests/auto/qtquick2/qquickpathview/data/pathview0.qml
new file mode 100644
index 0000000000..8b9378163f
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathview0.qml
@@ -0,0 +1,85 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property int count: view.count
+ property int currentA: -1
+ property int currentB: -1
+ property real delegateWidth: 60
+ property real delegateHeight: 20
+ property real delegateScale: 1.0
+ width: 240
+ height: 320
+ color: "#ffffff"
+ resources: [
+ Component {
+ id: delegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ property bool onPath: PathView.onPath
+ height: root.delegateHeight
+ width: root.delegateWidth
+ scale: root.delegateScale
+ color: PathView.isCurrentItem ? "lightsteelblue" : "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ Text {
+ x: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ PathView.onCurrentItemChanged: {
+ if (PathView.isCurrentItem) {
+ root.currentA = index;
+ root.currentB = wrapper.PathView.view.currentIndex;
+ }
+ }
+ }
+ }
+ ]
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: testModel
+ delegate: delegate
+ highlight: Rectangle {
+ width: 60
+ height: 20
+ color: "yellow"
+ }
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 000
+ control2X: 200
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathview1.qml b/tests/auto/qtquick2/qquickpathview/data/pathview1.qml
new file mode 100644
index 0000000000..53d375e596
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathview1.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+PathView {
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathview2.qml b/tests/auto/qtquick2/qquickpathview/data/pathview2.qml
new file mode 100644
index 0000000000..1d279c42a0
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathview2.qml
@@ -0,0 +1,57 @@
+import QtQuick 2.0
+
+PathView {
+ id: photoPathView
+ y: 100; width: 800; height: 330; pathItemCount: 10; z: 1
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+
+ delegate: Component {
+ id: photoDelegate
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+ scale: wrapper.PathView.scale
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0; angle: wrapper.PathView.angle
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathview3.qml b/tests/auto/qtquick2/qquickpathview/data/pathview3.qml
new file mode 100644
index 0000000000..ded5a3911c
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathview3.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+PathView {
+ id: photoPathView
+ y: 100; width: 800; height: 330; pathItemCount: 4; offset: 1
+ dragMargin: 24
+ preferredHighlightBegin: 0.50
+ preferredHighlightEnd: 0.50
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+
+ delegate: Component {
+ id: photoDelegate
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0
+ }
+ }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/pathview_package.qml b/tests/auto/qtquick2/qquickpathview/data/pathview_package.qml
new file mode 100644
index 0000000000..2af57e6bb1
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/pathview_package.qml
@@ -0,0 +1,88 @@
+import QtQuick 2.0
+
+Item {
+ width: 800; height: 600
+ Component {
+ id: photoDelegate
+ Package {
+ Item { id: pathItem; objectName: "pathItem"; Package.name: 'path'; width: 85; height: 85; scale: pathItem.PathView.scale }
+ Item { id: linearItem; Package.name: 'linear'; width: 85; height: 85 }
+ Rectangle {
+ id: wrapper
+ width: 85; height: 85; color: lColor
+
+ transform: Rotation {
+ id: itemRotation; origin.x: wrapper.width/2; origin.y: wrapper.height/2
+ axis.y: 1; axis.z: 0
+ }
+ state: 'path'
+ states: [
+ State {
+ name: 'path'
+ ParentChange { target: wrapper; parent: pathItem; x: 0; y: 0 }
+ PropertyChanges { target: wrapper; opacity: pathItem.PathView.onPath ? 1.0 : 0 }
+ }
+ ]
+ }
+ }
+ }
+ ListModel {
+ id: rssModel
+ ListElement { lColor: "red" }
+ ListElement { lColor: "green" }
+ ListElement { lColor: "yellow" }
+ ListElement { lColor: "blue" }
+ ListElement { lColor: "purple" }
+ ListElement { lColor: "gray" }
+ ListElement { lColor: "brown" }
+ ListElement { lColor: "thistle" }
+ }
+ VisualDataModel { id: visualModel; model: rssModel; delegate: photoDelegate }
+
+ PathView {
+ id: photoPathView
+ objectName: "photoPathView"
+ width: 800; height: 330; pathItemCount: 4; offset: 1
+ dragMargin: 24
+ preferredHighlightBegin: 0.50
+ preferredHighlightEnd: 0.50
+
+ path: Path {
+ startX: -50; startY: 40;
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: -45 }
+
+ PathCubic {
+ x: 400; y: 220
+ control1X: 140; control1Y: 40
+ control2X: 210; control2Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 1.2 }
+ PathAttribute { name: "angle"; value: 0 }
+
+ PathCubic {
+ x: 850; y: 40
+ control2X: 660; control2Y: 40
+ control1X: 590; control1Y: 220
+ }
+
+ PathAttribute { name: "scale"; value: 0.5 }
+ PathAttribute { name: "angle"; value: 45 }
+ }
+
+ model: visualModel.parts.path
+ }
+
+ PathView {
+ y: 400; width: 800; height: 330; pathItemCount: 8
+
+ path: Path {
+ startX: 0; startY: 40;
+ PathLine { x: 800; y: 40 }
+ }
+
+ model: visualModel.parts.linear
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/propertychanges.qml b/tests/auto/qtquick2/qquickpathview/data/propertychanges.qml
new file mode 100644
index 0000000000..09b309f86f
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/propertychanges.qml
@@ -0,0 +1,116 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 350; height: 220; color: "white"
+ Component {
+ id: myDelegate
+ Item {
+ id: wrapper
+ width: 180; height: 40;
+ opacity: PathView.opacity
+ Column {
+ x: 5; y: 5
+ Text { text: '<b>Name:</b> ' + name }
+ Text { text: '<b>Number:</b> ' + number }
+ }
+ }
+ }
+
+ PathView {
+ preferredHighlightBegin: 0.1
+ preferredHighlightEnd: 0.1
+ dragMargin: 5.0
+ id: pathView
+ objectName: "pathView"
+ anchors.fill: parent
+ model: listModel
+ delegate: myDelegate
+ focus: true
+ path: Path {
+ id: myPath
+ objectName: "path"
+ startX: 220; startY: 200
+ PathAttribute { name: "opacity"; value: 1.0; objectName: "pathAttribute"; }
+ PathQuad { x: 220; y: 25; controlX: 260; controlY: 75 }
+ PathAttribute { name: "opacity"; value: 0.3 }
+ PathQuad { x: 220; y: 200; controlX: -20; controlY: 75 }
+ }
+ Timer {
+ interval: 2000; running: true; repeat: true
+ onTriggered: {
+ if (pathView.path == alternatePath)
+ pathView.path = myPath;
+ else
+ pathView.path = alternatePath;
+ }
+ }
+ }
+
+ data:[
+ ListModel {
+ id: listModel
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ ListElement {
+ name: "Bill Smith"
+ number: "555 3264"
+ }
+ ListElement {
+ name: "John Brown"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Sam Wise"
+ number: "555 0473"
+ }
+ },
+ ListModel {
+ objectName: "alternateModel"
+ ListElement {
+ name: "Jack"
+ number: "555 8426"
+ }
+ ListElement {
+ name: "Mary"
+ number: "555 3264"
+ }
+ },
+ Path {
+ id: alternatePath
+ objectName: "alternatePath"
+ startX: 100; startY: 40
+ PathAttribute { name: "opacity"; value: 0.0 }
+ PathLine { x: 100; y: 160 }
+ PathAttribute { name: "opacity"; value: 0.2 }
+ PathLine { x: 300; y: 160 }
+ PathAttribute { name: "opacity"; value: 0.0 }
+ PathLine { x: 300; y: 40 }
+ PathAttribute { name: "opacity"; value: 0.2 }
+ PathLine { x: 100; y: 40 }
+ }
+ ]
+}
+
+
diff --git a/tests/auto/qtquick2/qquickpathview/data/treemodel.qml b/tests/auto/qtquick2/qquickpathview/data/treemodel.qml
new file mode 100644
index 0000000000..fcf6922d00
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/treemodel.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+PathView {
+ width: 320
+ height: 240
+ function setRoot(index) {
+ vdm.rootIndex = vdm.modelIndex(index);
+ }
+ model: VisualDataModel {
+ id: vdm
+ model: myModel
+ delegate: Text { objectName: "wrapper"; text: display }
+ }
+
+ path: Path {
+ startX: 0; startY: 120
+ PathLine { x: 320; y: 120 }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/undefinedpath.qml b/tests/auto/qtquick2/qquickpathview/data/undefinedpath.qml
new file mode 100644
index 0000000000..674e7cca8d
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/undefinedpath.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathView
+ width: 240; height: 200
+ path: Path {
+ startX: pathView.undef/2.0; startY: 0
+ PathLine { x: pathView.undef/2.0; y: 0 }
+ }
+
+ delegate: Text { text: value }
+ model: ListModel {
+ ListElement { value: "one" }
+ ListElement { value: "two" }
+ ListElement { value: "three" }
+ }
+}
diff --git a/tests/auto/qtquick2/qquickpathview/data/vdm.qml b/tests/auto/qtquick2/qquickpathview/data/vdm.qml
new file mode 100644
index 0000000000..839393d9bd
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/data/vdm.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+PathView {
+ id: pathView
+ width: 240; height: 320
+
+ pathItemCount: 4
+ preferredHighlightBegin : 0.5
+ preferredHighlightEnd : 0.5
+
+ path: Path {
+ startX: 120; startY: 20;
+ PathLine { x: 120; y: 300 }
+ }
+
+ ListModel {
+ id: mo
+ ListElement { value: "one" }
+ ListElement { value: "two" }
+ ListElement { value: "three" }
+ }
+
+ model: VisualDataModel {
+ delegate: Text { text: model.value }
+ model : mo
+ }
+}
+
diff --git a/tests/auto/qtquick2/qquickpathview/qquickpathview.pro b/tests/auto/qtquick2/qquickpathview/qquickpathview.pro
new file mode 100644
index 0000000000..6e16dd4879
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/qquickpathview.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_qquickpathview
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qquickpathview.cpp
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDataFiles
+
+CONFIG += parallel_test
+QT += core-private gui-private v8-private declarative-private quick-private widgets testlib
diff --git a/tests/auto/qtquick2/qquickpathview/tst_qquickpathview.cpp b/tests/auto/qtquick2/qquickpathview/tst_qquickpathview.cpp
new file mode 100644
index 0000000000..2f1d836c72
--- /dev/null
+++ b/tests/auto/qtquick2/qquickpathview/tst_qquickpathview.cpp
@@ -0,0 +1,1629 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtQuick/qquickview.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
+#include <QtQuick/private/qquickpathview_p.h>
+#include <QtQuick/private/qdeclarativepath_p.h>
+#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
+#include <QtDeclarative/private/qdeclarativelistmodel_p.h>
+#include <QtDeclarative/private/qdeclarativevaluetype_p.h>
+#include <QAbstractListModel>
+#include <QStringListModel>
+#include <QStandardItemModel>
+#include <QFile>
+
+#include "../../shared/util.h"
+
+static void initStandardTreeModel(QStandardItemModel *model)
+{
+ QStandardItem *item;
+ item = new QStandardItem(QLatin1String("Row 1 Item"));
+ model->insertRow(0, item);
+
+ item = new QStandardItem(QLatin1String("Row 2 Item"));
+ item->setCheckable(true);
+ model->insertRow(1, item);
+
+ QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item"));
+ item->setChild(0, childItem);
+
+ item = new QStandardItem(QLatin1String("Row 3 Item"));
+ item->setIcon(QIcon());
+ model->insertRow(2, item);
+}
+
+
+class tst_QQuickPathView : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QQuickPathView();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void initValues();
+ void items();
+ void dataModel();
+ void pathview2();
+ void pathview3();
+ void insertModel_data();
+ void insertModel();
+ void removeModel_data();
+ void removeModel();
+ void moveModel_data();
+ void moveModel();
+ void path();
+ void pathMoved();
+ void setCurrentIndex();
+ void resetModel();
+ void propertyChanges();
+ void pathChanges();
+ void componentChanges();
+ void modelChanges();
+ void pathUpdateOnStartChanged();
+ void package();
+ void emptyModel();
+ void closed();
+ void pathUpdate();
+ void visualDataModel();
+ void undefinedPath();
+ void mouseDrag();
+ void treeModel();
+ void changePreferredHighlight();
+ void missingPercent();
+ void creationContext();
+ void currentOffsetOnInsertion();
+ void asynchronous();
+
+private:
+ QQuickView *createView();
+ template<typename T>
+ T *findItem(QQuickItem *parent, const QString &objectName, int index=-1);
+ template<typename T>
+ QList<T*> findItems(QQuickItem *parent, const QString &objectName);
+};
+
+void tst_QQuickPathView::initTestCase()
+{
+}
+
+void tst_QQuickPathView::cleanupTestCase()
+{
+
+}
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool error READ error WRITE setError)
+ Q_PROPERTY(bool useModel READ useModel NOTIFY useModelChanged)
+ Q_PROPERTY(int pathItemCount READ pathItemCount NOTIFY pathItemCountChanged)
+
+public:
+ TestObject() : QObject(), mError(true), mUseModel(true), mPathItemCount(-1) {}
+
+ bool error() const { return mError; }
+ void setError(bool err) { mError = err; }
+
+ bool useModel() const { return mUseModel; }
+ void setUseModel(bool use) { mUseModel = use; emit useModelChanged(); }
+
+ int pathItemCount() const { return mPathItemCount; }
+ void setPathItemCount(int count) { mPathItemCount = count; emit pathItemCountChanged(); }
+
+signals:
+ void useModelChanged();
+ void pathItemCountChanged();
+
+private:
+ bool mError;
+ bool mUseModel;
+ int mPathItemCount;
+};
+
+class TestModel : public QAbstractListModel
+{
+public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ TestModel(QObject *parent=0) : QAbstractListModel(parent) {
+ QHash<int, QByteArray> roles;
+ roles[Name] = "name";
+ roles[Number] = "number";
+ setRoleNames(roles);
+ }
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const { Q_UNUSED(parent); return list.count(); }
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const {
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+ }
+
+ int count() const { return rowCount(); }
+ QString name(int index) const { return list.at(index).first; }
+ QString number(int index) const { return list.at(index).second; }
+
+ void addItem(const QString &name, const QString &number) {
+ beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ endInsertRows();
+ }
+
+ void insertItem(int index, const QString &name, const QString &number) {
+ beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ endInsertRows();
+ }
+
+ void insertItems(int index, const QList<QPair<QString, QString> > &items) {
+ beginInsertRows(QModelIndex(), index, index+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
+ endInsertRows();
+ }
+
+ void removeItem(int index) {
+ beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ endRemoveRows();
+ }
+
+ void removeItems(int index, int count) {
+ emit beginRemoveRows(QModelIndex(), index, index+count-1);
+ while (count--)
+ list.removeAt(index);
+ emit endRemoveRows();
+ }
+
+ void moveItem(int from, int to) {
+ beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ endMoveRows();
+ }
+
+ void moveItems(int from, int to, int count) {
+ beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
+ move(from, to, count);
+ endMoveRows();
+ }
+
+ void modifyItem(int idx, const QString &name, const QString &number) {
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+ }
+
+ void move(int from, int to, int n)
+ {
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ to = tto+n;
+ n = tfrom-tto;
+ }
+ if (n == 1) {
+ list.move(from, to);
+ } else {
+ QList<QPair<QString,QString> > replaced;
+ int i=0;
+ QList<QPair<QString,QString> >::ConstIterator it=list.begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=list.begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ QList<QPair<QString,QString> >::ConstIterator f=replaced.begin();
+ QList<QPair<QString,QString> >::Iterator t=list.begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+ }
+
+private:
+ QList<QPair<QString,QString> > list;
+};
+
+
+tst_QQuickPathView::tst_QQuickPathView()
+{
+}
+
+void tst_QQuickPathView::initValues()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview1.qml")));
+ QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() == 0);
+ QVERIFY(obj->delegate() == 0);
+ QCOMPARE(obj->model(), QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 0.);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.);
+ QCOMPARE(obj->dragMargin(), 0.);
+ QCOMPARE(obj->count(), 0);
+ QCOMPARE(obj->pathItemCount(), -1);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::items()
+{
+ QQuickView *canvas = createView();
+
+ TestModel model;
+ model.addItem("Fred", "12345");
+ model.addItem("John", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->count(), model.count());
+ QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+ QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
+
+ for (int i = 0; i < model.count(); ++i) {
+ QQuickText *name = findItem<QQuickText>(pathview, "textName", i);
+ QVERIFY(name != 0);
+ QCOMPARE(name->text(), model.name(i));
+ QQuickText *number = findItem<QQuickText>(pathview, "textNumber", i);
+ QVERIFY(number != 0);
+ QCOMPARE(number->text(), model.number(i));
+ }
+
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+
+ QVERIFY(pathview->highlightItem());
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;
+ offset.setX(pathview->highlightItem()->width()/2);
+ offset.setY(pathview->highlightItem()->height()/2);
+ QCOMPARE(pathview->highlightItem()->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::pathview2()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview2.qml")));
+ QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() != 0);
+ QVERIFY(obj->delegate() != 0);
+ QVERIFY(obj->model() != QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 0.);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.);
+ QCOMPARE(obj->dragMargin(), 0.);
+ QCOMPARE(obj->count(), 8);
+ QCOMPARE(obj->pathItemCount(), 10);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::pathview3()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathview3.qml")));
+ QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
+
+ QVERIFY(obj != 0);
+ QVERIFY(obj->path() != 0);
+ QVERIFY(obj->delegate() != 0);
+ QVERIFY(obj->model() != QVariant());
+ QCOMPARE(obj->currentIndex(), 0);
+ QCOMPARE(obj->offset(), 1.0);
+ QCOMPARE(obj->preferredHighlightBegin(), 0.5);
+ QCOMPARE(obj->dragMargin(), 24.);
+ QCOMPARE(obj->count(), 8);
+ QCOMPARE(obj->pathItemCount(), 4);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::insertModel_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("idx");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<qreal>("offset");
+
+ // We have 8 items, with currentIndex == 4
+ QTest::newRow("insert after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 5.;
+ QTest::newRow("insert before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
+ QTest::newRow("insert multiple after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 6.;
+ QTest::newRow("insert multiple before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
+ QTest::newRow("insert at end")
+ << int(QQuickPathView::StrictlyEnforceRange) << 8 << 1 << 5.;
+ QTest::newRow("insert at beginning")
+ << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
+ QTest::newRow("insert at current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 4.;
+
+ QTest::newRow("no range - insert after current")
+ << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 5.;
+ QTest::newRow("no range - insert before current")
+ << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
+ QTest::newRow("no range - insert multiple after current")
+ << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 6.;
+ QTest::newRow("no range - insert multiple before current")
+ << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
+ QTest::newRow("no range - insert at end")
+ << int(QQuickPathView::NoHighlightRange) << 8 << 1 << 5.;
+ QTest::newRow("no range - insert at beginning")
+ << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
+ QTest::newRow("no range - insert at current")
+ << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
+}
+
+void tst_QQuickPathView::insertModel()
+{
+ QFETCH(int, mode);
+ QFETCH(int, idx);
+ QFETCH(int, count);
+ QFETCH(qreal, offset);
+
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+ model.addItem("Jinny", "679");
+ model.addItem("Milly", "73378");
+ model.addItem("Jimmy", "3535");
+ model.addItem("Barb", "9039");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
+
+ pathview->setCurrentIndex(4);
+ if (mode == QQuickPathView::StrictlyEnforceRange)
+ QTRY_COMPARE(pathview->offset(), 4.0);
+ else
+ pathview->setOffset(4);
+
+ QList<QPair<QString, QString> > items;
+ for (int i = 0; i < count; ++i)
+ items.append(qMakePair(QString("New"), QString::number(i)));
+
+ model.insertItems(idx, items);
+ QTRY_COMPARE(pathview->offset(), offset);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::removeModel_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("idx");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<qreal>("offset");
+
+ // We have 8 items, with currentIndex == 4
+ QTest::newRow("remove after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 6 << 1 << 3.;
+ QTest::newRow("remove before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 2 << 1 << 4.;
+ QTest::newRow("remove multiple after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 5 << 2 << 2.;
+ QTest::newRow("remove multiple before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 1 << 2 << 4.;
+ QTest::newRow("remove last")
+ << int(QQuickPathView::StrictlyEnforceRange) << 7 << 1 << 3.;
+ QTest::newRow("remove first")
+ << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 4.;
+ QTest::newRow("remove current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 4 << 1 << 3.;
+
+ QTest::newRow("no range - remove after current")
+ << int(QQuickPathView::NoHighlightRange) << 6 << 1 << 3.;
+ QTest::newRow("no range - remove before current")
+ << int(QQuickPathView::NoHighlightRange) << 2 << 1 << 4.;
+ QTest::newRow("no range - remove multiple after current")
+ << int(QQuickPathView::NoHighlightRange) << 5 << 2 << 2.;
+ QTest::newRow("no range - remove multiple before current")
+ << int(QQuickPathView::NoHighlightRange) << 1 << 2 << 4.;
+ QTest::newRow("no range - remove last")
+ << int(QQuickPathView::NoHighlightRange) << 7 << 1 << 3.;
+ QTest::newRow("no range - remove first")
+ << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 4.;
+ QTest::newRow("no range - remove current offset")
+ << int(QQuickPathView::NoHighlightRange) << 4 << 1 << 4.;
+}
+
+void tst_QQuickPathView::removeModel()
+{
+ QFETCH(int, mode);
+ QFETCH(int, idx);
+ QFETCH(int, count);
+ QFETCH(qreal, offset);
+
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+ model.addItem("Jinny", "679");
+ model.addItem("Milly", "73378");
+ model.addItem("Jimmy", "3535");
+ model.addItem("Barb", "9039");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
+
+ pathview->setCurrentIndex(4);
+ if (mode == QQuickPathView::StrictlyEnforceRange)
+ QTRY_COMPARE(pathview->offset(), 4.0);
+ else
+ pathview->setOffset(4);
+
+ model.removeItems(idx, count);
+ QTRY_COMPARE(pathview->offset(), offset);
+
+ delete canvas;
+}
+
+
+void tst_QQuickPathView::moveModel_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("from");
+ QTest::addColumn<int>("to");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<qreal>("offset");
+
+ // We have 8 items, with currentIndex == 4
+ QTest::newRow("move after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 1 << 4.;
+ QTest::newRow("move before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 2 << 3 << 1 << 4.;
+ QTest::newRow("move before current to after")
+ << int(QQuickPathView::StrictlyEnforceRange) << 2 << 6 << 1 << 5.;
+ QTest::newRow("move multiple after current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 5 << 6 << 2 << 4.;
+ QTest::newRow("move multiple before current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 0 << 1 << 2 << 4.;
+ QTest::newRow("move before current to end")
+ << int(QQuickPathView::StrictlyEnforceRange) << 2 << 7 << 1 << 5.;
+ QTest::newRow("move last to beginning")
+ << int(QQuickPathView::StrictlyEnforceRange) << 7 << 0 << 1 << 3.;
+ QTest::newRow("move current")
+ << int(QQuickPathView::StrictlyEnforceRange) << 4 << 6 << 1 << 2.;
+
+ QTest::newRow("no range - move after current")
+ << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 1 << 4.;
+ QTest::newRow("no range - move before current")
+ << int(QQuickPathView::NoHighlightRange) << 2 << 3 << 1 << 4.;
+ QTest::newRow("no range - move before current to after")
+ << int(QQuickPathView::NoHighlightRange) << 2 << 6 << 1 << 5.;
+ QTest::newRow("no range - move multiple after current")
+ << int(QQuickPathView::NoHighlightRange) << 5 << 6 << 2 << 4.;
+ QTest::newRow("no range - move multiple before current")
+ << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 2 << 4.;
+ QTest::newRow("no range - move before current to end")
+ << int(QQuickPathView::NoHighlightRange) << 2 << 7 << 1 << 5.;
+ QTest::newRow("no range - move last to beginning")
+ << int(QQuickPathView::NoHighlightRange) << 7 << 0 << 1 << 3.;
+ QTest::newRow("no range - move current")
+ << int(QQuickPathView::NoHighlightRange) << 4 << 6 << 1 << 4.;
+ QTest::newRow("no range - move multiple incl. current")
+ << int(QQuickPathView::NoHighlightRange) << 0 << 1 << 5 << 4.;
+}
+
+void tst_QQuickPathView::moveModel()
+{
+ QFETCH(int, mode);
+ QFETCH(int, from);
+ QFETCH(int, to);
+ QFETCH(int, count);
+ QFETCH(qreal, offset);
+
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+ model.addItem("Jinny", "679");
+ model.addItem("Milly", "73378");
+ model.addItem("Jimmy", "3535");
+ model.addItem("Barb", "9039");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode);
+
+ pathview->setCurrentIndex(4);
+ if (mode == QQuickPathView::StrictlyEnforceRange)
+ QTRY_COMPARE(pathview->offset(), 4.0);
+ else
+ pathview->setOffset(4);
+
+ model.moveItems(from, to, count);
+ QTRY_COMPARE(pathview->offset(), offset);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::path()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("pathtest.qml")));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->startX(), 120.);
+ QCOMPARE(obj->startY(), 100.);
+ QVERIFY(obj->path() != QPainterPath());
+
+ QDeclarativeListReference list(obj, "pathElements");
+ QCOMPARE(list.count(), 5);
+
+ QDeclarativePathAttribute* attr = qobject_cast<QDeclarativePathAttribute*>(list.at(0));
+ QVERIFY(attr != 0);
+ QCOMPARE(attr->name(), QString("scale"));
+ QCOMPARE(attr->value(), 1.0);
+
+ QDeclarativePathQuad* quad = qobject_cast<QDeclarativePathQuad*>(list.at(1));
+ QVERIFY(quad != 0);
+ QCOMPARE(quad->x(), 120.);
+ QCOMPARE(quad->y(), 25.);
+ QCOMPARE(quad->controlX(), 260.);
+ QCOMPARE(quad->controlY(), 75.);
+
+ QDeclarativePathPercent* perc = qobject_cast<QDeclarativePathPercent*>(list.at(2));
+ QVERIFY(perc != 0);
+ QCOMPARE(perc->value(), 0.3);
+
+ QDeclarativePathLine* line = qobject_cast<QDeclarativePathLine*>(list.at(3));
+ QVERIFY(line != 0);
+ QCOMPARE(line->x(), 120.);
+ QCOMPARE(line->y(), 100.);
+
+ QDeclarativePathCubic* cubic = qobject_cast<QDeclarativePathCubic*>(list.at(4));
+ QVERIFY(cubic != 0);
+ QCOMPARE(cubic->x(), 180.);
+ QCOMPARE(cubic->y(), 0.);
+ QCOMPARE(cubic->control1X(), -10.);
+ QCOMPARE(cubic->control1Y(), 90.);
+ QCOMPARE(cubic->control2X(), 210.);
+ QCOMPARE(cubic->control2Y(), 90.);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::dataModel()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ TestObject *testObject = new TestObject;
+ ctxt->setContextProperty("testObject", testObject);
+
+ TestModel model;
+ model.addItem("red", "1");
+ model.addItem("green", "2");
+ model.addItem("blue", "3");
+ model.addItem("purple", "4");
+ model.addItem("gray", "5");
+ model.addItem("brown", "6");
+ model.addItem("yellow", "7");
+ model.addItem("thistle", "8");
+ model.addItem("cyan", "9");
+ model.addItem("peachpuff", "10");
+ model.addItem("powderblue", "11");
+ model.addItem("gold", "12");
+ model.addItem("sandybrown", "13");
+
+ ctxt->setContextProperty("testData", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("datamodel.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ QQuickItem *item = findItem<QQuickItem>(pathview, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), 110.0);
+ QCOMPARE(item->y(), 10.0);
+
+ model.insertItem(4, "orange", "10");
+ QTest::qWait(100);
+
+ QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 14);
+
+ QVERIFY(pathview->currentIndex() == 0);
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
+
+ QQuickText *text = findItem<QQuickText>(pathview, "myText", 4);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(4));
+
+ model.removeItem(2);
+ QCOMPARE(canvas->rootObject()->property("viewCount").toInt(), model.count());
+ text = findItem<QQuickText>(pathview, "myText", 2);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(2));
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
+
+ testObject->setPathItemCount(5);
+ QMetaObject::invokeMethod(canvas->rootObject(), "checkProperties");
+ QVERIFY(testObject->error() == false);
+
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+
+ QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4);
+ QVERIFY(testItem != 0);
+ testItem = findItem<QQuickRectangle>(pathview, "wrapper", 5);
+ QVERIFY(testItem == 0);
+
+ pathview->setCurrentIndex(1);
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
+ QTest::qWait(100);
+
+ model.insertItem(2, "pink", "2");
+ QTest::qWait(100);
+
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QVERIFY(pathview->currentIndex() == 1);
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
+
+ text = findItem<QQuickText>(pathview, "myText", 2);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(2));
+
+ model.removeItem(3);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ text = findItem<QQuickText>(pathview, "myText", 3);
+ QVERIFY(text);
+ QCOMPARE(text->text(), model.name(3));
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
+
+ model.moveItem(3, 5);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QList<QQuickItem*> items = findItems<QQuickItem>(pathview, "wrapper");
+ foreach (QQuickItem *item, items) {
+ QVERIFY(item->property("onPath").toBool());
+ }
+ QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
+
+ // QTBUG-14199
+ pathview->setOffset(7);
+ pathview->setOffset(0);
+ QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+
+ pathview->setCurrentIndex(model.count()-1);
+ model.removeItem(model.count()-1);
+ QCOMPARE(pathview->currentIndex(), model.count()-1);
+
+ delete canvas;
+ delete testObject;
+}
+
+void tst_QQuickPathView::pathMoved()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ pathview->setOffset(1.0);
+
+ for (int i=0; i<model.count(); i++) {
+ QQuickRectangle *curItem = findItem<QQuickRectangle>(pathview, "wrapper", i);
+ QPointF itemPos(path->pointAt(0.25 + i*0.25));
+ QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
+ }
+
+ pathview->setOffset(0.0);
+ QCOMPARE(firstItem->pos() + offset, start);
+
+ // Change delegate size
+ pathview->setOffset(0.1);
+ pathview->setOffset(0.0);
+ canvas->rootObject()->setProperty("delegateWidth", 30);
+ QCOMPARE(firstItem->width(), 30.0);
+ offset.setX(firstItem->width()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ // Change delegate scale
+ pathview->setOffset(0.1);
+ pathview->setOffset(0.0);
+ canvas->rootObject()->setProperty("delegateScale", 1.2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::setCurrentIndex()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ model.addItem("Ben", "12345");
+ model.addItem("Bohn", "2345");
+ model.addItem("Bob", "54321");
+ model.addItem("Bill", "4321");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview0.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QCOMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 0);
+ QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 0);
+
+ pathview->setCurrentIndex(2);
+
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(canvas->rootObject()->property("currentA").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("currentB").toInt(), 2);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 1);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 3);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->incrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ // move an item, set move duration to 0, and change currentIndex to moved item. QTBUG-22786
+ model.moveItem(0, 3);
+ pathview->setHighlightMoveDuration(0);
+ pathview->setCurrentIndex(3);
+ QCOMPARE(pathview->currentIndex(), 3);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
+ QVERIFY(firstItem);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ model.moveItem(3, 0);
+ pathview->setCurrentIndex(0);
+ pathview->setHighlightMoveDuration(300);
+
+ // Check the current item is still created when outside the bounds of pathItemCount.
+ pathview->setPathItemCount(2);
+ pathview->setHighlightRangeMode(QQuickPathView::NoHighlightRange);
+ QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 0));
+ QVERIFY(findItem<QQuickRectangle>(pathview, "wrapper", 1));
+ QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 2));
+ QVERIFY(!findItem<QQuickRectangle>(pathview, "wrapper", 3));
+
+ pathview->setCurrentIndex(2);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 2);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(false));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 1);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 1);
+ QVERIFY(firstItem);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ pathview->decrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 3);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 3);
+ QVERIFY(firstItem);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(false));
+
+ pathview->incrementCurrentIndex();
+ QTRY_COMPARE(pathview->currentIndex(), 0);
+ firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QCOMPARE(pathview->currentItem(), firstItem);
+ QCOMPARE(firstItem->property("onPath"), QVariant(true));
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::resetModel()
+{
+ QQuickView *canvas = createView();
+
+ QStringList strings;
+ strings << "one" << "two" << "three";
+ QStringListModel model(strings);
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("displaypath.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
+ QVERIFY(display != 0);
+ QCOMPARE(display->text(), strings.at(i));
+ }
+
+ strings.clear();
+ strings << "four" << "five" << "six" << "seven";
+ model.setStringList(strings);
+
+ QCOMPARE(pathview->count(), model.rowCount());
+
+ for (int i = 0; i < model.rowCount(); ++i) {
+ QQuickText *display = findItem<QQuickText>(pathview, "displayText", i);
+ QVERIFY(display != 0);
+ QCOMPARE(display->text(), strings.at(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::propertyChanges()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QSignalSpy snapPositionSpy(pathView, SIGNAL(preferredHighlightBeginChanged()));
+ QSignalSpy dragMarginSpy(pathView, SIGNAL(dragMarginChanged()));
+
+ QCOMPARE(pathView->preferredHighlightBegin(), 0.1);
+ QCOMPARE(pathView->dragMargin(), 5.0);
+
+ pathView->setPreferredHighlightBegin(0.4);
+ pathView->setPreferredHighlightEnd(0.4);
+ pathView->setDragMargin(20.0);
+
+ QCOMPARE(pathView->preferredHighlightBegin(), 0.4);
+ QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
+ QCOMPARE(pathView->dragMargin(), 20.0);
+
+ QCOMPARE(snapPositionSpy.count(), 1);
+ QCOMPARE(dragMarginSpy.count(), 1);
+
+ pathView->setPreferredHighlightBegin(0.4);
+ pathView->setPreferredHighlightEnd(0.4);
+ pathView->setDragMargin(20.0);
+
+ QCOMPARE(snapPositionSpy.count(), 1);
+ QCOMPARE(dragMarginSpy.count(), 1);
+ delete canvas;
+}
+
+void tst_QQuickPathView::pathChanges()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
+ QVERIFY(path);
+
+ QSignalSpy startXSpy(path, SIGNAL(startXChanged()));
+ QSignalSpy startYSpy(path, SIGNAL(startYChanged()));
+
+ QCOMPARE(path->startX(), 220.0);
+ QCOMPARE(path->startY(), 200.0);
+
+ path->setStartX(240.0);
+ path->setStartY(220.0);
+
+ QCOMPARE(path->startX(), 240.0);
+ QCOMPARE(path->startY(), 220.0);
+
+ QCOMPARE(startXSpy.count(),1);
+ QCOMPARE(startYSpy.count(),1);
+
+ path->setStartX(240);
+ path->setStartY(220);
+
+ QCOMPARE(startXSpy.count(),1);
+ QCOMPARE(startYSpy.count(),1);
+
+ QDeclarativePath *alternatePath = canvas->rootObject()->findChild<QDeclarativePath*>("alternatePath");
+ QVERIFY(alternatePath);
+
+ QSignalSpy pathSpy(pathView, SIGNAL(pathChanged()));
+
+ QCOMPARE(pathView->path(), path);
+
+ pathView->setPath(alternatePath);
+ QCOMPARE(pathView->path(), alternatePath);
+ QCOMPARE(pathSpy.count(),1);
+
+ pathView->setPath(alternatePath);
+ QCOMPARE(pathSpy.count(),1);
+
+ QDeclarativePathAttribute *pathAttribute = canvas->rootObject()->findChild<QDeclarativePathAttribute*>("pathAttribute");
+ QVERIFY(pathAttribute);
+
+ QSignalSpy nameSpy(pathAttribute, SIGNAL(nameChanged()));
+ QCOMPARE(pathAttribute->name(), QString("opacity"));
+
+ pathAttribute->setName("scale");
+ QCOMPARE(pathAttribute->name(), QString("scale"));
+ QCOMPARE(nameSpy.count(),1);
+
+ pathAttribute->setName("scale");
+ QCOMPARE(nameSpy.count(),1);
+ delete canvas;
+}
+
+void tst_QQuickPathView::componentChanges()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativeComponent delegateComponent(canvas->engine());
+ delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }", QUrl::fromLocalFile(""));
+
+ QSignalSpy delegateSpy(pathView, SIGNAL(delegateChanged()));
+
+ pathView->setDelegate(&delegateComponent);
+ QCOMPARE(pathView->delegate(), &delegateComponent);
+ QCOMPARE(delegateSpy.count(),1);
+
+ pathView->setDelegate(&delegateComponent);
+ QCOMPARE(delegateSpy.count(),1);
+ delete canvas;
+}
+
+void tst_QQuickPathView::modelChanges()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild<QDeclarativeListModel*>("alternateModel");
+ QVERIFY(alternateModel);
+ QVariant modelVariant = QVariant::fromValue<QObject *>(alternateModel);
+ QSignalSpy modelSpy(pathView, SIGNAL(modelChanged()));
+
+ pathView->setModel(modelVariant);
+ QCOMPARE(pathView->model(), modelVariant);
+ QCOMPARE(modelSpy.count(),1);
+
+ pathView->setModel(modelVariant);
+ QCOMPARE(modelSpy.count(),1);
+
+ pathView->setModel(QVariant());
+ QCOMPARE(modelSpy.count(),2);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::pathUpdateOnStartChanged()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathUpdateOnStartChanged.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QDeclarativePath *path = canvas->rootObject()->findChild<QDeclarativePath*>("path");
+ QVERIFY(path);
+ QCOMPARE(path->startX(), 400.0);
+ QCOMPARE(path->startY(), 300.0);
+
+ QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), path->startX() - item->width() / 2.0);
+ QCOMPARE(item->y(), path->startY() - item->height() / 2.0);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::package()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathview_package.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("photoPathView");
+ QVERIFY(pathView);
+
+ QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem");
+ QVERIFY(item);
+ QVERIFY(item->scale() != 1.0);
+
+ delete canvas;
+}
+
+//QTBUG-13017
+void tst_QQuickPathView::emptyModel()
+{
+ QQuickView *canvas = createView();
+
+ QStringListModel model;
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("emptyModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("emptymodel.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ QCOMPARE(pathview->offset(), qreal(0.0));
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::closed()
+{
+ QDeclarativeEngine engine;
+
+ {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("openPath.qml")));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->isClosed(), false);
+ delete obj;
+ }
+
+ {
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("closedPath.qml")));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->isClosed(), true);
+ delete obj;
+ }
+}
+
+// QTBUG-14239
+void tst_QQuickPathView::pathUpdate()
+{
+ QQuickView *canvas = createView();
+ QVERIFY(canvas);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathUpdate.qml")));
+
+ QQuickPathView *pathView = canvas->rootObject()->findChild<QQuickPathView*>("pathView");
+ QVERIFY(pathView);
+
+ QQuickItem *item = findItem<QQuickItem>(pathView, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->x(), 150.0);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::visualDataModel()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("vdm.qml")));
+
+ QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->count(), 3);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::undefinedPath()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("undefinedpath.qml")));
+
+ QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->count(), 3);
+
+ delete obj;
+}
+
+void tst_QQuickPathView::mouseDrag()
+{
+ QQuickView *canvas = createView();
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("dragpath.qml")));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(canvas, qGuiApp->focusWindow());
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ int current = pathview->currentIndex();
+
+ QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10,100));
+ QTest::qWait(100);
+
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(30,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+ {
+ QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QApplication::sendEvent(canvas, &mv);
+ }
+
+ QVERIFY(pathview->currentIndex() != current);
+
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(40,100));
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::treeModel()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ QStandardItemModel model;
+ initStandardTreeModel(&model);
+ canvas->engine()->rootContext()->setContextProperty("myModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("treemodel.qml")));
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+ QCOMPARE(pathview->count(), 3);
+
+ QQuickText *item = findItem<QQuickText>(pathview, "wrapper", 0);
+ QVERIFY(item);
+ QCOMPARE(item->text(), QLatin1String("Row 1 Item"));
+
+ QVERIFY(QMetaObject::invokeMethod(pathview, "setRoot", Q_ARG(QVariant, 1)));
+ QCOMPARE(pathview->count(), 1);
+
+ QTRY_VERIFY(item = findItem<QQuickText>(pathview, "wrapper", 0));
+ QTRY_COMPARE(item->text(), QLatin1String("Row 2 Child Item"));
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::changePreferredHighlight()
+{
+ QQuickView *canvas = createView();
+ canvas->setGeometry(0,0,400,200);
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("dragpath.qml")));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_COMPARE(canvas, qGuiApp->focusWindow());
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(canvas->rootObject());
+ QVERIFY(pathview != 0);
+
+ int current = pathview->currentIndex();
+ QCOMPARE(current, 0);
+
+ QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.5);
+ start.setX(qRound(start.x()));
+ start.setY(qRound(start.y()));
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+
+ pathview->setPreferredHighlightBegin(0.8);
+ pathview->setPreferredHighlightEnd(0.8);
+ start = path->pointAt(0.8);
+ start.setX(qRound(start.x()));
+ start.setY(qRound(start.y()));
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ QCOMPARE(pathview->currentIndex(), 0);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::creationContext()
+{
+ QQuickView canvas;
+ canvas.setGeometry(0,0,240,320);
+ canvas.setSource(QUrl::fromLocalFile(TESTDATA("creationContext.qml")));
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem *>(canvas.rootObject());
+ QVERIFY(rootItem);
+ QVERIFY(rootItem->property("count").toInt() > 0);
+
+ QQuickItem *item;
+ QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem", 0));
+ QCOMPARE(item->property("text").toString(), QString("Hello!"));
+}
+
+// QTBUG-21320
+void tst_QQuickPathView::currentOffsetOnInsertion()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathline.qml")));
+ qApp->processEvents();
+
+ QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view");
+ QVERIFY(pathview != 0);
+
+ pathview->setPreferredHighlightBegin(0.5);
+ pathview->setPreferredHighlightEnd(0.5);
+
+ QCOMPARE(pathview->count(), model.count());
+
+ model.addItem("item0", "0");
+
+ QCOMPARE(pathview->count(), model.count());
+
+ QQuickRectangle *item = 0;
+ QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0));
+
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+
+ QPointF start = path->pointAt(0.5);
+ start = QPointF(qRound(start.x()), qRound(start.y()));
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(item->width()/2);
+ offset.setY(item->height()/2);
+ QCOMPARE(item->pos() + offset, start);
+
+ QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged()));
+
+ // insert an item at the beginning
+ model.insertItem(0, "item1", "1");
+ qApp->processEvents();
+
+ QCOMPARE(currentIndexSpy.count(), 1);
+
+ // currentIndex is now 1
+ QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
+
+ // verify that current item (item 1) is still at offset 0.5
+ QCOMPARE(item->pos() + offset, start);
+
+ // insert another item at the beginning
+ model.insertItem(0, "item2", "2");
+ qApp->processEvents();
+
+ QCOMPARE(currentIndexSpy.count(), 2);
+
+ // currentIndex is now 2
+ QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 2));
+
+ // verify that current item (item 2) is still at offset 0.5
+ QCOMPARE(item->pos() + offset, start);
+
+ // verify that remove before current maintains current item
+ model.removeItem(0);
+ qApp->processEvents();
+
+ QCOMPARE(currentIndexSpy.count(), 3);
+
+ // currentIndex is now 1
+ QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1));
+
+ // verify that current item (item 1) is still at offset 0.5
+ QCOMPARE(item->pos() + offset, start);
+
+ delete canvas;
+}
+
+void tst_QQuickPathView::asynchronous()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->setSource(TESTDATA("asyncloader.qml"));
+
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
+ QVERIFY(rootObject);
+
+ QQuickPathView *pathview = 0;
+ while (!pathview) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ pathview = rootObject->findChild<QQuickPathView*>("view");
+ }
+
+ // items will be created one at a time
+ for (int i = 0; i < 5; ++i) {
+ QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(pathview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ // verify positioning
+ QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ pathview->setOffset(1.0);
+
+ for (int i=0; i<5; i++) {
+ QQuickItem *curItem = findItem<QQuickItem>(pathview, "wrapper", i);
+ QPointF itemPos(path->pointAt(0.2 + i*0.2));
+ QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
+ }
+
+ delete canvas;
+}
+
+QQuickView *tst_QQuickPathView::createView()
+{
+ QQuickView *canvas = new QQuickView(0);
+ canvas->setGeometry(0,0,240,320);
+
+ return canvas;
+}
+
+/*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+ */
+template<typename T>
+T *tst_QQuickPathView::findItem(QQuickItem *parent, const QString &objectName, int index)
+{
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->childItems().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QDeclarativeExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+}
+
+template<typename T>
+QList<T*> tst_QQuickPathView::findItems(QQuickItem *parent, const QString &objectName)
+{
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ //qDebug() << parent->QQuickItem::children().count() << "children";
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ //qDebug() << "try" << item;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ items.append(static_cast<T*>(item));
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+}
+
+void tst_QQuickPathView::missingPercent()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("missingPercent.qml")));
+ QDeclarativePath *obj = qobject_cast<QDeclarativePath*>(c.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->attributeAt("_qfx_percent", 1.0), qreal(1.0));
+ delete obj;
+}
+
+
+QTEST_MAIN(tst_QQuickPathView)
+
+#include "tst_qquickpathview.moc"