blob: d90d19bcafd3f6c5fac868de3e088d4a456ea835 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.2
import QtTest 1.0
import QtQuick.Layouts 1.3
Item {
id: container
width: 200
height: 200
TestCase {
id: testCase
name: "Tests_StackLayout"
when: windowShown
width: 200
height: 200
function geometry(item) {
return [item.x, item.y, item.width, item.height]
}
Component {
id: countGeometryChanges_Component
StackLayout {
id: stack
property alias col: _col
property alias row: _row
width: 100
ColumnLayout {
id: _col
property alias r1: _r1
property alias r2: _r2
property alias r3: _r3
spacing: 0
property int counter : 0
onWidthChanged: { ++counter; }
Rectangle {
id: _r1
implicitWidth: 20
implicitHeight: 20
Layout.fillWidth: true
property int counter : 0
onWidthChanged: { ++counter; }
}
Rectangle {
id: _r2
implicitWidth: 50
implicitHeight: 50
Layout.fillWidth: true
property int counter : 0
onWidthChanged: { ++counter; }
}
Rectangle {
id: _r3
implicitWidth: 40
implicitHeight: 40
Layout.fillWidth: true
property int counter : 0
onWidthChanged: { ++counter; }
}
}
RowLayout {
id: _row
property alias r5: _r5
spacing: 0
property int counter : 0
onWidthChanged: { ++counter; }
Rectangle {
id: _r5
implicitWidth: 100
implicitHeight: 100
Layout.fillWidth: true
property int counter : 0
onWidthChanged: { ++counter; }
}
}
}
}
function test_countGeometryChanges() {
var stack = countGeometryChanges_Component.createObject(container)
compare(stack.currentIndex, 0)
compare(stack.col.width, 100)
compare(stack.col.height, 110)
compare(stack.row.width, 100)
compare(stack.row.height, 100)
verify(stack.col.r1.counter <= 2)
compare(stack.col.r2.counter, 1)
verify(stack.col.r3.counter <= 2)
verify(stack.col.counter <= 2)
compare(stack.row.counter, 1) // not visible, will only receive the initial geometry change
compare(stack.row.r5.counter, 0)
stack.destroy()
}
Component {
id: layoutItem_Component
Rectangle {
implicitWidth: 20
implicitHeight: 20
}
}
Component {
id: emtpy_StackLayout_Component
StackLayout {
property int num_onCountChanged: 0
property int num_onCurrentIndexChanged: 0
onCountChanged: { ++num_onCountChanged; }
onCurrentIndexChanged: { ++num_onCurrentIndexChanged; }
}
}
function test_addAndRemoveItems()
{
var stack = emtpy_StackLayout_Component.createObject(container)
stack.currentIndex = 2
compare(stack.implicitWidth, 0)
compare(stack.implicitHeight, 0)
var rect0 = layoutItem_Component.createObject(stack)
compare(stack.implicitWidth, 20)
compare(stack.implicitHeight, 20)
compare(rect0.visible, false)
var rect1 = layoutItem_Component.createObject(stack)
rect1.Layout.preferredWidth = 30
rect1.Layout.preferredHeight = 10
compare(stack.implicitWidth, 30)
compare(stack.implicitHeight, 20)
compare(rect0.visible, false)
compare(rect1.visible, false)
var rect2 = layoutItem_Component.createObject(stack)
rect2.x = 42 // ### items in a stacklayout will have their x and y positions discarded.
rect2.y = 42
rect2.Layout.preferredWidth = 80
rect2.Layout.preferredHeight = 30
rect2.Layout.fillWidth = true
compare(stack.implicitWidth, 80)
compare(stack.implicitHeight, 30)
compare(rect0.visible, false)
compare(rect1.visible, false)
compare(rect2.visible, true)
compare(geometry(rect2), geometry(stack))
rect2.destroy()
wait(0) // this will hopefully effectuate the destruction of the object
compare(stack.implicitWidth, 30)
compare(stack.implicitHeight, 20)
rect0.destroy()
wait(0)
compare(stack.implicitWidth, 30)
compare(stack.implicitHeight, 10)
rect1.destroy()
wait(0)
compare(stack.implicitWidth, 0)
compare(stack.implicitHeight, 0)
stack.destroy()
}
function test_sizeHint_data() {
return [
{ tag: "propagateNone", layoutHints: [10, 20, 30], childHints: [11, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
{ tag: "propagateMinimumWidth", layoutHints: [-1, 20, 30], childHints: [10, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
{ tag: "propagatePreferredWidth", layoutHints: [10, -1, 30], childHints: [11, 20, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
{ tag: "propagateMaximumWidth", layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
{ tag: "propagateAll", layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
{ tag: "propagateCrazy", layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, Number.POSITIVE_INFINITY]},
{ tag: "expandMinToExplicitPref", layoutHints: [-1, 1, -1], childHints: [11, 21, 31], expected:[ 1, 1, Number.POSITIVE_INFINITY]},
{ tag: "expandMaxToExplicitPref", layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, Number.POSITIVE_INFINITY]},
{ tag: "expandAllToExplicitMin", layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, Number.POSITIVE_INFINITY]},
{ tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, Number.POSITIVE_INFINITY]},
{ tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, Number.POSITIVE_INFINITY]},
{ tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, Number.POSITIVE_INFINITY]},
];
}
function itemSizeHints(item) {
return [item.Layout.minimumWidth, item.implicitWidth, item.Layout.maximumWidth]
}
Component {
id: stacklayout_sizeHint_Component
StackLayout {
property int implicitWidthChangedCount : 0
onImplicitWidthChanged: { ++implicitWidthChangedCount }
ColumnLayout {
Rectangle {
id: r1
color: "red"
Layout.minimumWidth: 1
Layout.preferredWidth: 2
Layout.maximumWidth: 3
Layout.minimumHeight: 20
Layout.preferredHeight: 20
Layout.maximumHeight: 20
Layout.fillWidth: true
}
}
}
}
function test_sizeHint(data) {
var layout = stacklayout_sizeHint_Component.createObject(container)
var col = layout.children[0]
col.Layout.minimumWidth = data.layoutHints[0]
col.Layout.preferredWidth = data.layoutHints[1]
col.Layout.maximumWidth = data.layoutHints[2]
var child = col.children[0]
if (data.implicitWidth !== undefined) {
child.implicitWidth = data.implicitWidth
}
child.Layout.minimumWidth = data.childHints[0]
child.Layout.preferredWidth = data.childHints[1]
child.Layout.maximumWidth = data.childHints[2]
var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(effectiveSizeHintResult, data.expected)
layout.destroy()
}
Component {
id: stacklayout_addIgnoredItem_Component
StackLayout {
Repeater {
id: rep
model: 1
Rectangle {
id: r
}
}
}
}
// Items with no size information is ignored.
function test_addIgnoredItem()
{
var stack = stacklayout_addIgnoredItem_Component.createObject(container)
compare(stack.count, 1)
compare(stack.implicitWidth, 0)
compare(stack.implicitHeight, 0)
var r = stack.children[0]
r.Layout.preferredWidth = 20
r.Layout.preferredHeight = 30
compare(stack.count, 1)
compare(stack.implicitWidth, 20)
compare(stack.implicitHeight, 30)
stack.destroy();
}
function test_dontCrashWhenAnchoredToAWindow() {
var test_layoutStr =
'import QtQuick 2.2; \
import QtQuick.Window 2.1; \
import QtQuick.Layouts 1.3; \
Window { \
visible: true; \
width: stack.implicitWidth; \
height: stack.implicitHeight; \
StackLayout { \
id: stack; \
currentIndex: 0; \
anchors.fill: parent; \
Rectangle { \
color: "red"; \
implicitWidth: 300; \
implicitHeight: 200; \
} \
} \
} '
var lay = Qt.createQmlObject(test_layoutStr, container, '');
tryCompare(lay, 'width', 300);
lay.destroy()
}
Component {
id: test_dontCrashWhenChildIsResizedToNull_Component
StackLayout {
property alias rect : _rect
Rectangle {
id: _rect;
color: "red"
implicitWidth: 200
implicitHeight: 200
}
}
}
function test_dontCrashWhenChildIsResizedToNull() {
var layout = test_dontCrashWhenChildIsResizedToNull_Component.createObject(container)
layout.rect.width = 0
layout.width = 222 // trigger a rearrange with a valid size
layout.height = 222
}
Component {
id: test_currentIndex_Component
StackLayout {
currentIndex: 1
Text {
text: "0"
}
Text {
text: "1"
}
}
}
function test_currentIndex() {
var layout = test_currentIndex_Component.createObject(container)
var c0 = layout.children[0]
var c1 = layout.children[1]
compare(layout.currentIndex, 1)
tryCompare(layout, 'visible', true)
compare(c0.visible, false)
compare(c1.visible, true)
layout.currentIndex = 0
compare(c0.visible, true)
compare(c1.visible, false)
var c2 = layoutItem_Component.createObject(layout)
compare(c2.visible, false)
/*
* destroy the current item and check if visibility advances to next
*/
c0.destroy()
tryCompare(c1, 'visible', true)
compare(c2.visible, false)
c1.destroy()
tryCompare(c2, 'visible', true)
c2.destroy()
tryCompare(layout, 'currentIndex', 0)
layout.destroy()
/*
* Test the default/implicit value of currentIndex, either -1 (if empty) or 0:
*/
layout = emtpy_StackLayout_Component.createObject(container)
tryCompare(layout, 'visible', true)
compare(layout.currentIndex, -1)
compare(layout.num_onCurrentIndexChanged, 0)
// make it non-empty
c0 = layoutItem_Component.createObject(layout)
compare(layout.currentIndex, 0)
compare(layout.num_onCurrentIndexChanged, 1)
compare(c0.visible, true)
// make it empty again
c0.destroy()
wait(0)
compare(layout.currentIndex, -1)
//tryCompare(layout, 'currentIndex', -1)
compare(layout.num_onCurrentIndexChanged, 2)
/*
* Check that explicit value doesn't change,
* and that no items are visible if the index is invalid/out of range
*/
layout.currentIndex = 2
compare(layout.currentIndex, 2)
compare(layout.num_onCurrentIndexChanged, 3)
c0 = layoutItem_Component.createObject(layout)
compare(layout.currentIndex, 2)
compare(c0.visible, false)
c1 = layoutItem_Component.createObject(layout)
compare(layout.currentIndex, 2)
compare(c0.visible, false)
compare(c1.visible, false)
c2 = layoutItem_Component.createObject(layout)
compare(layout.currentIndex, 2)
compare(c0.visible, false)
compare(c1.visible, false)
compare(c2.visible, true)
c2.destroy()
wait(0)
compare(layout.currentIndex, 2)
compare(c0.visible, false)
compare(c1.visible, false)
c1.destroy()
wait(0)
compare(layout.currentIndex, 2)
compare(c0.visible, false)
c0.destroy()
wait(0)
compare(layout.currentIndex, 2)
compare(layout.num_onCurrentIndexChanged, 3)
}
function test_count() {
var layout = emtpy_StackLayout_Component.createObject(container)
tryCompare(layout, 'visible', true)
compare(layout.count, 0)
compare(layout.currentIndex, -1)
compare(layout.num_onCountChanged, 0)
compare(layout.num_onCurrentIndexChanged, 0)
var c0 = layoutItem_Component.createObject(layout)
compare(layout.count, 1)
compare(layout.currentIndex, 0)
compare(layout.num_onCurrentIndexChanged, 1)
compare(layout.num_onCountChanged, 1)
}
}
}