diff options
Diffstat (limited to 'tests/auto/quickcontrols')
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" |
