Revision control

Copy as Markdown

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import QtTest
import Qt.test.controls
TestCase {
id: testCase
width: 400
height: 400
visible: true
when: windowShown
name: "SplitView"
function initTestCase() {
// For the serialization tests.
Qt.application.name = "qtquickcontrols-splitview-auto-test"
Qt.application.domain = "org.qt-project"
Qt.application.organization = "QtProject"
}
function findHandles(splitView) {
let handles = []
for (let i = 0; i < splitView.children.length; ++i) {
let child = splitView.children[i]
if (child.objectName.toLowerCase().indexOf("handle") !== -1)
handles.push(child)
}
return handles
}
function compareSizes(control, expectedGeometries, context) {
if (context === undefined)
context = ""
else
context = " (" + context + ")"
compare(control.count, Math.floor(expectedGeometries.length / 2) + 1,
"Mismatch in actual vs expected number of split items" + context)
let handles = findHandles(control)
compare(handles.length, Math.floor(expectedGeometries.length / 2),
"Mismatch in actual vs expected number of handle items" + context)
for (let i = 0, splitItemIndex = 0, handleItemIndex = 0; i < expectedGeometries.length; ++i) {
let item = null
let itemType = ""
let typeSpecificIndex = -1
if (i % 2 == 0) {
item = control.itemAt(splitItemIndex)
itemType = "split item"
typeSpecificIndex = splitItemIndex
++splitItemIndex
} else {
item = handles[handleItemIndex]
itemType = "handle item"
typeSpecificIndex = handleItemIndex
++handleItemIndex
}
verify(item, itemType + " at index " + typeSpecificIndex + " should not be null" + context)
let expectedGeometry = expectedGeometries[i]
if (expectedGeometry.hasOwnProperty("hidden")) {
// It's geometry doesn't matter because it's hidden.
verify(!item.visible, itemType + " at index " + typeSpecificIndex + " should be hidden" + context)
continue
}
// Note that the indices mentioned here account for handles; they do not
// match the indices reported by QQuickSplitView's logging categories.
compare(item.x, expectedGeometry.x, "Mismatch in actual vs expected x value of "
+ itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.y, expectedGeometry.y, "Mismatch in actual vs expected y value of "
+ itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.width, expectedGeometry.width, "Mismatch in actual vs expected width value of "
+ itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.height, expectedGeometry.height, "Mismatch in actual vs expected height value of "
+ itemType + " " + item + " at index " + typeSpecificIndex + context)
}
}
property real defaultHorizontalHandleWidth: 10
property real defaultVerticalHandleHeight: 10
Component {
id: signalSpyComponent
SignalSpy {}
}
Component {
id: handleComponent
Rectangle {
objectName: `handle ${x},${y} ${width}x${height} visible: ${visible}`
implicitWidth: defaultHorizontalHandleWidth
implicitHeight: defaultVerticalHandleHeight
color: "#444"
Text {
objectName: text + "_Text"
text: parent.objectName
color: "white"
anchors.centerIn: parent
rotation: 90
}
}
}
Component {
id: defaultSplitView
SplitView {}
}
Component {
id: splitViewComponent
SplitView {
anchors.fill: parent
handle: handleComponent
}
}
Component {
id: rectangleComponent
Rectangle {}
}
function init() {
failOnWarning(/.?/)
}
function test_defaults() {
let control = createTemporaryObject(defaultSplitView, testCase)
verify(control)
}
function test_addItemsAfterCompletion() {
let control = createTemporaryObject(splitViewComponent, testCase)
verify(control)
let item0 = rectangleComponent.createObject(control, { implicitWidth: 25, color: "salmon" })
verify(item0)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
// The last item fills the width by default, and since there is only one item...
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, testCase.width)
compare(item0.height, testCase.height)
let item1 = rectangleComponent.createObject(control, { implicitWidth: 25, color: "steelblue" })
verify(item1)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
// Now that a second item has been added, the first item goes back to its preferred (implicit) width.
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, item0.implicitWidth)
compare(item0.height, testCase.height)
let handles = findHandles(control)
let handle0 = handles[0]
compare(handle0.x, item0.implicitWidth)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, item0.implicitWidth + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, testCase.width - item0.implicitWidth - defaultHorizontalHandleWidth)
compare(item1.height, testCase.height)
}
function test_addItemsWithNoSizeAfterCompletion() {
let control = createTemporaryObject(splitViewComponent, testCase)
verify(control)
let item0 = rectangleComponent.createObject(control, { color: "salmon" })
verify(item0)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, testCase.width)
compare(item0.height, testCase.height)
let item1 = rectangleComponent.createObject(control, { color: "steelblue" })
verify(item1)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 0)
compare(item0.height, testCase.height)
let handles = findHandles(control)
let handle0 = handles[0]
compare(handle0.x, 0)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, testCase.width - defaultHorizontalHandleWidth)
compare(item1.height, testCase.height)
}
Component {
id: threeZeroSizedItemsComponent
SplitView {
anchors.fill: parent
handle: handleComponent
Rectangle {
objectName: "salmon"
color: objectName
}
Rectangle {
objectName: "navajowhite"
color: objectName
}
Rectangle {
objectName: "steelblue"
color: objectName
}
}
}
function test_changeAttachedPropertiesAfterCompletion() {
let control = createTemporaryObject(threeZeroSizedItemsComponent, testCase)
verify(control)
let item0 = control.itemAt(0)
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 0)
compare(item0.height, testCase.height)
let handles = findHandles(control)
let handle0 = handles[0]
compare(handle0.x, 0)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
let item1 = control.itemAt(1)
compare(item1.x, defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, 0)
compare(item1.height, testCase.height)
let handle1 = handles[1]
compare(handle1.x, defaultHorizontalHandleWidth)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
let item2 = control.itemAt(2)
compare(item2.x, defaultHorizontalHandleWidth * 2)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
item0.SplitView.preferredWidth = 25
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 25)
compare(item0.height, testCase.height)
compare(handle0.x, item0.width)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, 25 + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, 0)
compare(item1.height, testCase.height)
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
compare(item2.x, item1.x + item1.width + defaultHorizontalHandleWidth)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
item0.SplitView.minimumWidth = 50
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 50)
compare(item0.height, testCase.height)
compare(handle0.x, item0.width)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, 50 + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, 0)
compare(item1.height, testCase.height)
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
compare(item2.x, item1.x + item1.width + defaultHorizontalHandleWidth)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
item0.SplitView.preferredWidth = 100
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 100)
compare(item0.height, testCase.height)
compare(handle0.x, item0.width)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, 100 + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, 0)
compare(item1.height, testCase.height)
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
compare(item2.x, item1.x + item1.width + defaultHorizontalHandleWidth)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
item0.SplitView.maximumWidth = 75
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 75)
compare(item0.height, testCase.height)
compare(handle0.x, item0.width)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, 75 + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, 0)
compare(item1.height, testCase.height)
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
compare(item2.x, item1.x + item1.width + defaultHorizontalHandleWidth)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
item1.SplitView.fillWidth = true
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, 75)
compare(item0.height, testCase.height)
compare(handle0.x, item0.width)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
compare(item1.x, 75 + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, testCase.width - 75 - defaultHorizontalHandleWidth * 2)
compare(item1.height, testCase.height)
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
compare(item2.x, testCase.width)
compare(item2.y, 0)
compare(item2.width, 0)
compare(item2.height, testCase.height)
}
Component {
id: itemComponent
Item {}
}
Component {
id: objectComponent
QtObject {}
}
function test_useAttachedPropertiesIncorrectly_data() {
let properties = [ "fillWidth", "fillHeight", "minimumWidth", "minimumHeight",
"preferredWidth", "preferredHeight", "maximumWidth", "maximumHeight" ]
let data = []
for (let i = 0; i < properties.length; ++i) {
let property = properties[i]
data.push({ tag: "Item," + property, component: itemComponent, property: property,
expectedWarning: /.*SplitView: attached properties must be accessed through a direct child of SplitView/ })
}
for (let i = 0; i < properties.length; ++i) {
let property = properties[i]
data.push({ tag: "QtObject," + property, component: objectComponent, property: property,
expectedWarning: /.*SplitView: attached properties can only be used on Items/ })
}
return data
}
function test_useAttachedPropertiesIncorrectly(data) {
// The object (whatever it may be) is not managed by a SplitView.
let object = createTemporaryObject(data.component, testCase, { objectName: data.tag })
verify(object)
ignoreWarning(data.expectedWarning)
// Should warn, but not crash.
object.SplitView[data.property] = 1;
}
function test_sizes_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
// When the combined size of items is too large, make them fit.
tag: "fillItemOnLeft",
expectedGeometries: [
// We're the fill item, but since the combined implicitWidths
// of the other two items take up all the space, we get none.
{ x: 0, y: 0, width: 0, height: splitViewHeight },
// First handle.
{ x: 0, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item does not fill, so its width should be unchanged.
{ x: defaultHorizontalHandleWidth, y: 0, width: 200, height: splitViewHeight },
// Second handle.
{ x: 200 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
// The third item is reduced from its implicitWidth to fit into SplitView.
{ x: 200 + defaultHorizontalHandleWidth * 2, y: 0, width: 200 - 2 * defaultHorizontalHandleWidth, height: splitViewHeight }
]
},
{
// Same as above except vertical.
tag: "fillItemOnTop",
expectedGeometries: [
// We're the fill item, but since the combined implicitHeights
// of the other two items take up all the space, we get none.
{ x: 0, y: 0, width: splitViewWidth, height: 0 },
// First handle.
{ x: 0, y: 0, width: splitViewWidth, height: defaultVerticalHandleHeight },
// The second item does not fill, so its height should be unchanged.
{ x: 0, y: defaultVerticalHandleHeight, width: splitViewWidth, height: 200 },
// Second handle.
{ x: 0, y: 200 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
// The third item is reduced from its implicitWidth to fit into SplitView.
{ x: 0, y: 200 + defaultVerticalHandleHeight * 2, width: splitViewWidth, height: 200 - 2 * defaultVerticalHandleHeight }
]
},
{
tag: "fillItemInMiddle",
expectedGeometries: [
// Our size is fixed.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
// First handle.
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item fills.
{ x: 25 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 25 - 200 - defaultHorizontalHandleWidth * 2, height: splitViewHeight },
// Second handle.
{ x: splitViewWidth - 200 - defaultHorizontalHandleWidth, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The third item's size is also fixed.
{ x: splitViewWidth - 200, y: 0, width: 200, height: splitViewHeight }
]
}
]
return data
}
function test_sizes(data) {
let component = Qt.createComponent("splitview/" + data.tag + ".qml")
compare(component.status, Component.Ready, component.errorString());
let control = createTemporaryObject(component, testCase, { "handle": handleComponent })
verify(control)
compareSizes(control, data.expectedGeometries)
}
Component {
id: threeSizedItemsComponent
SplitView {
anchors.fill: parent
handle: handleComponent
Rectangle {
objectName: "salmon"
color: objectName
implicitWidth: 25
implicitHeight: 25
}
Rectangle {
objectName: "navajowhite"
color: objectName
implicitWidth: 100
implicitHeight: 100
}
Rectangle {
objectName: "steelblue"
color: objectName
implicitWidth: 200
implicitHeight: 200
}
}
}
function test_resetAttachedProperties_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "resetMinimumWidth",
orientation: Qt.Horizontal,
// Set the minimumWidth to 50. It should be used instead of implicitWidth since it's greater than 25.
splitItemIndex: 0,
propertyName: "minimumWidth",
propertyValue: 50,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: 50, height: splitViewHeight },
{ x: 50, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 50 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 50 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
// minimumWidth is now undefined, so implicitWidth should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
]
},
{
tag: "resetMinimumHeight",
orientation: Qt.Vertical,
// Set the minimumHeight to 50. It should be used instead of implicitHeight since it's greater than 25.
splitItemIndex: 0,
propertyName: "minimumHeight",
propertyValue: 50,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: splitViewWidth, height: 50 },
{ x: 0, y: 50, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 50 - 100 - defaultVerticalHandleHeight * 2 }
],
// preferredHeight is now undefined, so implicitHeight should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 25 - 100 - defaultVerticalHandleHeight * 2 }
]
},
{
tag: "resetPreferredWidth",
orientation: Qt.Horizontal,
// Set the preferredWidth to 50; it should be used instead of implicitWidth.
splitItemIndex: 0,
propertyName: "preferredWidth",
propertyValue: 50,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: 50, height: splitViewHeight },
{ x: 50, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 50 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 50 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
// preferredWidth is now undefined, so implicitWidth should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
]
},
{
tag: "resetPreferredHeight",
orientation: Qt.Vertical,
// Set the preferredHeight to 50; it should be used instead of implicitHeight.
splitItemIndex: 0,
propertyName: "preferredHeight",
propertyValue: 50,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: splitViewWidth, height: 50 },
{ x: 0, y: 50, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 50 - 100 - defaultVerticalHandleHeight * 2 }
],
// preferredHeight is now undefined, so implicitHeight should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 25 - 100 - defaultVerticalHandleHeight * 2 }
]
},
{
tag: "resetMaximumWidth",
orientation: Qt.Horizontal,
// Set the maximumWidth to 15. It should be used instead of implicitWidth since it's less than 25.
splitItemIndex: 0,
propertyName: "maximumWidth",
propertyValue: 15,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: 15, height: splitViewHeight },
{ x: 15, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 15 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 15 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 15 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 15 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
// maximumWidth is now undefined, so implicitWidth should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
]
},
{
tag: "resetMaximumHeight",
orientation: Qt.Vertical,
// Set the preferredHeight to 15. It should be used instead of implicitHeight if it's not undefined.
splitItemIndex: 0,
propertyName: "maximumHeight",
propertyValue: 15,
expectedGeometriesBefore: [
{ x: 0, y: 0, width: splitViewWidth, height: 15 },
{ x: 0, y: 15, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 15 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 15 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 15 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 15 - 100 - defaultVerticalHandleHeight * 2 }
],
// preferredHeight is now undefined, so implicitHeight should be used instead.
expectedGeometriesAfter: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth,
height: splitViewHeight - 25 - 100 - defaultVerticalHandleHeight * 2 }
]
},
]
return data;
}
function test_resetAttachedProperties(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
let splitItem = control.itemAt(data.splitItemIndex)
splitItem.SplitView[data.propertyName] = data.propertyValue
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesBefore, "after setting attached property")
splitItem.SplitView[data.propertyName] = undefined
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesAfter, "after resetting attached property")
}
function test_orientation() {
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
let item0 = control.itemAt(0)
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, item0.implicitWidth)
compare(item0.height, testCase.height)
let handles = findHandles(control)
let handle0 = handles[0]
compare(handle0.x, item0.implicitWidth)
compare(handle0.y, 0)
compare(handle0.width, defaultHorizontalHandleWidth)
compare(handle0.height, testCase.height)
let item1 = control.itemAt(1)
compare(item1.x, item0.width + defaultHorizontalHandleWidth)
compare(item1.y, 0)
compare(item1.width, item1.implicitWidth)
compare(item1.height, testCase.height)
let handle1 = handles[1]
compare(handle1.x, item1.x + item1.width)
compare(handle1.y, 0)
compare(handle1.width, defaultHorizontalHandleWidth)
compare(handle1.height, testCase.height)
let item2 = control.itemAt(2)
compare(item2.x, item0.width + item1.width + defaultHorizontalHandleWidth * 2)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
control.orientation = Qt.Vertical
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, testCase.width)
compare(item0.height, item0.implicitHeight)
handles = findHandles(control)
handle0 = handles[0]
compare(handle0.x, 0)
compare(handle0.y, item0.implicitHeight)
compare(handle0.width, testCase.width)
compare(handle0.height, defaultVerticalHandleHeight)
compare(item1.x, 0)
compare(item1.y, item0.height + defaultVerticalHandleHeight)
compare(item1.width, testCase.width)
compare(item1.height, item1.implicitHeight)
handle1 = handles[1]
compare(handle1.x, 0)
compare(handle1.y, item1.y + item1.height)
compare(handle1.width, testCase.width)
compare(handle1.height, defaultVerticalHandleHeight)
compare(item2.x, 0)
compare(item2.y, item0.height + item1.height + defaultVerticalHandleHeight * 2)
compare(item2.width, testCase.width)
compare(item2.height, testCase.height - item2.y)
}
Component {
id: threeSizedItemsComponentWithDefaultHandle
SplitView {
anchors.fill: parent
Rectangle {
objectName: "salmon"
color: objectName
implicitWidth: 25
implicitHeight: 25
}
Rectangle {
objectName: "navajowhite"
color: objectName
implicitWidth: 100
implicitHeight: 100
}
Rectangle {
objectName: "steelblue"
color: objectName
implicitWidth: 200
implicitHeight: 200
}
}
}
function test_orientationWithDefaultHandle() {
const control = createTemporaryObject(threeSizedItemsComponentWithDefaultHandle, testCase)
verify(control)
const item0 = control.itemAt(0)
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, item0.implicitWidth)
compare(item0.height, testCase.height)
const item1 = control.itemAt(1)
let handleDefaultWidth = item1.x - item0.width // Find default handle width
compare(item1.x, item0.width + handleDefaultWidth)
compare(item1.y, 0)
compare(item1.width, item1.implicitWidth)
compare(item1.height, testCase.height)
const item2 = control.itemAt(2)
compare(item2.x, item0.width + item1.width + handleDefaultWidth * 2)
compare(item2.y, 0)
compare(item2.width, testCase.width - item2.x)
compare(item2.height, testCase.height)
control.orientation = Qt.Vertical
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(item0.x, 0)
compare(item0.y, 0)
compare(item0.width, testCase.width)
compare(item0.height, item0.implicitHeight)
compare(item1.x, 0)
compare(item1.y, item0.height + handleDefaultWidth)
compare(item1.width, testCase.width)
compare(item1.height, item1.implicitHeight)
compare(item2.x, 0)
compare(item2.y, item0.height + item1.height + handleDefaultWidth * 2)
compare(item2.width, testCase.width)
compare(item2.height, testCase.height - item2.y)
}
readonly property int splitViewMargins: 50
Component {
id: threeItemsMinSizeAndFillComponent
SplitView {
anchors.fill: parent
handle: handleComponent
Rectangle {
objectName: "salmon"
color: objectName
implicitWidth: 25
implicitHeight: 25
SplitView.minimumWidth: 25
SplitView.minimumHeight: 25
SplitView.fillWidth: true
SplitView.fillHeight: true
}
Rectangle {
objectName: "navajowhite"
color: objectName
implicitWidth: 100
implicitHeight: 100
}
Rectangle {
objectName: "steelblue"
color: objectName
implicitWidth: 200
implicitHeight: 200
}
}
}
Component {
id: repeaterSplitViewComponent
SplitView {
anchors.fill: parent
handle: handleComponent
property alias repeater: repeater
Repeater {
id: repeater
model: 3
delegate: Rectangle {
objectName: "rectDelegate" + index
SplitView.preferredWidth: 25
color: "#aaff0000"
Text {
text: parent.x + "," + parent.y + " " + parent.width + "x" + parent.height
color: "white"
rotation: 90
anchors.centerIn: parent
}
}
}
}
}
Component {
id: hiddenItemSplitViewComponent
SplitView {
anchors.fill: parent
handle: handleComponent
Rectangle {
objectName: "steelblue"
color: objectName
SplitView.minimumWidth: 50
}
Rectangle {
objectName: "tomato"
color: objectName
SplitView.fillWidth: true
SplitView.preferredWidth: 200
}
Rectangle {
objectName: "navajowhite"
color: objectName
visible: false
SplitView.minimumWidth: visible ? 100 : 0
}
Rectangle {
objectName: "mediumseagreen"
color: objectName
SplitView.minimumWidth: 50
}
}
}
function test_dragHandle_data() {
let splitViewWidth = testCase.width - splitViewMargins * 2
let splitViewHeight = testCase.height - splitViewMargins * 2
let data = [
{
tag: "fillThirdItemAndDragFirstHandlePastRightSide",
component: threeSizedItemsComponent,
orientation: Qt.Horizontal,
// The index of the item that will fill.
fillIndex: 2,
// The index of the handle to be dragged.
handleIndex: 0,
// The position where the center of the handle will be.
newHandlePos: Qt.point(testCase.width + 20, testCase.height / 2),
// The expected geometry of each item managed by the SplitView before dragging the handle.
expectedGeometriesBeforeDrag: [
// First item.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
// First handle.
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Second item.
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
// Second handle.
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Third item (fills).
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
// The expected geometry of each item managed by the SplitView after dragging the handle.
expectedGeometriesAfterDrag: [
// The fill item is to the right of the handle at index 0, so the handle belongs
// to the left item: us. We should consume all of the fill item's width.
{ x: 0, y: 0, width: splitViewWidth - 100 - defaultHorizontalHandleWidth * 2,
height: splitViewHeight },
// First handle.
{ x: splitViewWidth - defaultHorizontalHandleWidth * 2 - 100,
y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item does not fill, so its width should be unchanged.
{ x: splitViewWidth - 100 - defaultHorizontalHandleWidth,
y: 0, width: 100, height: splitViewHeight },
// Second handle.
{ x: splitViewWidth - defaultHorizontalHandleWidth,
y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The last item does fill, so it should lose all of its width.
{ x: splitViewWidth, y: 0, width: 0, height: splitViewHeight }
]
},
{
tag: "fillThirdItemAndDragFirstHandlePastBottomSide",
component: threeSizedItemsComponent,
orientation: Qt.Vertical,
fillIndex: 2,
handleIndex: 0,
newHandlePos: Qt.point(testCase.width / 2, testCase.height + 20),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2,
width: splitViewWidth, height: splitViewHeight - 25 - 100 - defaultVerticalHandleHeight * 2 }
],
// The expected geometry of each item managed by the SplitView after dragging the handle.
expectedGeometriesAfterDrag: [
// The fill item is to the bottom of the handle at index 0, so the handle belongs
// to the top item: us. We should consume all of the fill item's width.
{ x: 0, y: 0, width: splitViewWidth,
height: splitViewHeight - 100 - defaultVerticalHandleHeight * 2 },
// First handle.
{ x: 0, y: splitViewHeight - defaultVerticalHandleHeight * 2 - 100,
width: splitViewWidth, height: defaultVerticalHandleHeight },
// The second item does not fill, so its height should be unchanged.
{ x: 0, y: splitViewWidth - 100 - defaultVerticalHandleHeight,
width: splitViewWidth, height: 100 },
// Second handle.
{ x: 0, y: splitViewHeight - defaultVerticalHandleHeight,
width: splitViewWidth, height: defaultVerticalHandleHeight },
// The last item does fill, so it should lose all of its width.
{ x: 0, y: splitViewHeight, width: splitViewWidth, height: 0 }
]
},
{
tag: "fillThirdItemAndDragSecondHandlePastLeftSide",
component: threeSizedItemsComponent,
orientation: Qt.Horizontal,
fillIndex: 2,
handleIndex: 1,
newHandlePos: Qt.point(-20, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
expectedGeometriesAfterDrag: [
// The fill item is to the right of the handle at index 1, so the handle belongs
// to the second item; our width should be unchanged.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
// First handle.
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item is the one being resized, and since we're dragging its handle
// to the left, its width should decrease.
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 0, height: splitViewHeight },
// Second handle.
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: splitViewHeight },
// The last item fills, so it should get the second item's lost width.
{ x: 25 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 25 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
]
},
{
tag: "fillThirdItemAndDragSecondHandlePastTopSide",
component: threeSizedItemsComponent,
orientation: Qt.Vertical,
fillIndex: 2,
handleIndex: 1,
newHandlePos: Qt.point(testCase.width / 2, -20),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2,
width: splitViewWidth, height: splitViewHeight - 25 - 100 - defaultVerticalHandleHeight * 2 }
],
expectedGeometriesAfterDrag: [
// The fill item is to the bottom of the handle at index 1, so the handle belongs
// to the second item; our height should be unchanged.
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
// First handle.
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
// The second item is the one being resized, and since we're dragging its handle
// to the top, its height should decrease.
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth, height: 0 },
// Second handle.
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: splitViewWidth,
height: defaultVerticalHandleHeight },
// The last item fills, so it should get the second item's lost height.
{ x: 0, y: 25 + defaultVerticalHandleHeight * 2,
width: splitViewWidth, height: splitViewHeight - 25 - defaultVerticalHandleHeight * 2 }
]
},
{
// First item should start off empty and then eventually take up all of 3rd item's space
// as the handle is dragged past the right side.
tag: "fillFirstItemAndDragSecondHandlePastRightSide",
component: threeSizedItemsComponent,
orientation: Qt.Horizontal,
fillIndex: 0,
handleIndex: 1,
newHandlePos: Qt.point(testCase.width + 20, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 0, height: splitViewHeight },
{ x: 0, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth * 2, y: 0, width: 200 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
],
expectedGeometriesAfterDrag: [
// The fill item is to the left of the handle at index 1, so the handle belongs
// to the third item. Since we're moving the handle to the right side of the
// SplitView, our width should grow as we consume the width of the third item.
{ x: 0, y: 0, width: splitViewWidth - 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight },
// First handle.
{ x: splitViewWidth - 100 - defaultHorizontalHandleWidth * 2, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item's width remains unchanged.
{ x: splitViewWidth - 100 - defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
// Second handle.
{ x: splitViewWidth - defaultHorizontalHandleWidth, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The last item loses its width.
{ x: splitViewWidth, y: 0, width: 0, height: splitViewHeight }
]
},
{
// First item should start off empty and then eventually take up all of 3rd item's space
// as the handle is dragged past the bottom side.
tag: "fillFirstItemAndDragSecondHandlePastBottomSide",
component: threeSizedItemsComponent,
orientation: Qt.Vertical,
fillIndex: 0,
handleIndex: 1,
newHandlePos: Qt.point(testCase.width / 2, testCase.height + 20),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: splitViewWidth, height: 0 },
{ x: 0, y: 0, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
{ x: 0, y: 100 + defaultVerticalHandleHeight, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 100 + defaultVerticalHandleHeight * 2, width: splitViewWidth, height: 200 - defaultVerticalHandleHeight * 2 }
],
expectedGeometriesAfterDrag: [
// The fill item is to the top of the handle at index 1, so the handle belongs
// to the third item. Since we're moving the handle to the bottom side of the
// SplitView, our height should grow as we consume the height of the third item.
{ x: 0, y: 0, width: splitViewWidth, height: splitViewHeight - 100 - defaultVerticalHandleHeight * 2 },
// First handle.
{ x: 0, y: splitViewHeight - 100 - defaultVerticalHandleHeight * 2,
width: splitViewWidth, height: defaultVerticalHandleHeight },
// The second item's width remains unchanged.
{ x: 0, y: splitViewHeight - 100 - defaultVerticalHandleHeight, width: splitViewWidth, height: 100 },
// Second handle.
{ x: 0, y: splitViewHeight - defaultVerticalHandleHeight,
width: splitViewWidth, height: defaultVerticalHandleHeight },
// The last item loses its width.
{ x: 0, y: splitViewHeight, width: splitViewHeight, height: 0 }
]
},
{
tag: "fillFirstItemAndDragFirstHandlePastLeftSide",
component: threeSizedItemsComponent,
orientation: Qt.Horizontal,
fillIndex: 0,
handleIndex: 0,
newHandlePos: Qt.point(-20, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 0, height: splitViewHeight },
{ x: 0, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The second item's implicitWidth is 100, and ours is 200. The available width is 300,
// so this item gets size 300 - 100 - 2 * 10 = 180.
{ x: 100 + defaultHorizontalHandleWidth * 2, y: 0, width: splitViewWidth - 100 - 2 * defaultHorizontalHandleWidth, height: splitViewHeight }
],
// Should be unchanged.
expectedGeometriesAfterDrag: [
{ x: 0, y: 0, width: 0, height: splitViewHeight },
{ x: 0, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth * 2, y: 0, width: splitViewWidth - 100 - 2 * defaultHorizontalHandleWidth, height: splitViewHeight }
]
},
{
tag: "fillFirstItemWithMinWidthAndDragFirstHandlePastLeftSide",
component: threeItemsMinSizeAndFillComponent,
orientation: Qt.Horizontal,
fillIndex: 0,
handleIndex: 0,
newHandlePos: Qt.point(-20, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// The first item is the filling one, with minimum size 25. Second item is 100.
// The available size is 300, so third item is 300 - 100 - 25 - 2 * 10 = 155.
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0, width: splitViewWidth - 100 - 25 - 2 * defaultHorizontalHandleWidth, height: splitViewHeight }
],
// Should be unchanged.
expectedGeometriesAfterDrag: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0, width: splitViewWidth - 100 - 25 - 2 * defaultHorizontalHandleWidth, height: splitViewHeight }
]
},
{
tag: "repeater",
component: repeaterSplitViewComponent,
orientation: Qt.Horizontal,
fillIndex: 2,
handleIndex: 1,
newHandlePos: Qt.point(200, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 25, height: splitViewHeight },
{ x: 25 * 2 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 * 2 + defaultHorizontalHandleWidth * 2, y: 0, width: splitViewWidth - 70 , height: splitViewHeight }
],
expectedGeometriesAfterDrag: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 105, height: splitViewHeight },
{ x: 140, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 150, y: 0, width: 150, height: splitViewHeight }
]
},
{
tag: "hiddenItemSplitViewComponent",
// [50] | [200 (fill)] | [hidden] | [50]
component: hiddenItemSplitViewComponent,
orientation: Qt.Horizontal,
fillIndex: 1,
handleIndex: 1,
// Drag to the horizontal centre of the SplitView.
newHandlePos: Qt.point(splitViewMargins + 150, testCase.height / 2),
expectedGeometriesBeforeDrag: [
{ x: 0, y: 0, width: 50, height: splitViewHeight },
{ x: 50, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 50 + defaultHorizontalHandleWidth, y: 0, width: 200 - defaultHorizontalHandleWidth * 2, height: splitViewHeight },
{ x: 250 - (defaultHorizontalHandleWidth * 2) + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ hidden: true }, // Third item should be hidden.
{ hidden: true }, // Handle for third item should be hidden.
{ x: 250 - (defaultHorizontalHandleWidth * 2) + defaultHorizontalHandleWidth * 2, y: 0, width: 50, height: splitViewHeight }
],
expectedGeometriesAfterDrag: [
{ x: 0, y: 0, width: 50, height: splitViewHeight },
{ x: 50, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Width of the fill item should end up smaller.
{ x: 50 + defaultHorizontalHandleWidth, y: 0, width: 100 - defaultHorizontalHandleWidth * 2, height: splitViewHeight },
{ x: 150 - (defaultHorizontalHandleWidth * 2) + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ hidden: true }, // Third item should be hidden.
{ hidden: true }, // Handle for third item should be hidden.
// Width of the last item should grow.
{ x: 150 - (defaultHorizontalHandleWidth * 2) + defaultHorizontalHandleWidth * 2, y: 0, width: 150, height: splitViewHeight }
]
}
]
return data
}
function test_dragHandle(data) {
let control = createTemporaryObject(data.component, testCase)
verify(control)
control.orientation = data.orientation
// Ensure that there is space to drag outside of the SplitView.
control.anchors.margins = splitViewMargins
let fillItem = control.itemAt(data.fillIndex)
if (control.orientation === Qt.Horizontal)
fillItem.SplitView.fillWidth = true
else
fillItem.SplitView.fillHeight = true
// Check the sizes (and visibility) of the items before the drag.
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesBeforeDrag, "before drag")
// Drag the handle.
let handles = findHandles(control)
let targetHandle = handles[data.handleIndex]
verify(targetHandle.visible)
mousePress(targetHandle)
verify(control.resizing)
// newHandlePos is in scene coordinates, so map it to coordinates local to the handle.
let localPos = testCase.mapToItem(targetHandle, data.newHandlePos.x, data.newHandlePos.y)
mouseMove(targetHandle, localPos.x - targetHandle.width / 2, localPos.y - targetHandle.height / 2)
verify(control.resizing)
compareSizes(control, data.expectedGeometriesAfterDrag, "after drag move")
// The geometries should remain unchanged after releasing.
mouseRelease(targetHandle, localPos.x - targetHandle.width / 2, localPos.y - targetHandle.height / 2, Qt.LeftButton)
verify(!control.resizing)
compareSizes(control, data.expectedGeometriesAfterDrag, "after drag release")
}
function test_splitViewGeometryChanges_data() {
let defaultSplitViewWidth = testCase.width
let defaultSplitViewHeight = testCase.height
let data = [
{
tag: "growWidth",
orientation: Qt.Horizontal,
splitViewWidth: 800,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: defaultSplitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: defaultSplitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: defaultSplitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: defaultSplitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: 800 - 25 - 100 - defaultHorizontalHandleWidth * 2, height: defaultSplitViewHeight }
]
},
{
// Same as above except vertical.
tag: "growHeight",
orientation: Qt.Vertical,
splitViewHeight: 800,
expectedGeometries: [
{ x: 0, y: 0, width: defaultSplitViewWidth, height: 25 },
{ x: 0, y: 25, width: defaultSplitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: defaultSplitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: defaultSplitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2, width: defaultSplitViewWidth,
height: 800 - 25 - 100 - defaultVerticalHandleHeight * 2 }
]
},
{
tag: "shrinkWidth",
orientation: Qt.Horizontal,
splitViewWidth: 200,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: defaultSplitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: defaultSplitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: defaultSplitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: defaultSplitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: 200 - 25 - 100 - defaultHorizontalHandleWidth * 2, height: defaultSplitViewHeight }
]
},
{
// Same as above except vertical.
tag: "shrinkHeight",
orientation: Qt.Vertical,
splitViewHeight: 200,
expectedGeometries: [
{ x: 0, y: 0, width: defaultSplitViewWidth, height: 25 },
{ x: 0, y: 25, width: defaultSplitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight, width: defaultSplitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight, width: defaultSplitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + 100 + defaultVerticalHandleHeight * 2, width: defaultSplitViewWidth,
height: 200 - 25 - 100 - defaultVerticalHandleHeight * 2 }
]
},
]
return data
}
function test_splitViewGeometryChanges(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "handle": handleComponent, "anchors.fill": undefined, "orientation": data.orientation })
verify(control)
if (data.hasOwnProperty("splitViewWidth"))
control.width = data.splitViewWidth
else
control.width = testCase.width
if (data.hasOwnProperty("splitViewHeight"))
control.height = data.splitViewHeight
else
control.height = testCase.height
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometries)
}
function test_splitItemImplicitSizeChanges_data() {
let defaultSplitViewWidth = testCase.width
let defaultSplitViewHeight = testCase.height
let data = [
{
tag: "growImplicitWidth",
orientation: Qt.Horizontal,
splitItemImplicitWidth: 50,
expectedGeometries: [
{ x: 0, y: 0, width: 50, height: defaultSplitViewHeight },
{ x: 50, y: 0, width: defaultHorizontalHandleWidth, height: defaultSplitViewHeight },
{ x: 50 + defaultHorizontalHandleWidth, y: 0, width: 100, height: defaultSplitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth,
height: defaultSplitViewHeight },
{ x: 50 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: defaultSplitViewWidth - 50 - 100 - defaultHorizontalHandleWidth * 2, height: defaultSplitViewHeight }
]
},
{
tag: "growImplicitHeight",
orientation: Qt.Vertical,
splitItemImplicitHeight: 50,
expectedGeometries: [
{ x: 0, y: 0, width: defaultSplitViewWidth, height: 50 },
{ x: 0, y: 50, width: defaultSplitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + defaultVerticalHandleHeight, width: defaultSplitViewWidth, height: 100 },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight, width: defaultSplitViewWidth,
height: defaultVerticalHandleHeight },
{ x: 0, y: 50 + 100 + defaultVerticalHandleHeight * 2, width: defaultSplitViewWidth,
height: defaultSplitViewHeight - 50 - 100 - defaultVerticalHandleHeight * 2 }
]
}
]
return data
}
// Tests that implicitWidth/Height changes in items are noticed by SplitView.
function test_splitItemImplicitSizeChanges(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "handle": handleComponent, "orientation": data.orientation })
verify(control)
let firstItem = control.itemAt(0)
if (data.hasOwnProperty("splitItemImplicitWidth"))
firstItem.implicitWidth = data.splitItemImplicitWidth
if (data.hasOwnProperty("splitItemImplicitHeight"))
firstItem.implicitHeight = data.splitItemImplicitHeight
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometries)
}
Component {
id: largerHandle
Rectangle {
objectName: "largerHandle"
implicitWidth: 20
implicitHeight: 20
color: "#444"
}
}
Component {
id: smallerHandle
Rectangle {
objectName: "smallerHandle"
implicitWidth: 5
implicitHeight: 5
color: "#444"
}
}
function test_handleChanges_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "growHandleWidth",
orientation: Qt.Horizontal,
handleComponent: largerHandle,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: 20, height: splitViewHeight },
{ x: 25 + 20, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + 20, y: 0, width: 20, height: splitViewHeight },
{ x: 25 + 100 + 20 * 2, y: 0, width: splitViewWidth - 25 - 100 - 20 * 2,
height: splitViewHeight }
]
},
{
// Same as above except vertical.
tag: "growHandleHeight",
orientation: Qt.Vertical,
handleComponent: largerHandle,
expectedGeometries: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: 20 },
{ x: 0, y: 25 + 20, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + 20, width: splitViewWidth, height: 20 },
{ x: 0, y: 25 + 100 + 20 * 2, width: splitViewWidth,
height: splitViewHeight - 25 - 100 - 20 * 2 }
]
},
{
tag: "shrinkHandleWidth",
orientation: Qt.Horizontal,
handleComponent: smallerHandle,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: 5, height: splitViewHeight },
{ x: 25 + 5, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + 5, y: 0, width: 5, height: splitViewHeight },
{ x: 25 + 100 + 5 * 2, y: 0, width: splitViewWidth - 25 - 100 - 5 * 2,
height: splitViewHeight }
]
},
{
// Same as above except vertical.
tag: "shrinkHandleHeight",
orientation: Qt.Vertical,
handleComponent: smallerHandle,
expectedGeometries: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: 5 },
{ x: 0, y: 25 + 5, width: splitViewWidth, height: 100 },
{ x: 0, y: 25 + 100 + 5, width: splitViewWidth, height: 5 },
{ x: 0, y: 25 + 100 + 5 * 2, width: splitViewWidth,
height: splitViewHeight - 25 - 100 - 5 * 2 }
]
}
]
return data
}
function test_handleChanges(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
control.handle = data.handleComponent
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometries)
}
function test_insertRemoveItems_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "insertItemAtHorizontalEnd",
orientation: Qt.Horizontal,
insertItemAtIndex: 3,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 100, height: splitViewHeight },
{ x: 25 + 100 + defaultHorizontalHandleWidth, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// This was the fill item originally, but since no fill item is explicitly
// specified, and we added an item to the right of it, it is no longer the fill item
// because it's no longer last.
{ x: 25 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: 200, height: splitViewHeight },
// Handle for newly added item.
{ x: 25 + 100 + 200 + defaultHorizontalHandleWidth * 2, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Newly added item.
{ x: 25 + 100 + 200 + defaultHorizontalHandleWidth * 3, y: 0,
width: splitViewWidth - 25 - 100 - 200 - defaultHorizontalHandleWidth * 3,
height: splitViewHeight },
]
},
{
tag: "insertItemAtHorizontalBeginning",
orientation: Qt.Horizontal,
insertItemAtIndex: 0,
expectedGeometries: [
// Newly added item.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0, width: 25, height: splitViewHeight },
{ x: 25 * 2 + defaultHorizontalHandleWidth, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 * 2 + defaultHorizontalHandleWidth * 2, y: 0, width: 100, height: splitViewHeight },
{ x: 25 * 2 + 100 + defaultHorizontalHandleWidth * 2, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Fill item doesn't change.
{ x: 25 * 2 + 100 + defaultHorizontalHandleWidth * 3, y: 0,
width: splitViewWidth - 25 * 2 - 100 - defaultHorizontalHandleWidth * 3,
height: splitViewHeight },
]
},
{
tag: "removeItemFromHorizontalEnd",
orientation: Qt.Horizontal,
removeItemAtIndex: 2,
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 25 - defaultHorizontalHandleWidth, height: splitViewHeight },
]
},
{
tag: "removeItemFromHorizontalBeginning",
orientation: Qt.Horizontal,
removeItemAtIndex: 0,
expectedGeometries: [
{ x: 0, y: 0, width: 100, height: splitViewHeight },
{ x: 100, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 100 - defaultHorizontalHandleWidth, height: splitViewHeight },
]
}
]
return data
}
Component {
id: smallRectComponent
Rectangle {
objectName: "darkseagreen"
color: objectName
implicitWidth: 25
implicitHeight: 25
}
}
function test_insertRemoveItems(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
if (data.hasOwnProperty("removeItemAtIndex")) {
let itemToRemove = control.itemAt(data.removeItemAtIndex)
verify(itemToRemove)
control.removeItem(itemToRemove)
} else if (data.hasOwnProperty("insertItemAtIndex")) {
let itemToAdd = smallRectComponent.createObject(control)
control.insertItem(data.insertItemAtIndex, itemToAdd)
}
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometries)
}
function test_removeAllItems() {
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
while (control.count > 0)
control.removeItem(control.itemAt(0))
// Shouldn't crash.
}
function test_hideItems_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "hideItemAtHorizontalEnd",
orientation: Qt.Horizontal,
hideIndices: [2],
expectedGeometries: [
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 25 - defaultHorizontalHandleWidth, height: splitViewHeight },
{ hidden: true }, // Handle for second item should be hidden.
{ hidden: true } // Last item should be hidden.
]
},
{
tag: "hideItemAtHorizontalBeginning",
orientation: Qt.Horizontal,
hideIndices: [0],
expectedGeometries: [
{ hidden: true }, // First item should be hidden.
{ hidden: true }, // Handle for first item should be hidden.
{ x: 0, y: 0, width: 100, height: splitViewHeight },
{ x: 100, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 100 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 100 - defaultHorizontalHandleWidth, height: splitViewHeight }
]
},
{
tag: "hideItemAtVerticalEnd",
orientation: Qt.Vertical,
hideIndices: [2],
expectedGeometries: [
{ x: 0, y: 0, width: splitViewWidth, height: 25 },
{ x: 0, y: 25, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 25 + defaultVerticalHandleHeight,
width: splitViewWidth, height: splitViewHeight - 25 - defaultVerticalHandleHeight },
{ hidden: true }, // Handle for second item should be hidden.
{ hidden: true } // Last item should be hidden.
]
},
{
tag: "hideItemAtVerticalBeginning",
orientation: Qt.Vertical,
hideIndices: [0],
expectedGeometries: [
{ hidden: true }, // First item should be hidden.
{ hidden: true }, // Handle for first item should be hidden.
{ x: 0, y: 0, width: splitViewWidth, height: 100 },
{ x: 0, y: 100, width: splitViewWidth, height: defaultVerticalHandleHeight },
{ x: 0, y: 100 + defaultVerticalHandleHeight,
width: splitViewWidth, height: splitViewHeight - 100 - defaultVerticalHandleHeight }
]
},
{
// No handles should be visible when there's only one item.
tag: "hideLastTwoHorizontalItems",
orientation: Qt.Horizontal,
hideIndices: [1, 2],
expectedGeometries: [
{ x: 0, y: 0, width: splitViewWidth, height: splitViewHeight },
{ hidden: true }, // Handle for first item should be hidden.
{ hidden: true }, // Second item should be hidden.
{ hidden: true }, // Handle for second item should be hidden.
{ hidden: true } // Third item should be hidden.
]
}
]
return data
}
function test_hideItems(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
for (let i = 0; i < data.hideIndices.length; ++i) {
let itemToHide = control.itemAt(data.hideIndices[i])
verify(itemToHide)
itemToHide.visible = false
}
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometries)
}
function test_hideAndShowItems_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "hideLastTwoHorizontalItems",
orientation: Qt.Horizontal,
hideIndices: [1, 2],
expectedGeometriesAfterHiding: [
{ x: 0, y: 0, width: splitViewWidth, height: splitViewHeight },
{ hidden: true }, // Handle for first item should be hidden.
{ hidden: true }, // Second item should be hidden.
{ hidden: true }, // Handle for second item should be hidden.
{ hidden: true } // Third item should be hidden.
],
showIndices: [1],
expectedGeometriesAfterShowing: [
// First item should be visible with its implicit size.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
// Handle for first item should be visible.
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Second item should be visible and fill.
{ x: 25 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 25 - defaultHorizontalHandleWidth, height: splitViewHeight },
{ hidden: true }, // Handle for second item should be hidden.
{ hidden: true } // Third item should be hidden.
]
}
]
return data
}
function test_hideAndShowItems(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
for (let i = 0; i < data.hideIndices.length; ++i) {
let itemToHide = control.itemAt(data.hideIndices[i])
verify(itemToHide)
itemToHide.visible = false
}
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesAfterHiding, "after hiding")
for (let i = 0; i < data.showIndices.length; ++i) {
let itemToShow = control.itemAt(data.showIndices[i])
verify(itemToShow)
itemToShow.visible = true
}
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesAfterShowing, "after showing")
}
function test_moveHiddenItems_data() {
let splitViewWidth = testCase.width
let splitViewHeight = testCase.height
let data = [
{
tag: "hideSecondItemAndMoveItToFirst",
orientation: Qt.Horizontal,
hideIndices: [1],
moveFromIndex: 1,
moveToIndex: 0,
expectedGeometriesAfterMoving: [
{ hidden: true }, // First item (was second) should be hidden.
{ hidden: true }, // Handle for first item should be hidden.
// Second item (was first) should get its implicit size.
{ x: 0, y: 0, width: 25, height: splitViewHeight },
{ x: 25, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 25 + defaultHorizontalHandleWidth, y: 0,
width: splitViewWidth - 25 - defaultHorizontalHandleWidth, height: splitViewHeight },
],
showIndices: [0],
expectedGeometriesAfterShowing: [
// First item (was second) should be visible with its implicit size.
{ x: 0, y: 0, width: 100, height: splitViewHeight },
// Handle for first item (was second) should be visible.
{ x: 100, y: 0, width: defaultHorizontalHandleWidth, height: splitViewHeight },
// Second item (was first) should be visible with its implicit size.
{ x: 100 + defaultHorizontalHandleWidth, y: 0,
width: 25, height: splitViewHeight },
{ x: 100 + 25 + defaultHorizontalHandleWidth, y: 0,
width: defaultHorizontalHandleWidth, height: splitViewHeight },
{ x: 100 + 25 + defaultHorizontalHandleWidth * 2, y: 0,
width: splitViewWidth - 100 - 25 - defaultHorizontalHandleWidth * 2, height: splitViewHeight }
]
}
]
return data
}
function test_moveHiddenItems(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase,
{ "orientation": data.orientation })
verify(control)
for (let i = 0; i < data.hideIndices.length; ++i) {
let itemToHide = control.itemAt(data.hideIndices[i])
verify(itemToHide)
itemToHide.visible = false
}
control.moveItem(data.moveFromIndex, data.moveToIndex)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesAfterMoving, "after moving")
for (let i = 0; i < data.showIndices.length; ++i) {
let itemToShow = control.itemAt(data.showIndices[i])
verify(itemToShow)
itemToShow.visible = true
}
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compareSizes(control, data.expectedGeometriesAfterShowing, "after showing")
}
Component {
id: flickableComponent
Flickable {
anchors.fill: parent
anchors.margins: 100
}
}
function test_draggingHandleInFlickable() {
let flickable = createTemporaryObject(flickableComponent, testCase)
verify(flickable)
let control = threeSizedItemsComponent.createObject(flickable.contentItem)
verify(control)
control.anchors.fill = undefined
control.width = 400
control.height = control.parent.height - 100
flickable.contentWidth = control.width
flickable.contentHeight = control.height
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
let contentXSpy = signalSpyComponent.createObject(flickable,
{ target: flickable, signalName: "contentXChanged" })
verify(contentXSpy.valid)
let contentYSpy = signalSpyComponent.createObject(flickable,
{ target: flickable, signalName: "contentYChanged" })
verify(contentYSpy.valid)
// Drag the first handle to the right;
// the flickable's contentX and contentY shouldn't change.
let firstItem = control.itemAt(0)
let firstItemOriginalWidth = firstItem.width
let handles = findHandles(control)
let firstHandle = handles[0]
// Add some vertical movement in there as well.
mouseDrag(firstHandle, firstHandle.width / 2, firstHandle.height / 2, 100, 50)
compare(contentXSpy.count, 0)
compare(contentYSpy.count, 0)
verify(firstItem.width > firstItemOriginalWidth)
// Now do the same except vertically.
control.orientation = Qt.Vertical
control.width = control.parent.width - 100
control.height = 400
let firstItemOriginalHeight = firstItem.height
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
// Add some horizontal movement in there as well.
mouseDrag(firstHandle, firstHandle.width / 2, firstHandle.height / 2, 50, 100)
compare(contentXSpy.count, 0)
compare(contentYSpy.count, 0)
verify(firstItem.height > firstItemOriginalHeight)
}
Component {
id: splitViewHandleContainmentMaskComponent
MouseArea {
property alias mouseArea1: mouseArea1
property alias mouseArea2: mouseArea2
property alias splitView: splitView
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
Rectangle {
anchors.fill: parent
color: 'green'
opacity: 0.3
}
SplitView {
id: splitView
anchors {
fill: parent
margins: 100
}
handle: Rectangle {
id: handleRoot
readonly property bool containsMouse: SplitHandle.hovered
readonly property int defaultSize: 2
implicitWidth: splitView.orientation === Qt.Horizontal ? handleRoot.defaultSize : splitView.width
implicitHeight: splitView.orientation === Qt.Vertical ? handleRoot.defaultSize : splitView.height
color: 'red'
objectName: "handle"
Text {
objectName: "handleText_" + text
text: parent.x + "," + parent.y + " " + parent.width + "x" + parent.height
color: "black"
anchors.centerIn: parent
rotation: 90
}
containmentMask: Item {
readonly property real extraOverflow: 20
x: splitView.orientation === Qt.Horizontal ? -extraOverflow : 0
y: splitView.orientation === Qt.Horizontal ? 0 : -extraOverflow
width: splitView.orientation === Qt.Horizontal ? handleRoot.defaultSize + (extraOverflow * 2): handleRoot.width
height: splitView.orientation === Qt.Horizontal ? handleRoot.height : handleRoot.defaultSize + (extraOverflow * 2)
}
}
MouseArea {
id: mouseArea1
SplitView.fillHeight: splitView.orientation === Qt.Horizontal
SplitView.fillWidth: splitView.orientation === Qt.Vertical
SplitView.preferredWidth: splitView.orientation === Qt.Horizontal ? parent.width / 2 : undefined
SplitView.preferredHeight: splitView.orientation === Qt.Vertical ? parent.height / 2 : undefined
hoverEnabled: true
Rectangle {
anchors.fill: parent
color: 'cyan'
opacity: 0.3
}
}
MouseArea {
id: mouseArea2
SplitView.fillHeight: splitView.orientation === Qt.Horizontal
SplitView.fillWidth: splitView.orientation === Qt.Vertical
SplitView.preferredWidth: splitView.orientation === Qt.Horizontal ? parent.width / 2 : undefined
SplitView.preferredHeight: splitView.orientation === Qt.Vertical ? parent.height / 2 : undefined
hoverEnabled: true
Rectangle {
anchors.fill: parent
color: 'cyan'
opacity: 0.3
}
}
}
}
}
function test_handleContainmentMask_data() {
const data = [
{
tag: "handleContainmentMaskHorizontalLeftEdgeDragRight",
orientation: Qt.Horizontal,
press: {
x: (handle) => handle.containmentMask.x,
y: (handle) => handle.height / 2
},
dx: 25,
dy: 0,
},
{
tag: "handleContainmentMaskHorizontalRightEdgeDragLeft",
orientation: Qt.Horizontal,
press: {
x: (handle) => handle.containmentMask.x,
y: (handle) => handle.height / 2
},
dx: -50,
dy: 0
},
{
tag: "handleContainmentMaskHorizontalTopEdgeDragRight",
orientation: Qt.Horizontal,
press: {
x: (handle) => handle.containmentMask.x + handle.containmentMask.width - 1,
y: (handle) => handle.height / 2
},
dx: 25,
dy: 0,
},
{
tag: "handleContainmentMaskHorizontalBottomEdgeDragLeft",
orientation: Qt.Horizontal,
press: {
x: (handle) => handle.containmentMask.x + handle.containmentMask.width - 1,
y: (handle) => handle.containmentMask.y
},
dx: -50,
dy: 0
},
{
tag: "handleContainmentMaskVerticalTopEdgeDragUp",
orientation: Qt.Vertical,
press: {
x: (handle) => handle.width / 2,
y: (handle) => handle.containmentMask.y
},
dx: 0,
dy: -40,
},
{
tag: "handleContainmentMaskVerticalTopEdgeDragDown",
orientation: Qt.Vertical,
press: {
x: (handle) => handle.width / 2,
y: (handle) => handle.containmentMask.y
},
dx: 0,
dy: 70
},
{
tag: "handleContainmentMaskVerticalBottomEdgeDragUp",
orientation: Qt.Vertical,
press: {
x: (handle) => handle.width / 2,
y: (handle) => handle.containmentMask.y + handle.containmentMask.height - 1
},
dx: 0,
dy: -40,
},
{
tag: "handleContainmentMaskVerticalBottomEdgeDragDown",
orientation: Qt.Vertical,
press: {
x: (handle) => handle.width / 2,
y: (handle) => handle.containmentMask.y + handle.containmentMask.height - 1
},
dx: 0,
dy: 70
}
]
return data
}
function test_handleContainmentMask(data) {
const control = createTemporaryObject(splitViewHandleContainmentMaskComponent, testCase)
verify(control)
const splitView = control.splitView
splitView.orientation = data.orientation
const handle = findHandles(splitView)[0]
if (splitView.orientation === Qt.Vertical)
handle.height = handle.defaultHeight
verify(isPolishScheduled(splitView))
verify(waitForItemPolished(splitView))
const firstItem = control.mouseArea1
const secondItem = control.mouseArea2
const backgroundMouseAreaPress = signalSpyComponent.createObject(control,
{ target: control, signalName: "onPressed" })
const mouseArea1Press = signalSpyComponent.createObject(firstItem,
{ target: firstItem, signalName: "onPressed" })
const mouseArea2Press = signalSpyComponent.createObject(secondItem,
{ target: secondItem, signalName: "onPressed" })
verify(backgroundMouseAreaPress.valid)
verify(mouseArea1Press.valid)
verify(mouseArea2Press.valid)
const firstItemWidthBeforeDrag = firstItem.width
const secondItemWidthBeforeDrag = secondItem.width
const firstItemHeightBeforeDrag = firstItem.height
const secondItemHeightBeforeDrag = secondItem.height
const dx = data.dx
const dy = data.dy
const pressX = data.press.x(handle)
const pressY = data.press.y(handle)
mousePress(handle, pressX, pressY, Qt.LeftButton)
mouseMove(handle, pressX + dx, pressY + dy, -1, Qt.LeftButton)
mouseRelease(handle, pressX + dx, pressY + dy, Qt.LeftButton)
compare(firstItem.width, firstItemWidthBeforeDrag + dx)
compare(secondItem.width, secondItemWidthBeforeDrag - dx)
compare(firstItem.height, firstItemHeightBeforeDrag + dy)
compare(secondItem.height, secondItemHeightBeforeDrag - dy)
compare(backgroundMouseAreaPress.count, 0)
compare(mouseArea1Press.count, 0)
compare(mouseArea2Press.count, 0)
}
function test_handleContainmentMaskHovered_data() {
const data = [
{
tag: "firstItemHorizontalHover",
orientation: Qt.Horizontal,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "firstItem",
expectedHover: {
"firstItem": true,
"handle": false,
"secondItem": false
}
},
{
tag: "handleHorizontalHoverOnTheLeft",
orientation: Qt.Horizontal,
press: {
"x": (item) => item.containmentMask.x,
"y": (item) => item.height / 2
},
hoverItem: "handle",
expectedHover: {
"firstItem": true,
"handle": true,
"secondItem": false
}
},
{
tag: "handleHorizontalHoverOnTheCenter",
orientation: Qt.Horizontal,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "handle",
expectedHover: {
"firstItem": false,
"handle": true,
"secondItem": false
}
},
{
tag: "handleHorizontalHoverOnTheRight",
orientation: Qt.Horizontal,
press: {
"x": (item) => item.containmentMask.x + item.containmentMask.width - 1,
"y": (item) => item.height / 2
},
hoverItem: "handle",
expectedHover: {
"firstItem": false,
"handle": true,
"secondItem": true
}
},
{
tag: "secondItemHorizontalHover",
orientation: Qt.Horizontal,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "secondItem",
expectedHover: {
"firstItem": false,
"handle": false,
"secondItem": true
}
},
{
tag: "firstItemVerticalHover",
orientation: Qt.Vertical,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "firstItem",
expectedHover: {
"firstItem": true,
"handle": false,
"secondItem": false
}
},
{
tag: "handleVerticalHoverOnTheTop",
orientation: Qt.Vertical,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.containmentMask.y
},
hoverItem: "handle",
expectedHover: {
"firstItem": true,
"handle": true,
"secondItem": false
}
},
{
tag: "handleVerticalHoverOnTheCenter",
orientation: Qt.Vertical,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "handle",
expectedHover: {
"firstItem": false,
"handle": true,
"secondItem": false
}
},
{
tag: "handleVerticalHoverOnTheBottom",
orientation: Qt.Vertical,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.containmentMask.y + item.containmentMask.height - 1
},
hoverItem: "handle",
expectedHover: {
"firstItem": false,
"handle": true,
"secondItem": true
}
},
{
tag: "secondItemVerticalHover",
orientation: Qt.Vertical,
press: {
"x": (item) => item.width / 2,
"y": (item) => item.height / 2
},
hoverItem: "secondItem",
expectedHover: {
"firstItem": false,
"handle": false,
"secondItem": true
}
}
]
return data
}
function test_handleContainmentMaskHovered(data) {
if ((Qt.platform.pluginName === "offscreen") || (Qt.platform.pluginName === "minimal"))
skip("Mouse hovering not functional on offscreen/minimal platforms")
const control = createTemporaryObject(splitViewHandleContainmentMaskComponent, testCase)
verify(control)
const splitView = control.splitView
splitView.orientation = data.orientation
const handle = findHandles(splitView)[0]
if (splitView.orientation === Qt.Vertical)
handle.height = handle.defaultHeight
verify(isPolishScheduled(splitView))
verify(waitForItemPolished(splitView))
const firstItem = control.mouseArea1
const secondItem = control.mouseArea2
verify(!firstItem.containsMouse)
verify(!secondItem.containsMouse)
verify(!handle.containsMouse)
const actualItem = {
"firstItem": firstItem,
"secondItem": secondItem,
"handle": handle
}[data.hoverItem]
const pressX = data.press.x(actualItem)
const pressY = data.press.y(actualItem)
// Test fails if we don't do two moves for some reason...
mouseMove(actualItem, pressX, pressY)
mouseMove(actualItem, pressX, pressY)
compare(firstItem.containsMouse, data.expectedHover.firstItem)
compare(secondItem.containsMouse, data.expectedHover.secondItem)
compare(handle.containsMouse, data.expectedHover.handle)
// Hide SplitView, then all children shouldn't be hovered
control.visible = false
verify(isPolishScheduled(splitView))
verify(waitForItemPolished(splitView))
verify(!control.containsMouse)
verify(!firstItem.containsMouse)
verify(!secondItem.containsMouse)
tryCompare(handle, "containsMouse", false)
}
function test_hoveredPressed() {
if ((Qt.platform.pluginName === "offscreen") || (Qt.platform.pluginName === "minimal"))
skip("Mouse hovering not functional on offscreen/minimal platforms")
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
control.anchors.margins = 50
let handles = findHandles(control)
let firstHandle = handles[0]
let handleCenter = control.mapFromItem(firstHandle, firstHandle.width / 2, firstHandle.height / 2)
// Test fails if we don't do two moves for some reason...
mouseMove(control, handleCenter.x, handleCenter.y)
mouseMove(control, handleCenter.x, handleCenter.y)
verify(firstHandle.SplitHandle.hovered)
verify(!firstHandle.SplitHandle.pressed)
mousePress(control, handleCenter.x, handleCenter.y)
verify(firstHandle.SplitHandle.hovered)
verify(firstHandle.SplitHandle.pressed)
mouseRelease(control, handleCenter.x, handleCenter.y)
verify(firstHandle.SplitHandle.hovered)
verify(!firstHandle.SplitHandle.pressed)
mouseMove(control, 0, 0)
verify(!firstHandle.SplitHandle.hovered)
verify(!firstHandle.SplitHandle.pressed)
}
// Tests removing/adding/moving an item while it's pressed.
function test_modifyWhileHoveredPressed() {
if ((Qt.platform.pluginName === "offscreen") || (Qt.platform.pluginName === "minimal"))
skip("Mouse hovering not functional on offscreen/minimal platforms")
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
control.anchors.margins = 50
let handles = findHandles(control)
let firstHandle = handles[0]
// First, ensure that the handle is hovered + pressed.
let handleCenter = control.mapFromItem(firstHandle, firstHandle.width / 2, firstHandle.height / 2)
// Test fails if we don't do two moves for some reason...
mouseMove(control, handleCenter.x, handleCenter.y)
mouseMove(control, handleCenter.x, handleCenter.y)
verify(firstHandle.SplitHandle.hovered)
verify(!firstHandle.SplitHandle.pressed)
mousePress(control, handleCenter.x, handleCenter.y)
verify(firstHandle.SplitHandle.hovered)
verify(firstHandle.SplitHandle.pressed)
// Then, remove it by removing the first item.
control.removeItem(control.itemAt(0))
handles = findHandles(control)
firstHandle = null
compare(handles.length, 1)
// No handles should be hovered/pressed.
for (let i = 0; i < handles.length; ++i) {
let handle = handles[i]
verify(!handle.SplitHandle.hovered, "handle at index " + i + " should not be hovered")
verify(!handle.SplitHandle.pressed, "handle at index " + i + " should not be hovered")
}
mouseRelease(control, handleCenter.x, handleCenter.y)
}
Component {
id: settingsComponent
Settings {
id: settings
}
}
function test_saveAndRestoreState_data() {
return [
{ tag: "Horizontal", orientation: Qt.Horizontal, propertyName: "preferredWidth", propertyValue: 123 },
{ tag: "Vertical", orientation: Qt.Vertical, propertyName: "preferredHeight", propertyValue: 234 }
]
}
function test_saveAndRestoreState(data) {
let control = createTemporaryObject(threeSizedItemsComponent, testCase, { orientation: data.orientation })
verify(control)
compare(control.orientation, data.orientation)
let lastItem = control.itemAt(2)
verify(lastItem)
lastItem.SplitView[data.propertyName] = data.propertyValue
// Save the state.
let settings = createTemporaryObject(settingsComponent, testCase)
verify(settings)
settings.setValue("splitView", control.saveState())
// Recreate the item to restore it to its "default" values.
control = createTemporaryObject(threeSizedItemsComponent, testCase)
lastItem = control.itemAt(2)
verify(lastItem)
compare(lastItem.SplitView[data.propertyName], -1)
settings = createTemporaryObject(settingsComponent, testCase)
verify(settings)
// Restore the state.
control.restoreState(settings.value("splitView"))
compare(lastItem.SplitView[data.propertyName], data.propertyValue)
}
function test_changePreferredSizeDuringLayout() {
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
let firstItem = control.itemAt(0)
let secondItem = control.itemAt(1)
secondItem.widthChanged.connect(function() {
if (secondItem.width < 10)
firstItem.SplitView.preferredWidth = 50
})
// Change the size of the item so that a layout happens, but
// make the size small enough that the item's onWidthChanged handler gets triggered.
// The onWidthChanged handler will set the preferredWidth of another item during the
// layout, so we need to make sure the assignment isn't lost since we return early in that case.
secondItem.implicitWidth = 5
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(secondItem.width, 5)
compare(firstItem.width, 50)
// Now do the same for height.
control.orientation = Qt.Vertical
secondItem.heightChanged.connect(function() {
if (secondItem.height < 10)
firstItem.SplitView.preferredHeight = 50
})
// Get the polishes for the orientation out of the way so that they
// don't intefere with our results.
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
secondItem.implicitHeight = 5
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(secondItem.height, 5)
compare(firstItem.height, 50)
}
// When the user drags a handle, we internally set preferredWidth/Height
// to reflect the new value. However, we also have to make sure that when
// we do so, it doesn't trigger a delayed layout. This is why we have
// m_ignoreNextDelayedLayoutRequest. This test checks that
// m_ignoreNextDelayedLayoutRequest doesn't interfere with any action from
// the user that results in a delayed layout.
function test_changePreferredSizeDuringLayoutWhileDraggingHandle() {
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
let firstItem = control.itemAt(0)
let secondItem = control.itemAt(1)
firstItem.widthChanged.connect(function() {
if (firstItem.width === 0)
secondItem.SplitView.preferredWidth = 50
})
// Start dragging the handle.
let handles = findHandles(control)
let targetHandle = handles[0]
mousePress(targetHandle)
verify(control.resizing)
let localPos = testCase.mapToItem(targetHandle, 15, testCase.height / 2)
// Move the handle to the very left, so that the item's width becomes zero.
mouseMove(targetHandle, -100, targetHandle.height / 2)
verify(control.resizing)
compare(firstItem.width, 0)
compare(secondItem.SplitView.preferredWidth, 50)
// Wait for polish so item width becomes preferredWidth
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
compare(secondItem.width, 50)
mouseRelease(targetHandle, -100, targetHandle.height / 2, Qt.LeftButton)
verify(!control.resizing)
}
Component {
id: oneItemComponent
SplitView {
Item {}
}
}
// QTBUG-79270
function test_hideSplitViewWithOneItem() {
let control = createTemporaryObject(oneItemComponent, testCase)
verify(control)
// Shouldn't be an assertion failure.
control.visible = false
}
// QTBUG-79302: ensure that the Repeater's items are actually generated.
// test_dragHandle:repeater tests dragging behavior with a Repeater.
function test_repeater(data) {
let control = createTemporaryObject(repeaterSplitViewComponent, testCase)
verify(control)
compare(control.repeater.count, 3)
compare(control.contentChildren.length, 3)
}
Component {
id: hoverableChildrenSplitViewComponent
SplitView {
handle: handleComponent
anchors.fill: parent
MouseArea {
objectName: "mouseArea1"
hoverEnabled: true
SplitView.preferredWidth: 200
}
MouseArea {
objectName: "mouseArea2"
hoverEnabled: true
}
}
}
function test_hoverableChilden() {
if (Qt.platform.pluginName === "offscreen" || Qt.platform.pluginName === "minimal")
skip("Mouse hovering not functional on offscreen/minimal platforms")
let control = createTemporaryObject(hoverableChildrenSplitViewComponent, testCase)
verify(control)
verify(isPolishScheduled(control))
verify(waitForItemPolished(control))
// Move the mouse over the handle.
let handles = findHandles(control)
let targetHandle = handles[0]
// Test fails if we don't do two moves for some reason... QTBUG-94968
mouseMove(targetHandle, targetHandle.width / 2, targetHandle.height / 2)
mouseMove(targetHandle, targetHandle.width / 2, targetHandle.height / 2)
verify(targetHandle.SplitHandle.hovered)
// Move the mouse to the MouseArea on the left. The handle should no longer be hovered.
mouseMove(control, 100, control.height / 2)
verify(!targetHandle.SplitHandle.hovered)
// Move the mouse back over the handle.
mouseMove(targetHandle, targetHandle.width / 2, targetHandle.height / 2)
mouseMove(targetHandle, targetHandle.width / 2, targetHandle.height / 2)
verify(targetHandle.SplitHandle.hovered)
// Move the mouse to the MouseArea on the right. The handle should no longer be hovered.
mouseMove(control, control.width - 100, control.height / 2)
verify(!targetHandle.SplitHandle.hovered)
}
Component {
id: cppHandleSplitViewComponent
SplitView {
anchors.fill: parent
handle: ComponentCreator.createComponent(`
import QtQuick
Rectangle {
objectName: "handle"
implicitWidth: 10
implicitHeight: 10
color: "tomato"
}`)
Rectangle {
objectName: "navajowhite"
color: objectName
implicitWidth: 100
implicitHeight: 100
}
Rectangle {
objectName: "steelblue"
color: objectName
implicitWidth: 200
implicitHeight: 200
}
}
}
function test_handleComponentCreatedInCpp() {
let control = createTemporaryObject(cppHandleSplitViewComponent, testCase)
verify(control)
let handles = findHandles(control)
compare(handles.length, 1)
compare(handles[0].color, Qt.color("tomato"))
}
function test_touch() {
let control = createTemporaryObject(threeSizedItemsComponent, testCase)
verify(control)
let touch = touchEvent(control)
let handles = findHandles(control)
let firstHandle = handles[0]
let handleCenter = control.mapFromItem(firstHandle, firstHandle.width / 2, firstHandle.height / 2)
touch.press(0, control, handleCenter.x, handleCenter.y).commit()
verify(firstHandle.SplitHandle.pressed)
touch.move(0, control, handleCenter.x + 100, handleCenter.y).commit()
verify(firstHandle.SplitHandle.pressed)
let firstItem = control.itemAt(0)
compare(firstItem.width, 125)
touch.release(0, control, handleCenter.x + 100, handleCenter.y).commit()
verify(!firstHandle.SplitHandle.pressed)
compare(firstItem.width, 125)
}
Component {
id: hiddenItemComponent
SplitView {
anchors.fill: parent
handle: handleComponent
orientation: Qt.Horizontal
component SplitItem: Rectangle {
objectName: labelText
SplitView.preferredWidth: 50
SplitView.fillHeight: true
required property string labelText
Text {
anchors.fill: parent
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: `${parent.labelText} - width: ${parent.width.toFixed(2)}`
}
}
SplitItem {
color: "blue"
labelText: "View 1"
}
SplitItem {
color: "red"
labelText: "View 2 (hidden)"
visible: false
}
SplitItem {
color: "purple"
labelText: "View 3"
}
SplitItem {
color: "yellow"
labelText: "View 4"
}
}
}
function test_resizeHiddenItem() {
let control = createTemporaryObject(hiddenItemComponent, testCase)
verify(control)
const standardItemWidth = 50
let expectedGeometries = [
// First item.
{ x: 0, y: 0, width: standardItemWidth, height: control.height },
// First handle.
{ x: standardItemWidth, y: 0, width: defaultHorizontalHandleWidth, height: control.height },
// The second item and its handle are hidden.
{ hidden: true },
{ hidden: true },
// Third item.
{ x: standardItemWidth + defaultHorizontalHandleWidth, y: 0, width: standardItemWidth, height: control.height },
// Third handle.
{ x: (standardItemWidth * 2) + defaultHorizontalHandleWidth, y: 0, width: defaultHorizontalHandleWidth, height: control.height },
// Fourth item.
{ x: (standardItemWidth * 2) + (defaultHorizontalHandleWidth * 2), y: 0,
width: control.width - (standardItemWidth * 2) - (defaultHorizontalHandleWidth * 2), height: control.height }
]
compareSizes(control, expectedGeometries, "before dragging handle")
// Drag the third handle to the right.
let handles = findHandles(control)
let thirdHandle = handles[2]
// The third (index 4 here) item should get one pixel bigger, and the fourth one pixel smaller.
++expectedGeometries[4].width
++expectedGeometries[5].x // handle
++expectedGeometries[6].x
--expectedGeometries[6].width
// Use individual events rather than mouseDrag because that will move it past the drag threshold,
// which we don't want, since we only want to move by 1 pixel.
mousePress(thirdHandle)
mouseMove(thirdHandle, thirdHandle.width / 2 + 1, thirdHandle.height / 2, 16)
mouseRelease(thirdHandle)
compareSizes(control, expectedGeometries, "after dragging handle")
}
}