aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quickcontrols
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quickcontrols')
-rw-r--r--tests/auto/quickcontrols/CMakeLists.txt7
-rw-r--r--tests/auto/quickcontrols/controls/basic/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/controls/data/combobox/shader.frag19
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml2
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_button.qml17
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_buttongroup.qml6
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_checkbox.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_combobox.qml42
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_control.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_delaybutton.qml6
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_radiobutton.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_splitview.qml99
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml27
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_swipeview.qml2
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_switch.qml12
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml12
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_tumbler.qml158
-rw-r--r--tests/auto/quickcontrols/controls/fusion/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/controls/imagine/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/controls/ios/CMakeLists.txt2
-rw-r--r--tests/auto/quickcontrols/controls/macos/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/controls/material/CMakeLists.txt5
-rw-r--r--tests/auto/quickcontrols/controls/shared.cmake12
-rw-r--r--tests/auto/quickcontrols/controls/universal/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/controls/windows/CMakeLists.txt3
-rw-r--r--tests/auto/quickcontrols/focus/tst_focus.cpp7
-rw-r--r--tests/auto/quickcontrols/palette/data/comboBoxPopupWithApplicationWindow.qml32
-rw-r--r--tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml17
-rw-r--r--tests/auto/quickcontrols/palette/data/comboBoxPopupWithWindow.qml33
-rw-r--r--tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml19
-rw-r--r--tests/auto/quickcontrols/palette/tst_palette.cpp125
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml1
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml21
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp19
-rw-r--r--tests/auto/quickcontrols/qquickcontainer/CMakeLists.txt39
-rw-r--r--tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithListView.qml58
-rw-r--r--tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithRepeater.qml58
-rw-r--r--tests/auto/quickcontrols/qquickcontainer/tst_qquickcontainer.cpp107
-rw-r--r--tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp3
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/mnemonics.qml17
-rw-r--r--tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp240
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp16
-rw-r--r--tests/auto/quickcontrols/qquickpopup/BLACKLIST5
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml27
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml28
-rw-r--r--tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp129
-rw-r--r--tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp10
47 files changed, 1280 insertions, 189 deletions
diff --git a/tests/auto/quickcontrols/CMakeLists.txt b/tests/auto/quickcontrols/CMakeLists.txt
index f4f2e6b2c6..b7669d4f54 100644
--- a/tests/auto/quickcontrols/CMakeLists.txt
+++ b/tests/auto/quickcontrols/CMakeLists.txt
@@ -24,13 +24,16 @@ add_subdirectory(pressandhold)
add_subdirectory(qquickapplicationwindow)
add_subdirectory(qquickcontrol)
add_subdirectory(qquickcolor)
+add_subdirectory(qquickcontainer)
add_subdirectory(qquickdrawer)
add_subdirectory(qquickheaderview)
add_subdirectory(qquickiconimage)
add_subdirectory(qquickiconlabel)
add_subdirectory(qquickimaginestyle)
-add_subdirectory(qquickmaterialstyle)
-add_subdirectory(qquickmaterialstyleconf)
+if (QT_FEATURE_quickcontrols2_material)
+ add_subdirectory(qquickmaterialstyle)
+ add_subdirectory(qquickmaterialstyleconf)
+endif()
add_subdirectory(qquickmenu)
add_subdirectory(qquickmenubar)
add_subdirectory(qquickninepatchimage)
diff --git a/tests/auto/quickcontrols/controls/basic/CMakeLists.txt b/tests/auto/quickcontrols/controls/basic/CMakeLists.txt
index dabab76bbe..74bbf2954e 100644
--- a/tests/auto/quickcontrols/controls/basic/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/basic/CMakeLists.txt
@@ -43,6 +43,9 @@ set_source_files_properties(${test_data}
HEADER_FILE_ONLY ON
)
+set(test_target tst_basic)
+include(../shared.cmake)
+
#### Keys ignored in scope 1:.:.:basic.pro:<TRUE>:
# OTHER_FILES = "$$PWD/../data/*.qml"
# TEMPLATE = "app"
diff --git a/tests/auto/quickcontrols/controls/data/combobox/shader.frag b/tests/auto/quickcontrols/controls/data/combobox/shader.frag
new file mode 100644
index 0000000000..fbbef218e6
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/data/combobox/shader.frag
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+layout(binding = 1) uniform sampler2D source; // this item
+
+layout(std140, binding = 0) uniform buf {
+ float qt_Opacity; // inherited opacity of this item
+};
+
+
+void main() {
+ vec4 p = texture(source, qt_TexCoord0);
+ lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
+ fragColor = vec4(g, g, g, p.a) * qt_Opacity;
+}
diff --git a/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml b/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
index 4560c93dea..296aa2c507 100644
--- a/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
@@ -858,7 +858,7 @@ TestCase {
// Ensure that clicked is emitted when no handler is defined for the pressAndHold() signal.
// Note that even though signal spies aren't considered in QObject::isSignalConnected(),
// we can't use one here to check for pressAndHold(), because otherwise clicked() won't be emitted.
- wait(Qt.styleHints.mousePressAndHoldInterval + 100)
+ wait(Application.styleHints.mousePressAndHoldInterval + 100)
mouseRelease(control)
compare(clickedSpy.count, 1)
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_button.qml b/tests/auto/quickcontrols/controls/data/tst_button.qml
index 8720b55eff..4ca8ebfd6d 100644
--- a/tests/auto/quickcontrols/controls/data/tst_button.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_button.qml
@@ -4,6 +4,7 @@
import QtQuick
import QtTest
import QtQuick.Controls
+import Qt.test.controls
TestCase {
id: testCase
@@ -448,12 +449,20 @@ TestCase {
verify(!textLabel)
compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, false))
+ }
break;
case Button.TextOnly:
verify(!iconImage)
verify(textLabel)
compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, false))
+ compare(control.rightPadding, Material.buttonRightPadding(false, false, true))
+ }
break;
case Button.TextUnderIcon:
verify(iconImage)
@@ -461,6 +470,10 @@ TestCase {
compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
verify(iconImage.y < textLabel.y)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, true))
+ }
break;
case Button.TextBesideIcon:
verify(iconImage)
@@ -471,6 +484,10 @@ TestCase {
verify(iconImage.x < textLabel.x)
compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, true))
+ }
break;
}
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_buttongroup.qml b/tests/auto/quickcontrols/controls/data/tst_buttongroup.qml
index ef97405234..bec2d8ca88 100644
--- a/tests/auto/quickcontrols/controls/data/tst_buttongroup.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_buttongroup.qml
@@ -304,7 +304,9 @@ TestCase {
id: repeater
Column {
id: column
- property ButtonGroup group: ButtonGroup { buttons: column.children }
+ property ButtonGroup group: ButtonGroup {
+ buttons: column.children.filter((child) => child !== r)
+ }
property alias repeater: r
Repeater {
id: r
@@ -392,7 +394,7 @@ TestCase {
id: checkedButtonColumn
Column {
id: column
- ButtonGroup { buttons: column.children }
+ ButtonGroup { buttons: column.children.filter((child) => child !== repeater) }
Repeater {
id: repeater
delegate: Button {
diff --git a/tests/auto/quickcontrols/controls/data/tst_checkbox.qml b/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
index 7d80484123..7a8e563131 100644
--- a/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
@@ -201,7 +201,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -220,7 +220,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_combobox.qml b/tests/auto/quickcontrols/controls/data/tst_combobox.qml
index 8e671a38a6..0cc4de4d0c 100644
--- a/tests/auto/quickcontrols/controls/data/tst_combobox.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_combobox.qml
@@ -74,16 +74,7 @@ TestCase {
objectName: "ShaderFX"
width: rect.width
height: rect.height
- fragmentShader: "
- uniform lowp sampler2D source; // this item
- uniform lowp float qt_Opacity; // inherited opacity of this item
- varying highp vec2 qt_TexCoord0;
- void main() {
- lowp vec4 p = texture2D(source, qt_TexCoord0);
- lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
- gl_FragColor = vec4(g, g, g, p.a) * qt_Opacity;
- }"
-
+ fragmentShader: "qrc:/data/combobox/shader.frag.qsb"
}
}
}
@@ -1956,7 +1947,7 @@ TestCase {
// and then that ComboBox loses focus, its currentIndex should change
// to the index of the edit text (assuming a match is found).
function test_currentIndexChangeOnLostFocus() {
- if (Qt.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
+ if (Application.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
skip("This platform only allows tab focus for text controls")
let theModel = []
@@ -2004,11 +1995,16 @@ TestCase {
compare(currentIndexSpy.count, 1)
}
+ readonly property font testFont: ({
+ family: "Arial",
+ pixelSize: 12
+ })
+
Component {
- id: appFontTextFieldComponent
+ id: fixedFontTextFieldComponent
TextField {
objectName: "appFontTextField"
- font: Qt.application.font
+ font: testCase.testFont
// We don't want the background's implicit width to interfere with our tests,
// which are about implicit width of the contentItem of ComboBox, which is by default TextField.
background: null
@@ -2016,14 +2012,14 @@ TestCase {
}
Component {
- id: appFontContentItemComboBoxComponent
+ id: fixedFontContentItemComboBoxComponent
ComboBox {
// Override the contentItem so that the font doesn't vary between styles.
contentItem: TextField {
objectName: "appFontContentItemTextField"
// We do this just to be extra sure that the font never comes from the control,
- // as we want it to match that of the TextField in the appFontTextFieldComponent.
- font: Qt.application.font
+ // as we want it to match that of the TextField in the fixedFontTextFieldComponent.
+ font: testCase.testFont
background: null
}
}
@@ -2077,14 +2073,14 @@ TestCase {
function test_implicitContentWidthPolicy_ContentItemImplicitWidth() {
// Set ContentItemImplicitWidth and ensure that implicitContentWidth is as wide as the current item
// by comparing it against the implicitWidth of an identical TextField
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: ["Short", "Kinda long"],
implicitContentWidthPolicy: ComboBox.ContentItemImplicitWidth
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.ContentItemImplicitWidth)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
// Don't set any text on textField because we're not accounting for the widest
// text here, so we want to compare it against an empty TextField.
@@ -2103,14 +2099,14 @@ TestCase {
}
function test_implicitContentWidthPolicy_WidestText(data) {
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: data.model,
implicitContentWidthPolicy: ComboBox.WidestText
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.WidestText)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
textField.text = "Kinda long"
// Note that we don't need to change the current index here, as the implicitContentWidth
@@ -2137,7 +2133,7 @@ TestCase {
// Changes in font should result in the implicitContentWidth being updated.
textField.font.pixelSize *= 2
// We have to change the contentItem's font size manually since we break the
- // style's binding to the control's font when we set Qt.application.font to it.
+ // style's binding to the control's font when we set the fixed font on it.
control.contentItem.font.pixelSize *= 2
control.font.pixelSize *= 2
compare(Math.ceil(control.implicitContentWidth), Math.ceil(textField.implicitWidth))
@@ -2148,14 +2144,14 @@ TestCase {
}
function test_implicitContentWidthPolicy_WidestTextWhenCompleted(data) {
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: data.model,
implicitContentWidthPolicy: ComboBox.WidestTextWhenCompleted
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.WidestTextWhenCompleted)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
textField.text = "Kinda long"
compare(Math.ceil(control.implicitContentWidth), Math.ceil(textField.implicitWidth))
diff --git a/tests/auto/quickcontrols/controls/data/tst_control.qml b/tests/auto/quickcontrols/controls/data/tst_control.qml
index 4a2bc33b33..5c5e557f11 100644
--- a/tests/auto/quickcontrols/controls/data/tst_control.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_control.qml
@@ -1064,7 +1064,7 @@ TestCase {
verify(control)
compare(control.hovered, false)
- compare(control.hoverEnabled, Qt.styleHints.useHoverEffects)
+ compare(control.hoverEnabled, Application.styleHints.useHoverEffects)
control.hoverEnabled = false
@@ -1098,7 +1098,7 @@ TestCase {
function test_hoverEnabled() {
let control = createTemporaryObject(component, testCase)
- compare(control.hoverEnabled, Qt.styleHints.useHoverEffects)
+ compare(control.hoverEnabled, Application.styleHints.useHoverEffects)
let child = component.createObject(control)
let grandChild = component.createObject(child)
diff --git a/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml b/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
index 27145cd2ab..82d4f56495 100644
--- a/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
@@ -172,7 +172,7 @@ TestCase {
"pressed",
"activated"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
tryVerify(function() { return sequenceSpy.success})
@@ -190,7 +190,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -208,7 +208,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml b/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
index 08caac977d..47cbc7b72b 100644
--- a/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
@@ -154,7 +154,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -169,7 +169,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_splitview.qml b/tests/auto/quickcontrols/controls/data/tst_splitview.qml
index e835a8440f..a2054000b6 100644
--- a/tests/auto/quickcontrols/controls/data/tst_splitview.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_splitview.qml
@@ -74,20 +74,19 @@ TestCase {
// 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 + " at index " + typeSpecificIndex + context)
+ + itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.y, expectedGeometry.y, "Mismatch in actual vs expected y value of "
- + itemType + " at index " + typeSpecificIndex + context)
+ + itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.width, expectedGeometry.width, "Mismatch in actual vs expected width value of "
- + itemType + " at index " + typeSpecificIndex + context)
+ + itemType + " " + item + " at index " + typeSpecificIndex + context)
compare(item.height, expectedGeometry.height, "Mismatch in actual vs expected height value of "
- + itemType + " at index " + typeSpecificIndex + context)
+ + itemType + " " + item + " at index " + typeSpecificIndex + context)
}
}
property real defaultHorizontalHandleWidth: 10
property real defaultVerticalHandleHeight: 10
-
Component {
id: signalSpyComponent
SignalSpy {}
@@ -96,14 +95,14 @@ TestCase {
Component {
id: handleComponent
Rectangle {
- objectName: "handle"
+ objectName: `handle ${x},${y} ${width}x${height} visible: ${visible}`
implicitWidth: defaultHorizontalHandleWidth
implicitHeight: defaultVerticalHandleHeight
color: "#444"
Text {
- objectName: "handleText_" + text
- text: parent.x + "," + parent.y + " " + parent.width + "x" + parent.height
+ objectName: text + "_Text"
+ text: parent.objectName
color: "white"
anchors.centerIn: parent
rotation: 90
@@ -2672,4 +2671,88 @@ TestCase {
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")
+ }
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml b/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
index 8d57e37575..ddbd283c87 100644
--- a/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
@@ -14,7 +14,7 @@ TestCase {
when: windowShown
name: "SwipeDelegate"
- readonly property int dragDistance: Math.max(20, Qt.styleHints.startDragDistance + 5)
+ readonly property int dragDistance: Math.max(20, Application.styleHints.startDragDistance + 5)
Component {
id: backgroundFillComponent
@@ -655,6 +655,20 @@ TestCase {
width: 100
height: 120
+ property int rotation: 0
+
+ transform: [
+ Rotation {
+ angle: rotation
+ origin.x: 0
+ origin.y: 0
+ },
+ Translate {
+ x: (rotation === 90) ? parent.width : 0
+ y: 0
+ }
+ ]
+
model: ListModel {
ListElement { name: "Apple" }
ListElement { name: "Orange" }
@@ -712,15 +726,20 @@ TestCase {
function test_removableDelegates_data() {
return [
{ tag: "mouse", touch: false },
- { tag: "touch", touch: true }
+ { tag: "touch", touch: true },
+ { tag: "mouse_rotation_90", touch: false, rotation: 90 },
+ { tag: "touch_rotation_90", touch: true, rotation: 90 },
]
}
- function test_removableDelegates() {
- var listView = createTemporaryObject(removableDelegatesComponent, testCase);
+ function test_removableDelegates(data) {
+ let listView = createTemporaryObject(removableDelegatesComponent, testCase);
verify(listView);
compare(listView.count, 3);
+ if (data.rotation)
+ listView.rotation = data.rotation;
+
let touch = data.touch ? touchEvent(listView) : null
// Expose the remove button.
diff --git a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
index 0c69e26f12..694741ce45 100644
--- a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
@@ -561,7 +561,7 @@ TestCase {
}
function test_focus() {
- if (Qt.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
+ if (Application.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
skip("This platform only allows tab focus for text controls")
var control = createTemporaryObject(focusSwipeViewComponent, testCase)
diff --git a/tests/auto/quickcontrols/controls/data/tst_switch.qml b/tests/auto/quickcontrols/controls/data/tst_switch.qml
index 407513b914..8d6160cef1 100644
--- a/tests/auto/quickcontrols/controls/data/tst_switch.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_switch.qml
@@ -210,7 +210,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -227,7 +227,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -246,7 +246,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -265,7 +265,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -426,7 +426,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -462,7 +462,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width - 1).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml b/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
index 42d58b9668..570e89a531 100644
--- a/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
@@ -201,7 +201,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -218,7 +218,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -237,7 +237,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -256,7 +256,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -417,7 +417,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -453,7 +453,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width - 1).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/quickcontrols/controls/data/tst_tumbler.qml b/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
index 0bbade9c43..0491ab039e 100644
--- a/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
@@ -1149,25 +1149,46 @@ TestCase {
}
}
- function test_setCurrentIndexOnImperativeModelChange() {
- var tumbler = createTemporaryObject(setCurrentIndexOnImperativeModelChangeComponent, testCase);
- verify(tumbler);
+ function test_setCurrentIndexOnImperativeModelChange_data() {
+ return [
+ { tag: "default wrap", setWrap: false, initialWrap: false, newWrap: true },
+ { tag: "wrap=false", setWrap: true, initialWrap: false, newWrap: false },
+ { tag: "wrap=true", setWrap: true, initialWrap: true, newWrap: true },
+ ]
+ }
- tumbler.model = 4
- compare(tumbler.count, 4);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 4);
+ function test_setCurrentIndexOnImperativeModelChange(data) {
+ let tumbler = createTemporaryObject(setCurrentIndexOnImperativeModelChangeComponent, testCase,
+ data.setWrap ? {wrap: data.initialWrap} : {})
+ verify(tumbler)
- // 4 - 2 = 2
- compare(tumbler.currentIndex, 2);
+ let model = 4
+ let expectedCurrentIndex = model - 2
- ++tumbler.model;
- compare(tumbler.count, 5);
- compare(tumbler.wrap, true);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 5);
- // 5 - 2 = 3
- compare(tumbler.currentIndex, 3);
+ tumbler.model = model
+
+ compare(tumbler.count, model)
+ compare(tumbler.wrap, data.initialWrap)
+ compare(tumbler.currentIndex, expectedCurrentIndex)
+
+ let tumblerView = findView(tumbler)
+ verify(tumblerView)
+ tryCompare(tumblerView, "count", model)
+ tryCompare(tumblerView, "currentIndex", expectedCurrentIndex)
+
+ model = 5
+ expectedCurrentIndex = model - 2
+
+ tumbler.model = model
+
+ compare(tumbler.count, model)
+ compare(tumbler.wrap, data.newWrap)
+ compare(tumbler.currentIndex, expectedCurrentIndex)
+
+ tumblerView = findView(tumbler)
+ verify(tumblerView)
+ tryCompare(tumblerView, "count", model)
+ tryCompare(tumblerView, "currentIndex", expectedCurrentIndex)
}
Component {
@@ -1176,35 +1197,59 @@ TestCase {
Item {
property alias tumbler: tumbler
- property int setting: 4
+ required property int modelValue
+ property alias tumblerWrap: tumbler.wrap
Tumbler {
id: tumbler
- model: setting
+ model: modelValue
onModelChanged: currentIndex = model - 2
}
}
}
- function test_setCurrentIndexOnDeclarativeModelChange() {
- var root = createTemporaryObject(setCurrentIndexOnDeclarativeModelChangeComponent, testCase);
- verify(root);
+ function test_setCurrentIndexOnDeclarativeModelChange_data() {
+ return [
+ { tag: "default wrap", setWrap: false, initialWrap: false, newWrap: true },
+ { tag: "wrap=false", setWrap: true, initialWrap: false, newWrap: false },
+ { tag: "wrap=true", setWrap: true, initialWrap: true, newWrap: true },
+ ]
+ }
- var tumbler = root.tumbler;
- compare(tumbler.count, 4);
- compare(tumbler.wrap, false);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 4);
- // 4 - 2 = 2
- compare(tumbler.currentIndex, 2);
+ function test_setCurrentIndexOnDeclarativeModelChange(data) {
+ let model = 4
+ let expectedCurrentIndex = model - 2
- ++root.setting;
- compare(tumbler.count, 5);
- compare(tumbler.wrap, true);
- tumblerView = findView(tumbler);
- tryCompare(tumblerView, "count", 5);
- // 5 - 2 = 3
- compare(tumbler.currentIndex, 3);
+ let root = createTemporaryObject(setCurrentIndexOnDeclarativeModelChangeComponent, testCase,
+ data.setWrap ? {modelValue: model, tumblerWrap: data.initialWrap}
+ : {modelValue: model})
+ verify(root)
+
+ let tumbler = root.tumbler
+ verify(tumbler)
+
+ compare(tumbler.count, model)
+ compare(tumbler.wrap, data.initialWrap)
+ compare(tumbler.currentIndex, expectedCurrentIndex)
+
+ let tumberView = findView(tumbler)
+ verify(tumbler)
+ tryCompare(tumberView, "count", model)
+ tryCompare(tumberView, "currentIndex", expectedCurrentIndex)
+
+ model = 5
+ expectedCurrentIndex = model - 2
+
+ root.modelValue = model
+
+ compare(tumbler.count, model)
+ compare(tumbler.wrap, data.newWrap)
+ compare(tumbler.currentIndex, expectedCurrentIndex)
+
+ tumberView = findView(tumbler)
+ verify(tumbler)
+ tryCompare(tumberView, "count", model)
+ tryCompare(tumberView, "currentIndex", expectedCurrentIndex)
}
function test_displacementAfterResizing() {
@@ -1237,15 +1282,46 @@ TestCase {
height: 200
delegate: Text {text: modelData}
model: 10
- currentIndex: 4
+ currentIndex: 1
}
}
+ //QTBUG-127315
+ Component {
+ id: initialCurrentIndexTumblerNoDelegate
- function test_initialCurrentIndex() {
- var tumbler = createTemporaryObject(initialCurrentIndexTumbler, testCase, {wrap: true});
- compare(tumbler.currentIndex, 4);
- tumbler = createTemporaryObject(initialCurrentIndexTumbler, testCase, {wrap: false});
- compare(tumbler.currentIndex, 4);
+ Tumbler {
+ anchors.centerIn: parent
+ width: 60
+ height: 200
+ model: 10
+ }
+ }
+
+ function test_initialCurrentIndex_data() {
+ return [
+ { tag: "delegate: true, wrap: true, currentIndex: 1",
+ component: initialCurrentIndexTumbler, wrap: true, currentIndex: 1 },
+ { tag: "delegate: true, wrap: false, currentIndex: 1",
+ component: initialCurrentIndexTumbler, wrap: false, currentIndex: 1 },
+ { tag: "delegate: false, wrap: true, currentIndex: 1",
+ component: initialCurrentIndexTumblerNoDelegate, wrap: true, currentIndex: 1 },
+ { tag: "delegate: false, wrap: false, currentIndex: 1",
+ component: initialCurrentIndexTumblerNoDelegate, wrap: false, currentIndex: 1 },
+ { tag: "delegate: true, wrap: true, currentIndex: 4",
+ component: initialCurrentIndexTumbler, wrap: true, currentIndex: 4 },
+ { tag: "delegate: true, wrap: false, currentIndex: 4",
+ component: initialCurrentIndexTumbler, wrap: false, currentIndex: 4 },
+ { tag: "delegate: false, wrap: true, currentIndex: 4",
+ component: initialCurrentIndexTumblerNoDelegate, wrap: true, currentIndex: 4 },
+ { tag: "delegate: false, wrap: false, currentIndex: 4",
+ component: initialCurrentIndexTumblerNoDelegate, wrap: false, currentIndex: 4 },
+ ]
+ }
+
+ function test_initialCurrentIndex(data) {
+ let tumbler = createTemporaryObject(data.component, testCase,
+ {wrap: data.wrap, currentIndex: data.currentIndex});
+ compare(tumbler.currentIndex, data.currentIndex);
}
// QTBUG-109995
diff --git a/tests/auto/quickcontrols/controls/fusion/CMakeLists.txt b/tests/auto/quickcontrols/controls/fusion/CMakeLists.txt
index 5495efd858..e3d38e1cf3 100644
--- a/tests/auto/quickcontrols/controls/fusion/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/fusion/CMakeLists.txt
@@ -43,6 +43,9 @@ set_source_files_properties(${test_data}
HEADER_FILE_ONLY ON
)
+set(test_target tst_fusion)
+include(../shared.cmake)
+
#### Keys ignored in scope 1:.:.:fusion.pro:<TRUE>:
# OTHER_FILES = "$$PWD/../data/*.qml"
# TEMPLATE = "app"
diff --git a/tests/auto/quickcontrols/controls/imagine/CMakeLists.txt b/tests/auto/quickcontrols/controls/imagine/CMakeLists.txt
index 6efb1a0a45..c296a5b1a4 100644
--- a/tests/auto/quickcontrols/controls/imagine/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/imagine/CMakeLists.txt
@@ -43,6 +43,9 @@ set_source_files_properties(${test_data}
HEADER_FILE_ONLY ON
)
+set(test_target tst_imagine)
+include(../shared.cmake)
+
#### Keys ignored in scope 1:.:.:imagine.pro:<TRUE>:
# OTHER_FILES = "$$PWD/../data/*.qml"
# TEMPLATE = "app"
diff --git a/tests/auto/quickcontrols/controls/ios/CMakeLists.txt b/tests/auto/quickcontrols/controls/ios/CMakeLists.txt
index fe6839990f..4e0cb72e68 100644
--- a/tests/auto/quickcontrols/controls/ios/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/ios/CMakeLists.txt
@@ -26,3 +26,5 @@ qt_internal_add_test(tst_ios
TESTDATA ${test_data}
)
+set(test_target tst_ios)
+include(../shared.cmake)
diff --git a/tests/auto/quickcontrols/controls/macos/CMakeLists.txt b/tests/auto/quickcontrols/controls/macos/CMakeLists.txt
index 04d186c63f..3202601316 100644
--- a/tests/auto/quickcontrols/controls/macos/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/macos/CMakeLists.txt
@@ -36,3 +36,6 @@ set_source_files_properties(${test_data}
PROPERTIES
HEADER_FILE_ONLY ON
)
+
+set(test_target tst_macos)
+include(../shared.cmake)
diff --git a/tests/auto/quickcontrols/controls/material/CMakeLists.txt b/tests/auto/quickcontrols/controls/material/CMakeLists.txt
index 3e87bf1609..506509c774 100644
--- a/tests/auto/quickcontrols/controls/material/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/material/CMakeLists.txt
@@ -6,7 +6,7 @@
if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16)
project(tst_material LANGUAGES C CXX ASM)
- find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS ShaderTools STANDALONE_TEST)
endif()
#####################################################################
@@ -43,6 +43,9 @@ set_source_files_properties(${test_data}
HEADER_FILE_ONLY ON
)
+set(test_target tst_material)
+include(../shared.cmake)
+
#### Keys ignored in scope 1:.:.:material.pro:<TRUE>:
# OTHER_FILES = "$$PWD/../data/*.qml"
# TEMPLATE = "app"
diff --git a/tests/auto/quickcontrols/controls/shared.cmake b/tests/auto/quickcontrols/controls/shared.cmake
new file mode 100644
index 0000000000..ca62b88db6
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/shared.cmake
@@ -0,0 +1,12 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt6_add_shaders(${test_target} "${test_target}_shaders"
+ BATCHABLE
+ PREFIX
+ "/"
+ BASE
+ "../"
+ FILES
+ "../data/combobox/shader.frag"
+)
diff --git a/tests/auto/quickcontrols/controls/universal/CMakeLists.txt b/tests/auto/quickcontrols/controls/universal/CMakeLists.txt
index f0c7d2ed80..f39975ab15 100644
--- a/tests/auto/quickcontrols/controls/universal/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/universal/CMakeLists.txt
@@ -43,6 +43,9 @@ set_source_files_properties(${test_data}
HEADER_FILE_ONLY ON
)
+set(test_target tst_universal)
+include(../shared.cmake)
+
#### Keys ignored in scope 1:.:.:universal.pro:<TRUE>:
# OTHER_FILES = "$$PWD/../data/*.qml"
# TEMPLATE = "app"
diff --git a/tests/auto/quickcontrols/controls/windows/CMakeLists.txt b/tests/auto/quickcontrols/controls/windows/CMakeLists.txt
index a5ba30a51b..1d6ab1fc57 100644
--- a/tests/auto/quickcontrols/controls/windows/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/windows/CMakeLists.txt
@@ -36,3 +36,6 @@ set_source_files_properties(${test_data}
PROPERTIES
HEADER_FILE_ONLY ON
)
+
+set(test_target tst_windows)
+include(../shared.cmake)
diff --git a/tests/auto/quickcontrols/focus/tst_focus.cpp b/tests/auto/quickcontrols/focus/tst_focus.cpp
index ca70146885..78db22ffbc 100644
--- a/tests/auto/quickcontrols/focus/tst_focus.cpp
+++ b/tests/auto/quickcontrols/focus/tst_focus.cpp
@@ -29,6 +29,7 @@ public:
tst_focus();
private slots:
+ void init() override;
void initTestCase() override;
void navigation_data();
@@ -50,8 +51,14 @@ tst_focus::tst_focus()
{
}
+void tst_focus::init()
+{
+ QTest::failOnWarning(QRegularExpression(".?"));
+}
+
void tst_focus::initTestCase()
{
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickStyle::setStyle("Basic");
QQmlDataTest::initTestCase();
}
diff --git a/tests/auto/quickcontrols/palette/data/comboBoxPopupWithApplicationWindow.qml b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithApplicationWindow.qml
new file mode 100644
index 0000000000..436d3cdad6
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithApplicationWindow.qml
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias topLevelComboBox: topLevelComboBox
+ property alias popup: popup
+ property alias comboBoxInPopup: comboBoxInPopup
+
+ ComboBox {
+ id: topLevelComboBox
+ model: ["ONE", "TWO", "THREE"]
+ }
+
+ Popup {
+ id: popup
+ width: 200
+ height: 200
+ visible: true
+ palette.window: "red"
+
+ ComboBox {
+ id: comboBoxInPopup
+ model: ["ONE", "TWO", "THREE"]
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml
new file mode 100644
index 0000000000..592793fa3f
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias comboBox: comboBox
+
+ ComboBox {
+ id: comboBox
+ model: 1
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/data/comboBoxPopupWithWindow.qml b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithWindow.qml
new file mode 100644
index 0000000000..d806f30d01
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithWindow.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+
+Window {
+ width: 400
+ height: 400
+
+ property alias topLevelComboBox: topLevelComboBox
+ property alias popup: popup
+ property alias comboBoxInPopup: comboBoxInPopup
+
+ ComboBox {
+ id: topLevelComboBox
+ model: ["ONE", "TWO", "THREE"]
+ }
+
+ Popup {
+ id: popup
+ width: 200
+ height: 200
+ visible: true
+ palette.window: "red"
+
+ ComboBox {
+ id: comboBoxInPopup
+ model: ["ONE", "TWO", "THREE"]
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml b/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml
new file mode 100644
index 0000000000..3968c54cd0
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+
+ palette { toolTipBase: "white"; toolTipText: "black"}
+
+ Button {
+ objectName: "button"
+ text: qsTr("Button with Tooltip")
+
+ ToolTip.visible: false
+ ToolTip.text: qsTr("This is a tool tip.")
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/tst_palette.cpp b/tests/auto/quickcontrols/palette/tst_palette.cpp
index d8f4bfd804..621475b86e 100644
--- a/tests/auto/quickcontrols/palette/tst_palette.cpp
+++ b/tests/auto/quickcontrols/palette/tst_palette.cpp
@@ -7,17 +7,21 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
+#include <QtQuickTemplates2/private/qquicktooltip_p.h>
#include <QtQuickControls2/qquickstyle.h>
+using namespace QQuickVisualTestUtils;
using namespace QQuickControlsTestUtils;
// Need a more descriptive failure message: QTBUG-87039
@@ -55,6 +59,13 @@ private slots:
void resolve();
void updateBindingPalette();
+
+ void comboBoxPopup_data();
+ void comboBoxPopup();
+ void comboBoxPopupWithThemeDefault_data();
+ void comboBoxPopupWithThemeDefault();
+
+ void toolTipPaletteUpdate();
};
tst_palette::tst_palette()
@@ -485,6 +496,120 @@ void tst_palette::updateBindingPalette()
QCOMPARE(windowPalette->buttonText(), customPalette->buttonText());
}
+void tst_palette::comboBoxPopup_data()
+{
+ QTest::addColumn<QString>("style");
+ QTest::addColumn<QString>("qmlFilePath");
+
+ QTest::newRow("Window, Basic") << "Basic" << "comboBoxPopupWithWindow.qml";
+ QTest::newRow("ApplicationWindow, Basic") << "Basic" << "comboBoxPopupWithApplicationWindow.qml";
+ QTest::newRow("Window, Fusion") << "Fusion" << "comboBoxPopupWithWindow.qml";
+ QTest::newRow("ApplicationWindow, Fusion") << "Fusion" << "comboBoxPopupWithApplicationWindow.qml";
+}
+
+// Unlike regular popups, which should inherit their palette from the window and not the parent popup,
+// combo box popups should inherit their palette from the combo box itself.
+void tst_palette::comboBoxPopup()
+{
+ QFETCH(QString, style);
+ QFETCH(QString, qmlFilePath);
+
+ qmlClearTypeRegistrations();
+ QQuickStyle::setStyle(style);
+
+ QQuickApplicationHelper helper(this, qmlFilePath);
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ const auto *windowPalette = window->property("palette").value<QQuickPalette *>();
+ QVERIFY(windowPalette);
+
+ const auto *popup = window->property("popup").value<QQuickPopup *>();
+ QVERIFY(popup);
+ const auto *popupBackground = popup->background();
+ QCOMPARE(popupBackground->property("color"), QColorConstants::Red);
+ QCOMPARE(popupBackground->property("palette").value<QQuickPalette*>()->toQPalette().window().color(),
+ QColorConstants::Red);
+
+ // This has the default palette.
+ const auto *topLevelComboBox = window->property("topLevelComboBox").value<QQuickComboBox *>();
+ QVERIFY(topLevelComboBox);
+ const auto *topLevelComboBoxBackground = topLevelComboBox->popup()->background();
+ QCOMPARE_NE(topLevelComboBoxBackground->property("color"), QColorConstants::Red);
+ QCOMPARE_NE(topLevelComboBoxBackground->property("palette").value<QQuickPalette*>()->toQPalette().window().color(),
+ QColorConstants::Red);
+
+ // The popup that this combo box is in has its window role set to red,
+ // so the combo box's popup background should be red too.
+ const auto *comboBoxInPopup = window->property("comboBoxInPopup").value<QQuickComboBox *>();
+ QVERIFY(comboBoxInPopup);
+ const auto *comboBoxInPopupBackground = comboBoxInPopup->popup()->background();
+ QCOMPARE(comboBoxInPopupBackground->property("color"), QColorConstants::Red);
+ QCOMPARE(comboBoxInPopupBackground->property("palette").value<QQuickPalette*>()->toQPalette().window().color(),
+ QColorConstants::Red);
+}
+
+void tst_palette::comboBoxPopupWithThemeDefault_data()
+{
+ QTest::addColumn<QString>("style");
+ QTest::addColumn<QColor>("expectedComboBoxPopupBackgroundColor");
+
+ QTest::newRow("Basic") << "Basic" << QColor::fromRgb(0xFFFFFF);
+
+ // We can't test Fusion because it uses the default application palette,
+ // which is the default-constructed QPalette, so the test would always pass.
+}
+
+void tst_palette::comboBoxPopupWithThemeDefault()
+{
+ QFETCH(QString, style);
+ QFETCH(QColor, expectedComboBoxPopupBackgroundColor);
+
+ qmlClearTypeRegistrations();
+ QQuickStyle::setStyle(style);
+
+ QQuickApplicationHelper helper(this, "comboBoxPopupWithThemeDefault.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ const auto *comboBox = window->property("comboBox").value<QQuickComboBox *>();
+ QVERIFY(comboBox);
+ const auto *comboBoxBackground = comboBox->popup()->background();
+ QCOMPARE(comboBoxBackground->property("color"), expectedComboBoxPopupBackgroundColor);
+}
+
+void tst_palette::toolTipPaletteUpdate()
+{
+ QQuickApplicationHelper helper(this, "toolTipPaletteUpdate.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *button = window->findChild<QQuickButton *>("button");
+ QVERIFY(button);
+ auto *attachedToolTip = button->findChild<QQuickToolTipAttached *>();
+ QVERIFY(attachedToolTip);
+ auto *toolTip = attachedToolTip->toolTip();
+ QVERIFY(toolTip);
+
+ auto windowPalette = QQuickWindowPrivate::get(window)->palette();
+ auto toolTipPalette = QQuickPopupPrivate::get(toolTip)->palette();
+
+ QCOMPARE(toolTipPalette->toolTipBase(), windowPalette->toolTipBase());
+ QCOMPARE(toolTipPalette->toolTipText(), windowPalette->toolTipText());
+
+ windowPalette->setToolTipBase(Qt::blue);
+ windowPalette->setToolTipText(Qt::red);
+
+ QCOMPARE(toolTipPalette->toolTipBase(), windowPalette->toolTipBase());
+ QCOMPARE(toolTipPalette->toolTipText(), windowPalette->toolTipText());
+}
+
QTEST_MAIN(tst_palette)
#include "tst_palette.moc"
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml b/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
index 0e4ed277d0..db5470986f 100644
--- a/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
@@ -9,6 +9,7 @@ ApplicationWindow {
height: 400
background: Item {
+ objectName: "background"
implicitWidth: 123
implicitHeight: 456
}
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml b/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml
new file mode 100644
index 0000000000..67fdf7808c
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+ width: 600
+ height: 400
+
+ property real scaleFactor: 1
+
+ background: Rectangle {
+ objectName: "background"
+ color: "green"
+ width: window.width * window.scaleFactor
+ height: window.height * window.scaleFactor
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp b/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
index c7a5df4b68..a02ab9c595 100644
--- a/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
@@ -12,6 +12,7 @@
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p.h>
@@ -53,6 +54,7 @@ private slots:
void componentComplete();
void opacity();
void backgroundSize();
+ void explicitBackgroundSizeBinding();
};
tst_QQuickApplicationWindow::tst_QQuickApplicationWindow()
@@ -978,6 +980,23 @@ void tst_QQuickApplicationWindow::backgroundSize()
QCOMPARE(background->height(), 678);
}
+void tst_QQuickApplicationWindow::explicitBackgroundSizeBinding()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("explicitBackgroundSizeBinding.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *background = window->background();
+ QCOMPARE(background->width(), window->width());
+ QCOMPARE(background->height(), window->height());
+
+ window->setProperty("scaleFactor", 0.5);
+ QCOMPARE(background->width(), window->width() / 2);
+ QCOMPARE(background->height(), window->height() / 2);
+}
+
QTEST_MAIN(tst_QQuickApplicationWindow)
#include "tst_qquickapplicationwindow.moc"
diff --git a/tests/auto/quickcontrols/qquickcontainer/CMakeLists.txt b/tests/auto/quickcontrols/qquickcontainer/CMakeLists.txt
new file mode 100644
index 0000000000..c79e508cd1
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickcontainer/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickcontainer LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*
+)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickcontainer
+ SOURCES
+ tst_qquickcontainer.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QuickControls2
+ Qt::QuickControlsTestUtilsPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+ Qt::QuickTest
+ TESTDATA ${test_data}
+)
+
+qt_internal_extend_target(tst_qquickcontainer CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquickcontainer CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithListView.qml b/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithListView.qml
new file mode 100644
index 0000000000..43c3614866
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithListView.qml
@@ -0,0 +1,58 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias container: container
+ property alias text1: text1
+ property alias text2: text2
+ property alias text3: text3
+
+ component TextItem: Text {
+ font.pointSize: 24
+ width: container.width
+ height: container.height
+ }
+
+ Component {
+ id: textComponent
+ TextItem {}
+ }
+
+ function addTextItem() {
+ container.addItem(textComponent.createObject(container, { text: " 4 " }))
+ }
+
+ Item {
+ id: root
+ objectName: "root"
+
+ Container {
+ id: container
+ anchors.fill: parent
+ contentItem: ListView {
+ model: container.contentModel
+ snapMode: ListView.SnapOneItem
+ orientation: ListView.Horizontal
+ }
+
+ TextItem {
+ id: text1
+ text: "1 "
+ }
+ TextItem {
+ id: text2
+ text: " 2 "
+ }
+ TextItem {
+ id: text3
+ text: " 3 "
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithRepeater.qml b/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithRepeater.qml
new file mode 100644
index 0000000000..f78b6e273c
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickcontainer/data/zeroSizeWithRepeater.qml
@@ -0,0 +1,58 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias container: container
+ property alias text1: text1
+ property alias text2: text2
+ property alias text3: text3
+
+ component TextItem: Text {
+ font.pointSize: 24
+ width: container.width
+ height: container.height
+ }
+
+ Component {
+ id: textComponent
+ TextItem {}
+ }
+
+ function addTextItem() {
+ container.addItem(textComponent.createObject(container, { text: " 4 " }))
+ }
+
+ Item {
+ id: root
+ objectName: "root"
+
+ Container {
+ id: container
+ anchors.fill: parent
+ contentItem: Row {
+ Repeater {
+ model: container.contentModel
+ }
+ }
+
+ TextItem {
+ id: text1
+ text: "1 "
+ }
+ TextItem {
+ id: text2
+ text: " 2 "
+ }
+ TextItem {
+ id: text3
+ text: " 3 "
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickcontainer/tst_qquickcontainer.cpp b/tests/auto/quickcontrols/qquickcontainer/tst_qquickcontainer.cpp
new file mode 100644
index 0000000000..ce95f2cc37
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickcontainer/tst_qquickcontainer.cpp
@@ -0,0 +1,107 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest>
+#include <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtQuickControls2/qquickstyle.h>
+#include <QtQuickTest/QtQuickTest>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
+
+using namespace QQuickVisualTestUtils;
+using namespace QQuickControlsTestUtils;
+
+class tst_qquickcontainer : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_qquickcontainer();
+
+private slots:
+ void zeroSize_data();
+ void zeroSize();
+};
+
+tst_qquickcontainer::tst_qquickcontainer()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+
+ QQuickStyle::setStyle("Basic");
+}
+
+void tst_qquickcontainer::zeroSize_data()
+{
+ QTest::addColumn<QString>("qmlFileName");
+ QTest::addColumn<bool>("isItemView");
+
+ QTest::newRow("ListView") << "zeroSizeWithListView.qml" << true;
+ // See QQuickContainerPrivate::maybeCullItem for why this is false.
+ QTest::newRow("Repeater") << "zeroSizeWithRepeater.qml" << false;
+}
+
+// Tests that a zero-size Container with a QQuickItemView sub-class culls its items.
+// Based on a use case involving SwipeView: QTBUG-125416
+void tst_qquickcontainer::zeroSize()
+{
+ QFETCH(QString, qmlFileName);
+ QFETCH(bool, isItemView);
+
+ QQuickControlsApplicationHelper helper(this, qmlFileName);
+ QVERIFY2(helper.ready, helper.failureMessage());
+ centerOnScreen(helper.window);
+ helper.window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(helper.window));
+
+ auto *text1 = helper.window->property("text1").value<QQuickItem *>();
+ QVERIFY(text1);
+ QCOMPARE(QQuickItemPrivate::get(text1)->culled, isItemView);
+
+ auto *text2 = helper.window->property("text2").value<QQuickItem *>();
+ QVERIFY(text2);
+ QCOMPARE(QQuickItemPrivate::get(text2)->culled, isItemView);
+
+ auto *text3 = helper.window->property("text3").value<QQuickItem *>();
+ QVERIFY(text3);
+ QCOMPARE(QQuickItemPrivate::get(text3)->culled, isItemView);
+
+ // Add an item and check that it's culled appropriately.
+ QVERIFY(QMetaObject::invokeMethod(helper.window, "addTextItem"));
+ auto *container = helper.window->property("container").value<QQuickContainer *>();
+ QVERIFY(container);
+ auto *text4 = container->itemAt(3);
+ QVERIFY(text4);
+ QCOMPARE(QQuickItemPrivate::get(text4)->culled, isItemView);
+
+ // Give it a non-zero size (via its parent, which it fills).
+ container->parentItem()->setWidth(text1->implicitWidth());
+ container->parentItem()->setHeight(text1->implicitHeight());
+ if (isItemView) {
+ QVERIFY(QQuickTest::qIsPolishScheduled(helper.window));
+ QVERIFY(QQuickTest::qWaitForPolish(helper.window));
+ }
+ QCOMPARE(QQuickItemPrivate::get(text1)->culled, false);
+ // This one won't be culled for views either, because of cacheBuffer (and
+ // clipping apparently doesn't affect culling, if we were to set clip to true).
+ QCOMPARE(QQuickItemPrivate::get(text2)->culled, false);
+ QCOMPARE(QQuickItemPrivate::get(text3)->culled, isItemView);
+ QCOMPARE(QQuickItemPrivate::get(text4)->culled, isItemView);
+
+ // Go back to a zero size.
+ container->parentItem()->setWidth(0);
+ container->parentItem()->setHeight(0);
+ if (isItemView) {
+ QVERIFY(QQuickTest::qIsPolishScheduled(helper.window));
+ QVERIFY(QQuickTest::qWaitForPolish(helper.window));
+ }
+ QCOMPARE(QQuickItemPrivate::get(text1)->culled, isItemView);
+ QCOMPARE(QQuickItemPrivate::get(text2)->culled, isItemView);
+ QCOMPARE(QQuickItemPrivate::get(text3)->culled, isItemView);
+ QCOMPARE(QQuickItemPrivate::get(text4)->culled, isItemView);
+}
+
+QTEST_MAIN(tst_qquickcontainer)
+
+#include "tst_qquickcontainer.moc"
diff --git a/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp b/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
index ee0c6262d8..3e88bdb2b0 100644
--- a/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
+++ b/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
@@ -1051,8 +1051,7 @@ void tst_QQuickDrawer::interactive_data()
void tst_QQuickDrawer::interactive()
{
- if (!(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)))
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(QString, source);
QQuickControlsApplicationHelper helper(this, source);
diff --git a/tests/auto/quickcontrols/qquickmenu/data/mnemonics.qml b/tests/auto/quickcontrols/qquickmenu/data/mnemonics.qml
index 8929b00275..091d087dbb 100644
--- a/tests/auto/quickcontrols/qquickmenu/data/mnemonics.qml
+++ b/tests/auto/quickcontrols/qquickmenu/data/mnemonics.qml
@@ -5,14 +5,18 @@ import QtQuick
import QtQuick.Controls
ApplicationWindow {
+ id: root
width: 400
height: 400
+ property bool enabled: true
+ property bool checkable: false
property alias menu: menu
property alias action: action
property alias menuItem: menuItem
property alias subMenu: subMenu
property alias subMenuItem: subMenuItem
+ property alias subMenuAction: subMenuAction
Menu {
id: menu
@@ -20,20 +24,33 @@ ApplicationWindow {
Action {
id: action
text: "&Action"
+ checkable: root.checkable
+ enabled: root.enabled
}
MenuItem {
id: menuItem
text: "Menu &Item"
+ checkable: root.checkable
+ enabled: root.enabled
}
Menu {
id: subMenu
title: "Sub &Menu"
+ Action {
+ id: subMenuAction
+ text: "S&ub Menu Action"
+ checkable: root.checkable
+ enabled: root.enabled
+ }
+
MenuItem {
id: subMenuItem
text: "&Sub Menu Item"
+ checkable: root.checkable
+ enabled: root.enabled
}
}
}
diff --git a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
index fbb4e7d5f9..f54678b686 100644
--- a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
+++ b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
@@ -47,6 +47,10 @@ private slots:
void contextMenuKeyboard();
void disabledMenuItemKeyNavigation();
void mnemonics();
+#if QT_CONFIG(shortcut)
+ void checkableMnemonics_data();
+ void checkableMnemonics();
+#endif
void menuButton();
void addItem();
void menuSeparator();
@@ -87,9 +91,6 @@ private slots:
void customMenuCullItems();
void customMenuUseRepeaterAsTheContentItem();
void invalidUrlInImgTag();
-
-private:
- static bool hasWindowActivation();
};
tst_QQuickMenu::tst_QQuickMenu()
@@ -97,11 +98,6 @@ tst_QQuickMenu::tst_QQuickMenu()
{
}
-bool tst_QQuickMenu::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_QQuickMenu::defaults()
{
QQuickControlsApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
@@ -146,8 +142,7 @@ void tst_QQuickMenu::count()
void tst_QQuickMenu::mouse()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
@@ -278,8 +273,7 @@ void tst_QQuickMenu::pressAndHold()
void tst_QQuickMenu::contextMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -468,8 +462,7 @@ void tst_QQuickMenu::contextMenuKeyboard()
// QTBUG-70181
void tst_QQuickMenu::disabledMenuItemKeyNavigation()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -535,8 +528,7 @@ void tst_QQuickMenu::disabledMenuItemKeyNavigation()
void tst_QQuickMenu::mnemonics()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
#ifdef Q_OS_MACOS
QSKIP("Mnemonics are not used on macOS");
@@ -591,10 +583,207 @@ void tst_QQuickMenu::mnemonics()
QCOMPARE(subMenuItemSpy.size(), 1);
}
+#if QT_CONFIG(shortcut)
+namespace CheckableMnemonics {
+using MnemonicKey = std::pair<Qt::Key, QString>;
+
+enum class MenuItemType {
+ Action,
+ MenuItem
+};
+
+enum class SignalName {
+ CheckedChanged = 0x01,
+ Triggered = 0x02,
+};
+Q_DECLARE_FLAGS(SignalNames, SignalName);
+
+class ItemSignalSpy
+{
+public:
+ ItemSignalSpy(MenuItemType type, QObject *item) : item(item)
+ {
+ switch (type) {
+ case MenuItemType::Action:
+ initSignals<QQuickAction>(qobject_cast<QQuickAction *>(item));
+ break;
+ case MenuItemType::MenuItem:
+ initSignals<QQuickMenuItem>(qobject_cast<QQuickMenuItem *>(item));
+ break;
+ }
+ }
+
+ [[nodiscard]] bool isValid() const
+ {
+ return ((checkedChangedSpy && checkedChangedSpy->isValid()) &&
+ (triggeredSpy && triggeredSpy->isValid()));
+ }
+
+ [[nodiscard]] int signalSize(SignalName signal) const
+ {
+ constexpr int INVALID_SIZE = -1; // makes the test fail even when the signal is not expected
+ switch (signal) {
+ case SignalName::CheckedChanged:
+ return checkedChangedSpy ? checkedChangedSpy->size() : INVALID_SIZE;
+ case SignalName::Triggered:
+ return triggeredSpy ? triggeredSpy->size() : INVALID_SIZE;
+ }
+ Q_UNREACHABLE_RETURN(INVALID_SIZE);
+ }
+
+private:
+ template<typename Item>
+ void initSignals(Item *item)
+ {
+ checkedChangedSpy = std::make_unique<QSignalSpy>(item, &Item::checkedChanged);
+ triggeredSpy = std::make_unique<QSignalSpy>(item, &Item::triggered);
+ }
+
+private:
+ QPointer<QObject> item;
+ std::unique_ptr<QSignalSpy> checkedChangedSpy = nullptr;
+ std::unique_ptr<QSignalSpy> triggeredSpy = nullptr;
+};
+
+}
+
+void tst_QQuickMenu::checkableMnemonics_data()
+{
+ if (QKeySequence::mnemonic("&A").isEmpty())
+ QSKIP("Mnemonics are not enabled");
+
+ using namespace CheckableMnemonics;
+
+ QTest::addColumn<bool>("checkable");
+ QTest::addColumn<bool>("enabled");
+ QTest::addColumn<bool>("isSubMenu");
+ QTest::addColumn<MenuItemType>("itemType");
+ QTest::addColumn<MnemonicKey>("mnemonicKey");
+ QTest::addColumn<SignalNames>("expectedSignals");
+
+ QTest::addRow("checkable_enabled_action")
+ << true << true << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_action")
+ << true << false << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_action")
+ << false << true << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_action")
+ << false << false << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_menuItem")
+ << true << true << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_menuItem")
+ << true << false << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_menuItem")
+ << false << true << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_menuItem")
+ << false << false << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_subMenuItem")
+ << true << true << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_subMenuItem")
+ << true << false << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_subMenuItem")
+ << false << true << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_subMenuItem")
+ << false << false << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_subMenuAction")
+ << true << true << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_subMenuAction")
+ << true << false << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_subMenuAction")
+ << false << true << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_subMenuAction")
+ << false << false << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{};
+}
+
+// QTBUG-96630
+void tst_QQuickMenu::checkableMnemonics()
+{
+ using namespace CheckableMnemonics;
+
+ QFETCH(bool, checkable);
+ QFETCH(bool, enabled);
+ QFETCH(bool, isSubMenu);
+ QFETCH(MenuItemType, itemType);
+ QFETCH(MnemonicKey, mnemonicKey);
+ QFETCH(SignalNames, expectedSignals);
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("mnemonics.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ window->setProperty("checkable", checkable);
+ window->setProperty("enabled", enabled);
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+
+ auto clickKey = [window](const MnemonicKey &mnemonic) mutable {
+ QTest::simulateEvent(window, true, mnemonic.first, Qt::NoModifier, mnemonic.second, false);
+ QTest::simulateEvent(window, false, mnemonic.first, Qt::NoModifier, mnemonic.second, false);
+ };
+
+ constexpr auto EMPTY_ITEM_NAME = "";
+ const char *itemName = EMPTY_ITEM_NAME;
+ switch (itemType) {
+ case MenuItemType::Action:
+ itemName = isSubMenu ? "subMenuAction" : "action";
+ break;
+ case MenuItemType::MenuItem:
+ itemName = isSubMenu ? "subMenuItem" : "menuItem";
+ break;
+ }
+ QCOMPARE_NE(itemName, EMPTY_ITEM_NAME);
+
+ QObject *menuItem = window->property(itemName).value<QObject*>();
+ QVERIFY(menuItem);
+
+ menu->open();
+ QTRY_VERIFY(menu->isOpened());
+
+ if (isSubMenu) {
+ QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
+ QVERIFY(subMenu);
+ clickKey(MnemonicKey{Qt::Key_M, "M"}); // "Sub &Menu"
+ QTRY_VERIFY(subMenu->isOpened());
+ }
+
+ const ItemSignalSpy itemSignalSpy(itemType, menuItem);
+ QVERIFY(itemSignalSpy.isValid());
+
+ clickKey(mnemonicKey);
+ QCOMPARE(itemSignalSpy.signalSize(SignalName::CheckedChanged),
+ expectedSignals & SignalName::CheckedChanged ? 1 : 0);
+ QCOMPARE(itemSignalSpy.signalSize(SignalName::Triggered),
+ expectedSignals & SignalName::Triggered ? 1 : 0);
+}
+#endif
+
void tst_QQuickMenu::menuButton()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -648,8 +837,7 @@ void tst_QQuickMenu::addItem()
void tst_QQuickMenu::menuSeparator()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("menuSeparator.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1037,8 +1225,7 @@ void tst_QQuickMenu::actions()
#if QT_CONFIG(shortcut)
void tst_QQuickMenu::actionShortcuts()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("actionShortcuts.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1332,8 +1519,7 @@ void tst_QQuickMenu::subMenuKeyboard_data()
void tst_QQuickMenu::subMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -1461,8 +1647,7 @@ void tst_QQuickMenu::subMenuDisabledKeyboard_data()
// QTBUG-69540
void tst_QQuickMenu::subMenuDisabledKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -2050,8 +2235,7 @@ void tst_QQuickMenu::menuItemWidthAfterRetranslate()
void tst_QQuickMenu::giveMenuItemFocusOnButtonPress()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("giveMenuItemFocusOnButtonPress.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
diff --git a/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp b/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
index bbace286a8..b331fda1a3 100644
--- a/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
+++ b/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
@@ -38,8 +38,6 @@ private slots:
void checkHighlightWhenMenuDismissed();
private:
- static bool hasWindowActivation();
-
QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
@@ -54,11 +52,6 @@ tst_qquickmenubar::tst_qquickmenubar()
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
}
-bool tst_qquickmenubar::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_qquickmenubar::delegate()
{
QQmlApplicationEngine engine(testFileUrl("empty.qml"));
@@ -74,8 +67,7 @@ void tst_qquickmenubar::delegate()
void tst_qquickmenubar::mouse()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
@@ -286,8 +278,7 @@ void tst_qquickmenubar::touch()
void tst_qquickmenubar::keys()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
@@ -478,8 +469,7 @@ void tst_qquickmenubar::keys()
void tst_qquickmenubar::mnemonics()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
#if defined(Q_OS_MACOS) or defined(Q_OS_WEBOS)
QSKIP("Mnemonics are not used on this platform");
diff --git a/tests/auto/quickcontrols/qquickpopup/BLACKLIST b/tests/auto/quickcontrols/qquickpopup/BLACKLIST
index aa31440328..ed8288b5c9 100644
--- a/tests/auto/quickcontrols/qquickpopup/BLACKLIST
+++ b/tests/auto/quickcontrols/qquickpopup/BLACKLIST
@@ -12,3 +12,8 @@ opensuse-leap
[cursorShape]
opensuse-leap
+
+# QTBUG-125237
+[activeFocusItemAfterWindowInactive]
+android
+
diff --git a/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml b/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml
new file mode 100644
index 0000000000..1d4dc87e41
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/activeFocusAfterWindowInactive.qml
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias popup: popup
+ property alias button: button
+
+ Button {
+ id: button
+ text: "button"
+ focus: true
+ }
+
+ Popup {
+ id: popup
+ focus: true
+ width: 100
+ height: 100
+ anchors.centerIn: Overlay.overlay
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml b/tests/auto/quickcontrols/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml
new file mode 100644
index 0000000000..a7e66718ee
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/resetHoveredForItemsWithinOverlay.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+ width: 100
+ height: 100
+ property alias controlsPopup: _controlsPopup
+ property alias blockInputPopup: _blockInputPopup
+ Popup {
+ id: _controlsPopup
+ width: parent.width
+ height: parent.height
+ modal: true
+ Control {
+ id: controls
+ anchors.fill: parent
+ hoverEnabled: true
+ contentItem: Text { text: "Test Control" }
+ }
+ }
+ Popup {
+ id: _blockInputPopup
+ width: parent.width
+ height: parent.height
+ modal: true
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
index 09c0b29d2f..ee535caa8e 100644
--- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
@@ -65,6 +65,7 @@ private slots:
void activeFocusAfterExit();
void activeFocusOnDelayedEnter();
void activeFocusDespiteLowerStackingOrder();
+ void activeFocusItemAfterWindowInactive();
void hover_data();
void hover();
void wheel_data();
@@ -102,9 +103,9 @@ private slots:
void focusMultiplePopup();
void contentChildrenChange();
void doubleClickInMouseArea();
+ void resetHoveredStateForItemsWithinPopup();
private:
- static bool hasWindowActivation();
QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
@@ -128,11 +129,6 @@ void tst_QQuickPopup::visible_data()
QTest::newRow("ApplicationWindow") << "applicationwindow.qml";
}
-bool tst_QQuickPopup::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_QQuickPopup::visible()
{
QFETCH(QString, source);
@@ -511,8 +507,7 @@ void tst_QQuickPopup::closePolicy_data()
void tst_QQuickPopup::closePolicy()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(QString, source);
QFETCH(const QPointingDevice *, device);
@@ -654,8 +649,7 @@ void tst_QQuickPopup::closePolicy_grabberInside()
void tst_QQuickPopup::activeFocusOnClose1()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a popup that never sets focus: true (e.g. ToolTip) doesn't affect
// the active focus item when it closes.
@@ -700,8 +694,7 @@ void tst_QQuickPopup::activeFocusOnClose1()
void tst_QQuickPopup::activeFocusOnClose2()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a popup that sets focus: true but relinquishes focus (e.g. by
// calling forceActiveFocus() on another item) before it closes doesn't
@@ -742,8 +735,7 @@ void tst_QQuickPopup::activeFocusOnClose2()
void tst_QQuickPopup::activeFocusOnClose3()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a closing popup that had focus doesn't steal focus from
// another popup that the focus was transferred to.
@@ -778,8 +770,7 @@ void tst_QQuickPopup::activeFocusOnClose3()
void tst_QQuickPopup::activeFocusOnClosingSeveralPopups()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that active focus isn't lost when multiple popup closing simultaneously
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusOnClosingSeveralPopups.qml"));
@@ -830,8 +821,7 @@ void tst_QQuickPopup::activeFocusOnClosingSeveralPopups()
void tst_QQuickPopup::activeFocusAfterExit()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that after closing a popup the highest one in z-order receives it instead.
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusAfterExit.qml"));
@@ -882,8 +872,7 @@ void tst_QQuickPopup::activeFocusAfterExit()
void tst_QQuickPopup::activeFocusOnDelayedEnter()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that after opening two popups, first of which has an animation, does not cause
// the first one to receive focus after the animation stops.
@@ -911,8 +900,7 @@ void tst_QQuickPopup::activeFocusOnDelayedEnter()
// key events due to having active focus.
void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -951,6 +939,51 @@ void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder()
QVERIFY(!popup1->hasActiveFocus());
}
+void tst_QQuickPopup::activeFocusItemAfterWindowInactive()
+{
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
+ QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusAfterWindowInactive.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickPopup *popup = helper.appWindow->property("popup").value<QQuickPopup*>();
+ QQuickButton *button = helper.appWindow->property("button").value<QQuickButton*>();
+ QVERIFY(popup);
+ QVERIFY(button);
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+ QVERIFY(popup->hasActiveFocus());
+ QVERIFY(!button->hasActiveFocus());
+
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+ QVERIFY(button->hasActiveFocus());
+ QCOMPARE(window->activeFocusItem(), button);
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+
+ QQuickWindow newWindow;
+ newWindow.setTitle("newFocusWindow");
+ newWindow.show();
+ newWindow.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&newWindow));
+
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+ QTRY_VERIFY(!popup->isOpened());
+ QCOMPARE(QGuiApplication::focusWindow(), &newWindow);
+
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QCOMPARE(window->activeFocusItem(), button);
+}
+
void tst_QQuickPopup::hover_data()
{
QTest::addColumn<QString>("source");
@@ -1389,8 +1422,7 @@ void tst_QQuickPopup::componentComplete()
void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Tests the scenario in the Gallery example, where there are nested popups that should
// close in the correct order when the Escape key is pressed.
@@ -1459,8 +1491,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
void tst_QQuickPopup::closeOnEscapeWithVisiblePopup()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QStringLiteral("closeOnEscapeWithVisiblePopup.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1587,8 +1618,7 @@ void tst_QQuickPopup::qquickview()
// QTBUG-73447
void tst_QQuickPopup::disabledPalette()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "disabledPalette.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1627,8 +1657,7 @@ void tst_QQuickPopup::disabledPalette()
void tst_QQuickPopup::disabledParentPalette()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "disabledPalette.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1736,8 +1765,7 @@ void tst_QQuickPopup::setOverlayParentToNull()
void tst_QQuickPopup::tabFence()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -1849,8 +1877,7 @@ void tst_QQuickPopup::centerInOverlayWithinStackViewItem()
void tst_QQuickPopup::destroyDuringExitTransition()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "destroyDuringExitTransition.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -2287,6 +2314,40 @@ void tst_QQuickPopup::doubleClickInMouseArea()
QCOMPARE(longPressSpy.count(), 0);
}
+void tst_QQuickPopup::resetHoveredStateForItemsWithinPopup()
+{
+ QQuickControlsApplicationHelper helper(this, "resetHoveredForItemsWithinOverlay.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickPopup *controlsPopup = window->property("controlsPopup").value<QQuickPopup*>();
+ QVERIFY(controlsPopup);
+
+ QQuickPopup *blockInputPopup = window->property("blockInputPopup").value<QQuickPopup*>();
+ QVERIFY(controlsPopup);
+
+ controlsPopup->open();
+ QTRY_VERIFY(controlsPopup->isOpened());
+
+ QTest::mouseMove(window, QPoint(window->width() / 2 + 2, window->height() / 2 + 2));
+ QTest::mouseMove(window, QPoint(window->width() / 2, window->height() / 2));
+
+ auto *controlItem = qobject_cast<QQuickControl *>(controlsPopup->contentItem()->childItems().at(0));
+ QVERIFY(controlItem);
+ // Check hover enabled for the control item within the popup
+ QTRY_VERIFY(controlItem->isHovered());
+
+ // Open the modal popup window over the existing control item
+ blockInputPopup->open();
+ QTRY_VERIFY(blockInputPopup->isOpened());
+
+ // Control item hovered shall be disabled once we open the modal popup
+ QTRY_VERIFY(!controlItem->isHovered());
+}
+
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
#include "tst_qquickpopup.moc"
diff --git a/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp b/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
index 3788799f8a..1e3e0e46ee 100644
--- a/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
+++ b/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
@@ -12,6 +12,7 @@
#include <QtQuick/qquickview.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickTemplates2/private/qquicktextarea_p.h>
#include <QtQuickControlsTestUtils/private/qtest_quickcontrols_p.h>
@@ -29,7 +30,6 @@ private slots:
void touchscreenSetsFocusAndMovesCursor();
private:
- static bool hasWindowActivation();
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
@@ -102,8 +102,7 @@ void tst_QQuickTextArea::touchscreenDoesNotSelect()
void tst_QQuickTextArea::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
qunsetenv("QT_QUICK_CONTROLS_TEXT_SELECTION_BEHAVIOR");
QQuickView window;
@@ -158,11 +157,6 @@ void tst_QQuickTextArea::touchscreenSetsFocusAndMovesCursor()
QCOMPARE_GT(top->selectedText().size(), 0);
}
-bool tst_QQuickTextArea::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
QTEST_QUICKCONTROLS_MAIN(tst_QQuickTextArea)
#include "tst_qquicktextarea.moc"