aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/CMakeLists.txt1
-rw-r--r--tests/auto/accessibility/CMakeLists.txt3
-rw-r--r--tests/auto/controls/data/tst_abstractbutton.qml36
-rw-r--r--tests/auto/controls/data/tst_checkbox.qml3
-rw-r--r--tests/auto/controls/data/tst_combobox.qml40
-rw-r--r--tests/auto/controls/data/tst_control.qml14
-rw-r--r--tests/auto/controls/data/tst_delaybutton.qml4
-rw-r--r--tests/auto/controls/data/tst_dial.qml15
-rw-r--r--tests/auto/controls/data/tst_popup.qml52
-rw-r--r--tests/auto/controls/data/tst_progressbar.qml2
-rw-r--r--tests/auto/controls/data/tst_radiobutton.qml3
-rw-r--r--tests/auto/controls/data/tst_rangeslider.qml26
-rw-r--r--tests/auto/controls/data/tst_scrollbar.qml32
-rw-r--r--tests/auto/controls/data/tst_scrollview.qml74
-rw-r--r--tests/auto/controls/data/tst_selectionrectangle.qml311
-rw-r--r--tests/auto/controls/data/tst_slider.qml92
-rw-r--r--tests/auto/controls/data/tst_spinbox.qml29
-rw-r--r--tests/auto/controls/data/tst_splitview.qml3
-rw-r--r--tests/auto/controls/data/tst_swipedelegate.qml40
-rw-r--r--tests/auto/controls/data/tst_switch.qml8
-rw-r--r--tests/auto/controls/data/tst_switchdelegate.qml8
-rw-r--r--tests/auto/controls/data/tst_tooltip.qml18
-rw-r--r--tests/auto/cursor/CMakeLists.txt3
-rw-r--r--tests/auto/customization/CMakeLists.txt3
-rw-r--r--tests/auto/dialogs/CMakeLists.txt2
-rw-r--r--tests/auto/dialogs/dialogs.pro3
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/BLACKLIST7
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/CMakeLists.txt40
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/acceptRejectLabel.qml67
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/bindAllTxtHtmlNameFilters.qml66
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/bindCurrentFolder.qml68
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/bindTitle.qml65
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/bindTxtHtmlNameFilters.qml66
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/data/fileDialog.qml73
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/qquickfiledialogimpl.pro14
-rw-r--r--tests/auto/dialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp1349
-rw-r--r--tests/auto/dialogs/qquickfontdialogimpl/BLACKLIST4
-rw-r--r--tests/auto/dialogs/qquickfontdialogimpl/CMakeLists.txt39
-rw-r--r--tests/auto/dialogs/qquickfontdialogimpl/data/fontDialog.qml65
-rw-r--r--tests/auto/dialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp520
-rw-r--r--tests/auto/focus/CMakeLists.txt3
-rw-r--r--tests/auto/font/CMakeLists.txt3
-rw-r--r--tests/auto/palette/CMakeLists.txt3
-rw-r--r--tests/auto/palette/data/bindings.qml5
-rw-r--r--tests/auto/palette/data/palette-appwindow-custom.qml1
-rw-r--r--tests/auto/palette/data/palette-control-custom.qml1
-rw-r--r--tests/auto/palette/data/palette-popup-custom.qml1
-rw-r--r--tests/auto/palette/tst_palette.cpp1
-rw-r--r--tests/auto/qquickapplicationwindow/CMakeLists.txt3
-rw-r--r--tests/auto/qquickapplicationwindow/data/layoutLayout.qml66
-rw-r--r--tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp37
-rw-r--r--tests/auto/qquickcontrol/CMakeLists.txt3
-rw-r--r--tests/auto/qquickdrawer/BLACKLIST8
-rw-r--r--tests/auto/qquickdrawer/CMakeLists.txt3
-rw-r--r--tests/auto/qquickheaderview/CMakeLists.txt3
-rw-r--r--tests/auto/qquickiconimage/CMakeLists.txt3
-rw-r--r--tests/auto/qquickiconlabel/CMakeLists.txt3
-rw-r--r--tests/auto/qquickmaterialstyleconf/CMakeLists.txt3
-rw-r--r--tests/auto/qquickmenu/CMakeLists.txt3
-rw-r--r--tests/auto/qquickmenu/tst_qquickmenu.cpp42
-rw-r--r--tests/auto/qquickmenubar/CMakeLists.txt3
-rw-r--r--tests/auto/qquickninepatchimage/CMakeLists.txt3
-rw-r--r--tests/auto/qquickpopup/BLACKLIST9
-rw-r--r--tests/auto/qquickpopup/CMakeLists.txt3
-rw-r--r--tests/auto/qquickpopup/data/invisibleToolTipOpen.qml2
-rw-r--r--tests/auto/qquickpopup/tst_qquickpopup.cpp56
-rw-r--r--tests/auto/qquickstyle/CMakeLists.txt3
-rw-r--r--tests/auto/qquickuniversalstyleconf/CMakeLists.txt3
-rw-r--r--tests/auto/sanity/CMakeLists.txt3
-rw-r--r--tests/auto/sanity/tst_sanity.cpp8
-rw-r--r--tests/auto/shared/dialogtestutil.h144
-rw-r--r--tests/auto/shared/util.pri4
-rw-r--r--tests/auto/shared/visualtestutil.cpp103
-rw-r--r--tests/auto/shared/visualtestutil.h41
-rw-r--r--tests/auto/snippets/CMakeLists.txt2
-rw-r--r--tests/auto/styleimports/CMakeLists.txt7
-rw-r--r--tests/auto/styleimportscompiletimematerial/CMakeLists.txt3
-rw-r--r--tests/auto/styleimportscompiletimeqmlonly/CMakeLists.txt3
-rw-r--r--tests/auto/translation/CMakeLists.txt3
-rw-r--r--tests/benchmarks/creationtime/CMakeLists.txt3
-rw-r--r--tests/benchmarks/creationtime/tst_creationtime.cpp10
-rw-r--r--tests/benchmarks/objectcount/CMakeLists.txt3
-rw-r--r--tests/benchmarks/objectcount/tst_objectcount.cpp10
-rw-r--r--tests/manual/CMakeLists.txt5
-rw-r--r--tests/manual/buttons/CMakeLists.txt6
-rw-r--r--tests/manual/dialogs/CMakeLists.txt23
-rw-r--r--tests/manual/dialogs/FileDialogPage.qml357
-rw-r--r--tests/manual/dialogs/FontDialogPage.qml222
-rw-r--r--tests/manual/dialogs/StringListView.qml79
-rw-r--r--tests/manual/dialogs/Theme.qml57
-rw-r--r--tests/manual/dialogs/dialogs.cpp26
-rw-r--r--tests/manual/dialogs/dialogs.pro9
-rw-r--r--tests/manual/dialogs/dialogs.qml221
-rw-r--r--tests/manual/dialogs/qmldir3
-rw-r--r--tests/manual/fonts/CMakeLists.txt6
-rw-r--r--tests/manual/gifs/CMakeLists.txt6
-rw-r--r--tests/manual/headerview/CMakeLists.txt6
-rw-r--r--tests/manual/manual.pro9
-rw-r--r--tests/manual/qquickdialog/CMakeLists.txt31
-rw-r--r--tests/manual/qquickdialog/CustomDialog.qml (renamed from tests/manual/dialogs/CustomDialog.qml)0
-rw-r--r--tests/manual/qquickdialog/DialogLabel.qml (renamed from tests/manual/dialogs/DialogLabel.qml)0
-rw-r--r--tests/manual/qquickdialog/Marker.qml (renamed from tests/manual/dialogs/Marker.qml)0
-rw-r--r--tests/manual/qquickdialog/qquickdialog.cpp62
-rw-r--r--tests/manual/qquickdialog/qquickdialog.pro11
-rw-r--r--tests/manual/qquickdialog/qquickdialog.qml247
-rw-r--r--tests/manual/qquickdialog/qtquickcontrols2.conf (renamed from tests/manual/dialogs/qtquickcontrols2.conf)0
-rw-r--r--tests/manual/screenshots/CMakeLists.txt6
-rw-r--r--tests/manual/styles-cover-flow/CMakeLists.txt6
-rw-r--r--tests/manual/styles/CMakeLists.txt6
-rw-r--r--tests/manual/systemtrayicon/CMakeLists.txt6
-rw-r--r--tests/manual/testbench/CMakeLists.txt6
-rw-r--r--tests/manual/viewinqwidget/CMakeLists.txt6
112 files changed, 4927 insertions, 387 deletions
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index 5d7302c3..ef299bb7 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(controls)
add_subdirectory(cursor)
add_subdirectory(customization)
add_subdirectory(designer)
+add_subdirectory(dialogs)
add_subdirectory(focus)
add_subdirectory(font)
add_subdirectory(palette)
diff --git a/tests/auto/accessibility/CMakeLists.txt b/tests/auto/accessibility/CMakeLists.txt
index fe2a35d6..596bf3b9 100644
--- a/tests/auto/accessibility/CMakeLists.txt
+++ b/tests/auto/accessibility/CMakeLists.txt
@@ -21,7 +21,7 @@ qt_internal_add_test(tst_accessibility
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_accessibility.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -31,6 +31,7 @@ qt_internal_add_test(tst_accessibility
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml
index 74538053..72e56270 100644
--- a/tests/auto/controls/data/tst_abstractbutton.qml
+++ b/tests/auto/controls/data/tst_abstractbutton.qml
@@ -909,5 +909,41 @@ TestCase {
compare(releasedSpy.count, 2)
compare(clickedSpy.count, 1)
compare(doubleClickedSpy.count, 1)
+
+ let touch = touchEvent(control)
+ touch.press(0, control)
+ touch.commit()
+ compare(pressedSpy.count, 3)
+ compare(releasedSpy.count, 2)
+ compare(clickedSpy.count, 1)
+ compare(doubleClickedSpy.count, 1)
+
+ touch.release(0, control)
+ touch.commit()
+ compare(pressedSpy.count, 3)
+ compare(releasedSpy.count, 3)
+ compare(clickedSpy.count, 2)
+ compare(doubleClickedSpy.count, 1)
+
+ touch.press(0, control)
+ touch.commit()
+ compare(pressedSpy.count, 4)
+ compare(releasedSpy.count, 3)
+ compare(clickedSpy.count, 2)
+ compare(doubleClickedSpy.count, 1)
+
+ touch.release(0, control)
+ touch.commit()
+ compare(pressedSpy.count, 4)
+ compare(releasedSpy.count, 4)
+ compare(clickedSpy.count, 2)
+ compare(doubleClickedSpy.count, 2)
}
+
+ function test_checkedShouldNotSetCheckable() {
+ let control = createTemporaryObject(button, testCase, { checked: true })
+ verify(control)
+
+ verify(!control.checkable)
+ }
}
diff --git a/tests/auto/controls/data/tst_checkbox.qml b/tests/auto/controls/data/tst_checkbox.qml
index 81c3d6ca..be68ac0d 100644
--- a/tests/auto/controls/data/tst_checkbox.qml
+++ b/tests/auto/controls/data/tst_checkbox.qml
@@ -236,6 +236,8 @@ TestCase {
// uncheck
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -254,6 +256,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }],
"pressed"]
+ wait(Qt.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/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml
index 460c490a..5359f63c 100644
--- a/tests/auto/controls/data/tst_combobox.qml
+++ b/tests/auto/controls/data/tst_combobox.qml
@@ -157,6 +157,7 @@ TestCase {
verify(control.delegate)
verify(control.indicator)
verify(control.popup)
+ verify(control.acceptableInput)
compare(control.inputMethodHints, Qt.ImhNoPredictiveText)
}
@@ -2240,4 +2241,43 @@ TestCase {
verify(control.activeFocus)
verify(control.contentItem.focus)
}
+
+ Component {
+ id: intValidatorComponent
+ IntValidator {
+ bottom: 0
+ top: 255
+ }
+ }
+
+ function test_acceptableInput_QTBUG_94307() {
+ let items = [
+ { text: "A" },
+ { text: "2" },
+ { text: "3" }
+ ]
+ let control = createTemporaryObject(comboBox, testCase, {model: items, editable: true})
+ verify(control)
+
+ verify(control.acceptableInput)
+ compare(control.displayText, "A")
+
+ let acceptableInputSpy = signalSpy.createObject(control, {target: control, signalName: "acceptableInputChanged"})
+ verify(acceptableInputSpy.valid)
+
+ let intValidator = intValidatorComponent.createObject(testCase)
+ verify(intValidator)
+
+ control.validator = intValidator
+
+ compare(acceptableInputSpy.count, 1)
+ compare(control.displayText, "A")
+ compare(control.acceptableInput, false)
+
+ control.currentIndex = 1
+
+ compare(acceptableInputSpy.count, 2)
+ compare(control.displayText, "2")
+ compare(control.acceptableInput, true)
+ }
}
diff --git a/tests/auto/controls/data/tst_control.qml b/tests/auto/controls/data/tst_control.qml
index 1bbbe42a..4afa719e 100644
--- a/tests/auto/controls/data/tst_control.qml
+++ b/tests/auto/controls/data/tst_control.qml
@@ -435,8 +435,8 @@ TestCase {
compare(control.mirrored, false)
control.locale = Qt.locale("ar_EG")
- compare(control.mirrored, true)
- compare(mirroredSpy.count, 1)
+ compare(control.mirrored, false)
+ compare(mirroredSpy.count, 0)
control.LayoutMirroring.enabled = true
compare(control.mirrored, true)
@@ -960,14 +960,14 @@ TestCase {
control.locale = Qt.locale("ar_EG")
control.localespy.wait()
compare(control.localespy.count, 2)
- compare(control.mirroredspy.count, 1)
+ compare(control.mirroredspy.count, 0)
compare(control.locale.name, "ar_EG")
compare(control.item2_2.locale.name, "ar_EG")
compare(control.item2_3.locale.name, "ar_EG")
compare(control.localespy_2.count, 2)
- compare(control.mirroredspy_2.count, 1)
+ compare(control.mirroredspy_2.count, 0)
compare(control.localespy_3.count, 2)
- compare(control.mirroredspy_3.count, 1)
+ compare(control.mirroredspy_3.count, 0)
}
Component {
@@ -1051,11 +1051,11 @@ TestCase {
control.locale = Qt.locale("ar_EG")
control.localespy.wait()
compare(control.localespy.count, 2)
- compare(control.mirroredspy.count, 1)
+ compare(control.mirroredspy.count, 0)
compare(control.locale.name, "ar_EG")
compare(control.item6_5.locale.name, "ar_EG")
compare(control.localespy_5.count, 2)
- compare(control.mirroredspy_5.count, 1)
+ compare(control.mirroredspy_5.count, 0)
}
function test_hover_data() {
diff --git a/tests/auto/controls/data/tst_delaybutton.qml b/tests/auto/controls/data/tst_delaybutton.qml
index 731caf86..0e8d188d 100644
--- a/tests/auto/controls/data/tst_delaybutton.qml
+++ b/tests/auto/controls/data/tst_delaybutton.qml
@@ -203,6 +203,8 @@ TestCase {
["downChanged", { "down": true }],
"pressed",
"activated"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
tryVerify(function() { return sequenceSpy.success})
@@ -220,6 +222,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -237,6 +240,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
+ wait(Qt.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/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml
index 70645f8d..2d0c702e 100644
--- a/tests/auto/controls/data/tst_dial.qml
+++ b/tests/auto/controls/data/tst_dial.qml
@@ -691,4 +691,19 @@ TestCase {
compare(control.pressed, false);
compare(control.position, data.expectedPosition);
}
+
+ function test_integerStepping() {
+ var dial = createTemporaryObject(dialComponent, testCase)
+ verify(dial)
+
+ dial.from = 1
+ dial.to = 8
+ dial.stepSize = 1
+
+ for (let i = 1; i < 8; ++i) {
+ // compare as strings to avoid a fuzzy compare; we want an exact match
+ compare(""+dial.value, ""+1)
+ keyClick(Qt.Key_Right)
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml
index 2c94e87b..145f5552 100644
--- a/tests/auto/controls/data/tst_popup.qml
+++ b/tests/auto/controls/data/tst_popup.qml
@@ -810,9 +810,9 @@ TestCase {
compare(control.popup.button1.locale.name, defaultLocale.name)
compare(control.popup.button2.locale.name, defaultLocale.name)
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 3)
- compare(control.button.mirrorspy.count, 1)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 2)
compare(control.popup.button1.localespy.count, 2)
compare(control.popup.button2.localespy.count, 2)
@@ -825,14 +825,14 @@ TestCase {
compare(control.popup.button1.locale.name, "ar_EG")
compare(control.popup.button2.locale.name, "ar_EG")
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 3)
- compare(control.button.mirrorspy.count, 1)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 3)
compare(control.popup.button1.localespy.count, 3)
- compare(control.popup.button1.mirrorspy.count, 1)
+ compare(control.popup.button1.mirrorspy.count, 0)
compare(control.popup.button2.localespy.count, 3)
- compare(control.popup.button2.mirrorspy.count, 1)
+ compare(control.popup.button2.mirrorspy.count, 0)
control.button.locale = Qt.locale("nb_NO")
compare(control.ApplicationWindow.window.locale.name, "ar_EG")
@@ -842,9 +842,9 @@ TestCase {
compare(control.popup.button1.locale.name, "ar_EG")
compare(control.popup.button2.locale.name, "ar_EG")
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 3)
compare(control.popup.button1.localespy.count, 3)
compare(control.popup.button2.localespy.count, 3)
@@ -857,9 +857,9 @@ TestCase {
compare(control.popup.button1.locale.name, "ar_EG")
compare(control.popup.button2.locale.name, "ar_EG")
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 3)
compare(control.popup.button1.localespy.count, 3)
compare(control.popup.button2.localespy.count, 3)
@@ -872,14 +872,14 @@ TestCase {
compare(control.popup.button1.locale.name, "nb_NO")
compare(control.popup.button2.locale.name, "ar_EG")
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 3)
compare(control.popup.button1.localespy.count, 4)
- compare(control.popup.button1.mirrorspy.count, 2)
+ compare(control.popup.button1.mirrorspy.count, 0)
compare(control.popup.button2.localespy.count, 3)
- compare(control.popup.button2.mirrorspy.count, 1)
+ compare(control.popup.button2.mirrorspy.count, 0)
control.popup.locale = Qt.locale("fi_FI")
compare(control.ApplicationWindow.window.locale.name, "ar_EG")
@@ -889,14 +889,14 @@ TestCase {
compare(control.popup.button1.locale.name, "nb_NO")
compare(control.popup.button2.locale.name, "fi_FI")
compare(control.localespy.count, 3)
- compare(control.mirrorspy.count, 1)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 4)
compare(control.popup.button1.localespy.count, 4)
- compare(control.popup.button1.mirrorspy.count, 2)
+ compare(control.popup.button1.mirrorspy.count, 0)
compare(control.popup.button2.localespy.count, 4)
- compare(control.popup.button2.mirrorspy.count, 2)
+ compare(control.popup.button2.mirrorspy.count, 0)
control.ApplicationWindow.window.locale = undefined
compare(control.ApplicationWindow.window.locale.name, defaultLocale.name)
@@ -906,14 +906,14 @@ TestCase {
compare(control.popup.button1.locale.name, "nb_NO")
compare(control.popup.button2.locale.name, "fi_FI")
compare(control.localespy.count, 4)
- compare(control.mirrorspy.count, 2)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 4)
compare(control.popup.button1.localespy.count, 4)
- compare(control.popup.button1.mirrorspy.count, 2)
+ compare(control.popup.button1.mirrorspy.count, 0)
compare(control.popup.button2.localespy.count, 4)
- compare(control.popup.button2.mirrorspy.count, 2)
+ compare(control.popup.button2.mirrorspy.count, 0)
control.popup.locale = undefined
compare(control.ApplicationWindow.window.locale.name, defaultLocale.name)
@@ -923,14 +923,14 @@ TestCase {
compare(control.popup.button1.locale.name, "nb_NO")
compare(control.popup.button2.locale.name, defaultLocale.name)
compare(control.localespy.count, 4)
- compare(control.mirrorspy.count, 2)
+ compare(control.mirrorspy.count, 0)
compare(control.button.localespy.count, 4)
- compare(control.button.mirrorspy.count, 2)
+ compare(control.button.mirrorspy.count, 0)
compare(control.popup.localespy.count, 5)
compare(control.popup.button1.localespy.count, 4)
- compare(control.popup.button1.mirrorspy.count, 2)
+ compare(control.popup.button1.mirrorspy.count, 0)
compare(control.popup.button2.localespy.count, 5)
- compare(control.popup.button2.mirrorspy.count, 2)
+ compare(control.popup.button2.mirrorspy.count, 0)
}
function test_size() {
diff --git a/tests/auto/controls/data/tst_progressbar.qml b/tests/auto/controls/data/tst_progressbar.qml
index 1bb66bb7..2d264409 100644
--- a/tests/auto/controls/data/tst_progressbar.qml
+++ b/tests/auto/controls/data/tst_progressbar.qml
@@ -163,7 +163,7 @@ TestCase {
// RTL locale
control.locale = Qt.locale("ar_EG")
- compare(control.visualPosition, 0.75)
+ compare(control.visualPosition, 0.25)
// RTL locale + LayoutMirroring
control.LayoutMirroring.enabled = true
diff --git a/tests/auto/controls/data/tst_radiobutton.qml b/tests/auto/controls/data/tst_radiobutton.qml
index 42ef9a15..973e56a3 100644
--- a/tests/auto/controls/data/tst_radiobutton.qml
+++ b/tests/auto/controls/data/tst_radiobutton.qml
@@ -193,6 +193,8 @@ TestCase {
// attempt uncheck
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -207,6 +209,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ wait(Qt.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/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml
index 55fedd1c..c42a1d1e 100644
--- a/tests/auto/controls/data/tst_rangeslider.qml
+++ b/tests/auto/controls/data/tst_rangeslider.qml
@@ -235,8 +235,8 @@ TestCase {
// RTL locale
control.locale = Qt.locale("ar_EG")
- compare(control.first.visualPosition, 0.75)
- compare(control.second.visualPosition, 0.0)
+ compare(control.first.visualPosition, 0.25)
+ compare(control.second.visualPosition, 1.0)
// RTL locale + LayoutMirroring
control.LayoutMirroring.enabled = true
@@ -612,7 +612,7 @@ TestCase {
}
function test_overlappingHandles() {
- var control = createTemporaryObject(sliderComponent, testCase, { orientation: data.orientation })
+ var control = createTemporaryObject(sliderComponent, testCase)
verify(control)
// By default, we force the second handle to be after the first in
@@ -786,13 +786,12 @@ TestCase {
control.first.value = 0
control.locale = Qt.locale("ar_EG")
- mousePress(control, control.first.handle.x + control.first.handle.width / 2,
- control.first.handle.y + control.first.handle.height / 2, Qt.LeftButton)
+ mousePress(control, control.first.handle.x, control.first.handle.y, Qt.LeftButton)
compare(firstPressedSpy.count, 3)
compare(control.first.pressed, true)
compare(control.first.value, 0.0)
compare(control.first.position, 0.0)
- compare(control.first.visualPosition, 1.0)
+ compare(control.first.visualPosition, 0.0)
mouseMove(control, control.leftPadding + control.availableWidth * 0.5, control.height * 0.5, 0)
compare(firstPressedSpy.count, 3)
@@ -805,7 +804,7 @@ TestCase {
compare(firstPressedSpy.count, 3)
compare(control.first.pressed, true)
compare(control.first.value, 0.0)
- verify(control.first.position < 0.5)
+ verify(control.first.position > 0.5)
verify(control.first.visualPosition > 0.5)
mouseRelease(control, control.leftPadding + control.availableWidth * 0.5, control.height * 0.5, Qt.LeftButton)
@@ -1064,17 +1063,16 @@ TestCase {
function test_valueAt_data() {
return [
- { tag: "0.0..1.0", from: 0.0, to: 1.0, values: [0.0, 0.2, 0.5, 1.0] },
- { tag: "0..100", from: 0, to: 100, values: [0, 20, 50, 100] },
- { tag: "100..-100", from: 100, to: -100, values: [100, 60, 0, -100] },
- { tag: "-7..7", from: -7, to: 7, stepSize: 1.0, values: [-7.0, -4.0, 0.0, 7.0] },
- { tag: "-3..7", from: -3, to: 7, stepSize: 5.0, values: [-3.0, -3.0, 2.0, 7.0] },
+ { tag: "0.0..1.0", properties: { from: 0.0, to: 1.0 }, values: [0.0, 0.2, 0.5, 1.0] },
+ { tag: "0..100", properties: { from: 0, to: 100 }, values: [0, 20, 50, 100] },
+ { tag: "100..-100", properties: { from: 100, to: -100 }, values: [100, 60, 0, -100] },
+ { tag: "-7..7", properties: { from: -7, to: 7, stepSize: 1.0 }, values: [-7.0, -4.0, 0.0, 7.0] },
+ { tag: "-3..7", properties: { from: -3, to: 7, stepSize: 5.0 }, values: [-3.0, -3.0, 2.0, 7.0] },
]
}
function test_valueAt(data) {
- var control = createTemporaryObject(sliderComponent, testCase,
- { from: data.from, to: data.to, stepSize: data.stepSize })
+ var control = createTemporaryObject(sliderComponent, testCase, data.properties)
verify(control)
compare(control.valueAt(0.0), data.values[0])
diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml
index 3121f1b0..9e649e37 100644
--- a/tests/auto/controls/data/tst_scrollbar.qml
+++ b/tests/auto/controls/data/tst_scrollbar.qml
@@ -196,6 +196,36 @@ TestCase {
compare(horizontal.width, oldWidth)
}
+ function test_attachTwice() {
+ let container = createTemporaryObject(flickable, testCase)
+ verify(container)
+ waitForRendering(container)
+
+ container.ScrollBar.vertical = scrollBar.createObject(container, { objectName: "oldVerticalScrollBar" })
+ verify(container.ScrollBar.vertical)
+ let oldVerticalScrollBar = findChild(container, "oldVerticalScrollBar")
+ verify(oldVerticalScrollBar)
+ verify(oldVerticalScrollBar.visible)
+
+ container.ScrollBar.horizontal = scrollBar.createObject(container, { objectName: "oldHorizontalScrollBar" })
+ verify(container.ScrollBar.horizontal)
+ let oldHorizontalScrollBar = findChild(container, "oldHorizontalScrollBar")
+ verify(oldHorizontalScrollBar)
+ verify(oldHorizontalScrollBar.visible)
+
+ container.ScrollBar.vertical = scrollBar.createObject(container, { objectName: "newVerticalScrollBar" })
+ let newVerticalScrollBar = findChild(container, "newVerticalScrollBar")
+ verify(newVerticalScrollBar)
+ verify(newVerticalScrollBar.visible)
+ verify(!oldVerticalScrollBar.visible)
+
+ container.ScrollBar.horizontal = scrollBar.createObject(container, { objectName: "newHorizontalScrollBar" })
+ let newHorizontalScrollBar = findChild(container, "newHorizontalScrollBar")
+ verify(newHorizontalScrollBar)
+ verify(newHorizontalScrollBar.visible)
+ verify(!oldHorizontalScrollBar.visible)
+ }
+
function test_mouse_data() {
return [
{ tag: "horizontal", properties: { visible: true, orientation: Qt.Horizontal, width: testCase.width } },
@@ -516,7 +546,7 @@ TestCase {
container.ScrollBar.vertical = scrollBar.createObject(container)
compare(container.ScrollBar.vertical.x, container.width - container.ScrollBar.vertical.width)
container.ScrollBar.vertical.locale = Qt.locale("ar_EG")
- compare(container.ScrollBar.vertical.x, 0)
+ compare(container.ScrollBar.vertical.x, container.width - container.ScrollBar.vertical.width)
}
function test_hover_data() {
diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml
index d8c210a4..46afa503 100644
--- a/tests/auto/controls/data/tst_scrollview.qml
+++ b/tests/auto/controls/data/tst_scrollview.qml
@@ -71,6 +71,11 @@ TestCase {
}
Component {
+ id: scrollBarComponent
+ ScrollBar {}
+ }
+
+ Component {
id: scrollableLabel
ScrollView {
Label {
@@ -188,6 +193,15 @@ TestCase {
}
}
}
+ Component {
+ id: scrollableTextAreaWithSibling
+ ScrollView {
+ Item {
+ }
+ TextArea {
+ }
+ }
+ }
function test_scrollBars() {
var control = createTemporaryObject(scrollView, testCase, {width: 200, height: 200})
@@ -502,4 +516,64 @@ TestCase {
compare(control.contentWidth, flickable.contentWidth)
compare(control.contentHeight, flickable.contentHeight)
}
+
+ function test_textAreaWithSibling() {
+ // Checks that it does not crash when the ScrollView is deleted
+ var control = createTemporaryObject(scrollableTextAreaWithSibling, testCase)
+ verify(control)
+ }
+
+ Component {
+ id: zeroSizedContentItemComponent
+ ScrollView {
+ width: 100
+ height: 100
+ contentItem: Item {}
+ }
+ }
+
+ function test_zeroSizedContentItem() {
+ ignoreWarning(/ScrollView only supports Flickable types as its contentItem/)
+ let control = createTemporaryObject(zeroSizedContentItemComponent, testCase)
+ verify(control)
+
+ let verticalScrollBar = control.ScrollBar.vertical
+ verify(verticalScrollBar)
+ // Scrolling a ScrollView with a zero-sized contentItem shouldn't crash.
+ mouseDrag(verticalScrollBar, verticalScrollBar.width / 2, verticalScrollBar.height / 2, 0, 50)
+
+ let horizontalScrollBar = control.ScrollBar.horizontal
+ verify(verticalScrollBar)
+ mouseDrag(horizontalScrollBar, horizontalScrollBar.width / 2, horizontalScrollBar.height / 2, 50, 0)
+ }
+
+ function test_customScrollBars() {
+ let control = createTemporaryObject(scrollView, testCase)
+ verify(control)
+ control.ScrollBar.vertical.objectName = "oldVerticalScrollBar"
+ control.ScrollBar.horizontal.objectName = "oldHorizontalScrollBar"
+
+ let oldVerticalScrollBar = control.ScrollBar.vertical
+ verify(oldVerticalScrollBar)
+ compare(oldVerticalScrollBar.objectName, "oldVerticalScrollBar")
+
+ let oldHorizontalScrollBar = control.ScrollBar.horizontal
+ verify(oldHorizontalScrollBar)
+ compare(oldHorizontalScrollBar.objectName, "oldHorizontalScrollBar")
+
+ // Create the new scroll bars imperatively so that we can easily access the old ones.
+ control.ScrollBar.vertical = scrollBarComponent.createObject(control, { objectName: "newVerticalScrollBar" })
+ verify(control.ScrollBar.vertical)
+ let newVerticalScrollBar = findChild(control, "newVerticalScrollBar")
+ verify(newVerticalScrollBar)
+ verify(newVerticalScrollBar.visible)
+ verify(!oldVerticalScrollBar.visible)
+
+ control.ScrollBar.horizontal = scrollBarComponent.createObject(control, { objectName: "newHorizontalScrollBar" })
+ verify(control.ScrollBar.horizontal)
+ let newHorizontalScrollBar = findChild(control, "newHorizontalScrollBar")
+ verify(newHorizontalScrollBar)
+ verify(newHorizontalScrollBar.visible)
+ verify(!oldHorizontalScrollBar.visible)
+ }
}
diff --git a/tests/auto/controls/data/tst_selectionrectangle.qml b/tests/auto/controls/data/tst_selectionrectangle.qml
new file mode 100644
index 00000000..13ddf00f
--- /dev/null
+++ b/tests/auto/controls/data/tst_selectionrectangle.qml
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtTest
+import QtQuick.Controls
+import Qt.labs.qmlmodels
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "SelectionRectangle"
+
+ property real cellWidth: 50
+ property real cellHeight: 20
+ property Item handle: null
+ property bool handleWasDragged: false
+
+ Component {
+ id: handleComp
+ Rectangle {
+ id: handle
+ width: 28
+ height: width
+ radius: width / 2
+ property bool dragging: SelectionRectangle.dragging
+ property Item control: SelectionRectangle.control
+ border.width: 1
+ border.color: "red"
+ visible: SelectionRectangle.control.active
+
+ SelectionRectangle.onDraggingChanged: {
+ if (SelectionRectangle.dragging)
+ testCase.handleWasDragged = true
+ }
+
+ Component.onCompleted: testCase.handle = handle
+ }
+ }
+
+ Component {
+ id: tableviewComp
+ TableView {
+ id: tableView
+ clip: true
+ anchors.fill: parent
+
+ model: TableModel {
+ TableModelColumn { display: "c1" }
+ TableModelColumn { display: "c2" }
+ TableModelColumn { display: "c3" }
+ TableModelColumn { display: "c4" }
+ rows: [
+ { "c1": "v1", "c2":"v2", "c3":"v3", "c4": "v4" },
+ { "c1": "v1", "c2":"v2", "c3":"v3", "c4": "v4" },
+ { "c1": "v1", "c2":"v2", "c3":"v3", "c4": "v4" },
+ { "c1": "v1", "c2":"v2", "c3":"v3", "c4": "v4" },
+ ]
+ }
+
+ delegate: Rectangle {
+ required property bool selected
+ implicitWidth: cellWidth
+ implicitHeight: cellHeight
+ color: selected ? "lightblue" : "gray"
+ Text { text: "cell" }
+ }
+
+ selectionModel: ItemSelectionModel {
+ model: tableView.model
+ }
+
+ property alias selectionRectangle: selectionRectangle
+ SelectionRectangle {
+ id: selectionRectangle
+ target: tableView
+ }
+ }
+
+ }
+
+ Component {
+ id: signalSpy
+ SignalSpy { }
+ }
+
+ function test_set_target() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ compare(selectionRectangle.target, tableView)
+
+ selectionRectangle.target = null
+ compare(selectionRectangle.target, null)
+
+ selectionRectangle.target = tableView
+ compare(selectionRectangle.target, tableView)
+ }
+
+ function test_set_selectionMode() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ // Default selection mode should be Auto
+ compare(selectionRectangle.selectionMode, SelectionRectangle.Auto)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+ compare(selectionRectangle.selectionMode, SelectionRectangle.Drag)
+
+ selectionRectangle.selectionMode = SelectionRectangle.PressAndHold
+ compare(selectionRectangle.selectionMode, SelectionRectangle.PressAndHold)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Auto
+ compare(selectionRectangle.selectionMode, SelectionRectangle.Auto)
+ }
+
+ function test_set_handles() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.topLeftHandle = null
+ compare(selectionRectangle.topLeftHandle, null)
+
+ selectionRectangle.bottomRightHandle = null
+ compare(selectionRectangle.bottomRightHandle, null)
+
+ selectionRectangle.topLeftHandle = handleComp
+ compare(selectionRectangle.topLeftHandle, handleComp)
+
+ selectionRectangle.bottomRightHandle = handleComp
+ compare(selectionRectangle.bottomRightHandle, handleComp)
+ }
+
+ function test_drag() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+
+ let activeSpy = signalSpy.createObject(selectionRectangle, {target: selectionRectangle, signalName: "activeChanged"})
+ let draggingSpy = signalSpy.createObject(selectionRectangle, {target: selectionRectangle, signalName: "draggingChanged"})
+ verify(activeSpy.valid)
+ verify(draggingSpy.valid)
+
+ verify(!tableView.selectionModel.hasSelection)
+ mouseDrag(tableView, 1, 1, (cellWidth * 2) - 2, 1, Qt.LeftButton)
+ verify(tableView.selectionModel.hasSelection)
+ compare(tableView.selectionModel.selectedIndexes.length, 2)
+ verify(tableView.selectionModel.isSelected(tableView.model.index(0, 0)))
+ verify(tableView.selectionModel.isSelected(tableView.model.index(0, 1)))
+
+ compare(activeSpy.count, 1)
+ compare(draggingSpy.count, 2)
+
+ // Remove selection
+ mouseClick(tableView, 1, 1, Qt.LeftButton)
+ verify(!tableView.selectionModel.hasSelection)
+ compare(draggingSpy.count, 2)
+ compare(activeSpy.count, 2)
+
+ // Ensure that a press and hold doesn't start a selection
+ mousePress(tableView, 1, 1, Qt.LeftButton)
+ mousePress(tableView, 1, 1, Qt.LeftButton, Qt.NoModifier, 1000)
+ verify(!tableView.selectionModel.hasSelection)
+ }
+
+ function test_pressAndHold() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.PressAndHold
+
+ let activeSpy = signalSpy.createObject(selectionRectangle, {target: selectionRectangle, signalName: "activeChanged"})
+ let draggingSpy = signalSpy.createObject(selectionRectangle, {target: selectionRectangle, signalName: "draggingChanged"})
+ verify(activeSpy.valid)
+ verify(draggingSpy.valid)
+
+ verify(!tableView.selectionModel.hasSelection)
+ // Do a press and hold
+ mousePress(tableView, 1, 1, Qt.LeftButton)
+ mousePress(tableView, 1, 1, Qt.LeftButton, Qt.NoModifier, 1000)
+ verify(tableView.selectionModel.hasSelection)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ verify(tableView.selectionModel.isSelected(tableView.model.index(0, 0)))
+
+ compare(draggingSpy.count, 0)
+ compare(activeSpy.count, 1)
+
+ // Remove selection
+ mouseClick(tableView, 1, 1, Qt.LeftButton)
+ verify(!tableView.selectionModel.hasSelection)
+ compare(draggingSpy.count, 0)
+ compare(activeSpy.count, 2)
+
+ // Ensure that a drag doesn't start a selection
+ mouseDrag(tableView, 1, 1, (cellWidth * 2) - 2, 1, Qt.LeftButton)
+ verify(!tableView.selectionModel.hasSelection)
+ }
+
+ function test_handleDragTopLeft() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+
+ verify(!tableView.selectionModel.hasSelection)
+ // Select four cells in the middle
+ mouseDrag(tableView, cellWidth + 1, cellHeight + 1, (cellWidth * 2) - 2, (cellHeight * 2) - 2, Qt.LeftButton)
+ compare(tableView.selectionModel.selectedIndexes.length, 4)
+ for (var x = 1; x < 3; ++x) {
+ for (var y = 1; y < 3; ++y) {
+ verify(tableView.selectionModel.isSelected(tableView.model.index(x, y)))
+ }
+ }
+
+ // Drag on the top left handle, so that the selection extends to cell 0, 0
+ mouseDrag(tableView, cellWidth, cellHeight, -cellWidth / 2, -cellHeight / 2, Qt.LeftButton)
+ compare(tableView.selectionModel.selectedIndexes.length, 9)
+ for (x = 0; x < 3; ++x) {
+ for (y = 0; y < 3; ++y) {
+ verify(tableView.selectionModel.isSelected(tableView.model.index(x, y)))
+ }
+ }
+ }
+
+ function test_handleDragBottomRight() {
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+
+ verify(!tableView.selectionModel.hasSelection)
+ // Select four cells in the middle
+ mouseDrag(tableView, cellWidth + 1, cellHeight + 1, (cellWidth * 2) - 2, (cellHeight * 2) - 2, Qt.LeftButton)
+ compare(tableView.selectionModel.selectedIndexes.length, 4)
+ for (var x = 1; x < 3; ++x) {
+ for (var y = 1; y < 3; ++y) {
+ verify(tableView.selectionModel.isSelected(tableView.model.index(x, y)))
+ }
+ }
+
+ // Drag on the bottom right handle, so that the selection shrinks to cell 1, 1
+ mouseDrag(tableView, cellWidth * 2, cellHeight * 2, -cellWidth / 2, -cellHeight / 2, Qt.LeftButton)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ verify(tableView.selectionModel.isSelected(tableView.model.index(1, 1)))
+ }
+}
diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml
index 9f123476..73031a70 100644
--- a/tests/auto/controls/data/tst_slider.qml
+++ b/tests/auto/controls/data/tst_slider.qml
@@ -179,7 +179,7 @@ TestCase {
// RTL locale
control.locale = Qt.locale("ar_EG")
- compare(control.visualPosition, 0.75)
+ compare(control.visualPosition, 0.25)
// RTL locale + LayoutMirroring
control.LayoutMirroring.enabled = true
@@ -623,7 +623,7 @@ TestCase {
compare(pressedSpy.count, 3)
compare(control.pressed, true)
compare(control.value, 0.0)
- compare(control.position, 1.0)
+ compare(control.position, 0.0)
compare(control.visualPosition, 0.0)
mouseMove(control, control.leftPadding + control.availableWidth * 0.5, control.height * 0.5, 0)
@@ -637,7 +637,7 @@ TestCase {
compare(pressedSpy.count, 3)
compare(control.pressed, true)
compare(control.value, 0.0)
- verify(control.position < 0.5)
+ verify(control.position > 0.5)
verify(control.visualPosition > 0.5)
mouseRelease(control, control.leftPadding + control.availableWidth * 0.5, control.height * 0.5, Qt.LeftButton)
@@ -648,7 +648,12 @@ TestCase {
compare(control.visualPosition, 0.5)
}
- function test_snapMode_data(immediate) {
+ function calcMousePos(control, t) {
+ t = Math.min(Math.max(t, 0.0), 1.0);
+ return control.leftPadding + control.handle.width * 0.5 + t * (control.availableWidth - control.handle.width)
+ }
+
+ function snapModeData(immediate) {
return [
{ tag: "NoSnap", snapMode: Slider.NoSnap, from: 0, to: 2, values: [0, 0, 0.25], positions: [0, 0.1, 0.1] },
{ tag: "SnapAlways (0..2)", snapMode: Slider.SnapAlways, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] },
@@ -658,57 +663,66 @@ TestCase {
{ tag: "SnapOnRelease (0..2)", snapMode: Slider.SnapOnRelease, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] },
{ tag: "SnapOnRelease (1..3)", snapMode: Slider.SnapOnRelease, from: 1, to: 3, values: [1.0, 1.0, 1.2], positions: [0.0, 0.1, 0.1] },
{ tag: "SnapOnRelease (-1..1)", snapMode: Slider.SnapOnRelease, from: -1, to: 1, values: [0.0, 0.0, -0.8], positions: [immediate ? 0.0 : 0.5, 0.1, 0.1] },
- { tag: "SnapOnRelease (1..-1)", snapMode: Slider.SnapOnRelease, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [immediate ? 0.0 : 0.5, 0.1, 0.1] }
+ { tag: "SnapOnRelease (1..-1)", snapMode: Slider.SnapOnRelease, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [immediate ? 0.0 : 0.5, 0.1, 0.1] },
+ // Live
+ { tag: "SnapAlwaysLive", snapMode: Slider.SnapAlways, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.6, values: [0, 1, 1], positions: [0, 1, 1] },
+ { tag: "SnapAlwaysLive", snapMode: Slider.SnapAlways, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.4, values: [0, 0, 0], positions: [0, 0, 0] },
+ { tag: "NoSnapLive", snapMode: Slider.NoSnap, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.6, values: [0, 1, 1], positions: [0, 0.6, 0.6] },
+ { tag: "NoSnapLive", snapMode: Slider.NoSnap, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.4, values: [0, 0, 0], positions: [0, 0.4, 0.4] },
+ { tag: "SnapOnReleaseLive", snapMode: Slider.SnapOnRelease, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.6, values: [0, 1, 1], positions: [0, 0.6, 1] },
+ { tag: "SnapOnReleaseLive", snapMode: Slider.SnapOnRelease, from: 0, to: 1, value: 0, stepSize: 1, live: true, sliderPos: 0.4, values: [0, 0, 0], positions: [0, 0.4, 0] },
]
}
- function test_snapMode_mouse_data() {
- return test_snapMode_data(true)
- }
+ function testSnapMode(data, useMouse) {
+ let live = data.live !== undefined ? data.live : false
+ let stepSize = data.stepSize !== undefined ? data.stepSize : 0.2
+ let sliderPos = data.sliderPos !== undefined ? data.sliderPos : 0.1
+ let fuzz = 0.05
- function test_snapMode_mouse(data) {
- var control = createTemporaryObject(slider, testCase, {live: false, snapMode: data.snapMode, from: data.from, to: data.to, stepSize: 0.2})
+ var control = createTemporaryObject(slider, testCase, {live: live, snapMode: data.snapMode, from: data.from, to: data.to, stepSize: stepSize})
verify(control)
+ var touch = useMouse ? null : touchEvent(control)
- var fuzz = 0.05
+ if (useMouse)
+ mousePress(control, calcMousePos(control, 0.0))
+ else
+ touch.press(0, control, calcMousePos(control, 0.0)).commit()
- mousePress(control, control.leftPadding)
- compare(control.value, data.values[0])
- compare(control.position, data.positions[0])
+ fuzzyCompare(control.value, data.values[0], fuzz)
+ fuzzyCompare(control.position, data.positions[0], fuzz)
- mouseMove(control, control.leftPadding + 0.15 * (control.availableWidth + control.handle.width / 2))
+ if (useMouse)
+ mouseMove(control, calcMousePos(control, sliderPos))
+ else
+ touch.move(0, control, calcMousePos(control, sliderPos)).commit()
fuzzyCompare(control.value, data.values[1], fuzz)
fuzzyCompare(control.position, data.positions[1], fuzz)
- mouseRelease(control, control.leftPadding + 0.15 * (control.availableWidth + control.handle.width / 2))
+ if (useMouse)
+ mouseRelease(control, calcMousePos(control, sliderPos))
+ else
+ touch.release(0, control, calcMousePos(control, sliderPos)).commit()
+
fuzzyCompare(control.value, data.values[2], fuzz)
fuzzyCompare(control.position, data.positions[2], fuzz)
}
function test_snapMode_touch_data() {
- return test_snapMode_data(false)
+ return snapModeData(false)
}
function test_snapMode_touch(data) {
- var control = createTemporaryObject(slider, testCase, {live: false, snapMode: data.snapMode, from: data.from, to: data.to, stepSize: 0.2})
- verify(control)
-
- var fuzz = 0.05
-
- var touch = touchEvent(control)
- touch.press(0, control, control.leftPadding).commit()
- compare(control.value, data.values[0])
- compare(control.position, data.positions[0])
-
- touch.move(0, control, control.leftPadding + 0.15 * (control.availableWidth + control.handle.width / 2)).commit()
+ return testSnapMode(data, false)
+ }
- fuzzyCompare(control.value, data.values[1], fuzz)
- fuzzyCompare(control.position, data.positions[1], fuzz)
+ function test_snapMode_mouse_data() {
+ return snapModeData(true)
+ }
- touch.release(0, control, control.leftPadding + 0.15 * (control.availableWidth + control.handle.width / 2)).commit()
- fuzzyCompare(control.value, data.values[2], fuzz)
- fuzzyCompare(control.position, data.positions[2], fuzz)
+ function test_snapMode_mouse(data) {
+ return testSnapMode(data, true)
}
function test_wheel_data() {
@@ -831,16 +845,16 @@ TestCase {
function test_valueAt_data() {
return [
- { tag: "0.0..1.0", from: 0.0, to: 1.0, values: [0.0, 0.2, 0.5, 1.0] },
- { tag: "0..100", from: 0, to: 100, values: [0, 20, 50, 100] },
- { tag: "100..-100", from: 100, to: -100, values: [100, 60, 0, -100] },
- { tag: "-7..7", from: -7, to: 7, stepSize: 1.0, values: [-7.0, -4.0, 0.0, 7.0] },
- { tag: "-3..7", from: -3, to: 7, stepSize: 5.0, values: [-3.0, -3.0, 2.0, 7.0] },
+ { tag: "0.0..1.0", properties: { from: 0.0, to: 1.0 }, values: [0.0, 0.2, 0.5, 1.0] },
+ { tag: "0..100", properties: { from: 0, to: 100 }, values: [0, 20, 50, 100] },
+ { tag: "100..-100", properties: { from: 100, to: -100 }, values: [100, 60, 0, -100] },
+ { tag: "-7..7", properties: { from: -7, to: 7, stepSize: 1.0 }, values: [-7.0, -4.0, 0.0, 7.0] },
+ { tag: "-3..7", properties: { from: -3, to: 7, stepSize: 5.0 }, values: [-3.0, -3.0, 2.0, 7.0] },
]
}
function test_valueAt(data) {
- var control = createTemporaryObject(slider, testCase, {from: data.from, to: data.to, stepSize: data.stepSize})
+ let control = createTemporaryObject(slider, testCase, data.properties)
verify(control)
compare(control.valueAt(0.0), data.values[0])
diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml
index 8934543d..6220a857 100644
--- a/tests/auto/controls/data/tst_spinbox.qml
+++ b/tests/auto/controls/data/tst_spinbox.qml
@@ -244,17 +244,17 @@ TestCase {
function test_keys_data() {
return [
- { tag: "1", from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3,4], downSteps: [3,2,1,1] },
- { tag: "2", from: 1, to: 10, value: 10, stepSize: 2, upSteps: [10,10], downSteps: [8,6,4] },
- { tag: "25", from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,100], downSteps: [75,50,25,0,0] },
- { tag: "wrap1", wrap: true, from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3], downSteps: [2,1,10,9] },
- { tag: "wrap2", wrap: true, from: 1, to: 10, value: 10, stepSize: 2, upSteps: [1,3,5], downSteps: [3,1,10,8,6] },
- { tag: "wrap25", wrap: true, from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,0,25], downSteps: [0,100,75] }
+ { tag: "1", properties: { from: 1, to: 10, value: 1, stepSize: 1 }, upSteps: [2,3,4], downSteps: [3,2,1,1] },
+ { tag: "2", properties: { from: 1, to: 10, value: 10, stepSize: 2 }, upSteps: [10,10], downSteps: [8,6,4] },
+ { tag: "25", properties: { from: 0, to: 100, value: 50, stepSize: 25 }, upSteps: [75,100,100], downSteps: [75,50,25,0,0] },
+ { tag: "wrap1", properties: { wrap: true, from: 1, to: 10, value: 1, stepSize: 1 }, upSteps: [2,3], downSteps: [2,1,10,9] },
+ { tag: "wrap2", properties: { wrap: true, from: 1, to: 10, value: 10, stepSize: 2 }, upSteps: [1,3,5], downSteps: [3,1,10,8,6] },
+ { tag: "wrap25", properties: { wrap: true, from: 0, to: 100, value: 50, stepSize: 25 }, upSteps: [75,100,0,25], downSteps: [0,100,75] }
]
}
function test_keys(data) {
- var control = createTemporaryObject(spinBox, testCase, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize})
+ var control = createTemporaryObject(spinBox, testCase, data.properties)
verify(control)
var upPressedCount = 0
@@ -396,12 +396,12 @@ TestCase {
function test_wheel_data() {
return [
- { tag: "1", from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3,4], downSteps: [3,2,1,1] },
- { tag: "2", from: 1, to: 10, value: 10, stepSize: 2, upSteps: [10,10], downSteps: [8,6,4] },
- { tag: "25", from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,100], downSteps: [75,50,25,0,0] },
- { tag: "wrap1", wrap: true, from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3], downSteps: [2,1,10,9] },
- { tag: "wrap2", wrap: true, from: 1, to: 10, value: 10, stepSize: 2, upSteps: [1,3,5], downSteps: [3,1,10,8,6] },
- { tag: "wrap25", wrap: true, from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,0,25], downSteps: [0,100,75] }
+ { tag: "1", properties: { from: 1, to: 10, value: 1, stepSize: 1 }, upSteps: [2,3,4], downSteps: [3,2,1,1] },
+ { tag: "2", properties: { from: 1, to: 10, value: 10, stepSize: 2 }, upSteps: [10,10], downSteps: [8,6,4] },
+ { tag: "25", properties: { from: 0, to: 100, value: 50, stepSize: 25 }, upSteps: [75,100,100], downSteps: [75,50,25,0,0] },
+ { tag: "wrap1", properties: { wrap: true, from: 1, to: 10, value: 1, stepSize: 1 }, upSteps: [2,3], downSteps: [2,1,10,9] },
+ { tag: "wrap2", properties: { wrap: true, from: 1, to: 10, value: 10, stepSize: 2 }, upSteps: [1,3,5], downSteps: [3,1,10,8,6] },
+ { tag: "wrap25", properties: { wrap: true, from: 0, to: 100, value: 50, stepSize: 25 }, upSteps: [75,100,0,25], downSteps: [0,100,75] }
]
}
@@ -409,7 +409,8 @@ TestCase {
var ma = createTemporaryObject(mouseArea, testCase, {width: 100, height: 100})
verify(ma)
- var control = spinBox.createObject(ma, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize, wheelEnabled: true})
+ data.properties.wheelEnabled = true
+ var control = spinBox.createObject(ma, data.properties)
verify(control)
var valueModifiedCount = 0
diff --git a/tests/auto/controls/data/tst_splitview.qml b/tests/auto/controls/data/tst_splitview.qml
index f9dbb1ad..5281e1e8 100644
--- a/tests/auto/controls/data/tst_splitview.qml
+++ b/tests/auto/controls/data/tst_splitview.qml
@@ -1838,8 +1838,7 @@ TestCase {
var flickable = createTemporaryObject(flickableComponent, testCase)
verify(flickable)
- var control = threeSizedItemsComponent.createObject(flickable.contentItem,
- { "orientation": data.orientation })
+ var control = threeSizedItemsComponent.createObject(flickable.contentItem)
verify(control)
control.anchors.fill = undefined
diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml
index 17440042..d0d4e318 100644
--- a/tests/auto/controls/data/tst_swipedelegate.qml
+++ b/tests/auto/controls/data/tst_swipedelegate.qml
@@ -702,7 +702,9 @@ TestCase {
property alias removeAnimation: onRemoveAnimation
- ListView.onRemove: SequentialAnimation {
+ ListView.onRemove: onRemoveAnimation.start()
+
+ SequentialAnimation {
id: onRemoveAnimation
PropertyAction {
@@ -1274,10 +1276,10 @@ TestCase {
// When this happens, it will grab the mouse and hence we must clear
// that action's pressed state so that it doesn't stay pressed after releasing.
function test_dragSideAction() {
- var listView = createTemporaryObject(removableDelegatesComponent, testCase);
+ let listView = createTemporaryObject(removableDelegatesComponent, testCase);
verify(listView);
- var control = listView.itemAt(0, 0);
+ let control = listView.itemAt(0, 0);
verify(control);
// Expose the side action.
@@ -1285,15 +1287,43 @@ TestCase {
verify(control.swipe.leftItem);
tryCompare(control.swipe, "complete", true);
- var pressedSpy = signalSpyComponent.createObject(control,
+ let pressedSpy = signalSpyComponent.createObject(control,
{ target: control.swipe.leftItem.SwipeDelegate, signalName: "pressedChanged" });
verify(pressedSpy);
verify(pressedSpy.valid);
+ let movingHorizontallySpy = createTemporaryObject(signalSpyComponent, testCase,
+ { target: listView, signalName: "movingHorizontallyChanged" })
+ verify(movingHorizontallySpy)
+ verify(movingHorizontallySpy.valid)
+
+ let movingVerticallySpy = createTemporaryObject(signalSpyComponent, testCase,
+ { target: listView, signalName: "movingVerticallyChanged" })
+ verify(movingVerticallySpy)
+ verify(movingVerticallySpy.valid)
+
+ let flickingHorizontallySpy = createTemporaryObject(signalSpyComponent, testCase,
+ { target: listView, signalName: "flickingHorizontallyChanged" })
+ verify(flickingHorizontallySpy)
+ verify(flickingHorizontallySpy.valid)
+
+ let flickingVerticallySpy = createTemporaryObject(signalSpyComponent, testCase,
+ { target: listView, signalName: "flickingVerticallyChanged" })
+ verify(flickingVerticallySpy)
+ verify(flickingVerticallySpy.valid)
+
+ // Drag the ListView vertically; its contentY should change.
mouseDrag(listView, 20, 20, 0, listView.height);
compare(pressedSpy.count, 2);
- verify(listView.contentY !== 0);
+ // Wait for it to stop moving.
+ tryCompare(listView, "flickingVertically", false)
+
+ // 2 because it should change to true then false.
+ compare(movingHorizontallySpy.count, 0)
+ compare(movingVerticallySpy.count, 2)
+ compare(flickingHorizontallySpy.count, 0)
+ compare(flickingVerticallySpy.count, 2)
compare(control.swipe.leftItem.SwipeDelegate.pressed, false);
}
diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml
index 9050964f..175cd741 100644
--- a/tests/auto/controls/data/tst_switch.qml
+++ b/tests/auto/controls/data/tst_switch.qml
@@ -249,6 +249,8 @@ TestCase {
// uncheck
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -265,6 +267,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -283,6 +286,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -301,6 +305,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -460,6 +465,8 @@ TestCase {
// press-drag-release outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -495,6 +502,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml
index fabd6279..f7f0ead4 100644
--- a/tests/auto/controls/data/tst_switchdelegate.qml
+++ b/tests/auto/controls/data/tst_switchdelegate.qml
@@ -245,6 +245,8 @@ TestCase {
// uncheck
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -261,6 +263,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -279,6 +282,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -297,6 +301,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -456,6 +461,8 @@ TestCase {
// press-drag-release outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
+ // Don't want to double-click.
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -491,6 +498,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
+ wait(Qt.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml
index b4e992a4..2f98a5f3 100644
--- a/tests/auto/controls/data/tst_tooltip.qml
+++ b/tests/auto/controls/data/tst_tooltip.qml
@@ -75,6 +75,11 @@ TestCase {
SignalSpy { }
}
+ Component {
+ id: itemComponent
+ Item {}
+ }
+
QtObject {
id: object
}
@@ -446,6 +451,19 @@ TestCase {
verify(item.ToolTip.toolTip.contentItem.width < item.ToolTip.toolTip.contentItem.implicitWidth)
}
+ // QTBUG-83630: Test that newlines are accounted for in the implicit contentWidth.
+ function test_newLines() {
+ var item = createTemporaryObject(itemComponent, testCase)
+ verify(item)
+
+ item.ToolTip.show("This is one line of text\nThis is another line of text")
+
+ // The implicitWidth of the Text item for the text above will be larger than
+ // its contentWidth. ToolTip's implicitWidth uses contentWidth in its calculation,
+ // so we check that it's less than the Text's implicitWidth.
+ verify(item.ToolTip.toolTip.implicitWidth < item.ToolTip.toolTip.contentItem.implicitWidth)
+ }
+
function test_timeoutAfterOpened() {
let control = createTemporaryObject(toolTipWithExitTransition, testCase, { timeout: 1, exit: null })
verify(control)
diff --git a/tests/auto/cursor/CMakeLists.txt b/tests/auto/cursor/CMakeLists.txt
index f7a22928..5f02758c 100644
--- a/tests/auto/cursor/CMakeLists.txt
+++ b/tests/auto/cursor/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_cursor
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_cursor.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_cursor
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/customization/CMakeLists.txt b/tests/auto/customization/CMakeLists.txt
index 70a7b88c..54e689f4 100644
--- a/tests/auto/customization/CMakeLists.txt
+++ b/tests/auto/customization/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_customization
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_customization.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_customization
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/dialogs/CMakeLists.txt b/tests/auto/dialogs/CMakeLists.txt
new file mode 100644
index 00000000..94485f87
--- /dev/null
+++ b/tests/auto/dialogs/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(qquickfiledialogimpl)
+add_subdirectory(qquickfontdialogimpl)
diff --git a/tests/auto/dialogs/dialogs.pro b/tests/auto/dialogs/dialogs.pro
new file mode 100644
index 00000000..004641ec
--- /dev/null
+++ b/tests/auto/dialogs/dialogs.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += \
+ qquickfiledialogimpl
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/BLACKLIST b/tests/auto/dialogs/qquickfiledialogimpl/BLACKLIST
new file mode 100644
index 00000000..822b92dd
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/BLACKLIST
@@ -0,0 +1,7 @@
+# QTBUG-92094
+[tabFocusNavigation]
+*
+
+# QTBUG-92585
+[fileMode:OpenFiles]
+*
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/CMakeLists.txt b/tests/auto/dialogs/qquickfiledialogimpl/CMakeLists.txt
new file mode 100644
index 00000000..22e64546
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/CMakeLists.txt
@@ -0,0 +1,40 @@
+# 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_qquickfiledialogimpl
+ SOURCES
+ ../../shared/qtest_quickcontrols.h
+ ../../shared/util.cpp ../../shared/util.h
+ ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
+ tst_qquickfiledialogimpl.cpp
+ DEFINES
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src\\\"
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2
+ Qt::QuickControls2Private
+ Qt::QuickDialogs2Private
+ Qt::QuickDialogs2QuickImplPrivate
+ Qt::QuickDialogs2UtilsPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+ Qt::QuickTest
+ Qt::TestPrivate
+ TESTDATA ${test_data}
+)
+
+qt_internal_extend_target(tst_qquickfiledialogimpl CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\":/data\\\"
+)
+
+qt_internal_extend_target(tst_qquickfiledialogimpl CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+)
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/acceptRejectLabel.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/acceptRejectLabel.qml
new file mode 100644
index 00000000..3cd526e3
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/acceptRejectLabel.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ id: window
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ FileDialog {
+ id: dialog
+ acceptLabel: "AcceptTest"
+ rejectLabel: "RejectTest"
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/bindAllTxtHtmlNameFilters.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/bindAllTxtHtmlNameFilters.qml
new file mode 100644
index 00000000..5010c422
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/bindAllTxtHtmlNameFilters.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ FileDialog {
+ id: dialog
+ objectName: "FileDialog"
+ nameFilters: ["All files (*)", "Text files (*.txt)", "HTML files (*.html)"]
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/bindCurrentFolder.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/bindCurrentFolder.qml
new file mode 100644
index 00000000..03cd61bc
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/bindCurrentFolder.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ id: window
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+ required property url initialFolder
+
+ FileDialog {
+ id: dialog
+ objectName: "FileDialog"
+ currentFolder: window.initialFolder
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/bindTitle.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/bindTitle.qml
new file mode 100644
index 00000000..60657f58
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/bindTitle.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ FileDialog {
+ id: dialog
+ title: "Test Title"
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/bindTxtHtmlNameFilters.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/bindTxtHtmlNameFilters.qml
new file mode 100644
index 00000000..1e312fbc
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/bindTxtHtmlNameFilters.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ FileDialog {
+ id: dialog
+ objectName: "FileDialog"
+ nameFilters: ["Text files (*.txt)", "HTML files (*.html)"]
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/data/fileDialog.qml b/tests/auto/dialogs/qquickfiledialogimpl/data/fileDialog.qml
new file mode 100644
index 00000000..febad45c
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/data/fileDialog.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ function doneAccepted() {
+ dialog.done(FileDialog.Accepted)
+ }
+
+ function doneRejected() {
+ dialog.done(FileDialog.Rejected)
+ }
+
+ FileDialog {
+ id: dialog
+ objectName: "FileDialog"
+ }
+}
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/qquickfiledialogimpl.pro b/tests/auto/dialogs/qquickfiledialogimpl/qquickfiledialogimpl.pro
new file mode 100644
index 00000000..3f6e83d7
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/qquickfiledialogimpl.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+TARGET = tst_qquickfiledialogimpl
+SOURCES += tst_qquickfiledialogimpl.cpp
+
+macos:CONFIG -= app_bundle
+
+QT += core-private gui-private testlib qml-private quick-private qmltest quicktemplates2-private
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+OTHER_FILES += \
+ data/*.qml
diff --git a/tests/auto/dialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp b/tests/auto/dialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp
new file mode 100644
index 00000000..a8fe4c15
--- /dev/null
+++ b/tests/auto/dialogs/qquickfiledialogimpl/tst_qquickfiledialogimpl.cpp
@@ -0,0 +1,1349 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../../shared/dialogtestutil.h"
+#include "../../shared/util.h"
+#include "../../shared/visualtestutil.h"
+
+#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuickTest/quicktest.h>
+#include <QtQuickDialogs2/private/qquickfiledialog_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickplatformfiledialog_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfiledialogdelegate_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfolderbreadcrumbbar_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfolderbreadcrumbbar_p_p.h>
+#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p_p.h>
+#include <QtQuickTemplates2/private/qquicklabel_p.h>
+#include <QtQuickTemplates2/private/qquickoverlay_p.h>
+
+using namespace QQuickDialogTestUtil;
+using namespace QQuickVisualTestUtil;
+
+class tst_QQuickFileDialogImpl : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() override;
+ void cleanupTestCase();
+
+ void defaults();
+ void chooseFileViaStandardButtons();
+ void chooseFileViaDoubleClick();
+ void chooseFileViaTextEdit();
+ void chooseFileViaEnter();
+ void bindCurrentFolder_data();
+ void bindCurrentFolder();
+ void changeFolderViaStandardButtons();
+ void changeFolderViaDoubleClick();
+ void chooseFolderViaTextEdit();
+ void chooseFolderViaEnter();
+ void cancelDialogWhileTextEditHasFocus();
+ void goUp();
+ void goUpWhileTextEditHasFocus();
+ void goIntoLargeFolder();
+ void keyAndShortcutHandling();
+ void bindNameFilters();
+ void changeNameFilters();
+ void changeNameFiltersAfterChangingFolder();
+ void tabFocusNavigation();
+ void acceptRejectLabel();
+ void bindTitle();
+ void itemsDisabledWhenNecessary();
+ void fileMode_data();
+ void fileMode();
+ void defaultSuffix_data();
+ void defaultSuffix();
+ void done_data();
+ void done();
+
+private:
+ QQuickAbstractButton *findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText);
+ void enterText(QWindow *window, const QString &textToEnter);
+
+ QTemporaryDir tempDir;
+ QScopedPointer<QFile> tempFile1;
+ QScopedPointer<QFile> tempFile2;
+ QDir tempSubDir;
+ QDir tempSubSubDir;
+ QScopedPointer<QFile> tempSubFile1;
+ QScopedPointer<QFile> tempSubFile2;
+ QDir oldCurrentDir;
+};
+
+QQuickAbstractButton *tst_QQuickFileDialogImpl::findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText)
+{
+ for (int i = 0; i < box->count(); ++i) {
+ auto button = qobject_cast<QQuickAbstractButton*>(box->itemAt(i));
+ if (button && button->text().toUpper() == buttonText.toUpper())
+ return button;
+ }
+ return nullptr;
+}
+
+void tst_QQuickFileDialogImpl::enterText(QWindow *window, const QString &textToEnter)
+{
+ for (int i = 0; i < textToEnter.size(); ++i) {
+ const QChar key = textToEnter.at(i);
+ QTest::keyClick(window, key.toLatin1());
+ }
+}
+
+void tst_QQuickFileDialogImpl::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+
+ QVERIFY(tempDir.isValid());
+ // QTEST_QUICKCONTROLS_MAIN constructs the test case object once,
+ // and then calls qRun() for each style, and qRun() calls initTestCase().
+ // So, we need to check if we've already made the temporary directory.
+ // Note that this is only necessary if the test is run with more than one style.
+ if (!QDir(tempDir.path()).isEmpty())
+ return;
+
+ /*
+ Create a couple of files within the temporary directory. The structure is:
+
+ [temp directory]
+ ├── sub-dir
+ │ ├── sub-sub-dir
+ │ ├── sub-file1.txt
+ │ └── sub-file2.txt
+ ├── file1.txt
+ └── file2.txt
+ */
+ tempSubDir = QDir(tempDir.path());
+ QVERIFY2(tempSubDir.mkdir("sub-dir"), qPrintable(QString::fromLatin1(
+ "Failed to make sub-directory \"sub-dir\" in %1. Permissions are: %2")
+ .arg(tempDir.path()).arg(QDebug::toString(QFileInfo(tempDir.path()).permissions()))));
+ QVERIFY(tempSubDir.cd("sub-dir"));
+
+ tempSubSubDir = QDir(tempSubDir.path());
+ QVERIFY2(tempSubSubDir.mkdir("sub-sub-dir"), qPrintable(QString::fromLatin1(
+ "Failed to make sub-directory \"sub-sub-dir\" in %1. Permissions are: %2")
+ .arg(tempSubDir.path()).arg(QDebug::toString(QFileInfo(tempSubDir.path()).permissions()))));
+ QVERIFY(tempSubSubDir.cd("sub-sub-dir"));
+
+ tempSubFile1.reset(new QFile(tempSubDir.path() + "/sub-file1.txt"));
+ QVERIFY(tempSubFile1->open(QIODevice::ReadWrite));
+
+ tempSubFile2.reset(new QFile(tempSubDir.path() + "/sub-file2.txt"));
+ QVERIFY(tempSubFile2->open(QIODevice::ReadWrite));
+
+ tempFile1.reset(new QFile(tempDir.path() + "/file1.txt"));
+ QVERIFY(tempFile1->open(QIODevice::ReadWrite));
+
+ tempFile2.reset(new QFile(tempDir.path() + "/file2.txt"));
+ QVERIFY(tempFile2->open(QIODevice::ReadWrite));
+
+ // Ensure that each test starts off in the temporary directory.
+ oldCurrentDir = QDir::current();
+ QDir::setCurrent(tempDir.path());
+}
+
+void tst_QQuickFileDialogImpl::cleanupTestCase()
+{
+ // Just in case...
+ QDir::setCurrent(oldCurrentDir.path());
+}
+
+bool verifyFileDialogDelegates(QQuickListView *fileDialogListView, const QStringList &expectedFiles,
+ QString &failureMessage)
+{
+ if (QQuickTest::qIsPolishScheduled(fileDialogListView)) {
+ if (!QQuickTest::qWaitForItemPolished(fileDialogListView)) {
+ failureMessage = QLatin1String("Failed to polish fileDialogListView");
+ return false;
+ }
+ }
+
+ QStringList actualFiles;
+ for (int i = 0; i < fileDialogListView->count(); ++i) {
+ auto delegate = qobject_cast<QQuickFileDialogDelegate*>(findViewDelegateItem(fileDialogListView, i));
+ if (!delegate) {
+ failureMessage = QString::fromLatin1("Delegate at index %1 is null").arg(i);
+ return false;
+ }
+
+ // Need to call absoluteFilePath on Windows; see comment in dialogtestutil.h.
+ actualFiles.append(QFileInfo(delegate->file().toLocalFile()).absoluteFilePath());
+ }
+
+ if (actualFiles != expectedFiles) {
+ failureMessage = QString::fromLatin1("Mismatch in actual vs expected "
+ "delegates in fileDialogListView:\n expected: %1\n actual: %2")
+ .arg(QDebug::toString(expectedFiles)).arg(QDebug::toString(actualFiles));
+ return false;
+ }
+
+ return true;
+}
+
+bool verifyBreadcrumbDelegates(QQuickFolderBreadcrumbBar *breadcrumbBar, const QUrl &expectedFolder,
+ QString &failureMessage)
+{
+ if (!breadcrumbBar) {
+ failureMessage = QLatin1String("breadcrumbBar is null");
+ return false;
+ }
+
+ auto breadcrumbBarListView = qobject_cast<QQuickListView*>(breadcrumbBar->contentItem());
+ if (!breadcrumbBarListView) {
+ failureMessage = QLatin1String("breadcrumbBar's ListView is null");
+ return false;
+ }
+
+ if (QQuickTest::qIsPolishScheduled(breadcrumbBarListView)) {
+ if (!QQuickTest::qWaitForItemPolished(breadcrumbBarListView)) {
+ failureMessage = QLatin1String("Failed to polish breadcrumbBarListView");
+ return false;
+ }
+ }
+
+ QStringList actualCrumbs;
+ for (int i = 0; i < breadcrumbBarListView->count(); ++i) {
+ auto delegate = qobject_cast<QQuickAbstractButton*>(findViewDelegateItem(breadcrumbBarListView, i));
+ if (!delegate) {
+ // It's a separator or some other non-crumb item.
+ continue;
+ }
+
+ actualCrumbs.append(delegate->text());
+ }
+
+ QStringList expectedCrumbs = QQuickFolderBreadcrumbBarPrivate::crumbPathsForFolder(expectedFolder);
+ for (int i = 0; i < expectedCrumbs.size(); ++i) {
+ QString &crumbPath = expectedCrumbs[i];
+ crumbPath = QQuickFolderBreadcrumbBarPrivate::folderBaseName(crumbPath);
+ }
+
+ if (actualCrumbs != expectedCrumbs) {
+ failureMessage = QString::fromLatin1("Mismatch in actual vs expected "
+ "delegates in breadcrumbBarListView:\n expected: %1\n actual: %2")
+ .arg(QDebug::toString(expectedCrumbs)).arg(QDebug::toString(actualCrumbs));
+ return false;
+ }
+
+ return true;
+}
+
+void tst_QQuickFileDialogImpl::defaults()
+{
+ QQuickApplicationHelper helper(this, "fileDialog.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickFileDialog *dialog = window->property("dialog").value<QQuickFileDialog*>();
+ QVERIFY(dialog);
+ COMPARE_URL(dialog->selectedFile(), QUrl());
+ // It should default to the current directory.
+ COMPARE_URL(dialog->currentFolder(), QUrl::fromLocalFile(QDir().absolutePath()));
+ // The first file in the directory should be selected, but not until the dialog is actually open,
+ // as QQuickFileDialogImpl hasn't been created yet.
+ COMPARE_URL(dialog->currentFile(), QUrl());
+ COMPARE_URLS(dialog->currentFiles(), {});
+ QCOMPARE(dialog->title(), QString());
+
+ dialog->open();
+ QQuickFileDialogImpl *quickDialog = window->findChild<QQuickFileDialogImpl*>();
+ QTRY_VERIFY(quickDialog->isOpened());
+ QVERIFY(quickDialog);
+ COMPARE_URL(quickDialog->selectedFile(), QUrl());
+ COMPARE_URL(quickDialog->currentFolder(), QUrl::fromLocalFile(QDir().absolutePath()));
+ COMPARE_URL(dialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ COMPARE_URLS(dialog->currentFiles(), { QUrl::fromLocalFile(tempSubDir.path()) });
+ COMPARE_URL(quickDialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ QCOMPARE(quickDialog->title(), QString());
+}
+
+void tst_QQuickFileDialogImpl::chooseFileViaStandardButtons()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Select the delegate by clicking once.
+ QSignalSpy dialogFileChangedSpy(dialogHelper.dialog, SIGNAL(selectedFileChanged()));
+ QVERIFY(dialogFileChangedSpy.isValid());
+ QSignalSpy dialogCurrentFileChangedSpy(dialogHelper.dialog, SIGNAL(currentFileChanged()));
+ QVERIFY(dialogCurrentFileChangedSpy.isValid());
+ QSignalSpy quickDialogCurrentFileChangedSpy(dialogHelper.quickDialog, SIGNAL(currentFileChanged(const QUrl &)));
+ QVERIFY(quickDialogCurrentFileChangedSpy.isValid());
+
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 2, delegate));
+ COMPARE_URL(delegate->file(), QUrl::fromLocalFile(tempFile2->fileName()));
+ QVERIFY(clickButton(delegate));
+ COMPARE_URL(dialogHelper.quickDialog->currentFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) });
+ // Only currentFile-related signals should be emitted.
+ QCOMPARE(dialogFileChangedSpy.count(), 0);
+ QCOMPARE(dialogCurrentFileChangedSpy.count(), 1);
+ QCOMPARE(quickDialogCurrentFileChangedSpy.count(), 1);
+
+ // Click the "Open" button.
+ QVERIFY(dialogHelper.quickDialog->footer());
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton* openButton = findDialogButton(dialogButtonBox, "Open");
+ QVERIFY(openButton);
+ QVERIFY(clickButton(openButton));
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) });
+ QCOMPARE(dialogFileChangedSpy.count(), 1);
+ COMPARE_URL(dialogHelper.quickDialog->selectedFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+ QVERIFY(!dialogHelper.dialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::chooseFileViaDoubleClick()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Select the delegate by double-clicking.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 2, delegate));
+ COMPARE_URL(delegate->file(), QUrl::fromLocalFile(tempFile2->fileName()))
+ QVERIFY(doubleClickButton(delegate));
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile2->fileName()))
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) })
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl::fromLocalFile(tempFile2->fileName()))
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) })
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::chooseFileViaTextEdit()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+ QCOMPARE(breadcrumbBar->textField()->text(), dialogHelper.dialog->currentFolder().toLocalFile());
+ QCOMPARE(breadcrumbBar->textField()->selectedText(), breadcrumbBar->textField()->text());
+
+ // Enter the path to the file in the text edit.
+ enterText(dialogHelper.window(), tempFile2->fileName());
+ QCOMPARE(breadcrumbBar->textField()->text(), tempFile2->fileName());
+
+ // Hit enter to accept.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Return);
+ COMPARE_URL(dialogHelper.quickDialog->selectedFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) });
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::chooseFileViaEnter()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Before moving down, the first delegate in the view should be selected and have focus.
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *subDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subDirDelegate));
+ COMPARE_URL(subDirDelegate->file(), QUrl::fromLocalFile(tempSubDir.path()));
+ QVERIFY(subDirDelegate->hasActiveFocus());
+
+ // Select the first file in the view by navigating with the down key.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Down);
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile1->fileName()));
+
+ // Select the delegate by pressing enter.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Return);
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl::fromLocalFile(tempFile1->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { QUrl::fromLocalFile(tempFile1->fileName()) });
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+ QCOMPARE(dialogHelper.dialog->result(), QQuickFileDialog::Accepted);
+}
+
+void tst_QQuickFileDialogImpl::bindCurrentFolder_data()
+{
+ QTest::addColumn<QUrl>("initialFolder");
+ QTest::addColumn<QUrl>("expectedFolder");
+ QTest::addColumn<QStringList>("expectedVisibleFiles");
+
+ const auto currentDirUrl = QUrl::fromLocalFile(QDir::current().path());
+ const auto tempSubDirUrl = QUrl::fromLocalFile(tempSubDir.path());
+ const auto tempSubFile1Url = QUrl::fromLocalFile(tempSubFile1->fileName());
+
+ const QStringList currentDirFiles = { tempSubDir.path(), tempFile1->fileName(), tempFile2->fileName() };
+ const QStringList tempSubDirFiles = { tempSubSubDir.path(), tempSubFile1->fileName(), tempSubFile2->fileName() };
+
+ // Setting the folder to "sub-dir" should result in "sub-file1.txt" and "sub-file2.txt" being visible.
+ QTest::addRow("sub-dir") << tempSubDirUrl << tempSubDirUrl << tempSubDirFiles;
+ // Setting a file as the folder shouldn't work, and the dialog shouldn't change its folder.
+ QTest::addRow("sub-dir/sub-file1.txt") << tempSubFile1Url << currentDirUrl << currentDirFiles;
+}
+
+void tst_QQuickFileDialogImpl::bindCurrentFolder()
+{
+ QFETCH(QUrl, initialFolder);
+ QFETCH(QUrl, expectedFolder);
+ QFETCH(QStringList, expectedVisibleFiles);
+
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", initialFolder }});
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), expectedFolder);
+
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QString failureMessage;
+ // Even waiting for ListView polish and that the FolderListModel's status is ready aren't enough
+ // on Windows, apparently, as sometimes there just aren't any delegates by the time we do the check.
+ // So, we use QTRY_VERIFY2 each time we call this function just to be safe.
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView, expectedVisibleFiles, failureMessage), qPrintable(failureMessage));
+
+ // Check that the breadcrumb bar is correct by constructing the expected files from the expectedFolder.
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY2(verifyBreadcrumbDelegates(breadcrumbBar, expectedFolder, failureMessage), qPrintable(failureMessage));
+}
+
+void tst_QQuickFileDialogImpl::changeFolderViaStandardButtons()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Select the delegate by clicking once.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, delegate));
+ COMPARE_URL(delegate->file(), QUrl::fromLocalFile(tempSubDir.path()));
+ QVERIFY(clickButton(delegate));
+ // The selectedFile and currentFolder shouldn't change yet.
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl());
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), {});
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempDir.path()));
+ // The currentFile should, though.
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempSubDir.path()) });
+
+ // Click the "Open" button. The dialog should navigate to that directory, but still be open.
+ QVERIFY(dialogHelper.quickDialog->footer());
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton* openButton = findDialogButton(dialogButtonBox, "Open");
+ QVERIFY(openButton);
+ QVERIFY(clickButton(openButton));
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::changeFolderViaDoubleClick()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Select the "sub-dir" delegate by double-clicking.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *subDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subDirDelegate));
+ COMPARE_URL(subDirDelegate->file(), QUrl::fromLocalFile(tempSubDir.path()));
+ QVERIFY(doubleClickButton(subDirDelegate));
+ // The first file in the directory should be selected, which is "sub-sub-dir".
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubSubDir.path()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempSubSubDir.path()) });
+ QQuickFileDialogDelegate *subSubDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subSubDirDelegate));
+ QCOMPARE(subSubDirDelegate->isHighlighted(), true);
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl());
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), {});
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+ // Since we only chose a folder, the dialog should still be open.
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::chooseFolderViaTextEdit()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+ QCOMPARE(breadcrumbBar->textField()->text(), dialogHelper.dialog->currentFolder().toLocalFile());
+ QCOMPARE(breadcrumbBar->textField()->selectedText(), breadcrumbBar->textField()->text());
+
+ // Enter the path to the folder in the text edit.
+ enterText(dialogHelper.window(), tempSubDir.path());
+ QCOMPARE(breadcrumbBar->textField()->text(), tempSubDir.path());
+
+ // Hit enter to accept.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Return);
+ // The first file in the directory should be selected, which is "sub-sub-dir".
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubSubDir.path()));
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *subSubDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subSubDirDelegate));
+ QCOMPARE(subSubDirDelegate->isHighlighted(), true);
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl());
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), {});
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+ QTRY_VERIFY(dialogHelper.dialog->isVisible());
+
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::chooseFolderViaEnter()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Fhe first delegate in the view should be selected and have focus.
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempDir.path()));
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempSubDir.path()) });
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *subDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subDirDelegate));
+ COMPARE_URL(subDirDelegate->file(), QUrl::fromLocalFile(tempSubDir.path()));
+ QVERIFY(subDirDelegate->hasActiveFocus());
+
+ // Select the delegate by pressing enter.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Return);
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+ // The first file in the new directory should be selected, which is "sub-sub-dir".
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubSubDir.path()));
+ // Since we only chose a folder, the dialog should still be open.
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::cancelDialogWhileTextEditHasFocus()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->hasActiveFocus());
+
+ // Close it via the cancel button.
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ const QString cancelText = QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::Cancel);
+ auto cancelButton = findDialogButton(dialogButtonBox, cancelText);
+ QVERIFY(cancelButton);
+ QVERIFY(clickButton(cancelButton));
+
+ // Open it again. The text field should not be visible, but the breadcrumb bar itself should be.
+ dialogHelper.dialog->open();
+ QVERIFY(dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(dialogHelper.quickDialog->isOpened());
+ QVERIFY(breadcrumbBar->isVisible());
+ // The ListView that contains the breadcrumb delegates should be visible.
+ QVERIFY(breadcrumbBar->contentItem()->isVisible());
+ QVERIFY(!breadcrumbBar->textField()->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::goUp()
+{
+ // Open the dialog. Start off in "sub-dir".
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", QUrl::fromLocalFile(tempSubDir.path()) }});
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Go up a directory via the button next to the breadcrumb bar.
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ auto barListView = qobject_cast<QQuickListView*>(breadcrumbBar->contentItem());
+ QVERIFY(barListView);
+ if (QQuickTest::qIsPolishScheduled(barListView))
+ QVERIFY(QQuickTest::qWaitForItemPolished(barListView));
+ QVERIFY(clickButton(breadcrumbBar->upButton()));
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempDir.path()));
+ // The previous directory that we were in should now be selected (matches e.g. Windows and Ubuntu).
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempSubDir.path()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempSubDir.path()) });
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *subDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subDirDelegate));
+ QCOMPARE(subDirDelegate->isHighlighted(), true);
+
+ // Go up a directory via the keyboard shortcut next to the breadcrumb bar.
+ const auto goUpKeySequence = QKeySequence(Qt::ALT | Qt::Key_Up);
+ QTest::keySequence(dialogHelper.window(), goUpKeySequence);
+ QDir tempParentDir(tempDir.path());
+ QVERIFY(tempParentDir.cdUp());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempParentDir.path()));
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempDir.path()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempDir.path()) });
+}
+
+void tst_QQuickFileDialogImpl::goUpWhileTextEditHasFocus()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", QUrl::fromLocalFile(tempSubDir.path()) }});
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->hasActiveFocus());
+
+ // Go up a directory via the button next to the breadcrumb bar.
+ auto barListView = qobject_cast<QQuickListView*>(breadcrumbBar->contentItem());
+ QVERIFY(barListView);
+ if (QQuickTest::qIsPolishScheduled(barListView))
+ QVERIFY(QQuickTest::qWaitForItemPolished(barListView));
+ QVERIFY(clickButton(breadcrumbBar->upButton()));
+ // The path should have changed to the parent directory.
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempDir.path()));
+ // The text edit should be hidden when it loses focus.
+ QVERIFY(!breadcrumbBar->textField()->hasActiveFocus());
+ QVERIFY(!breadcrumbBar->textField()->isVisible());
+ // The focus should be given to the first delegate.
+ QVERIFY(dialogHelper.window()->activeFocusItem());
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *firstDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, firstDelegate));
+ QCOMPARE(dialogHelper.window()->activeFocusItem(), firstDelegate);
+}
+
+void tst_QQuickFileDialogImpl::goIntoLargeFolder()
+{
+ // Create a throwaway directory with a lot of folders within it...
+ QTemporaryDir anotherTempDir;
+ QVERIFY(anotherTempDir.isValid());
+ for (int i = 0; i < 30; ++i) {
+ QDir newDir(anotherTempDir.path());
+ QVERIFY(newDir.exists());
+ // Pad with zeroes so that the directories are ordered as we expect.
+ QVERIFY(newDir.mkdir(QString::fromLatin1("dir%1").arg(i, 2, 10, QLatin1Char('0'))));
+ }
+
+ // ... and within one of those folders, more folders.
+ QDir dir20(anotherTempDir.path() + "/dir20");
+ QVERIFY(dir20.exists());
+ for (int i = 0; i < 30; ++i) {
+ QDir newDir(dir20.path());
+ QVERIFY(newDir.exists());
+ QVERIFY(newDir.mkdir(QString::fromLatin1("subdir%1").arg(i, 2, 10, QLatin1Char('0'))));
+ }
+
+ // Open the dialog. Start off in the throwaway directory.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", QUrl::fromLocalFile(anotherTempDir.path()) }});
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // If the screen is so tall that the contentItem is not vertically larger than the view,
+ // then the test makes no sense.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ if (QQuickTest::qIsPolishScheduled(fileDialogListView))
+ QVERIFY(QQuickTest::qWaitForItemPolished(fileDialogListView));
+ // Just to be safe, make sure it's at least twice as big.
+ if (fileDialogListView->contentItem()->height() < fileDialogListView->height() * 2) {
+ QSKIP(qPrintable(QString::fromLatin1("Expected height of fileDialogListView's contentItem (%1)" \
+ " to be at least twice as big as the ListView's height (%2)")
+ .arg(fileDialogListView->contentItem()->height()).arg(fileDialogListView->height())));
+ }
+
+ // Scroll down to dir20. The view should be somewhere past the middle.
+ QVERIFY(QMetaObject::invokeMethod(fileDialogListView, "positionViewAtIndex", Qt::DirectConnection,
+ Q_ARG(int, 20), Q_ARG(int, QQuickItemView::PositionMode::Center)));
+ QVERIFY(fileDialogListView->contentY() > 0);
+
+ // Go into it. The view should start at the top of the directory, not at the same contentY
+ // that it had in the previous directory.
+ QQuickFileDialogDelegate *dir20Delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 20, dir20Delegate));
+ COMPARE_URL(dir20Delegate->file(), QUrl::fromLocalFile(dir20.path()));
+ QVERIFY(doubleClickButton(dir20Delegate));
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(dir20.path()));
+ COMPARE_URL(dialogHelper.quickDialog->currentFolder(), QUrl::fromLocalFile(dir20.path()));
+ QCOMPARE(fileDialogListView->contentY(), 0);
+}
+
+void tst_QQuickFileDialogImpl::keyAndShortcutHandling()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+ QCOMPARE(breadcrumbBar->textField()->text(), dialogHelper.dialog->currentFolder().toLocalFile());
+ QCOMPARE(breadcrumbBar->textField()->selectedText(), breadcrumbBar->textField()->text());
+
+ // Ctrl+L shouldn't hide it.
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+
+ // Cancel it with the escape key.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Escape);
+ QVERIFY(!breadcrumbBar->textField()->isVisible());
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ // Make it visible.
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+
+ // Cancel it with the escape key again.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Escape);
+ QVERIFY(!breadcrumbBar->textField()->isVisible());
+ QVERIFY(dialogHelper.dialog->isVisible());
+
+ // Pressing escape now should close the dialog.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Escape);
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFileDialogImpl::bindNameFilters()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindTxtHtmlNameFilters.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Only "sub-dir", "text1.txt" and "text2.txt" should be visible, since *.txt is the first filter.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QString failureMessage;
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView,
+ { tempSubDir.path(), tempFile1->fileName(), tempFile2->fileName() }, failureMessage), qPrintable(failureMessage));
+}
+
+void tst_QQuickFileDialogImpl::changeNameFilters()
+{
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+
+ // Open the dialog and check that selectedNameFilter is correct.
+ // By default, QFileDialogOptions::defaultNameFilterString() is used.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->name(), "All Files");
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->name(), "All Files");
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->index(), 0);
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->index(), 0);
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->extensions(), { "*" });
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->extensions(), { "*" });
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->globs(), { "*" });
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->globs(), { "*" });
+
+ // Close the dialog.
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+
+ // Set .txt and .html filters.
+ QSignalSpy nameFiltersChangedSpy(dialogHelper.dialog, SIGNAL(nameFiltersChanged()));
+ QVERIFY(nameFiltersChangedSpy.isValid());
+ const QStringList nameFilters = { "Text files (*.txt)", "HTML files (*.html)" };
+ dialogHelper.dialog->setNameFilters(nameFilters);
+ QCOMPARE(dialogHelper.dialog->nameFilters(), nameFilters);
+ QCOMPARE(nameFiltersChangedSpy.count(), 1);
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->name(), "Text files");
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->index(), 0);
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->extensions(), { "txt" });
+ QCOMPARE(dialogHelper.dialog->selectedNameFilter()->globs(), { "*.txt" });
+
+ // Re-open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ // QQuickFileDialogImpl's values only get set before opening.
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->name(), "Text files");
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->index(), 0);
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->extensions(), { "txt" });
+ QCOMPARE(dialogHelper.quickDialog->selectedNameFilter()->globs(), { "*.txt" });
+
+ // Only "sub-dir", "text1.txt" and "text2.txt" should be visible, since *.txt is the first filter.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QString failureMessage;
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView,
+ { tempSubDir.path(), tempFile1->fileName(), tempFile2->fileName() }, failureMessage), qPrintable(failureMessage));
+
+ // Open the ComboBox's popup.
+ const QQuickComboBox *comboBox = dialogHelper.quickDialog->findChild<QQuickComboBox*>();
+ QVERIFY(comboBox);
+ const QPoint comboBoxCenterPos = comboBox->mapToScene({ comboBox->width() / 2, comboBox->height() / 2 }).toPoint();
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, comboBoxCenterPos);
+ QTRY_VERIFY(comboBox->popup()->isOpened());
+
+ // Select the .html delegate and close the combobox popup. The only visible entry should be the sub-dir.
+ QQuickListView *comboBoxPopupListView = qobject_cast<QQuickListView*>(comboBox->popup()->contentItem());
+ QVERIFY(comboBoxPopupListView);
+ {
+ QQuickAbstractButton *htmlDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(comboBoxPopupListView, 1, htmlDelegate));
+ QVERIFY(clickButton(htmlDelegate));
+ }
+ QTRY_VERIFY(!comboBox->popup()->isVisible());
+ // Use QTRY_VERIFY2 here to fix a failure on QEMU armv7 (QT_QPA_PLATFORM=offscreen).
+ // Not sure why it's necessary.
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView, { tempSubDir.path() }, failureMessage), qPrintable(failureMessage));
+
+ // Open the popup again.
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, comboBoxCenterPos);
+ QTRY_VERIFY(comboBox->popup()->isOpened());
+
+ // Select .txt and close the combobox popup. The original entries should be visible.
+ {
+ QQuickAbstractButton *txtDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(comboBoxPopupListView, 0, txtDelegate));
+ QCOMPARE(txtDelegate->text(), nameFilters.at(0));
+ QVERIFY(clickButton(txtDelegate));
+ }
+ QTRY_VERIFY(!comboBox->popup()->isVisible());
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView,
+ { tempSubDir.path(), tempFile1->fileName(), tempFile2->fileName() }, failureMessage), qPrintable(failureMessage));
+}
+
+void tst_QQuickFileDialogImpl::changeNameFiltersAfterChangingFolder()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindAllTxtHtmlNameFilters.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Go into the "sub-dir" folder.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QString failureMessage;
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView,
+ { tempSubDir.path(), tempFile1->fileName(), tempFile2->fileName() }, failureMessage), qPrintable(failureMessage));
+ QQuickFileDialogDelegate *subDirDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, subDirDelegate));
+ QVERIFY(doubleClickButton(subDirDelegate));
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+ COMPARE_URL(dialogHelper.quickDialog->currentFolder(), QUrl::fromLocalFile(tempSubDir.path()));
+
+ // Open the ComboBox's popup.
+ const QQuickComboBox *comboBox = dialogHelper.quickDialog->findChild<QQuickComboBox*>();
+ QVERIFY(comboBox);
+ const QPoint comboBoxCenterPos = comboBox->mapToScene({ comboBox->width() / 2, comboBox->height() / 2 }).toPoint();
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, comboBoxCenterPos);
+ QTRY_VERIFY(comboBox->popup()->isOpened());
+
+ // Select the .html delegate, close the combobox popup, and ensure that the change had an effect.
+ QQuickListView *comboBoxPopupListView = qobject_cast<QQuickListView*>(comboBox->popup()->contentItem());
+ QVERIFY(comboBoxPopupListView);
+ {
+ QQuickAbstractButton *htmlDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(comboBoxPopupListView, 2, htmlDelegate));
+ QVERIFY(clickButton(htmlDelegate));
+ }
+ QTRY_VERIFY(!comboBox->popup()->isVisible());
+ // There are no HTML files in "sub-dir", so there should only be the one "sub-sub-dir" delegate.
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView, { tempSubSubDir.path() }, failureMessage), qPrintable(failureMessage));
+}
+
+void tst_QQuickFileDialogImpl::tabFocusNavigation()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindTxtHtmlNameFilters.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QList<QQuickItem*> expectedFocusItems;
+
+ // The initial focus should be on the first delegate.
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *firstDelegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, firstDelegate));
+ expectedFocusItems << firstDelegate;
+
+ // Tab should move to the name filters combobox.
+ QQuickComboBox *comboBox = dialogHelper.quickDialog->findChild<QQuickComboBox*>();
+ QVERIFY(comboBox);
+ expectedFocusItems << comboBox;
+
+ // Next, the left-most dialog button.
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QCOMPARE(dialogButtonBox->count(), 2);
+ auto leftMostButton = qobject_cast<QQuickAbstractButton*>(dialogButtonBox->itemAt(0));
+ QVERIFY(leftMostButton);
+ expectedFocusItems << leftMostButton;
+
+ // Then, the right-most dialog button.
+ auto rightMostButton = qobject_cast<QQuickAbstractButton*>(dialogButtonBox->itemAt(1));
+ QVERIFY(rightMostButton);
+ expectedFocusItems << rightMostButton;
+
+ // Then, the up button.
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ expectedFocusItems << breadcrumbBar->upButton();
+
+ // Finally, add each bread crumb delegate.
+ for (int i = 0; i < fileDialogListView->count(); ++i) {
+ QQuickFileDialogDelegate *delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, i, delegate));
+ expectedFocusItems << delegate;
+ }
+
+ // Tab through each item, checking the focus after each.
+ for (auto expectedFocusItem : qAsConst(expectedFocusItems)) {
+ // Check the focus item first so that we account for the first item.
+ // Print detailed failure message as workaround for QTBUG-92102.
+ QVERIFY2(dialogHelper.window()->activeFocusItem() == expectedFocusItem, qPrintable(QString::fromLatin1(
+ "\n Actual: %1\n Expected: %2").arg(QDebug::toString(dialogHelper.window()->activeFocusItem()))
+ .arg(QDebug::toString(expectedFocusItem))));
+
+ if (expectedFocusItem != expectedFocusItems.last())
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Tab);
+ }
+
+ // Ensure the order is reversed when shift-tabbing.
+ std::reverse(expectedFocusItems.begin(), expectedFocusItems.end());
+ // We know the first (last) item has focus already, so skip it.
+ expectedFocusItems.removeFirst();
+ for (auto expectedFocusItem : qAsConst(expectedFocusItems)) {
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Tab, Qt::ShiftModifier);
+
+ QCOMPARE(dialogHelper.window()->activeFocusItem(), expectedFocusItem);
+ }
+}
+
+void tst_QQuickFileDialogImpl::acceptRejectLabel()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "acceptRejectLabel.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Check that the accept and reject buttons' labels have changed.
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QVERIFY(findDialogButton(dialogButtonBox, "AcceptTest"));
+ QVERIFY(findDialogButton(dialogButtonBox, "RejectTest"));
+
+ // Close the dialog.
+ dialogHelper.dialog->close();
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+
+ // Reset back to the default text.
+ dialogHelper.dialog->resetAcceptLabel();
+ dialogHelper.dialog->resetRejectLabel();
+
+ // Re-open the dialog.
+ dialogHelper.dialog->open();
+ QVERIFY(dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(dialogHelper.quickDialog->isOpened());
+
+ // Check that the defaults are back.
+ const QString openText = QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::Open);
+ QVERIFY2(findDialogButton(dialogButtonBox, openText), qPrintable(QString::fromLatin1(
+ "Failed to find dialog button with text \"%1\"").arg(openText)));
+ const QString cancelText = QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::Cancel);
+ QVERIFY2(findDialogButton(dialogButtonBox, cancelText), qPrintable(QString::fromLatin1(
+ "Failed to find dialog button with text \"%1\"").arg(cancelText)));
+}
+
+void tst_QQuickFileDialogImpl::bindTitle()
+{
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindTitle.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Open the dialog and check that the correct title is displayed.
+ QQuickFileDialog *dialog = dialogHelper.window()->property("dialog").value<QQuickFileDialog*>();
+ QVERIFY(dialog);
+ const QString expectedTitle = QLatin1String("Test Title");
+ QCOMPARE(dialogHelper.dialog->title(), expectedTitle);
+ QCOMPARE(dialogHelper.quickDialog->title(), expectedTitle);
+ auto header = dialogHelper.quickDialog->header();
+ QVERIFY(header);
+ auto dialogTitleBarLabel = dialogHelper.quickDialog->header()->findChild<QQuickLabel*>("dialogTitleBarLabel");
+ QVERIFY(dialogTitleBarLabel);
+ QCOMPARE(dialogTitleBarLabel->text(), expectedTitle);
+}
+
+void tst_QQuickFileDialogImpl::itemsDisabledWhenNecessary()
+{
+ QTemporaryDir anotherTempDir;
+ QVERIFY(anotherTempDir.isValid());
+ QDir subDir(anotherTempDir.path());
+ QVERIFY(subDir.mkdir("emptyDir"));
+ QVERIFY(subDir.cd("emptyDir"));
+
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", QUrl::fromLocalFile(subDir.path()) }});
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(subDir.path()));
+ COMPARE_URL(dialogHelper.quickDialog->currentFolder(), QUrl::fromLocalFile(subDir.path()));
+
+ // We opened it in a folder that has no files, so the Open button should be disabled.
+ QVERIFY(dialogHelper.quickDialog->footer());
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton* openButton = findDialogButton(dialogButtonBox, "Open");
+ QVERIFY(openButton);
+ QCOMPARE(openButton->isEnabled(), false);
+
+ // Now go up. The Open button should now be enabled.
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(clickButton(breadcrumbBar->upButton()));
+ QCOMPARE(openButton->isEnabled(), true);
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(anotherTempDir.path()));
+ COMPARE_URL(dialogHelper.quickDialog->currentFolder(), QUrl::fromLocalFile(anotherTempDir.path()));
+
+ // Get the text edit visible with Ctrl+L. The Open button should now be disabled.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+ QCOMPARE(openButton->isEnabled(), false);
+
+ // Hide it with the escape key. The Open button should now be enabled.
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Escape);
+ QVERIFY(!breadcrumbBar->textField()->isVisible());
+ QCOMPARE(openButton->isEnabled(), true);
+}
+
+void tst_QQuickFileDialogImpl::fileMode_data()
+{
+ QTest::addColumn<QQuickFileDialog::FileMode>("fileMode");
+
+ QTest::newRow("OpenFile") << QQuickFileDialog::OpenFile;
+ QTest::newRow("OpenFiles") << QQuickFileDialog::OpenFiles;
+ QTest::newRow("SaveFile") << QQuickFileDialog::SaveFile;
+}
+
+void tst_QQuickFileDialogImpl::fileMode()
+{
+ QFETCH(QQuickFileDialog::FileMode, fileMode);
+
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ dialogHelper.dialog->setFileMode(fileMode);
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Select the first file (not a directory).
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QQuickFileDialogDelegate *tempFile1Delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 1, tempFile1Delegate));
+ COMPARE_URL(tempFile1Delegate->file(), QUrl::fromLocalFile(tempFile1->fileName()));
+ QVERIFY(clickButton(tempFile1Delegate));
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile1->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempFile1->fileName()) });
+
+ // All modes should support opening an existing file, so the Open button should be enabled.
+ QVERIFY(dialogHelper.quickDialog->footer());
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton* openButton = findDialogButton(dialogButtonBox, "Open");
+ QVERIFY(openButton);
+ QCOMPARE(openButton->isEnabled(), true);
+
+ // Only the OpenFiles mode should allow multiple files to be selected, however.
+ QQuickFileDialogDelegate *tempFile2Delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 2, tempFile2Delegate));
+ COMPARE_URL(tempFile2Delegate->file(), QUrl::fromLocalFile(tempFile2->fileName()));
+ QTest::keyPress(dialogHelper.window(), Qt::Key_Shift);
+ QVERIFY(clickButton(tempFile2Delegate));
+ QTest::keyRelease(dialogHelper.window(), Qt::Key_Shift);
+ if (fileMode == QQuickFileDialog::OpenFiles) {
+ // currentFile() always points to the first file in the list of selected files.
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile1->fileName()));
+ const QList<QUrl> expectedSelectedFiles = {
+ QUrl::fromLocalFile(tempFile1->fileName()), QUrl::fromLocalFile(tempFile2->fileName()) };
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), expectedSelectedFiles);
+ } else {
+ // OpenFile and SaveFile dialogs should have tempFile2 selected since it was clicked,
+ // but the shift should do nothing, so tempFile1 should no longer be selected.
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) });
+ }
+
+ // Get the text edit visible with Ctrl+L.
+ const auto editPathKeySequence = QKeySequence(Qt::CTRL | Qt::Key_L);
+ QTest::keySequence(dialogHelper.window(), editPathKeySequence);
+ auto breadcrumbBar = dialogHelper.quickDialog->findChild<QQuickFolderBreadcrumbBar*>();
+ QVERIFY(breadcrumbBar);
+ QVERIFY(breadcrumbBar->textField()->isVisible());
+
+ // Typing in the name of an non-existent file should only work for SaveFile.
+ const QString nonExistentFilePath = "/foo/bar.txt";
+ enterText(dialogHelper.window(), nonExistentFilePath);
+ QCOMPARE(breadcrumbBar->textField()->text(), nonExistentFilePath);
+ QTest::keyClick(dialogHelper.window(), Qt::Key_Return);
+ if (fileMode == QQuickFileDialog::SaveFile) {
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), QUrl::fromLocalFile(nonExistentFilePath));
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { QUrl::fromLocalFile(nonExistentFilePath) });
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+ } else {
+ // For OpenFile(s), we do what Qt Quick Dialogs 1.x did, and restore the previous (valid) dir path.
+ // The currentFile(s) should remain unchanged too.
+ QVERIFY(dialogHelper.dialog->isVisible());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempDir.path()));
+ QCOMPARE(breadcrumbBar->textField()->text(), tempDir.path());
+
+ // Should be unchanged from the last time.
+ if (fileMode == QQuickFileDialog::OpenFiles) {
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile1->fileName()));
+ const QList<QUrl> expectedSelectedFiles = {
+ QUrl::fromLocalFile(tempFile1->fileName()), QUrl::fromLocalFile(tempFile2->fileName()) };
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), expectedSelectedFiles);
+ } else { // OpenFile
+ COMPARE_URL(dialogHelper.dialog->currentFile(), QUrl::fromLocalFile(tempFile2->fileName()));
+ COMPARE_URLS(dialogHelper.dialog->currentFiles(), { QUrl::fromLocalFile(tempFile2->fileName()) });
+ }
+ }
+}
+
+void tst_QQuickFileDialogImpl::defaultSuffix_data()
+{
+ QTest::addColumn<QString>("defaultSuffix");
+
+ QTest::newRow("txt") << "txt";
+ QTest::newRow(".txt") << ".txt";
+}
+
+void tst_QQuickFileDialogImpl::defaultSuffix()
+{
+ QFETCH(QString, defaultSuffix);
+
+ // Simplify the test by using a directory with no files, and add a single file there.
+ QFile tempFile1(tempSubSubDir.path() + "/file1");
+ QVERIFY(tempFile1.open(QIODevice::ReadWrite));
+
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "bindCurrentFolder.qml", {},
+ {{ "initialFolder", QUrl::fromLocalFile(tempSubSubDir.path()) }});
+ dialogHelper.dialog->setDefaultSuffix(defaultSuffix);
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ COMPARE_URL(dialogHelper.dialog->currentFolder(), QUrl::fromLocalFile(tempSubSubDir.path()));
+
+ // There should be one extension-less file: "file1".
+ auto fileDialogListView = dialogHelper.quickDialog->findChild<QQuickListView*>("fileDialogListView");
+ QVERIFY(fileDialogListView);
+ QString failureMessage;
+ const QStringList expectedVisibleFiles = { tempFile1.fileName() };
+ QTRY_VERIFY2(verifyFileDialogDelegates(fileDialogListView, expectedVisibleFiles, failureMessage), qPrintable(failureMessage));
+
+ // Choose the delegate. The suffix should be added to the delegates.
+ QQuickFileDialogDelegate *file1Delegate = nullptr;
+ QTRY_VERIFY(findViewDelegateItem(fileDialogListView, 0, file1Delegate));
+ COMPARE_URL(file1Delegate->file(), QUrl::fromLocalFile(tempFile1.fileName()));
+ QVERIFY(doubleClickButton(file1Delegate));
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+ const QUrl fileUrlWithSuffix = QUrl::fromLocalFile(tempFile1.fileName() + ".txt");
+ COMPARE_URL(dialogHelper.dialog->selectedFile(), fileUrlWithSuffix);
+ COMPARE_URLS(dialogHelper.dialog->selectedFiles(), { fileUrlWithSuffix });
+}
+
+void tst_QQuickFileDialogImpl::done_data()
+{
+ QTest::addColumn<QQuickFileDialog::StandardCode>("result");
+
+ QTest::newRow("Accepted") << QQuickFileDialog::Accepted;
+ QTest::newRow("Rejected") << QQuickFileDialog::Rejected;
+}
+
+void tst_QQuickFileDialogImpl::done()
+{
+ QFETCH(QQuickFileDialog::StandardCode, result);
+
+ // Open the dialog.
+ DialogTestHelper<QQuickFileDialog, QQuickFileDialogImpl> dialogHelper(this, "fileDialog.qml");
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage());
+ QVERIFY(dialogHelper.waitForWindowActive());
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ switch (result) {
+ case QQuickFileDialog::Accepted:
+ QVERIFY(QMetaObject::invokeMethod(dialogHelper.window(), "doneAccepted"));
+ break;
+ case QQuickFileDialog::Rejected:
+ QVERIFY(QMetaObject::invokeMethod(dialogHelper.window(), "doneRejected"));
+ break;
+ }
+
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+ QCOMPARE(dialogHelper.dialog->result(), result);
+}
+
+int main(int argc, char *argv[])
+{
+ // We need to set this attribute, and this (defining main() ourselves and
+ // calling QTEST_MAIN_IMPL) seems to be the nicest way to do it without
+ // duplicating too much code.
+ // We also don't want to run this for every style, as each one will have
+ // different ways of implementing the dialogs.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
+ // For now we only test one style.
+ QQuickStyle::setStyle("Basic");
+ QTEST_MAIN_IMPL(tst_QQuickFileDialogImpl)
+}
+
+#include "tst_qquickfiledialogimpl.moc"
diff --git a/tests/auto/dialogs/qquickfontdialogimpl/BLACKLIST b/tests/auto/dialogs/qquickfontdialogimpl/BLACKLIST
new file mode 100644
index 00000000..acabf6c5
--- /dev/null
+++ b/tests/auto/dialogs/qquickfontdialogimpl/BLACKLIST
@@ -0,0 +1,4 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+# QTBUG-94225
+[listViews]
+b2qt
diff --git a/tests/auto/dialogs/qquickfontdialogimpl/CMakeLists.txt b/tests/auto/dialogs/qquickfontdialogimpl/CMakeLists.txt
new file mode 100644
index 00000000..0250c64e
--- /dev/null
+++ b/tests/auto/dialogs/qquickfontdialogimpl/CMakeLists.txt
@@ -0,0 +1,39 @@
+# 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_qquickfontdialogimpl
+ SOURCES
+ ../../shared/qtest_quickcontrols.h
+ ../../shared/util.cpp ../../shared/util.h
+ ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
+ tst_qquickfontdialogimpl.cpp
+ DEFINES
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/imports\\\"
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2
+ Qt::QuickControls2Private
+ Qt::QuickDialogs2Private
+ Qt::QuickDialogs2QuickImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+ Qt::QuickTest
+ Qt::TestPrivate
+ TESTDATA ${test_data}
+)
+
+qt_internal_extend_target(tst_qquickfontdialogimpl CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\":/data\\\"
+)
+
+qt_internal_extend_target(tst_qquickfontdialogimpl CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+)
diff --git a/tests/auto/dialogs/qquickfontdialogimpl/data/fontDialog.qml b/tests/auto/dialogs/qquickfontdialogimpl/data/fontDialog.qml
new file mode 100644
index 00000000..4979d473
--- /dev/null
+++ b/tests/auto/dialogs/qquickfontdialogimpl/data/fontDialog.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ width: 640
+ height: 480
+
+ property alias dialog: dialog
+
+ FontDialog {
+ id: dialog
+ objectName: "FontDialog"
+ }
+}
diff --git a/tests/auto/dialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp b/tests/auto/dialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp
new file mode 100644
index 00000000..42f60f1b
--- /dev/null
+++ b/tests/auto/dialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../../shared/dialogtestutil.h"
+#include "../../shared/util.h"
+#include "../../shared/visualtestutil.h"
+
+#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+#include <QtQuickDialogs2/private/qquickfontdialog_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfontdialogimpl_p.h>
+#include <QtQuickTest/quicktest.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p_p.h>
+#include <QtQuickTemplates2/private/qquicklabel_p.h>
+#include <QtQuickTemplates2/private/qquickoverlay_p.h>
+
+using namespace QQuickDialogTestUtil;
+using namespace QQuickVisualTestUtil;
+
+class tst_QQuickFontDialogImpl : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void writingSystem();
+ void listViews();
+ void effects();
+ void changeFontSize();
+ void changeDialogTitle();
+ void searchFamily();
+
+private:
+ QQuickAbstractButton *findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText)
+ {
+ for (int i = 0; i < box->count(); ++i) {
+ auto button = qobject_cast<QQuickAbstractButton *>(box->itemAt(i));
+ if (button && button->text().toUpper() == buttonText.toUpper())
+ return button;
+ }
+ return nullptr;
+ }
+
+ bool closePopup(DialogTestHelper<QQuickFontDialog, QQuickFontDialogImpl> *dialogHelper,
+ QString dialogButton, QString &failureMessage)
+ {
+ auto dialogButtonBox =
+ dialogHelper->quickDialog->footer()->findChild<QQuickDialogButtonBox *>();
+
+ if (!dialogButtonBox) {
+ failureMessage = QLatin1String("dialogButtonBox is null");
+ return false;
+ }
+
+ QQuickAbstractButton *openButton = findDialogButton(dialogButtonBox, dialogButton);
+
+ if (!openButton) {
+ failureMessage =
+ QLatin1String("Couldn't find a button with text '%1'").arg(dialogButton);
+ return false;
+ }
+
+ bool clicked = clickButton(openButton);
+
+ if (!clicked) {
+ failureMessage = QLatin1String("'%1' button was never clicked").arg(dialogButton);
+ return false;
+ }
+
+ bool visible = dialogHelper->dialog->isVisible();
+ if (visible) {
+ failureMessage = QLatin1String("Dialog is still visible after clicking the '%1' button")
+ .arg(dialogButton);
+ return false;
+ }
+ return true;
+ }
+};
+
+#define CREATE_DIALOG_TEST_HELPER \
+ DialogTestHelper<QQuickFontDialog, QQuickFontDialogImpl> dialogHelper(this, "fontDialog.qml"); \
+ QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage()); \
+ QVERIFY(dialogHelper.waitForWindowActive());
+
+#define CLOSE_DIALOG(BUTTON) \
+ QString errorMessage; \
+ QVERIFY2(closePopup(&dialogHelper, BUTTON, errorMessage), qPrintable(errorMessage)); \
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+
+void tst_QQuickFontDialogImpl::writingSystem()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ const QQuickTextEdit *sampleEdit =
+ dialogHelper.quickDialog->findChild<QQuickTextEdit *>("sampleEdit");
+ QVERIFY(sampleEdit);
+
+ QCOMPARE(sampleEdit->text(), QFontDatabase::writingSystemSample(QFontDatabase::Any));
+
+ // Check that the font family list view exist and add signal spy.
+ const QQuickListView *fontFamilyListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("familyListView");
+ QVERIFY(fontFamilyListView);
+ QSignalSpy fontFamilyModelSpy(fontFamilyListView, SIGNAL(modelChanged()));
+
+ // Open the ComboBox's popup.
+ const QQuickComboBox *writingSystemComboBox = dialogHelper.quickDialog->findChild<QQuickComboBox*>();
+ QVERIFY(writingSystemComboBox);
+ const QPoint comboBoxCenterPos = writingSystemComboBox->mapToScene({ writingSystemComboBox->width() / 2, writingSystemComboBox->height() / 2 }).toPoint();
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, comboBoxCenterPos);
+ QTRY_VERIFY(writingSystemComboBox->popup()->isOpened());
+
+ // "Any" should be selected by default.
+ QQuickListView *comboBoxPopupListView = qobject_cast<QQuickListView*>(writingSystemComboBox->popup()->contentItem());
+ QVERIFY(comboBoxPopupListView);
+ const int anyIndex = QFontDatabase::Any;
+ QQuickAbstractButton *anyDelegate = qobject_cast<QQuickAbstractButton*>(findViewDelegateItem(comboBoxPopupListView, anyIndex));
+ QVERIFY(anyDelegate);
+ QCOMPARE(anyDelegate->text(), QFontDatabase::writingSystemName(QFontDatabase::Any));
+
+ QCOMPARE(fontFamilyModelSpy.count(), 0);
+
+ // Select "Japanese" from the ComboBox.
+ const int japaneseIndex = QFontDatabase::Japanese;
+ QQuickAbstractButton *japaneseDelegate = qobject_cast<QQuickAbstractButton*>(findViewDelegateItem(comboBoxPopupListView, japaneseIndex));
+ QVERIFY(japaneseDelegate);
+ QCOMPARE(japaneseDelegate->text(), QFontDatabase::writingSystemName(QFontDatabase::Japanese));
+ QVERIFY(clickButton(japaneseDelegate));
+ QTRY_VERIFY(!writingSystemComboBox->popup()->isVisible());
+
+ // Check that the contents of the font family listview changed
+ QCOMPARE(fontFamilyModelSpy.count(), 1);
+
+ // And that the sample text is correctly set
+ QCOMPARE(sampleEdit->text(), QFontDatabase::writingSystemSample(QFontDatabase::Japanese));
+
+ // Then accept it to close it.
+ auto dialogButtonBox = dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox*>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton* openButton = findDialogButton(dialogButtonBox, "Ok");
+ QVERIFY(openButton);
+ QVERIFY(clickButton(openButton));
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+}
+
+void tst_QQuickFontDialogImpl::listViews()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QQuickListView *fontFamilyListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("familyListView");
+ QVERIFY(fontFamilyListView);
+
+ const QQuickListView *fontStyleListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("styleListView");
+ QVERIFY(fontStyleListView);
+
+ const QQuickListView *fontSizeListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("sizeListView");
+ QVERIFY(fontSizeListView);
+
+ QSignalSpy currentFontSpy(dialogHelper.dialog, SIGNAL(currentFontChanged()));
+ QSignalSpy styleModelSpy(fontStyleListView, SIGNAL(modelChanged()));
+ QSignalSpy sizeModelSpy(fontSizeListView, SIGNAL(modelChanged()));
+
+ QCOMPARE(fontFamilyListView->currentIndex(), 0);
+ QCOMPARE(fontStyleListView->currentIndex(), 0);
+ QCOMPARE(fontSizeListView->currentIndex(), 0);
+
+ auto fontListModel = QFontDatabase::families(QFontDatabase::WritingSystem::Any);
+ fontListModel.removeIf(QFontDatabase::isPrivateFamily);
+
+ // In case the font database contains a significant number of font families
+ const int maxNumberOfFamiliesToTest = 10;
+
+ for (auto i = 1; i < qMin(fontListModel.size(), maxNumberOfFamiliesToTest); ++i) {
+ currentFontSpy.clear();
+ styleModelSpy.clear();
+ sizeModelSpy.clear();
+
+ const QString err = QString("LOOP INDEX %1, EXPECTED %2, ACTUAL %3").arg(i);
+
+ const QFont currentFont = dialogHelper.dialog->currentFont();
+
+ const auto oldStyleModel = fontStyleListView->model();
+ const auto oldSizeModel = fontSizeListView->model();
+
+ const QString expected1 = fontListModel[i - 1], actual1 = currentFont.family();
+ QVERIFY2(expected1 == actual1, qPrintable(err.arg(expected1, actual1)));
+
+ QQuickAbstractButton *fontDelegate =
+ qobject_cast<QQuickAbstractButton *>(findViewDelegateItem(fontFamilyListView, i));
+ QVERIFY2(fontDelegate, qPrintable(QString("LOOP INDEX %1").arg(i)));
+
+ QVERIFY2(clickButton(fontDelegate), qPrintable(QString("LOOP INDEX %1").arg(i)));
+
+ const QString expected2 = fontListModel[i],
+ actual2 = dialogHelper.dialog->currentFont().family();
+ QVERIFY2(expected2 == actual2, qPrintable(err.arg(expected2, actual2).append(" font: ").append(fontDelegate->text())));
+ QVERIFY2(currentFontSpy.count() == 1, qPrintable(err.arg(1, currentFontSpy.count())));
+ QVERIFY2((oldStyleModel == fontStyleListView->model()) != (styleModelSpy.count() == 1),
+ qPrintable(QString("LOOP INDEX %1").arg(i)));
+ QVERIFY2((oldSizeModel == fontSizeListView->model()) != (sizeModelSpy.count() == 1),
+ qPrintable(QString("LOOP INDEX %1").arg(i)));
+ }
+
+ // Then accept it to close it.
+ QVERIFY(dialogHelper.dialog->currentFont() != dialogHelper.dialog->selectedFont());
+
+ CLOSE_DIALOG("Ok");
+
+ QVERIFY(dialogHelper.dialog->currentFont() == dialogHelper.dialog->selectedFont());
+}
+
+void tst_QQuickFontDialogImpl::effects()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QSignalSpy currentFontSpy(dialogHelper.dialog, SIGNAL(currentFontChanged()));
+
+ QQuickCheckBox *underlineCheckBox =
+ dialogHelper.quickDialog->findChild<QQuickCheckBox *>("underlineEffect");
+ QVERIFY(underlineCheckBox);
+
+ QQuickCheckBox *strikeoutCheckBox =
+ dialogHelper.quickDialog->findChild<QQuickCheckBox *>("strikeoutEffect");
+ QVERIFY(strikeoutCheckBox);
+
+ QVERIFY(!dialogHelper.dialog->currentFont().underline());
+ QVERIFY(!dialogHelper.dialog->currentFont().strikeOut());
+
+ QVERIFY(clickButton(underlineCheckBox));
+
+ QCOMPARE(currentFontSpy.count(), 1);
+ QVERIFY(dialogHelper.dialog->currentFont().underline());
+ QVERIFY(!dialogHelper.dialog->currentFont().strikeOut());
+
+ QVERIFY(clickButton(underlineCheckBox));
+
+ QCOMPARE(currentFontSpy.count(), 2);
+ QVERIFY(!dialogHelper.dialog->currentFont().underline());
+ QVERIFY(!dialogHelper.dialog->currentFont().strikeOut());
+
+ QVERIFY(clickButton(strikeoutCheckBox));
+
+ QCOMPARE(currentFontSpy.count(), 3);
+ QVERIFY(!dialogHelper.dialog->currentFont().underline());
+ QVERIFY(dialogHelper.dialog->currentFont().strikeOut());
+
+ QVERIFY(clickButton(strikeoutCheckBox));
+
+ QCOMPARE(currentFontSpy.count(), 4);
+ QVERIFY(!dialogHelper.dialog->currentFont().underline());
+ QVERIFY(!dialogHelper.dialog->currentFont().strikeOut());
+
+ // Then accept it to close it.
+ CLOSE_DIALOG("Ok");
+}
+
+void tst_QQuickFontDialogImpl::changeFontSize()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ QQuickTextField *sizeEdit = dialogHelper.quickDialog->findChild<QQuickTextField *>("sizeEdit");
+ QVERIFY(sizeEdit);
+
+ QQuickListView *fontSizeListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("sizeListView");
+ QVERIFY(fontSizeListView);
+
+ const QQuickItemDelegate *firstSizeDelegate =
+ qobject_cast<QQuickItemDelegate *>(findViewDelegateItem(fontSizeListView, 0));
+
+ QCOMPARE(dialogHelper.dialog->currentFont().pointSize(), firstSizeDelegate->text().toInt());
+
+ sizeEdit->setText("15");
+ QCOMPARE(dialogHelper.dialog->currentFont().pointSize(), 15);
+
+ sizeEdit->setText("22");
+ QCOMPARE(dialogHelper.dialog->currentFont().pointSize(), 22);
+
+ QVERIFY(dialogHelper.dialog->currentFont() != dialogHelper.dialog->selectedFont());
+
+ // Then accept it to close it.
+ CLOSE_DIALOG("Ok");
+
+ QVERIFY(dialogHelper.dialog->currentFont() == dialogHelper.dialog->selectedFont());
+}
+
+void tst_QQuickFontDialogImpl::changeDialogTitle()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ const auto dialogButtonBox =
+ dialogHelper.quickDialog->footer()->findChild<QQuickDialogButtonBox *>();
+ QVERIFY(dialogButtonBox);
+ QQuickAbstractButton *cancelButton = findDialogButton(dialogButtonBox, "Cancel");
+ QVERIFY(cancelButton);
+
+ const QQuickLabel *titleLabel = dialogHelper.quickDialog->header()->findChild<QQuickLabel *>();
+ QVERIFY(titleLabel);
+
+ QCOMPARE(titleLabel->text(), QString());
+
+ const QString newTitle1 = QLatin1String("Some random title #1");
+
+ // Dialog must be closed for the title to update
+ QVERIFY(clickButton(cancelButton));
+ QVERIFY(!dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible());
+
+ dialogHelper.dialog->setTitle(newTitle1);
+
+ // Reopen the dialog
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+ QVERIFY(dialogHelper.dialog->isVisible());
+ QTRY_VERIFY(dialogHelper.quickDialog->isVisible());
+
+ QCOMPARE(titleLabel->text(), newTitle1);
+
+ const QString newTitle2 = QLatin1String("Some random other title #2");
+
+ dialogHelper.dialog->setTitle(newTitle2);
+
+ // Shouldn't update unless you reopen the dialog
+ QCOMPARE(titleLabel->text(), newTitle1);
+
+ QVERIFY(clickButton(cancelButton));
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ // Should now be updated
+ QCOMPARE(titleLabel->text(), newTitle2);
+
+ CLOSE_DIALOG("Ok");
+}
+
+/*
+ Represents the expected search logic we use when the user types text into
+ one of the read-only text edits.
+
+ As we test against real fonts installed on the system and hence cannot use
+ a hard-coded list, we need this helper to ensure that the (non-trivial)
+ searching behavior matches what we expect.
+*/
+class ListSearchHelper
+{
+public:
+ ListSearchHelper(const QStringList &model)
+ : m_model(model)
+ {
+ }
+
+ int expectedCurrentIndexForSearch(const QString &searchText)
+ {
+ bool redo = false;
+
+ do {
+ m_searchText.append(searchText);
+
+ for (int i = 0; i < m_model.count(); ++i) {
+ if (m_model.at(i).startsWith(m_searchText, Qt::CaseInsensitive))
+ return i;
+ }
+
+ m_searchText.clear();
+
+ redo = !redo;
+ } while (redo);
+
+ return -1;
+ }
+
+private:
+ QStringList m_model;
+ QString m_searchText;
+};
+
+void tst_QQuickFontDialogImpl::searchFamily()
+{
+ CREATE_DIALOG_TEST_HELPER
+
+ // Open the dialog.
+ QVERIFY(dialogHelper.openDialog());
+ QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+ const QQuickTextField *familyEdit =
+ dialogHelper.quickDialog->findChild<QQuickTextField *>("familyEdit");
+ QVERIFY(familyEdit);
+
+ QQuickListView *fontFamilyListView =
+ dialogHelper.quickDialog->findChild<QQuickListView *>("familyListView");
+ QVERIFY(fontFamilyListView);
+
+ const QPoint familyEditCenterPos =
+ familyEdit->mapToScene({ familyEdit->width() / 2, familyEdit->height() / 2 }).toPoint();
+ QTest::mouseClick(dialogHelper.window(), Qt::LeftButton, Qt::NoModifier, familyEditCenterPos);
+ QVERIFY(familyEdit->hasActiveFocus());
+
+ QSignalSpy familyListViewCurrentIndexSpy(fontFamilyListView, SIGNAL(currentIndexChanged()));
+ QVERIFY(familyListViewCurrentIndexSpy.isValid());
+
+ const QString alphabet("abcdefghijklmnopqrstuvwxyz");
+ QStringList model = QFontDatabase::families(QFontDatabase::WritingSystem::Any);
+ model.removeIf(QFontDatabase::isPrivateFamily);
+
+ ListSearchHelper listSearchHelper(model);
+
+ // For each letter in the alphabet, press the corresponding key
+ // and check that the relevant delegate item in familyListView is selected.
+ for (auto alphabet_it = alphabet.cbegin(); alphabet_it != alphabet.cend(); alphabet_it++) {
+ const int previousIndex = fontFamilyListView->currentIndex();
+
+ const char keyEntered = alphabet_it->toLatin1();
+ QTest::keyClick(dialogHelper.window(), keyEntered);
+
+ int expectedListViewIndex = listSearchHelper.expectedCurrentIndexForSearch(QString(keyEntered));
+ if (expectedListViewIndex == -1) {
+ // There was no match, so the currentIndex should remain unchanged.
+ expectedListViewIndex = previousIndex;
+ }
+ if (fontFamilyListView->currentIndex() == expectedListViewIndex) {
+ // Working as expected; keep testing.
+ continue;
+ }
+
+ // Get the actual text of the current delegate item and the expected text.
+ auto currentDelegateItem = findViewDelegateItem(fontFamilyListView, fontFamilyListView->currentIndex());
+ QVERIFY(currentDelegateItem);
+ const auto actualDelegateText = currentDelegateItem->property("text").toString();
+ const auto expectedDelegateText = expectedListViewIndex != -1 ? model.at(expectedListViewIndex) : "(none)";
+
+ QFAIL(qPrintable(QString::fromLatin1("Expected fontFamilyListView to"
+ " change its currentIndex to %1 (%2) after typing '%3', but it is %4 (%5)")
+ .arg(expectedListViewIndex)
+ .arg(expectedDelegateText)
+ .arg(keyEntered)
+ .arg(fontFamilyListView->currentIndex())
+ .arg(actualDelegateText)));
+ }
+
+ CLOSE_DIALOG("Ok");
+}
+
+int main(int argc, char *argv[])
+{
+ // We need to set this attribute, and this (defining main() ourselves and
+ // calling QTEST_MAIN_IMPL) seems to be the nicest way to do it without
+ // duplicating too much code.
+ // We also don't want to run this for every style, as each one will have
+ // different ways of implementing the dialogs.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
+ // For now we only test one style.
+ // TODO: use Basic
+ QQuickStyle::setStyle("Fusion");
+ QTEST_MAIN_IMPL(tst_QQuickFontDialogImpl)
+}
+
+#include "tst_qquickfontdialogimpl.moc"
diff --git a/tests/auto/focus/CMakeLists.txt b/tests/auto/focus/CMakeLists.txt
index 404dcfa4..b9932df1 100644
--- a/tests/auto/focus/CMakeLists.txt
+++ b/tests/auto/focus/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_focus
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_focus.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_focus
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/font/CMakeLists.txt b/tests/auto/font/CMakeLists.txt
index 5cc92d88..2f356eee 100644
--- a/tests/auto/font/CMakeLists.txt
+++ b/tests/auto/font/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_font
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_font.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_font
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/palette/CMakeLists.txt b/tests/auto/palette/CMakeLists.txt
index 6702ac8a..a924fd16 100644
--- a/tests/auto/palette/CMakeLists.txt
+++ b/tests/auto/palette/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_palette
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_palette.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_palette
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/palette/data/bindings.qml b/tests/auto/palette/data/bindings.qml
index 5f156c96..215fb034 100644
--- a/tests/auto/palette/data/bindings.qml
+++ b/tests/auto/palette/data/bindings.qml
@@ -69,6 +69,11 @@ ApplicationWindow {
buttonText: "bisque"
}
+ inactive {
+ button: "khaki"
+ buttonText: "bisque"
+ }
+
disabled {
buttonText: "lavender"
button: "coral"
diff --git a/tests/auto/palette/data/palette-appwindow-custom.qml b/tests/auto/palette/data/palette-appwindow-custom.qml
index f5f75ae7..95f9fde6 100644
--- a/tests/auto/palette/data/palette-appwindow-custom.qml
+++ b/tests/auto/palette/data/palette-appwindow-custom.qml
@@ -71,4 +71,5 @@ ApplicationWindow {
palette.toolTipText: "orchid"
palette.window: "plum"
palette.windowText: "salmon"
+ palette.placeholderText: "magenta"
}
diff --git a/tests/auto/palette/data/palette-control-custom.qml b/tests/auto/palette/data/palette-control-custom.qml
index 6915404d..7f3bfde5 100644
--- a/tests/auto/palette/data/palette-control-custom.qml
+++ b/tests/auto/palette/data/palette-control-custom.qml
@@ -71,4 +71,5 @@ Control {
palette.toolTipText: "orchid"
palette.window: "plum"
palette.windowText: "salmon"
+ palette.placeholderText: "magenta"
}
diff --git a/tests/auto/palette/data/palette-popup-custom.qml b/tests/auto/palette/data/palette-popup-custom.qml
index 47f52d17..6f35f452 100644
--- a/tests/auto/palette/data/palette-popup-custom.qml
+++ b/tests/auto/palette/data/palette-popup-custom.qml
@@ -71,4 +71,5 @@ Popup {
palette.toolTipText: "orchid"
palette.window: "plum"
palette.windowText: "salmon"
+ palette.placeholderText: "magenta"
}
diff --git a/tests/auto/palette/tst_palette.cpp b/tests/auto/palette/tst_palette.cpp
index ca1675f1..d8e1a3bf 100644
--- a/tests/auto/palette/tst_palette.cpp
+++ b/tests/auto/palette/tst_palette.cpp
@@ -130,6 +130,7 @@ void tst_palette::palette_data()
customPalette.setColor(QPalette::ToolTipText, QColor("orchid"));
customPalette.setColor(QPalette::Window, QColor("plum"));
customPalette.setColor(QPalette::WindowText, QColor("salmon"));
+ customPalette.setColor(QPalette::PlaceholderText, QColor("magenta"));
QTest::newRow("Control:custom") << "palette-control-custom.qml" << customPalette;
QTest::newRow("AppWindow:custom") << "palette-appwindow-custom.qml" << customPalette;
diff --git a/tests/auto/qquickapplicationwindow/CMakeLists.txt b/tests/auto/qquickapplicationwindow/CMakeLists.txt
index 20268703..1c346d15 100644
--- a/tests/auto/qquickapplicationwindow/CMakeLists.txt
+++ b/tests/auto/qquickapplicationwindow/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickapplicationwindow
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickapplicationwindow.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickapplicationwindow
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickapplicationwindow/data/layoutLayout.qml b/tests/auto/qquickapplicationwindow/data/layoutLayout.qml
new file mode 100644
index 00000000..670306fa
--- /dev/null
+++ b/tests/auto/qquickapplicationwindow/data/layoutLayout.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ApplicationWindow {
+ width: 200
+ height: 200
+ visible: true
+
+ header: RowLayout {
+ Rectangle { color: "red"; implicitWidth: 20; implicitHeight: 20; Layout.fillWidth: true}
+ }
+ footer: ColumnLayout {
+ Rectangle { color: "green"; implicitWidth: 20; implicitHeight: 20; Layout.fillWidth: true}
+ }
+}
diff --git a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
index 7816622c..f6bf7d74 100644
--- a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
+++ b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
@@ -79,6 +79,7 @@ private slots:
void focusAfterPopupClosed();
void clearFocusOnDestruction();
void layout();
+ void layoutLayout();
void componentComplete();
void opacity();
};
@@ -869,6 +870,42 @@ void tst_QQuickApplicationWindow::layout()
QCOMPARE(content->height(), qreal(window->height()));
}
+void tst_QQuickApplicationWindow::layoutLayout()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("layoutLayout.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+ QQuickApplicationWindow* window = qobject_cast<QQuickApplicationWindow*>(object.data());
+ QVERIFY(window);
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickItem *content = window->contentItem();
+ QVERIFY(content);
+ QQuickItem *header = window->header();
+ QVERIFY(header);
+ QQuickItem *footer = window->footer();
+ QVERIFY(footer);
+
+ QQuickItem *headerChild = header->findChild<QQuickItem*>();
+ QVERIFY(headerChild);
+ QCOMPARE(header->x(), 0.0);
+ QCOMPARE(header->y(), -header->height());
+ QCOMPARE(header->width(), qreal(window->width()));
+ QCOMPARE(headerChild->width(), qreal(window->width()));
+ QVERIFY(header->height() > 0);
+
+ QQuickItem *footerChild = header->findChild<QQuickItem*>();
+ QVERIFY(footerChild);
+ QCOMPARE(footer->x(), 0.0);
+ QCOMPARE(footer->y(), content->height());
+ QCOMPARE(footer->width(), qreal(window->width()));
+ QCOMPARE(footerChild->width(), qreal(window->width()));
+ QVERIFY(footer->height() > 0.0);
+}
+
class FriendlyApplicationWindow : public QQuickApplicationWindow
{
friend class tst_QQuickApplicationWindow;
diff --git a/tests/auto/qquickcontrol/CMakeLists.txt b/tests/auto/qquickcontrol/CMakeLists.txt
index 5d6eefd2..3448a8c7 100644
--- a/tests/auto/qquickcontrol/CMakeLists.txt
+++ b/tests/auto/qquickcontrol/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickcontrol
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickcontrol.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickcontrol
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickdrawer/BLACKLIST b/tests/auto/qquickdrawer/BLACKLIST
new file mode 100644
index 00000000..9f3f96be
--- /dev/null
+++ b/tests/auto/qquickdrawer/BLACKLIST
@@ -0,0 +1,8 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+
+# QTBUG-77946
+[slider]
+opensuse-leap
+
+[position]
+opensuse-leap
diff --git a/tests/auto/qquickdrawer/CMakeLists.txt b/tests/auto/qquickdrawer/CMakeLists.txt
index 1c2342f0..812e4d20 100644
--- a/tests/auto/qquickdrawer/CMakeLists.txt
+++ b/tests/auto/qquickdrawer/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickdrawer
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickdrawer.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickdrawer
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickheaderview/CMakeLists.txt b/tests/auto/qquickheaderview/CMakeLists.txt
index dfcaa452..9f428a48 100644
--- a/tests/auto/qquickheaderview/CMakeLists.txt
+++ b/tests/auto/qquickheaderview/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickheaderview
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickheaderview.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -28,6 +28,7 @@ qt_internal_add_test(tst_qquickheaderview
Qt::QuickPrivate
Qt::QuickTemplates2
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickiconimage/CMakeLists.txt b/tests/auto/qquickiconimage/CMakeLists.txt
index fdad6ef9..dbe810ac 100644
--- a/tests/auto/qquickiconimage/CMakeLists.txt
+++ b/tests/auto/qquickiconimage/CMakeLists.txt
@@ -21,7 +21,7 @@ qt_internal_add_test(tst_qquickiconimage
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickiconimage.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
LIBRARIES
Qt::QuickControls2ImplPrivate
Qt::QuickPrivate
@@ -36,6 +36,7 @@ qt_internal_add_test(tst_qquickiconimage
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickiconlabel/CMakeLists.txt b/tests/auto/qquickiconlabel/CMakeLists.txt
index ffa084f7..a26abc48 100644
--- a/tests/auto/qquickiconlabel/CMakeLists.txt
+++ b/tests/auto/qquickiconlabel/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickiconlabel
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickiconlabel.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
LIBRARIES
Qt::QuickControls2ImplPrivate
Qt::QuickPrivate
@@ -32,6 +32,7 @@ qt_internal_add_test(tst_qquickiconlabel
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickmaterialstyleconf/CMakeLists.txt b/tests/auto/qquickmaterialstyleconf/CMakeLists.txt
index 1244961a..72d848dc 100644
--- a/tests/auto/qquickmaterialstyleconf/CMakeLists.txt
+++ b/tests/auto/qquickmaterialstyleconf/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickmaterialstyleconf
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickmaterialstyleconf.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickmaterialstyleconf
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickmenu/CMakeLists.txt b/tests/auto/qquickmenu/CMakeLists.txt
index 702c5747..10c28116 100644
--- a/tests/auto/qquickmenu/CMakeLists.txt
+++ b/tests/auto/qquickmenu/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickmenu
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickmenu.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickmenu
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp
index 05c96246..92ea452a 100644
--- a/tests/auto/qquickmenu/tst_qquickmenu.cpp
+++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp
@@ -1236,8 +1236,11 @@ void tst_QQuickMenu::subMenuKeyboard()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
QVERIFY(mainMenu);
@@ -1359,8 +1362,11 @@ void tst_QQuickMenu::subMenuDisabledKeyboard()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
QVERIFY(mainMenu);
@@ -1454,8 +1460,11 @@ void tst_QQuickMenu::subMenuPosition()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
mainMenu->setCascade(cascade);
QCOMPARE(mainMenu->cascade(), cascade);
@@ -1733,8 +1742,11 @@ void tst_QQuickMenu::menuItemWidth()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
QVERIFY(menu);
@@ -1762,8 +1774,11 @@ void tst_QQuickMenu::menuItemWidthAfterMenuWidthChanged()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
QVERIFY(menu);
@@ -1807,8 +1822,11 @@ void tst_QQuickMenu::menuItemWidthAfterImplicitWidthChanged()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- if (mirrored)
- window->setLocale(QLocale("ar_EG"));
+ if (mirrored) {
+ QQmlExpression mirroringExpression(qmlContext(window), window,
+ "LayoutMirroring.childrenInherit = true; LayoutMirroring.enabled = true");
+ QVERIFY2(mirroringExpression.evaluate().isValid(), qPrintable(mirroringExpression.error().toString()));
+ }
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
QVERIFY(menu);
diff --git a/tests/auto/qquickmenubar/CMakeLists.txt b/tests/auto/qquickmenubar/CMakeLists.txt
index c6043f87..97575129 100644
--- a/tests/auto/qquickmenubar/CMakeLists.txt
+++ b/tests/auto/qquickmenubar/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickmenubar
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickmenubar.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickmenubar
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickninepatchimage/CMakeLists.txt b/tests/auto/qquickninepatchimage/CMakeLists.txt
index 83cf364b..9d041643 100644
--- a/tests/auto/qquickninepatchimage/CMakeLists.txt
+++ b/tests/auto/qquickninepatchimage/CMakeLists.txt
@@ -21,7 +21,7 @@ qt_internal_add_test(tst_qquickninepatchimage
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickninepatchimage.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
LIBRARIES
Qt::GuiPrivate
Qt::QuickControls2Private
@@ -37,6 +37,7 @@ qt_internal_add_test(tst_qquickninepatchimage
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickpopup/BLACKLIST b/tests/auto/qquickpopup/BLACKLIST
index a4358b7c..ebe6d040 100644
--- a/tests/auto/qquickpopup/BLACKLIST
+++ b/tests/auto/qquickpopup/BLACKLIST
@@ -1,3 +1,5 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+
[overlay]
macos # QTBUG-89938
@@ -6,3 +8,10 @@ macos # QTBUG-89938
[closePolicy]
macos # QTBUG-89938
+
+# QTBUG-94251
+[closePolicy]
+opensuse-leap
+
+[cursorShape]
+opensuse-leap
diff --git a/tests/auto/qquickpopup/CMakeLists.txt b/tests/auto/qquickpopup/CMakeLists.txt
index 9b736f80..6fb43676 100644
--- a/tests/auto/qquickpopup/CMakeLists.txt
+++ b/tests/auto/qquickpopup/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickpopup
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickpopup.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickpopup
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickpopup/data/invisibleToolTipOpen.qml b/tests/auto/qquickpopup/data/invisibleToolTipOpen.qml
index aaed154b..6607dc6f 100644
--- a/tests/auto/qquickpopup/data/invisibleToolTipOpen.qml
+++ b/tests/auto/qquickpopup/data/invisibleToolTipOpen.qml
@@ -9,13 +9,11 @@ Window {
property alias loader: loader
MouseArea {
id: mouseArea
- property bool isToolTipVisible: false
width: 200
height: 200
hoverEnabled: true
ToolTip.text: "static tooltip"
ToolTip.visible: containsMouse
- ToolTip.onVisibleChanged: isToolTipVisible = ToolTip.visible
}
Loader {
id: loader
diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp
index a0dc1d88..9a08c340 100644
--- a/tests/auto/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp
@@ -54,6 +54,7 @@
#include <QtQuickTemplates2/private/qquickslider_p.h>
#include <QtQuickTemplates2/private/qquickstackview_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquicktooltip_p.h>
using namespace QQuickVisualTestUtil;
@@ -132,7 +133,7 @@ void tst_QQuickPopup::visible()
QQuickItem *popupItem = popup->popupItem();
popup->open();
- QVERIFY(popup->isVisible());
+ QTRY_VERIFY(popup->isOpened());
QQuickOverlay *overlay = QQuickOverlay::overlay(window);
QVERIFY(overlay);
@@ -143,7 +144,7 @@ void tst_QQuickPopup::visible()
QVERIFY(!overlay->childItems().contains(popupItem));
popup->setVisible(true);
- QVERIFY(popup->isVisible());
+ QTRY_VERIFY(popup->isOpened());
QVERIFY(overlay->childItems().contains(popupItem));
popup->setVisible(false);
@@ -305,7 +306,7 @@ void tst_QQuickPopup::overlay()
popup->open();
QVERIFY(popup->isVisible());
QVERIFY(overlay->isVisible());
-
+ QTRY_VERIFY(popup->isOpened());
QTest::touchEvent(window, device.data()).press(0, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
@@ -327,6 +328,7 @@ void tst_QQuickPopup::overlay()
QVERIFY(popup->isVisible());
QVERIFY(overlay->isVisible());
QVERIFY(!button->isPressed());
+ QTRY_VERIFY(popup->isOpened());
QTest::touchEvent(window, device.data()).press(0, button->mapToScene(QPointF(1, 1)).toPoint());
QVERIFY(popup->isVisible());
@@ -387,8 +389,8 @@ void tst_QQuickPopup::zOrder()
// on top and must be closed first, even if the other popup was opened last
popup2->open();
popup->open();
- QVERIFY(popup2->isVisible());
- QVERIFY(popup->isVisible());
+ QTRY_VERIFY(popup2->isOpened());
+ QTRY_VERIFY(popup->isOpened());
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QTRY_VERIFY(!popup2->isVisible());
@@ -897,9 +899,11 @@ void tst_QQuickPopup::nested()
modalPopup->open();
QCOMPARE(modalPopup->isVisible(), true);
+ QTRY_COMPARE(modalPopup->isOpened(), true);
modelessPopup->open();
QCOMPARE(modelessPopup->isVisible(), true);
+ QTRY_COMPARE(modelessPopup->isOpened(), true);
// click outside the modeless popup on the top, but inside the modal popup below
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 150));
@@ -986,12 +990,12 @@ void tst_QQuickPopup::cursorShape()
const QPoint textFieldPos(popup->x() - 10, textField->height() / 2);
QVERIFY(textField->contains(textField->mapFromScene(textFieldPos)));
QTest::mouseMove(window, textFieldPos);
- QCOMPARE(window->cursor().shape(), textField->cursor().shape());
+ QTRY_COMPARE(window->cursor().shape(), textField->cursor().shape());
// Move the mouse over the popup where it overlaps with the text field.
const QPoint textFieldOverlapPos(popup->x() + 10, textField->height() / 2);
QTest::mouseMove(window, textFieldOverlapPos);
- QCOMPARE(window->cursor().shape(), popup->popupItem()->cursor().shape());
+ QTRY_COMPARE(window->cursor().shape(), popup->popupItem()->cursor().shape());
popup->close();
QTRY_VERIFY(!popup->isVisible());
@@ -1011,7 +1015,8 @@ void tst_QQuickPopup::componentComplete()
QQmlComponent component(&engine);
component.setData("import QtQuick.Controls; Popup { }", QUrl());
- FriendlyPopup *qmlPopup = static_cast<FriendlyPopup *>(component.beginCreate(engine.rootContext()));
+ QScopedPointer<QObject> o(component.beginCreate(engine.rootContext()));
+ FriendlyPopup *qmlPopup = static_cast<FriendlyPopup *>(o.data());
QVERIFY(qmlPopup);
QVERIFY(!qmlPopup->isComponentComplete());
@@ -1045,7 +1050,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
QQuickPopup *optionsMenu = window->findChild<QQuickPopup*>("optionsMenu");
QVERIFY(optionsMenu);
- QTRY_VERIFY(optionsMenu->isVisible());
+ QTRY_VERIFY(optionsMenu->isOpened());
QQuickItem *settingsMenuItem = window->findChild<QQuickItem*>("settingsMenuItem");
QVERIFY(settingsMenuItem);
@@ -1057,7 +1062,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
QQuickPopup *settingsDialog = window->contentItem()->findChild<QQuickPopup*>("settingsDialog");
QVERIFY(settingsDialog);
- QTRY_VERIFY(settingsDialog->isVisible());
+ QTRY_VERIFY(settingsDialog->isOpened());
QQuickComboBox *comboBox = window->contentItem()->findChild<QQuickComboBox*>("comboBox");
QVERIFY(comboBox);
@@ -1066,7 +1071,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
const QPoint comboBoxCenter = comboBox->mapToScene(
QPointF(comboBox->width() / 2, comboBox->height() / 2)).toPoint();
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, comboBoxCenter);
- QTRY_VERIFY(comboBox->popup()->isVisible());
+ QTRY_VERIFY(comboBox->popup()->isOpened());
// Close the combo box popup with the escape key. The settings dialog should still be visible.
QTest::keyClick(window, Qt::Key_Escape);
@@ -1149,7 +1154,7 @@ void tst_QQuickPopup::orientation()
QQuickPopup *popup = window->property("popup").value<QQuickPopup*>();
QVERIFY(popup);
popup->open();
-
+ QTRY_VERIFY(popup->isOpened());
QCOMPARE(popup->popupItem()->position(), position);
}
@@ -1337,8 +1342,9 @@ void tst_QQuickPopup::tabFence()
QQuickPopup *popup = window->property("dialog").value<QQuickPopup*>();
QVERIFY(popup);
- popup->open();
popup->setModal(true);
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
QQuickButton *outsideButton1 = window->property("outsideButton1").value<QQuickButton*>();
QVERIFY(outsideButton1);
@@ -1393,6 +1399,11 @@ void tst_QQuickPopup::invisibleToolTipOpen()
QQuickItem *mouseArea = qvariant_cast<QQuickItem *>(window->property("mouseArea"));
QVERIFY(mouseArea);
+ auto toolTipAttached = qobject_cast<QQuickToolTipAttached*>(
+ qmlAttachedPropertiesObject<QQuickToolTip>(mouseArea, false));
+ QVERIFY(toolTipAttached);
+ QQuickPopup *toolTip = toolTipAttached->toolTip();
+ QVERIFY(toolTip);
QObject *loader = qvariant_cast<QObject *>(window->property("loader"));
QVERIFY(loader);
@@ -1400,7 +1411,7 @@ void tst_QQuickPopup::invisibleToolTipOpen()
// As an added bonus, this is also slightly more realistic. :D
QTest::mouseMove(window, QPoint(mouseArea->width() / 2 - 1, mouseArea->height() / 2 - 1));
QTest::mouseMove(window, QPoint(mouseArea->width() / 2, mouseArea->height() / 2));
- QTRY_VERIFY(mouseArea->property("isToolTipVisible").toBool());
+ QTRY_VERIFY(toolTip->isOpened());
QSignalSpy componentLoadedSpy(loader, SIGNAL(loaded()));
QVERIFY(componentLoadedSpy.isValid());
@@ -1408,7 +1419,7 @@ void tst_QQuickPopup::invisibleToolTipOpen()
loader->setProperty("active", true);
QTRY_COMPARE(componentLoadedSpy.count(), 1);
- QTRY_VERIFY(mouseArea->property("isToolTipVisible").toBool());
+ QTRY_VERIFY(toolTip->isVisible());
}
void tst_QQuickPopup::centerInOverlayWithinStackViewItem()
@@ -1436,17 +1447,20 @@ void tst_QQuickPopup::destroyDuringExitTransition()
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
- QPointer<QQuickPopup> dialog2 = window->property("dialog2").value<QQuickPopup*>();
- QVERIFY(dialog2);
- QTRY_COMPARE(dialog2->isVisible(), true);
+ {
+ QPointer<QQuickPopup> dialog2 = window->property("dialog2").value<QQuickPopup*>();
+ QVERIFY(dialog2);
+ QTRY_COMPARE(dialog2->isOpened(), true);
- // Close the second dialog, destroying it before its exit transition can finish.
- QTest::keyClick(window, Qt::Key_Escape);
- QTRY_VERIFY(!dialog2);
+ // Close the second dialog, destroying it before its exit transition can finish.
+ QTest::keyClick(window, Qt::Key_Escape);
+ QTRY_VERIFY(!dialog2);
+ }
// Events should go through to the dialog underneath.
QQuickPopup *dialog1 = window->property("dialog1").value<QQuickPopup*>();
QVERIFY(dialog1);
+ QTRY_COMPARE(dialog1->isOpened(), true);
QQuickButton *button = dialog1->property("button").value<QQuickButton*>();
QVERIFY(button);
const auto buttonClickPos = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
diff --git a/tests/auto/qquickstyle/CMakeLists.txt b/tests/auto/qquickstyle/CMakeLists.txt
index 153cf19e..93b63a19 100644
--- a/tests/auto/qquickstyle/CMakeLists.txt
+++ b/tests/auto/qquickstyle/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickstyle
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickstyle.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
@@ -31,6 +31,7 @@ qt_internal_add_test(tst_qquickstyle
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qquickuniversalstyleconf/CMakeLists.txt b/tests/auto/qquickuniversalstyleconf/CMakeLists.txt
index ab754043..6aeeaa32 100644
--- a/tests/auto/qquickuniversalstyleconf/CMakeLists.txt
+++ b/tests/auto/qquickuniversalstyleconf/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_qquickuniversalstyleconf
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickuniversalstyleconf.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qquickuniversalstyleconf
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/sanity/CMakeLists.txt b/tests/auto/sanity/CMakeLists.txt
index 63a8eeb7..804640b7 100644
--- a/tests/auto/sanity/CMakeLists.txt
+++ b/tests/auto/sanity/CMakeLists.txt
@@ -11,7 +11,7 @@ qt_internal_add_test(tst_sanity
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_sanity.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -22,6 +22,7 @@ qt_internal_add_test(tst_sanity
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
)
diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp
index 8ec590e5..a19319b3 100644
--- a/tests/auto/sanity/tst_sanity.cpp
+++ b/tests/auto/sanity/tst_sanity.cpp
@@ -171,10 +171,10 @@ void tst_Sanity::initTestCase()
// Then, collect the files from each installed style directory.
const QVector<QPair<QString, QString>> styleRelativePaths = {
- { "controls/basic", "QtQuick/Controls/Basic" },
- { "controls/fusion", "QtQuick/Controls/Fusion" },
- { "controls/material", "QtQuick/Controls/Material" },
- { "controls/universal", "QtQuick/Controls/Universal" },
+ { "quickcontrols2/basic", "QtQuick/Controls/Basic" },
+ { "quickcontrols2/fusion", "QtQuick/Controls/Fusion" },
+ { "quickcontrols2/material", "QtQuick/Controls/Material" },
+ { "quickcontrols2/universal", "QtQuick/Controls/Universal" },
};
for (const auto &stylePathPair : styleRelativePaths) {
forEachControl(&engine, stylePathPair.first, stylePathPair.second, QStringList(),
diff --git a/tests/auto/shared/dialogtestutil.h b/tests/auto/shared/dialogtestutil.h
new file mode 100644
index 00000000..c10c4001
--- /dev/null
+++ b/tests/auto/shared/dialogtestutil.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOGTESTUTIL_H
+#define QQUICKDIALOGTESTUTIL_H
+
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+
+#include "util.h"
+#include "visualtestutil.h"
+
+// We need these for Windows, because FolderListModel returns a lowercase drive letter; e.g.:
+// "file:///c:/blah.txt", whereas other API returns "file:///C:/blah.txt".
+#define COMPARE_URL(url1, url2) \
+ QCOMPARE(QFileInfo(url1.toLocalFile()).absoluteFilePath(), QFileInfo(url2.toLocalFile()).absoluteFilePath());
+
+// Store a copy of the arguments in case { ... } list initializer syntax is used as an argument,
+// which could result in two different lists being created and passed to std::transform()
+// (and would also require it to be enclosed in parentheses everywhere it's used).
+#define COMPARE_URLS(actualUrls, expectedUrls) \
+{ \
+ const QList<QUrl> actualUrlsCopy = actualUrls; \
+ QList<QString> actualPaths; \
+ std::transform(actualUrlsCopy.begin(), actualUrlsCopy.end(), std::back_insert_iterator(actualPaths), \
+ [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
+ const QList<QUrl> expectedUrlsCopy = expectedUrls; \
+ QList<QString> expectedPaths; \
+ std::transform(expectedUrlsCopy.begin(), expectedUrlsCopy.end(), std::back_insert_iterator(expectedPaths), \
+ [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
+ QCOMPARE(actualPaths, expectedPaths); \
+}
+
+namespace QQuickDialogTestUtil
+{
+
+// Saves duplicating a bunch of code in every test.
+template<typename DialogType, typename QuickDialogType>
+class DialogTestHelper
+{
+public:
+ DialogTestHelper(QQmlDataTest *testCase, const QString &testFilePath,
+ const QStringList &qmlImportPaths = {}, const QVariantMap &initialProperties = {}) :
+ appHelper(testCase, testFilePath, qmlImportPaths, initialProperties)
+ {
+ if (!appHelper.ready)
+ return;
+
+ dialog = appHelper.window->property("dialog").value<DialogType*>();
+ if (!dialog) {
+ appHelper.errorMessage = "\"dialog\" property is not valid";
+ return;
+ }
+
+ appHelper.window->show();
+ appHelper.window->requestActivate();
+ }
+
+ Q_REQUIRED_RESULT bool isWindowInitialized() const
+ {
+ return appHelper.ready;
+ }
+
+ Q_REQUIRED_RESULT bool waitForWindowActive()
+ {
+ return QTest::qWaitForWindowActive(appHelper.window);
+ }
+
+ bool openDialog()
+ {
+ dialog->open();
+ if (!dialog->isVisible()) {
+ appHelper.errorMessage = "Dialog is not visible";
+ return false;
+ }
+
+ // We might want to call this function more than once,
+ // and we only need to get these members the first time.
+ if (!quickDialog) {
+ quickDialog = appHelper.window->findChild<QuickDialogType*>();
+ if (!quickDialog) {
+ appHelper.errorMessage = "Can't find Qt Quick-based dialog";
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool isQuickDialogOpen() const
+ {
+ return quickDialog->isOpened();
+ }
+
+ QQuickWindow *window() const
+ {
+ return appHelper.window;
+ }
+
+ const char *failureMessage() const
+ {
+ return appHelper.errorMessage.constData();
+ }
+
+ QQuickVisualTestUtil::QQuickApplicationHelper appHelper;
+ DialogType *dialog = nullptr;
+ QuickDialogType *quickDialog = nullptr;
+};
+
+}
+
+#endif // QQUICKDIALOGTESTUTIL_H
diff --git a/tests/auto/shared/util.pri b/tests/auto/shared/util.pri
index c2eb9f0a..6366776b 100644
--- a/tests/auto/shared/util.pri
+++ b/tests/auto/shared/util.pri
@@ -1,4 +1,4 @@
-QT += testlib-private core-private gui-private qml-private quick-private quicktemplates2-private quickcontrols2 quickcontrols2-private
+QT += testlib-private core-private gui-private qml-private quick-private qmltest quicktemplates2-private quickcontrols2 quickcontrols2-private
HEADERS += $$PWD/visualtestutil.h \
$$PWD/util.h \
@@ -11,4 +11,4 @@ android|ios {
} else {
DEFINES += QT_QMLTEST_DATADIR=\\\"$${_PRO_FILE_PWD_}/data\\\"
}
-DEFINES += QQC2_IMPORT_PATH=\\\"$$QQC2_SOURCE_TREE/src/imports\\\"
+DEFINES += QQC2_IMPORT_PATH=\\\"$$QQC2_SOURCE_TREE/src\\\"
diff --git a/tests/auto/shared/visualtestutil.cpp b/tests/auto/shared/visualtestutil.cpp
index 4e33c6f1..ff0d9e8e 100644
--- a/tests/auto/shared/visualtestutil.cpp
+++ b/tests/auto/shared/visualtestutil.cpp
@@ -41,6 +41,7 @@
#include <QtGui/QCursor>
#include <QtCore/QCoreApplication>
#include <QtQml/QQmlFile>
+#include <QtTest/qsignalspy.h>
#include <QtTest/QTest>
bool QQuickVisualTestUtil::delegateVisible(QQuickItem *item)
@@ -95,6 +96,35 @@ void QQuickVisualTestUtil::centerOnScreen(QQuickWindow *window)
window->setFramePosition(screenGeometry.center() - offset);
}
+/*!
+ \internal
+
+ Finds the delegate at \c index belonging to \c itemView, using the given \c flags.
+
+ If the view needs to be polished, the function will wait for it to be done before continuing,
+ and returns \c nullptr if the polish didn't happen.
+*/
+QQuickItem *QQuickVisualTestUtil::findViewDelegateItem(QQuickItemView *itemView, int index, FindViewDelegateItemFlags flags)
+{
+ if (QQuickTest::qIsPolishScheduled(itemView)) {
+ if (!QQuickTest::qWaitForItemPolished(itemView)) {
+ qWarning() << "failed to polish" << itemView;
+ return nullptr;
+ }
+ }
+
+ // Do this after the polish, just in case the count changes after a polish...
+ if (index <= -1 || index >= itemView->count()) {
+ qWarning() << "index" << index << "is out of bounds for" << itemView;
+ return nullptr;
+ }
+
+ if (flags.testFlag(FindViewDelegateItemFlag::PositionViewAtIndex))
+ itemView->positionViewAtIndex(index, QQuickItemView::Center);
+
+ return itemView->itemAtIndex(index);
+}
+
void QQuickVisualTestUtil::forEachControl(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skipList, QQuickVisualTestUtil::ForEachCallback callback)
{
// We cannot use QQmlComponent to load QML files directly from the source tree.
@@ -167,3 +197,76 @@ void QQuickVisualTestUtil::MnemonicKeySimulator::click(Qt::Key key)
press(key);
release(key);
}
+
+
+bool QQuickVisualTestUtil::verifyButtonClickable(QQuickAbstractButton *button)
+{
+ if (!button->window()) {
+ qWarning() << "button" << button << "doesn't have an associated window";
+ return false;
+ }
+
+ if (!button->isEnabled()) {
+ qWarning() << "button" << button << "is not enabled";
+ return false;
+ }
+
+ if (!button->isVisible()) {
+ qWarning() << "button" << button << "is not visible";
+ return false;
+ }
+
+ if (button->width() <= 0.0) {
+ qWarning() << "button" << button << "must have a width greater than 0";
+ return false;
+ }
+
+ if (button->height() <= 0.0) {
+ qWarning() << "button" << button << "must have a height greater than 0";
+ return false;
+ }
+
+ return true;
+}
+
+bool QQuickVisualTestUtil::clickButton(QQuickAbstractButton *button)
+{
+ if (!verifyButtonClickable(button))
+ return false;
+
+ QSignalSpy spy(button, &QQuickAbstractButton::clicked);
+ if (!spy.isValid()) {
+ qWarning() << "button" << button << "must have a valid clicked signal";
+ return false;
+ }
+
+ const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
+ QTest::mouseClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
+ if (spy.count() != 1) {
+ qWarning() << "clicked signal of button" << button << "was not emitted after clicking";
+ return false;
+ }
+
+ return true;
+}
+
+bool QQuickVisualTestUtil::doubleClickButton(QQuickAbstractButton *button)
+{
+ if (!verifyButtonClickable(button))
+ return false;
+
+ QSignalSpy spy(button, &QQuickAbstractButton::clicked);
+ if (!spy.isValid()) {
+ qWarning() << "button" << button << "must have a valid doubleClicked signal";
+ return false;
+ }
+
+ const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
+ QTest::mouseDClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
+ if (spy.count() != 1) {
+ qWarning() << "doubleClicked signal of button" << button << "was not emitted after double-clicking";
+ return false;
+ }
+
+ return true;
+}
diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h
index 78c625ea..142aefd2 100644
--- a/tests/auto/shared/visualtestutil.h
+++ b/tests/auto/shared/visualtestutil.h
@@ -43,8 +43,11 @@
#include <QtQuick/QQuickItem>
#include <QtQml/QQmlExpression>
#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemview_p.h>
+#include <QtQuickTest/quicktest.h>
#include <QtQuickControls2/qquickstyle.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
#include "util.h"
@@ -115,11 +118,35 @@ namespace QQuickVisualTestUtil
return items;
}
+ enum class FindViewDelegateItemFlag {
+ None = 0x0,
+ PositionViewAtIndex = 0x01
+ };
+ Q_DECLARE_FLAGS(FindViewDelegateItemFlags, FindViewDelegateItemFlag)
+
+ QQuickItem* findViewDelegateItem(QQuickItemView *itemView, int index,
+ FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex);
+
+ /*!
+ \internal
+
+ Same as above except allows use in QTRY_* functions without having to call it again
+ afterwards to assign the delegate.
+ */
+ template<typename T>
+ bool findViewDelegateItem(QQuickItemView *itemView, int index, T &delegateItem,
+ FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex)
+ {
+ delegateItem = qobject_cast<T>(findViewDelegateItem(itemView, index, flags));
+ return delegateItem != nullptr;
+ }
+
class QQuickApplicationHelper
{
public:
QQuickApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath,
- const QStringList &qmlImportPaths = QStringList())
+ const QStringList &qmlImportPaths = {},
+ const QVariantMap &initialProperties = {})
{
for (const auto &path : qmlImportPaths)
engine.addImportPath(path);
@@ -127,9 +154,10 @@ namespace QQuickVisualTestUtil
QQmlComponent component(&engine);
component.loadUrl(testCase->testFileUrl(testFilePath));
- QObject *rootObject = component.create();
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QObject *rootObject = component.createWithInitialProperties(initialProperties);
cleanup.reset(rootObject);
- if (!rootObject) {
+ if (component.isError() || !rootObject) {
errorMessage = QString::fromUtf8("Failed to create window: %1").arg(component.errorString()).toUtf8();
return;
}
@@ -176,9 +204,10 @@ namespace QQuickVisualTestUtil
if (!currentStyle.isEmpty() && style == currentStyle)
return false;
- engine.reset(new QQmlEngine);
+ engine.reset();
currentStyle = style;
qmlClearTypeRegistrations();
+ engine.reset(new QQmlEngine);
QQuickStyle::setStyle(style);
QQmlComponent component(engine.data());
@@ -211,6 +240,10 @@ namespace QQuickVisualTestUtil
QPointer<QWindow> m_window;
Qt::KeyboardModifiers m_modifiers;
};
+
+ [[nodiscard]] bool verifyButtonClickable(QQuickAbstractButton *button);
+ [[nodiscard]] bool clickButton(QQuickAbstractButton *button);
+ [[nodiscard]] bool doubleClickButton(QQuickAbstractButton *button);
}
#define QQUICK_VERIFY_POLISH(item) \
diff --git a/tests/auto/snippets/CMakeLists.txt b/tests/auto/snippets/CMakeLists.txt
index cecbbc79..a8d02b7d 100644
--- a/tests/auto/snippets/CMakeLists.txt
+++ b/tests/auto/snippets/CMakeLists.txt
@@ -14,7 +14,7 @@ qt_internal_add_test(tst_snippets
SOURCES
tst_snippets.cpp
DEFINES
- QQC2_SNIPPETS_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports/controls/doc/snippets\\\"
+ QQC2_SNIPPETS_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/quickcontrols2/doc/snippets\\\"
PUBLIC_LIBRARIES
Qt::Gui
Qt::Quick
diff --git a/tests/auto/styleimports/CMakeLists.txt b/tests/auto/styleimports/CMakeLists.txt
index 94e7bce8..ee626ac5 100644
--- a/tests/auto/styleimports/CMakeLists.txt
+++ b/tests/auto/styleimports/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_styleimports
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_styleimports.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -28,14 +28,15 @@ qt_internal_add_test(tst_styleimports
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
# Resources:
set(qmake_resourcestyle_resource_files
- "ResourceStyle/Button.qml" # special case: QTBUG-86726
- "ResourceStyle/qmldir" # special case
+ "resources/ResourceStyle/Button.qml"
+ "resources/ResourceStyle/qmldir"
)
qt_internal_add_resource(tst_styleimports "qmake_resourcestyle"
diff --git a/tests/auto/styleimportscompiletimematerial/CMakeLists.txt b/tests/auto/styleimportscompiletimematerial/CMakeLists.txt
index 9201503b..8ea0508b 100644
--- a/tests/auto/styleimportscompiletimematerial/CMakeLists.txt
+++ b/tests/auto/styleimportscompiletimematerial/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_styleimportscompiletimematerial
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_styleimportscompiletimematerial.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_styleimportscompiletimematerial
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/styleimportscompiletimeqmlonly/CMakeLists.txt b/tests/auto/styleimportscompiletimeqmlonly/CMakeLists.txt
index 57fbc1d3..40dc8dca 100644
--- a/tests/auto/styleimportscompiletimeqmlonly/CMakeLists.txt
+++ b/tests/auto/styleimportscompiletimeqmlonly/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_styleimportscompiletimeqmlonly
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_styleimportscompiletimeqmlonly.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_styleimportscompiletimeqmlonly
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/translation/CMakeLists.txt b/tests/auto/translation/CMakeLists.txt
index ec8e81ce..9a2a1bf1 100644
--- a/tests/auto/translation/CMakeLists.txt
+++ b/tests/auto/translation/CMakeLists.txt
@@ -17,7 +17,7 @@ qt_internal_add_test(tst_translation
../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_translation.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_translation
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
TESTDATA ${test_data}
)
diff --git a/tests/benchmarks/creationtime/CMakeLists.txt b/tests/benchmarks/creationtime/CMakeLists.txt
index f3c5ad07..51880533 100644
--- a/tests/benchmarks/creationtime/CMakeLists.txt
+++ b/tests/benchmarks/creationtime/CMakeLists.txt
@@ -11,7 +11,7 @@ qt_internal_add_test(tst_creationtime
../../auto/shared/visualtestutil.cpp ../../auto/shared/visualtestutil.h
tst_creationtime.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -22,6 +22,7 @@ qt_internal_add_test(tst_creationtime
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
)
diff --git a/tests/benchmarks/creationtime/tst_creationtime.cpp b/tests/benchmarks/creationtime/tst_creationtime.cpp
index 87869bca..f5383716 100644
--- a/tests/benchmarks/creationtime/tst_creationtime.cpp
+++ b/tests/benchmarks/creationtime/tst_creationtime.cpp
@@ -111,7 +111,7 @@ void tst_CreationTime::basicStyle()
void tst_CreationTime::basicStyle_data()
{
QTest::addColumn<QUrl>("url");
- addTestRowForEachControl(styleHelper.engine.data(), "controls/basic", "QtQuick/Controls/Basic", QStringList() << "ApplicationWindow");
+ addTestRowForEachControl(styleHelper.engine.data(), "quickcontrols2/basic", "QtQuick/Controls/Basic", QStringList() << "ApplicationWindow");
}
void tst_CreationTime::fusion()
@@ -123,7 +123,7 @@ void tst_CreationTime::fusion()
void tst_CreationTime::fusion_data()
{
QTest::addColumn<QUrl>("url");
- addTestRowForEachControl(styleHelper.engine.data(), "controls/fusion", "QtQuick/Controls/Fusion", QStringList() << "ApplicationWindow" << "ButtonPanel" << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator");
+ addTestRowForEachControl(styleHelper.engine.data(), "quickcontrols2/fusion", "QtQuick/Controls/Fusion", QStringList() << "ApplicationWindow" << "ButtonPanel" << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator");
}
void tst_CreationTime::imagine()
@@ -135,7 +135,7 @@ void tst_CreationTime::imagine()
void tst_CreationTime::imagine_data()
{
QTest::addColumn<QUrl>("url");
- addTestRowForEachControl(styleHelper.engine.data(), "controls/imagine", "QtQuick/Controls/Imagine", QStringList() << "ApplicationWindow");
+ addTestRowForEachControl(styleHelper.engine.data(), "quickcontrols2/imagine", "QtQuick/Controls/Imagine", QStringList() << "ApplicationWindow");
}
void tst_CreationTime::material()
@@ -147,7 +147,7 @@ void tst_CreationTime::material()
void tst_CreationTime::material_data()
{
QTest::addColumn<QUrl>("url");
- addTestRowForEachControl(styleHelper.engine.data(), "controls/material", "QtQuick/Controls/Material", QStringList() << "ApplicationWindow" << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate");
+ addTestRowForEachControl(styleHelper.engine.data(), "quickcontrols2/material", "QtQuick/Controls/Material", QStringList() << "ApplicationWindow" << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate");
}
void tst_CreationTime::universal()
@@ -159,7 +159,7 @@ void tst_CreationTime::universal()
void tst_CreationTime::universal_data()
{
QTest::addColumn<QUrl>("url");
- addTestRowForEachControl(styleHelper.engine.data(), "controls/universal", "QtQuick/Controls/Universal", QStringList() << "ApplicationWindow" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
+ addTestRowForEachControl(styleHelper.engine.data(), "quickcontrols2/universal", "QtQuick/Controls/Universal", QStringList() << "ApplicationWindow" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
}
QTEST_MAIN(tst_CreationTime)
diff --git a/tests/benchmarks/objectcount/CMakeLists.txt b/tests/benchmarks/objectcount/CMakeLists.txt
index 932e18c6..122842cd 100644
--- a/tests/benchmarks/objectcount/CMakeLists.txt
+++ b/tests/benchmarks/objectcount/CMakeLists.txt
@@ -11,7 +11,7 @@ qt_internal_add_test(tst_objectcount
../../auto/shared/visualtestutil.cpp ../../auto/shared/visualtestutil.h
tst_objectcount.cpp
DEFINES
- QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src/imports\\\"
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../src\\\"
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::Gui
@@ -22,6 +22,7 @@ qt_internal_add_test(tst_objectcount
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
+ Qt::QuickTest
Qt::TestPrivate
)
diff --git a/tests/benchmarks/objectcount/tst_objectcount.cpp b/tests/benchmarks/objectcount/tst_objectcount.cpp
index cd8b4aee..c8d29486 100644
--- a/tests/benchmarks/objectcount/tst_objectcount.cpp
+++ b/tests/benchmarks/objectcount/tst_objectcount.cpp
@@ -93,11 +93,11 @@ void tst_ObjectCount::cleanup()
static void initTestRows(QQmlEngine *engine)
{
- addTestRowForEachControl(engine, "controls/basic", "QtQuick/Controls/Basic");
- addTestRowForEachControl(engine, "controls/fusion", "QtQuick/Controls/Fusion", QStringList() << "ButtonPanel" << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator");
- addTestRowForEachControl(engine, "controls/imagine", "QtQuick/Controls/Imagine");
- addTestRowForEachControl(engine, "controls/material", "QtQuick/Controls/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate");
- addTestRowForEachControl(engine, "controls/universal", "QtQuick/Controls/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
+ addTestRowForEachControl(engine, "quickcontrols2/basic", "QtQuick/Controls/Basic");
+ addTestRowForEachControl(engine, "quickcontrols2/fusion", "QtQuick/Controls/Fusion", QStringList() << "ButtonPanel" << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator");
+ addTestRowForEachControl(engine, "quickcontrols2/imagine", "QtQuick/Controls/Imagine");
+ addTestRowForEachControl(engine, "quickcontrols2/material", "QtQuick/Controls/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate");
+ addTestRowForEachControl(engine, "quickcontrols2/universal", "QtQuick/Controls/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
}
template <typename T>
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
index 79d19753..ca545da7 100644
--- a/tests/manual/CMakeLists.txt
+++ b/tests/manual/CMakeLists.txt
@@ -1,11 +1,14 @@
# Generated from manual.pro.
add_subdirectory(buttons)
-add_subdirectory(gifs)
+add_subdirectory(dialogs)
add_subdirectory(fonts)
+add_subdirectory(gifs)
add_subdirectory(headerview)
+add_subdirectory(qquickdialog)
add_subdirectory(screenshots)
add_subdirectory(styles)
+add_subdirectory(styles-cover-flow)
add_subdirectory(testbench)
if(QT_FEATURE_systemtrayicon)
add_subdirectory(systemtrayicon)
diff --git a/tests/manual/buttons/CMakeLists.txt b/tests/manual/buttons/CMakeLists.txt
index e57611a5..57f80c88 100644
--- a/tests/manual/buttons/CMakeLists.txt
+++ b/tests/manual/buttons/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from buttons.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(buttons LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## buttons Binary:
#####################################################################
diff --git a/tests/manual/dialogs/CMakeLists.txt b/tests/manual/dialogs/CMakeLists.txt
index b0fe5dd5..cc132f36 100644
--- a/tests/manual/dialogs/CMakeLists.txt
+++ b/tests/manual/dialogs/CMakeLists.txt
@@ -1,8 +1,8 @@
-# Generated from dialogs.pro.
-
-#####################################################################
-## dialogs Binary:
-#####################################################################
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(dialogs LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
qt_internal_add_manual_test(dialogs
GUI
@@ -16,11 +16,12 @@ qt_internal_add_manual_test(dialogs
# Resources:
set(qmake_immediate_resource_files
- "CustomDialog.qml"
- "DialogLabel.qml"
- "Marker.qml"
"dialogs.qml"
- "qtquickcontrols2.conf"
+ "FileDialogPage.qml"
+ "FontDialogPage.qml"
+ "StringListView.qml"
+ "qmldir"
+ "Theme.qml"
)
qt_internal_add_resource(dialogs "qmake_immediate"
@@ -29,7 +30,3 @@ qt_internal_add_resource(dialogs "qmake_immediate"
FILES
${qmake_immediate_resource_files}
)
-
-
-#### Keys ignored in scope 1:.:.:dialogs.pro:<TRUE>:
-# TEMPLATE = "app"
diff --git a/tests/manual/dialogs/FileDialogPage.qml b/tests/manual/dialogs/FileDialogPage.qml
new file mode 100644
index 00000000..9faad47e
--- /dev/null
+++ b/tests/manual/dialogs/FileDialogPage.qml
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+import QtQuick.Layouts
+
+import "."
+
+ColumnLayout {
+ property alias dialog: fileDialog
+
+ // Put it all in another ColumnLayout so we can easily add margins.
+ ColumnLayout {
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+ Layout.topMargin: 12
+ Layout.bottomMargin: 12
+
+ GroupBox {
+ title: qsTr("Dialog properties")
+
+ Layout.fillWidth: true
+
+ GridLayout {
+ columns: 2
+ anchors.fill: parent
+
+ Label {
+ text: qsTr("modality")
+
+ Layout.alignment: Qt.AlignTop
+ Layout.minimumWidth: ApplicationWindow.window.width * 0.2
+ Layout.maximumWidth: ApplicationWindow.window.width * 0.2
+ }
+ ButtonGroup {
+ id: modalityButtonGroup
+ buttons: modalityColumnLayout.children
+ }
+ ColumnLayout {
+ id: modalityColumnLayout
+
+ RadioButton {
+ text: qsTr("Qt.NonModal")
+
+ readonly property int modality: Qt.NonModal
+ }
+ RadioButton {
+ text: qsTr("Qt.WindowModal")
+ checked: true
+
+ readonly property int modality: Qt.WindowModal
+ }
+ RadioButton {
+ text: qsTr("Qt.ApplicationModal")
+
+ readonly property int modality: Qt.ApplicationModal
+ }
+ }
+
+ Label {
+ text: qsTr("result")
+ }
+ TextField {
+ id: resultTextField
+ text: fileDialog.result === 1 ? qsTr("Accepted") : qsTr("Rejected")
+ readOnly: true
+ enabled: false
+ }
+
+ Label {
+ text: qsTr("title")
+ }
+ TextField {
+ id: titleTextField
+ text: qsTr("Choose a file")
+ }
+ }
+ }
+
+ GroupBox {
+ title: qsTr("FileDialog properties")
+
+ Layout.fillWidth: true
+
+ GridLayout {
+ columns: 2
+ anchors.fill: parent
+
+ Label {
+ text: qsTr("acceptLabel")
+
+ Layout.minimumWidth: ApplicationWindow.window.width * 0.2
+ Layout.maximumWidth: ApplicationWindow.window.width * 0.2
+ }
+ TextField {
+ id: acceptLabelTextField
+ text: qsTr("OK")
+ }
+
+ Label {
+ text: qsTr("currentFile")
+ }
+ TextField {
+ id: currentFileTextField
+ text: fileDialog.currentFile
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("currentFolder")
+ }
+ TextField {
+ id: currentFolderTextField
+ text: fileDialog.currentFolder
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("currentFiles")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ StringListView {
+ id: currentFilesListView
+ // QTBUG-72906
+ model: [].concat(fileDialog.currentFiles)
+ }
+
+ Label {
+ text: qsTr("fileOptions")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ ColumnLayout {
+ id: fileOptionsColumnLayout
+
+ CheckBox {
+ id: dontResolveSymlinksCheckBox
+ text: qsTr("DontResolveSymlinks")
+
+ readonly property int fileOption: checked ? FileDialog.DontResolveSymlinks : 0
+ }
+ CheckBox {
+ id: dontConfirmOverwriteCheckBox
+ text: qsTr("DontConfirmOverwrite")
+
+ readonly property int fileOption: checked ? FileDialog.DontConfirmOverwrite : 0
+ }
+ CheckBox {
+ id: readOnlyCheckBox
+ text: qsTr("ReadOnly")
+
+ readonly property int fileOption: checked ? FileDialog.ReadOnly : 0
+ }
+ CheckBox {
+ id: hideNameFilterDetailsCheckBox
+ text: qsTr("HideNameFilterDetails")
+
+ readonly property int fileOption: checked ? FileDialog.HideNameFilterDetails : 0
+ }
+ }
+
+ Label {
+ text: qsTr("fileMode")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ ButtonGroup {
+ id: fileModeButtonGroup
+ buttons: fileModeColumnLayout.children
+ }
+ ColumnLayout {
+ id: fileModeColumnLayout
+
+ RadioButton {
+ text: qsTr("OpenFile")
+
+ readonly property int fileMode: FileDialog.OpenFile
+ }
+ RadioButton {
+ text: qsTr("OpenFiles")
+ checked: true
+
+ readonly property int fileMode: FileDialog.OpenFiles
+ }
+ RadioButton {
+ text: qsTr("SaveFile")
+
+ readonly property int fileMode: FileDialog.SaveFile
+ }
+ }
+
+ Label {
+ text: qsTr("nameFilters")
+ }
+ TextField {
+ id: nameFiltersTextField
+ text: ["Text files (*.txt)", "HTML files (*.html)"].join(",")
+
+ Layout.fillWidth: true
+
+ ToolTip.text: qsTr("For this example, a comma-separated string")
+ ToolTip.visible: hovered
+ ToolTip.delay: Theme.toolTipDelay
+ }
+
+ Label {
+ text: qsTr("rejectLabel")
+ }
+ TextField {
+ id: rejectLabelTextField
+ text: qsTr("Cancel")
+ }
+
+ Label {
+ text: qsTr("selectedFile")
+ }
+ TextField {
+ id: selectedFileTextField
+ text: fileDialog.selectedFile
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("selectedFiles")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ StringListView {
+ id: selectedFilesListView
+ // QTBUG-72906
+ model: [].concat(fileDialog.selectedFiles)
+ }
+
+ Label {
+ text: qsTr("selectedNameFilter.name")
+ }
+ TextField {
+ id: selectedNameFilterNameTextField
+ text: fileDialog.selectedNameFilter.name
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("selectedNameFilter.globs")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ StringListView {
+ id: selectedNameFilterGlobsListView
+ // QTBUG-72906
+ model: [].concat(fileDialog.selectedNameFilter.globs)
+ }
+
+ Label {
+ text: qsTr("selectedNameFilter.index")
+ }
+ TextField {
+ id: selectedNameFilterIndexTextField
+ text: fileDialog.selectedNameFilter.index
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("selectedNameFilter.extensions")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ StringListView {
+ id: selectedNameFilterExtensionsListView
+ // QTBUG-72906
+ model: [].concat(fileDialog.selectedNameFilter.extensions)
+ }
+ }
+ }
+
+ FileDialog {
+ id: fileDialog
+
+ modality: modalityButtonGroup.checkedButton.modality
+ title: titleTextField.text
+
+ acceptLabel: acceptLabelTextField.text
+ fileMode: fileModeButtonGroup.checkedButton.fileMode
+ options: dontResolveSymlinksCheckBox.fileOption
+ | dontConfirmOverwriteCheckBox.fileOption
+ | readOnlyCheckBox.fileOption
+ | hideNameFilterDetailsCheckBox.fileOption
+ nameFilters: nameFiltersTextField.text.split(",")
+ rejectLabel: rejectLabelTextField.text
+ }
+ }
+}
diff --git a/tests/manual/dialogs/FontDialogPage.qml b/tests/manual/dialogs/FontDialogPage.qml
new file mode 100644
index 00000000..5b5d1034
--- /dev/null
+++ b/tests/manual/dialogs/FontDialogPage.qml
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+import QtQuick.Layouts
+
+import "."
+
+ColumnLayout {
+ property alias dialog: fontDialog
+
+ // Put it all in another ColumnLayout so we can easily add margins.
+ ColumnLayout {
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+ Layout.topMargin: 12
+ Layout.bottomMargin: 12
+
+ GroupBox {
+ title: qsTr("Dialog properties")
+
+ Layout.fillWidth: true
+
+ GridLayout {
+ columns: 2
+ anchors.fill: parent
+
+ Label {
+ text: qsTr("modality")
+
+ Layout.alignment: Qt.AlignTop
+ Layout.minimumWidth: ApplicationWindow.window.width * 0.2
+ Layout.maximumWidth: ApplicationWindow.window.width * 0.2
+ }
+ ButtonGroup {
+ id: modalityButtonGroup
+ buttons: modalityColumnLayout.children
+ }
+ ColumnLayout {
+ id: modalityColumnLayout
+
+ RadioButton {
+ text: qsTr("Qt.NonModal")
+
+ readonly property int modality: Qt.NonModal
+ }
+ RadioButton {
+ text: qsTr("Qt.WindowModal")
+ checked: true
+
+ readonly property int modality: Qt.WindowModal
+ }
+ RadioButton {
+ text: qsTr("Qt.ApplicationModal")
+
+ readonly property int modality: Qt.ApplicationModal
+ }
+ }
+
+ Label {
+ text: qsTr("result")
+ }
+ TextField {
+ id: resultTextField
+ text: fontDialog.result === 1 ? qsTr("Accepted") : qsTr("Rejected")
+ readOnly: true
+ enabled: false
+ }
+
+ Label {
+ text: qsTr("title")
+ }
+ TextField {
+ id: titleTextField
+ text: qsTr("Pick a font")
+ }
+ }
+ }
+
+ GroupBox {
+ title: qsTr("FontDialog properties")
+
+ Layout.fillWidth: true
+
+ GridLayout {
+ columns: 2
+ anchors.fill: parent
+
+ Label {
+ Layout.minimumWidth: ApplicationWindow.window.width * 0.2
+ Layout.maximumWidth: ApplicationWindow.window.width * 0.2
+ text: qsTr("currentFont")
+ }
+ TextField {
+ id: currentFontTextField
+ text: qsTr("AaBbYyZz")
+ font: fontDialog.currentFont
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("selectedFont")
+ }
+ TextField {
+ id: selectedFontTextField
+ text: qsTr("AaBbYyZz")
+ font: fontDialog.selectedFont
+ readOnly: true
+ selectByMouse: true
+
+ Layout.fillWidth: true
+ }
+
+ Label {
+ text: qsTr("fontOptions")
+
+ Layout.alignment: Qt.AlignTop
+ }
+ ColumnLayout {
+ id: fontOptionsColumnLayout
+
+ CheckBox {
+ id: noButtons
+ text: qsTr("NoButtons")
+
+ readonly property int fontOption: checked ? FontDialog.NoButtons : 0
+ }
+ CheckBox {
+ id: scalableFonts
+ text: qsTr("ScalableFonts")
+
+ readonly property int fontOption: checked ? FontDialog.ScalableFonts : 0
+ }
+ CheckBox {
+ id: nonScalableFonts
+ text: qsTr("NonScalableFonts")
+
+ readonly property int fontOption: checked ? FontDialog.NonScalableFonts : 0
+ }
+ CheckBox {
+ id: monospacedFonts
+ text: qsTr("MonospacedFonts")
+
+ readonly property int fontOption: checked ? FontDialog.MonospacedFonts : 0
+ }
+ CheckBox {
+ id: proportionalFonts
+ text: qsTr("ProportionalFonts")
+
+ readonly property int fontOption: checked ? FontDialog.ProportionalFonts : 0
+ }
+ }
+ }
+ }
+
+ FontDialog {
+ id: fontDialog
+
+ modality: modalityButtonGroup.checkedButton.modality
+ title: titleTextField.text
+ options: noButtons.fontOption
+ | scalableFonts.fontOption
+ | nonScalableFonts.fontOption
+ | monospacedFonts.fontOption
+ | proportionalFonts.fontOption
+ }
+ }
+}
diff --git a/tests/manual/dialogs/StringListView.qml b/tests/manual/dialogs/StringListView.qml
new file mode 100644
index 00000000..4a229404
--- /dev/null
+++ b/tests/manual/dialogs/StringListView.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "."
+
+ListView {
+ id: root
+ clip: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: count > 0 ? 128 : noneLabel.implicitHeight
+
+ ScrollBar.vertical: ScrollBar {}
+
+ delegate: TextField {
+ width: root.width
+ text: modelData
+ readOnly: true
+ selectByMouse: true
+ }
+
+ Label {
+ id: noneLabel
+ text: qsTr("(None)")
+ visible: root.count === 0
+ }
+}
diff --git a/tests/manual/dialogs/Theme.qml b/tests/manual/dialogs/Theme.qml
new file mode 100644
index 00000000..8114f14e
--- /dev/null
+++ b/tests/manual/dialogs/Theme.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+pragma Singleton
+
+import QtQml
+
+QtObject {
+ readonly property int toolTipDelay: 1000
+}
diff --git a/tests/manual/dialogs/dialogs.cpp b/tests/manual/dialogs/dialogs.cpp
index 79d26c2b..8bab70e2 100644
--- a/tests/manual/dialogs/dialogs.cpp
+++ b/tests/manual/dialogs/dialogs.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -48,15 +48,33 @@
**
****************************************************************************/
-#include <QGuiApplication>
-#include <QQmlApplicationEngine>
+#include <QtCore/qsettings.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQml/qqmlapplicationengine.h>
+#include <QtQuickControls2/qquickstyle.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
+ QCoreApplication::setApplicationName("dialogs-manual-test");
+ QCoreApplication::setOrganizationName("QtProject");
+
+ // Use native dialogs by default unless the user asked us not to.
+ QSettings settings;
+ const QVariant useNativeDialogs = settings.value("useNativeDialogs");
+ if (useNativeDialogs.isValid()) {
+ if (!useNativeDialogs.toBool())
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
+ } else {
+ // Set the default here so that we can use an alias in QML.
+ // Without this it defaults to CheckBox's checked default value, which is false.
+ settings.setValue("useNativeDialogs", true);
+ }
+
QQmlApplicationEngine engine;
- engine.load(QUrl("qrc:/dialogs.qml"));
+ engine.setInitialProperties({{ "style", QQuickStyle::name() }});
+ engine.load(QUrl(QStringLiteral("qrc:/dialogs.qml")));
return app.exec();
}
diff --git a/tests/manual/dialogs/dialogs.pro b/tests/manual/dialogs/dialogs.pro
index 4863923f..7dc1b8fd 100644
--- a/tests/manual/dialogs/dialogs.pro
+++ b/tests/manual/dialogs/dialogs.pro
@@ -4,8 +4,9 @@ QT += qml quickcontrols2
SOURCES += dialogs.cpp
RESOURCES += \
- qtquickcontrols2.conf \
dialogs.qml \
- Marker.qml \
- CustomDialog.qml \
- DialogLabel.qml
+ FileDialogPage.qml \
+ FontDialogPage.qml \
+ StringListView.qml \
+ qmldir \
+ Theme.qml
diff --git a/tests/manual/dialogs/dialogs.qml b/tests/manual/dialogs/dialogs.qml
index e7c8c2e1..6e64659e 100644
--- a/tests/manual/dialogs/dialogs.qml
+++ b/tests/manual/dialogs/dialogs.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -52,196 +52,77 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
+import Qt.labs.settings
+
ApplicationWindow {
id: window
- width: 1200
- height: 800
- title: "Buttons"
+ width: 800
+ height: 600
+ title: "dialogs - style: " + style
visible: true
- property alias visualizeDialogButtonBoxContentItem: visualizeDialogButtonBoxContentItemMenuItem.checked
- property alias visualizeDialogButtonBox: visualizeDialogButtonBoxMenuItem.checked
-
- property int dialogSpacing: 60
-
- header: ToolBar {
- RowLayout {
- anchors.fill: parent
- Item {
- Layout.fillWidth: true
- }
-
- ToolButton {
- text: "Settings"
- onClicked: settingsMenu.open()
-
- Menu {
- id: settingsMenu
- width: 400
-
- MenuItem {
- id: visualizeDialogButtonBoxContentItemMenuItem
- text: "Visualize DialogButtonBox contentItem"
- checkable: true
- }
-
- MenuItem {
- id: visualizeDialogButtonBoxMenuItem
- text: "Visualize DialogButtonBox"
- checkable: true
- }
- }
- }
- }
- }
-
+ required property string style
- DialogLabel {
- text: "implicit width"
- dialog: dialogImplicitWidthNoButtons
- width: 100
- }
- CustomDialog {
- id: dialogImplicitWidthNoButtons
- x: dialogSpacing
- y: dialogSpacing
- space: 200
+ Component.onCompleted: {
+ x = Screen.width / 2 - width / 2
+ y = Screen.height / 2 - height / 2
}
- DialogLabel {
- text: "title, implicit width"
- dialog: dialogImplicitWidthTitleNoButtons
- width: 150
- }
- CustomDialog {
- id: dialogImplicitWidthTitleNoButtons
- y: dialogSpacing
- title: "Test"
- previousDialog: dialogImplicitWidthNoButtons
- space: 200
- }
+ Settings {
+ id: settings
- DialogLabel {
- text: "title, fixed width"
- dialog: dialogFixedWidthTitleNoButtons
- }
- CustomDialog {
- id: dialogFixedWidthTitleNoButtons
- y: dialogSpacing
- width: 300
- title: "Test"
- previousDialog: dialogImplicitWidthTitleNoButtons
- space: 200
+ property alias useNativeDialogs: useNativeDialogsCheckBox.checked
}
+ Page {
+ anchors.fill: parent
- DialogLabel {
- text: "one standard button, implicit width"
- dialog: dialogImplicitWidthOneButton
- }
- CustomDialog {
- id: dialogImplicitWidthOneButton
- x: dialogSpacing
- y: dialogFixedWidthTitleNoButtons.y + dialogFixedWidthTitleNoButtons.height + dialogSpacing
- standardButtons: Dialog.Ok
- }
-
- DialogLabel {
- text: "two standard buttons, implicit width"
- dialog: dialogImplicitWidthTwoButtons
- }
- CustomDialog {
- id: dialogImplicitWidthTwoButtons
- standardButtons: Dialog.Ok | Dialog.Cancel
- previousDialog: dialogImplicitWidthOneButton
- }
-
- DialogLabel {
- text: "three standard buttons, implicit width"
- dialog: dialogImplicitWidthThreeButtons
- }
- CustomDialog {
- id: dialogImplicitWidthThreeButtons
- standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
- previousDialog: dialogImplicitWidthTwoButtons
- }
-
+ header: TabBar {
+ id: tabBar
- DialogLabel {
- text: "text, one standard button, implicit width"
- dialog: dialogTextImplicitWidthOneButton
- }
- CustomDialog {
- id: dialogTextImplicitWidthOneButton
- x: dialogSpacing
- y: dialogImplicitWidthThreeButtons.y + dialogImplicitWidthThreeButtons.height + dialogSpacing
- standardButtons: Dialog.Ok
-
- Label {
- text: "A Label"
+ TabButton {
+ text: qsTr("FileDialog")
+ }
+ TabButton {
+ text: qsTr("FontDialog")
+ }
}
- }
- DialogLabel {
- text: "text, two standard buttons, implicit width"
- dialog: dialogTextImplicitWidthTwoButtons
- }
- CustomDialog {
- id: dialogTextImplicitWidthTwoButtons
- standardButtons: Dialog.Ok | Dialog.Cancel
- previousDialog: dialogTextImplicitWidthOneButton
-
- Label {
- text: "A Label"
- }
- }
+ ScrollView {
+ id: scrollView
+ anchors.fill: parent
+ clip: true
- DialogLabel {
- text: "text, three standard buttons, implicit width"
- dialog: dialogTextImplicitWidthThreeButtons
- }
- CustomDialog {
- id: dialogTextImplicitWidthThreeButtons
- standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
- previousDialog: dialogTextImplicitWidthTwoButtons
+ StackLayout {
+ id: stackLayout
+ currentIndex: tabBar.currentIndex
+ width: scrollView.width
- Label {
- text: "A Label"
+ FileDialogPage {}
+ FontDialogPage {}
+ }
}
}
+ footer: ToolBar {
+ RowLayout {
+ anchors.fill: parent
- DialogLabel {
- text: "one standard button, fixed width (300)"
- dialog: dialogFixedWidthOneButton
- }
- CustomDialog {
- id: dialogFixedWidthOneButton
- x: dialogSpacing
- y: dialogTextImplicitWidthThreeButtons.y + dialogTextImplicitWidthThreeButtons.height + dialogSpacing
- width: 300
- standardButtons: Dialog.Ok
- }
+ CheckBox {
+ id: useNativeDialogsCheckBox
+ text: qsTr("Use Native Dialogs (requires restart)")
+ checked: settings.useNativeDialogs
+ }
- DialogLabel {
- text: "two standard buttons, fixed width (300)"
- dialog: dialogFixedWidthTwoButtons
- }
- CustomDialog {
- id: dialogFixedWidthTwoButtons
- width: 300
- standardButtons: Dialog.Ok | Dialog.Cancel
- previousDialog: dialogFixedWidthOneButton
- }
+ Item {
+ Layout.fillWidth: true
+ }
- DialogLabel {
- text: "three standard buttons, fixed width (300)"
- dialog: dialogFixedWidthThreeButtons
- }
- CustomDialog {
- id: dialogFixedWidthThreeButtons
- width: 300
- standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
- previousDialog: dialogFixedWidthTwoButtons
+ Button {
+ text: qsTr("Open")
+
+ onClicked: stackLayout.children[stackLayout.currentIndex].dialog.open()
+ }
+ }
}
}
diff --git a/tests/manual/dialogs/qmldir b/tests/manual/dialogs/qmldir
new file mode 100644
index 00000000..4f4a6b7b
--- /dev/null
+++ b/tests/manual/dialogs/qmldir
@@ -0,0 +1,3 @@
+module org.qtproject.examples.dialogs
+
+singleton Theme 1.0 Theme.qml
diff --git a/tests/manual/fonts/CMakeLists.txt b/tests/manual/fonts/CMakeLists.txt
index b0670fe2..6160ff11 100644
--- a/tests/manual/fonts/CMakeLists.txt
+++ b/tests/manual/fonts/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from fonts.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(fonts LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## fonts Binary:
#####################################################################
diff --git a/tests/manual/gifs/CMakeLists.txt b/tests/manual/gifs/CMakeLists.txt
index 8bbec940..a2fc5355 100644
--- a/tests/manual/gifs/CMakeLists.txt
+++ b/tests/manual/gifs/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from gifs.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_gifs LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## tst_gifs Test:
#####################################################################
diff --git a/tests/manual/headerview/CMakeLists.txt b/tests/manual/headerview/CMakeLists.txt
index 035082d1..4c4ae94a 100644
--- a/tests/manual/headerview/CMakeLists.txt
+++ b/tests/manual/headerview/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from headerview.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(headerview LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## headerview Binary:
#####################################################################
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index fba3c12a..27ec27f1 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -1,12 +1,17 @@
TEMPLATE = subdirs
SUBDIRS += \
buttons \
- gifs \
+ dialogs \
fonts \
+ gifs \
headerview \
+ qquickdialog \
screenshots \
styles \
- testbench
+ styles-cover-flow \
+ systemtrayicon \
+ testbench \
+ viewinqwidget
qtConfig(systemtrayicon): SUBDIRS += systemtrayicon
diff --git a/tests/manual/qquickdialog/CMakeLists.txt b/tests/manual/qquickdialog/CMakeLists.txt
new file mode 100644
index 00000000..661a7dc7
--- /dev/null
+++ b/tests/manual/qquickdialog/CMakeLists.txt
@@ -0,0 +1,31 @@
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(qquickdialog LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_manual_test(qquickdialog
+ GUI
+ SOURCES
+ qquickdialog.cpp
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ Qt::Qml
+ Qt::QuickControls2
+)
+
+# Resources:
+set(qmake_immediate_resource_files
+ "CustomDialog.qml"
+ "DialogLabel.qml"
+ "Marker.qml"
+ "qquickdialog.qml"
+ "qtquickcontrols2.conf"
+)
+
+qt_internal_add_resource(qquickdialog "qmake_immediate"
+ PREFIX
+ "/"
+ FILES
+ ${qmake_immediate_resource_files}
+)
diff --git a/tests/manual/dialogs/CustomDialog.qml b/tests/manual/qquickdialog/CustomDialog.qml
index fb191c9f..fb191c9f 100644
--- a/tests/manual/dialogs/CustomDialog.qml
+++ b/tests/manual/qquickdialog/CustomDialog.qml
diff --git a/tests/manual/dialogs/DialogLabel.qml b/tests/manual/qquickdialog/DialogLabel.qml
index 3a1533eb..3a1533eb 100644
--- a/tests/manual/dialogs/DialogLabel.qml
+++ b/tests/manual/qquickdialog/DialogLabel.qml
diff --git a/tests/manual/dialogs/Marker.qml b/tests/manual/qquickdialog/Marker.qml
index cd93d055..cd93d055 100644
--- a/tests/manual/dialogs/Marker.qml
+++ b/tests/manual/qquickdialog/Marker.qml
diff --git a/tests/manual/qquickdialog/qquickdialog.cpp b/tests/manual/qquickdialog/qquickdialog.cpp
new file mode 100644
index 00000000..77863abe
--- /dev/null
+++ b/tests/manual/qquickdialog/qquickdialog.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl("qrc:/qquickdialog.qml"));
+
+ return app.exec();
+}
diff --git a/tests/manual/qquickdialog/qquickdialog.pro b/tests/manual/qquickdialog/qquickdialog.pro
new file mode 100644
index 00000000..aee7655b
--- /dev/null
+++ b/tests/manual/qquickdialog/qquickdialog.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+TARGET = qquickdialog
+QT += qml quickcontrols2
+
+SOURCES += qquickdialog.cpp
+RESOURCES += \
+ qtquickcontrols2.conf \
+ qquickdialog.qml \
+ Marker.qml \
+ CustomDialog.qml \
+ DialogLabel.qml
diff --git a/tests/manual/qquickdialog/qquickdialog.qml b/tests/manual/qquickdialog/qquickdialog.qml
new file mode 100644
index 00000000..41bf6ab7
--- /dev/null
+++ b/tests/manual/qquickdialog/qquickdialog.qml
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ApplicationWindow {
+ id: window
+ width: 1200
+ height: 800
+ title: "qquickdialog"
+ visible: true
+
+ property alias visualizeDialogButtonBoxContentItem: visualizeDialogButtonBoxContentItemMenuItem.checked
+ property alias visualizeDialogButtonBox: visualizeDialogButtonBoxMenuItem.checked
+
+ property int dialogSpacing: 60
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ Item {
+ Layout.fillWidth: true
+ }
+
+ ToolButton {
+ text: "Settings"
+ onClicked: settingsMenu.open()
+
+ Menu {
+ id: settingsMenu
+ width: 400
+
+ MenuItem {
+ id: visualizeDialogButtonBoxContentItemMenuItem
+ text: "Visualize DialogButtonBox contentItem"
+ checkable: true
+ }
+
+ MenuItem {
+ id: visualizeDialogButtonBoxMenuItem
+ text: "Visualize DialogButtonBox"
+ checkable: true
+ }
+ }
+ }
+ }
+ }
+
+
+ DialogLabel {
+ text: "implicit width"
+ dialog: dialogImplicitWidthNoButtons
+ width: 100
+ }
+ CustomDialog {
+ id: dialogImplicitWidthNoButtons
+ x: dialogSpacing
+ y: dialogSpacing
+ space: 200
+ }
+
+ DialogLabel {
+ text: "title, implicit width"
+ dialog: dialogImplicitWidthTitleNoButtons
+ width: 150
+ }
+ CustomDialog {
+ id: dialogImplicitWidthTitleNoButtons
+ y: dialogSpacing
+ title: "Test"
+ previousDialog: dialogImplicitWidthNoButtons
+ space: 200
+ }
+
+ DialogLabel {
+ text: "title, fixed width"
+ dialog: dialogFixedWidthTitleNoButtons
+ }
+ CustomDialog {
+ id: dialogFixedWidthTitleNoButtons
+ y: dialogSpacing
+ width: 300
+ title: "Test"
+ previousDialog: dialogImplicitWidthTitleNoButtons
+ space: 200
+ }
+
+
+ DialogLabel {
+ text: "one standard button, implicit width"
+ dialog: dialogImplicitWidthOneButton
+ }
+ CustomDialog {
+ id: dialogImplicitWidthOneButton
+ x: dialogSpacing
+ y: dialogFixedWidthTitleNoButtons.y + dialogFixedWidthTitleNoButtons.height + dialogSpacing
+ standardButtons: Dialog.Ok
+ }
+
+ DialogLabel {
+ text: "two standard buttons, implicit width"
+ dialog: dialogImplicitWidthTwoButtons
+ }
+ CustomDialog {
+ id: dialogImplicitWidthTwoButtons
+ standardButtons: Dialog.Ok | Dialog.Cancel
+ previousDialog: dialogImplicitWidthOneButton
+ }
+
+ DialogLabel {
+ text: "three standard buttons, implicit width"
+ dialog: dialogImplicitWidthThreeButtons
+ }
+ CustomDialog {
+ id: dialogImplicitWidthThreeButtons
+ standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
+ previousDialog: dialogImplicitWidthTwoButtons
+ }
+
+
+ DialogLabel {
+ text: "text, one standard button, implicit width"
+ dialog: dialogTextImplicitWidthOneButton
+ }
+ CustomDialog {
+ id: dialogTextImplicitWidthOneButton
+ x: dialogSpacing
+ y: dialogImplicitWidthThreeButtons.y + dialogImplicitWidthThreeButtons.height + dialogSpacing
+ standardButtons: Dialog.Ok
+
+ Label {
+ text: "A Label"
+ }
+ }
+
+ DialogLabel {
+ text: "text, two standard buttons, implicit width"
+ dialog: dialogTextImplicitWidthTwoButtons
+ }
+ CustomDialog {
+ id: dialogTextImplicitWidthTwoButtons
+ standardButtons: Dialog.Ok | Dialog.Cancel
+ previousDialog: dialogTextImplicitWidthOneButton
+
+ Label {
+ text: "A Label"
+ }
+ }
+
+ DialogLabel {
+ text: "text, three standard buttons, implicit width"
+ dialog: dialogTextImplicitWidthThreeButtons
+ }
+ CustomDialog {
+ id: dialogTextImplicitWidthThreeButtons
+ standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
+ previousDialog: dialogTextImplicitWidthTwoButtons
+
+ Label {
+ text: "A Label"
+ }
+ }
+
+
+ DialogLabel {
+ text: "one standard button, fixed width (300)"
+ dialog: dialogFixedWidthOneButton
+ }
+ CustomDialog {
+ id: dialogFixedWidthOneButton
+ x: dialogSpacing
+ y: dialogTextImplicitWidthThreeButtons.y + dialogTextImplicitWidthThreeButtons.height + dialogSpacing
+ width: 300
+ standardButtons: Dialog.Ok
+ }
+
+ DialogLabel {
+ text: "two standard buttons, fixed width (300)"
+ dialog: dialogFixedWidthTwoButtons
+ }
+ CustomDialog {
+ id: dialogFixedWidthTwoButtons
+ width: 300
+ standardButtons: Dialog.Ok | Dialog.Cancel
+ previousDialog: dialogFixedWidthOneButton
+ }
+
+ DialogLabel {
+ text: "three standard buttons, fixed width (300)"
+ dialog: dialogFixedWidthThreeButtons
+ }
+ CustomDialog {
+ id: dialogFixedWidthThreeButtons
+ width: 300
+ standardButtons: Dialog.Apply | Dialog.RestoreDefaults | Dialog.Cancel
+ previousDialog: dialogFixedWidthTwoButtons
+ }
+}
diff --git a/tests/manual/dialogs/qtquickcontrols2.conf b/tests/manual/qquickdialog/qtquickcontrols2.conf
index 53f380bf..53f380bf 100644
--- a/tests/manual/dialogs/qtquickcontrols2.conf
+++ b/tests/manual/qquickdialog/qtquickcontrols2.conf
diff --git a/tests/manual/screenshots/CMakeLists.txt b/tests/manual/screenshots/CMakeLists.txt
index c01418ef..b6bd2926 100644
--- a/tests/manual/screenshots/CMakeLists.txt
+++ b/tests/manual/screenshots/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from screenshots.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(screenshots LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## screenshots Binary:
#####################################################################
diff --git a/tests/manual/styles-cover-flow/CMakeLists.txt b/tests/manual/styles-cover-flow/CMakeLists.txt
index 4c9fd13b..ab62046c 100644
--- a/tests/manual/styles-cover-flow/CMakeLists.txt
+++ b/tests/manual/styles-cover-flow/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from styles-cover-flow.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(styles-cover-flow LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## stylescoverflow Binary:
#####################################################################
diff --git a/tests/manual/styles/CMakeLists.txt b/tests/manual/styles/CMakeLists.txt
index b900da1b..7ba6c733 100644
--- a/tests/manual/styles/CMakeLists.txt
+++ b/tests/manual/styles/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from styles.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(styles LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## styles Binary:
#####################################################################
diff --git a/tests/manual/systemtrayicon/CMakeLists.txt b/tests/manual/systemtrayicon/CMakeLists.txt
index 667fc7f7..b44a4496 100644
--- a/tests/manual/systemtrayicon/CMakeLists.txt
+++ b/tests/manual/systemtrayicon/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from systemtrayicon.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(systemtrayicon LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## systemtrayicon Binary:
#####################################################################
diff --git a/tests/manual/testbench/CMakeLists.txt b/tests/manual/testbench/CMakeLists.txt
index 2fe24d60..66933a92 100644
--- a/tests/manual/testbench/CMakeLists.txt
+++ b/tests/manual/testbench/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from testbench.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(testbench LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## testbench Binary:
#####################################################################
diff --git a/tests/manual/viewinqwidget/CMakeLists.txt b/tests/manual/viewinqwidget/CMakeLists.txt
index 9a5021fa..f91b0d8c 100644
--- a/tests/manual/viewinqwidget/CMakeLists.txt
+++ b/tests/manual/viewinqwidget/CMakeLists.txt
@@ -1,5 +1,11 @@
# Generated from viewinqwidget.pro.
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(viewinqwidget LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
#####################################################################
## viewinqwidget Binary:
#####################################################################