aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto')
-rw-r--r--tests/auto/accessibility/tst_accessibility.cpp22
-rw-r--r--tests/auto/auto.pro13
-rw-r--r--tests/auto/controls/controls.pro2
-rw-r--r--tests/auto/controls/data/tst_abstractbutton.qml193
-rw-r--r--tests/auto/controls/data/tst_action.qml140
-rw-r--r--tests/auto/controls/data/tst_actiongroup.qml381
-rw-r--r--tests/auto/controls/data/tst_button.qml81
-rw-r--r--tests/auto/controls/data/tst_buttongroup.qml62
-rw-r--r--tests/auto/controls/data/tst_checkdelegate.qml81
-rw-r--r--tests/auto/controls/data/tst_combobox.qml66
-rw-r--r--tests/auto/controls/data/tst_container.qml42
-rw-r--r--tests/auto/controls/data/tst_dialog.qml42
-rw-r--r--tests/auto/controls/data/tst_dialogbuttonbox.qml12
-rw-r--r--tests/auto/controls/data/tst_drawer.qml4
-rw-r--r--tests/auto/controls/data/tst_itemdelegate.qml80
-rw-r--r--tests/auto/controls/data/tst_menuitem.qml94
-rw-r--r--tests/auto/controls/data/tst_page.qml6
-rw-r--r--tests/auto/controls/data/tst_pageindicator.qml2
-rw-r--r--tests/auto/controls/data/tst_popup.qml38
-rw-r--r--tests/auto/controls/data/tst_radiodelegate.qml81
-rw-r--r--tests/auto/controls/data/tst_rangeslider.qml7
-rw-r--r--tests/auto/controls/data/tst_roundbutton.qml79
-rw-r--r--tests/auto/controls/data/tst_scrollbar.qml14
-rw-r--r--tests/auto/controls/data/tst_scrollindicator.qml14
-rw-r--r--tests/auto/controls/data/tst_slider.qml7
-rw-r--r--tests/auto/controls/data/tst_spinbox.qml157
-rw-r--r--tests/auto/controls/data/tst_stackview.qml78
-rw-r--r--tests/auto/controls/data/tst_swipedelegate.qml80
-rw-r--r--tests/auto/controls/data/tst_swipeview.qml4
-rw-r--r--tests/auto/controls/data/tst_switch.qml8
-rw-r--r--tests/auto/controls/data/tst_switchdelegate.qml81
-rw-r--r--tests/auto/controls/data/tst_tabbar.qml161
-rw-r--r--tests/auto/controls/data/tst_tabbutton.qml80
-rw-r--r--tests/auto/controls/data/tst_textfield.qml12
-rw-r--r--tests/auto/controls/data/tst_toolbutton.qml59
-rw-r--r--tests/auto/controls/data/tst_tooltip.qml6
-rw-r--r--tests/auto/controls/data/tst_tumbler.qml4
-rw-r--r--tests/auto/controls/fusion/dependencies.qml6
-rw-r--r--tests/auto/controls/fusion/fusion.pro15
-rw-r--r--tests/auto/controls/fusion/tst_fusion.cpp47
-rw-r--r--tests/auto/controls/imagine/dependencies.qml6
-rw-r--r--tests/auto/controls/imagine/imagine.pro15
-rw-r--r--tests/auto/controls/imagine/tst_imagine.cpp47
-rw-r--r--tests/auto/cursor/tst_cursor.cpp5
-rw-r--r--tests/auto/font/data/font-appwindow-custom.qml2
-rw-r--r--tests/auto/font/data/font-appwindow-default.qml2
-rw-r--r--tests/auto/font/data/font-control-custom.qml2
-rw-r--r--tests/auto/font/data/font-control-default.qml2
-rw-r--r--tests/auto/font/data/font-popup-custom.qml2
-rw-r--r--tests/auto/font/data/font-popup-default.qml2
-rw-r--r--tests/auto/font/data/inheritance-childcontrol.qml2
-rw-r--r--tests/auto/font/data/inheritance-childpopup.qml2
-rw-r--r--tests/auto/font/data/inheritance-control.qml2
-rw-r--r--tests/auto/font/data/inheritance-dynamicchildcontrol.qml2
-rw-r--r--tests/auto/font/data/inheritance-dynamicchildpopup.qml2
-rw-r--r--tests/auto/font/data/inheritance-dynamiccontrol.qml2
-rw-r--r--tests/auto/font/data/inheritance-dynamicpopup.qml2
-rw-r--r--tests/auto/font/data/inheritance-popup.qml2
-rw-r--r--tests/auto/font/tst_font.cpp8
-rw-r--r--tests/auto/palette/data/inheritance-childcontrol.qml76
-rw-r--r--tests/auto/palette/data/inheritance-childpopup.qml76
-rw-r--r--tests/auto/palette/data/inheritance-control.qml74
-rw-r--r--tests/auto/palette/data/inheritance-dynamicchildcontrol.qml75
-rw-r--r--tests/auto/palette/data/inheritance-dynamicchildpopup.qml80
-rw-r--r--tests/auto/palette/data/inheritance-dynamiccontrol.qml71
-rw-r--r--tests/auto/palette/data/inheritance-dynamicpopup.qml76
-rw-r--r--tests/auto/palette/data/inheritance-popup.qml74
-rw-r--r--tests/auto/palette/data/listview.qml79
-rw-r--r--tests/auto/palette/data/palette-appwindow-custom.qml74
-rw-r--r--tests/auto/palette/data/palette-appwindow-default.qml55
-rw-r--r--tests/auto/palette/data/palette-control-custom.qml74
-rw-r--r--tests/auto/palette/data/palette-control-default.qml55
-rw-r--r--tests/auto/palette/data/palette-popup-custom.qml74
-rw-r--r--tests/auto/palette/data/palette-popup-default.qml55
-rw-r--r--tests/auto/palette/palette.pro16
-rw-r--r--tests/auto/palette/qtquickcontrols2.conf5
-rw-r--r--tests/auto/palette/tst_palette.cpp407
-rw-r--r--tests/auto/qquickapplicationwindow/data/layout.qml3
-rw-r--r--tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp68
-rw-r--r--tests/auto/qquickcolor/data/tst_color.qml65
-rw-r--r--tests/auto/qquickcolor/qquickcolor.pro12
-rw-r--r--tests/auto/qquickcolor/tst_qquickcolor.cpp38
-rw-r--r--tests/auto/qquickdrawer/BLACKLIST14
-rw-r--r--tests/auto/qquickiconimage/data/alignment.qml16
-rw-r--r--tests/auto/qquickiconimage/data/color.qml18
-rw-r--r--tests/auto/qquickiconimage/data/fileSelectors.qml16
-rw-r--r--tests/auto/qquickiconimage/data/nameBindingNoSizes.qml7
-rw-r--r--tests/auto/qquickiconimage/data/nameBindingSourceSize.qml16
-rw-r--r--tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml10
-rw-r--r--tests/auto/qquickiconimage/data/root.qml6
-rw-r--r--tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml15
-rw-r--r--tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml16
-rw-r--r--tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml10
-rw-r--r--tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml8
-rw-r--r--tests/auto/qquickiconimage/data/svgNoSizes.qml15
-rw-r--r--tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml17
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.pngbin0 -> 897 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new.pngbin0 -> 1146 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new@2x.pngbin0 -> 256 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.pngbin0 -> 1411 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new@2x.pngbin0 -> 4075 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original.pngbin0 -> 1105 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original@2x.pngbin0 -> 173 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted.pngbin0 -> 1111 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted@2x.pngbin0 -> 172 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/+testselector/appointment-new.pngbin0 -> 256 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/appointment-new.pngbin0 -> 4075 bytes
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/appointment-new.svg425
-rw-r--r--tests/auto/qquickiconimage/icons/testtheme/index.theme21
-rw-r--r--tests/auto/qquickiconimage/qquickiconimage.pro17
-rw-r--r--tests/auto/qquickiconimage/resources.qrc17
-rw-r--r--tests/auto/qquickiconimage/tst_qquickiconimage.cpp493
-rw-r--r--tests/auto/qquickiconlabel/data/colorChanges.qml66
-rw-r--r--tests/auto/qquickiconlabel/data/iconlabel.qml66
-rw-r--r--tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml66
-rw-r--r--tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml63
-rw-r--r--tests/auto/qquickiconlabel/qquickiconlabel.pro13
-rw-r--r--tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp326
-rw-r--r--tests/auto/qquickimaginestyle/control-assets/button-background.9.pngbin0 -> 251 bytes
-rw-r--r--tests/auto/qquickimaginestyle/data/tst_imagine.qml97
-rw-r--r--tests/auto/qquickimaginestyle/qquickimaginestyle.pro16
-rw-r--r--tests/auto/qquickimaginestyle/qtquickcontrols2.conf2
-rw-r--r--tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp38
-rw-r--r--tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf4
-rw-r--r--tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp10
-rw-r--r--tests/auto/qquickmenu/data/actions.qml67
-rw-r--r--tests/auto/qquickmenu/data/mnemonics.qml87
-rw-r--r--tests/auto/qquickmenu/data/popup.qml124
-rw-r--r--tests/auto/qquickmenu/data/removeTakeItem.qml91
-rw-r--r--tests/auto/qquickmenu/data/subMenus.qml92
-rw-r--r--tests/auto/qquickmenu/tst_qquickmenu.cpp832
-rw-r--r--tests/auto/qquickmenubar/data/empty.qml54
-rw-r--r--tests/auto/qquickmenubar/data/menubar.qml106
-rw-r--r--tests/auto/qquickmenubar/qquickmenubar.pro14
-rw-r--r--tests/auto/qquickmenubar/tst_qquickmenubar.cpp569
-rw-r--r--tests/auto/qquickninepatchimage/data/foo.9.pngbin0 -> 213 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/foo@2x.9.pngbin0 -> 295 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/foo@3x.9.pngbin0 -> 377 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/foo@4x.9.pngbin0 -> 482 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-all.9.pngbin0 -> 245 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-all@2x.9.pngbin0 -> 341 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-all@3x.9.pngbin0 -> 470 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-all@4x.9.pngbin0 -> 577 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-bottomright.9.pngbin0 -> 246 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.pngbin0 -> 348 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.pngbin0 -> 460 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.pngbin0 -> 565 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-topleft.9.pngbin0 -> 227 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.pngbin0 -> 305 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.pngbin0 -> 420 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.pngbin0 -> 516 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/ninepatchimage.qml7
-rw-r--r--tests/auto/qquickninepatchimage/data/padding.9.pngbin0 -> 226 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/padding@2x.9.pngbin0 -> 298 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/padding@3x.9.pngbin0 -> 381 bytes
-rw-r--r--tests/auto/qquickninepatchimage/data/padding@4x.9.pngbin0 -> 485 bytes
-rw-r--r--tests/auto/qquickninepatchimage/qquickninepatchimage.pro14
-rw-r--r--tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp245
-rw-r--r--tests/auto/qquickpopup/BLACKLIST10
-rw-r--r--tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml2
-rw-r--r--tests/auto/qquickpopup/tst_qquickpopup.cpp64
-rw-r--r--tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml2
-rw-r--r--tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml2
-rw-r--r--tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml2
-rw-r--r--tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml2
-rw-r--r--tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp20
-rw-r--r--tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf4
-rw-r--r--tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp10
-rw-r--r--tests/auto/sanity/tst_sanity.cpp1
-rw-r--r--tests/auto/shared/qtest_quickcontrols.h86
-rw-r--r--tests/auto/shared/util.pri5
-rw-r--r--tests/auto/shared/visualtestutil.cpp23
-rw-r--r--tests/auto/shared/visualtestutil.h4
173 files changed, 8410 insertions, 205 deletions
diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp
index 4208a366..7e491b54 100644
--- a/tests/auto/accessibility/tst_accessibility.cpp
+++ b/tests/auto/accessibility/tst_accessibility.cpp
@@ -43,6 +43,9 @@
#include "../shared/util.h"
#if QT_CONFIG(accessibility)
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/qpa/qplatformaccessibility.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
#endif
@@ -114,12 +117,10 @@ void tst_accessibility::a11y_data()
}
#if QT_CONFIG(accessibility)
-static QQuickAccessibleAttached *accessibleAttached(QQuickItem *item)
+static QPlatformAccessibility *platformAccessibility()
{
- QQuickAccessibleAttached *acc = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false));
- if (!acc)
- acc = item->findChild<QQuickAccessibleAttached *>();
- return acc;
+ QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration();
+ return pfIntegration ? pfIntegration->accessibility() : nullptr;
}
#endif
@@ -152,7 +153,7 @@ void tst_accessibility::a11y()
QVERIFY(item);
#if QT_CONFIG(accessibility)
- QQuickAccessibleAttached *acc = accessibleAttached(item);
+ QQuickAccessibleAttached *acc = QQuickAccessibleAttached::attachedProperties(item);
if (name != QLatin1Literal("dayofweekrow")
&& name != QLatin1Literal("monthgrid")
&& name != QLatin1Literal("weeknumbercolumn")) {
@@ -160,8 +161,11 @@ void tst_accessibility::a11y()
QVERIFY(acc);
} else {
QVERIFY(!acc);
- QAccessible::setActive(true);
- acc = accessibleAttached(item);
+ QPlatformAccessibility *accessibility = platformAccessibility();
+ if (!accessibility)
+ QSKIP("No QPlatformAccessibility available.");
+ accessibility->setActive(true);
+ acc = QQuickAccessibleAttached::attachedProperties(item);
}
}
QVERIFY(acc);
@@ -170,8 +174,6 @@ void tst_accessibility::a11y()
#else
Q_UNUSED(role)
Q_UNUSED(text)
- QObject *acc = qmlAttachedPropertiesObject<QObject>(item, false);
- QVERIFY(!acc);
#endif
}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 0aeef414..7dfd552e 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -6,13 +6,20 @@ SUBDIRS += \
cursor \
focus \
font \
+ palette \
platform \
pressandhold \
qquickapplicationwindow \
+ qquickcolor \
qquickdrawer \
+ qquickiconimage \
+ qquickiconlabel \
+ qquickimaginestyle \
qquickmaterialstyle \
qquickmaterialstyleconf \
qquickmenu \
+ qquickmenubar \
+ qquickninepatchimage \
qquickpopup \
qquickstyle \
qquickstyleselector \
@@ -21,9 +28,3 @@ SUBDIRS += \
revisions \
sanity \
snippets
-
-# QTBUG-60268
-boot2qt: SUBDIRS -= qquickapplicationwindow calendar controls cursor \
- qquickdrawer focus font qquickmenu platform qquickpopup qquickmaterialstyle \
- qquickmaterialstyleconf qquickuniversalstyle \
- qquickuniversalstyleconf snippets
diff --git a/tests/auto/controls/controls.pro b/tests/auto/controls/controls.pro
index 8f2f8e69..fd852c4b 100644
--- a/tests/auto/controls/controls.pro
+++ b/tests/auto/controls/controls.pro
@@ -1,5 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += \
default \
+ fusion \
+ imagine \
material \
universal
diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml
index bddb952f..7579d410 100644
--- a/tests/auto/controls/data/tst_abstractbutton.qml
+++ b/tests/auto/controls/data/tst_abstractbutton.qml
@@ -50,7 +50,7 @@
import QtQuick 2.2
import QtTest 1.0
-import QtQuick.Controls 2.2
+import QtQuick.Controls 2.3
TestCase {
id: testCase
@@ -71,6 +71,11 @@ TestCase {
}
Component {
+ id: action
+ Action { }
+ }
+
+ Component {
id: signalSpy
SignalSpy { }
}
@@ -162,4 +167,190 @@ TestCase {
keyRelease(data.key)
compare(container.lastKeyRelease, data.result)
}
+
+ function test_icon() {
+ var control = createTemporaryObject(button, testCase)
+ verify(control)
+ compare(control.icon.name, "")
+ compare(control.icon.source, "")
+ compare(control.icon.width, 0)
+ compare(control.icon.height, 0)
+ compare(control.icon.color, "#00000000")
+
+ var iconSpy = signalSpy.createObject(control, { target: control, signalName: "iconChanged"} )
+ verify(iconSpy.valid)
+
+ control.icon.name = "test-name"
+ compare(control.icon.name, "test-name")
+ compare(iconSpy.count, 1)
+
+ control.icon.source = "qrc:/test-source"
+ compare(control.icon.source, "qrc:/test-source")
+ compare(iconSpy.count, 2)
+
+ control.icon.width = 32
+ compare(control.icon.width, 32)
+ compare(iconSpy.count, 3)
+
+ control.icon.height = 32
+ compare(control.icon.height, 32)
+ compare(iconSpy.count, 4)
+
+ control.icon.color = "#ff0000"
+ compare(control.icon.color, "#ff0000")
+ compare(iconSpy.count, 5)
+ }
+
+ Component {
+ id: actionButton
+ AbstractButton {
+ action: Action {
+ text: "Default"
+ icon.name: "default"
+ icon.source: "qrc:/icons/default.png"
+ checkable: true
+ checked: true
+ enabled: false
+ }
+ }
+ }
+
+ function test_action() {
+ var control = createTemporaryObject(actionButton, testCase)
+ verify(control)
+
+ // initial values
+ compare(control.text, "Default")
+ compare(control.icon.name, "default")
+ compare(control.icon.source, "qrc:/icons/default.png")
+ compare(control.checkable, true)
+ compare(control.checked, true)
+ compare(control.enabled, false)
+
+ // changes via action
+ control.action.text = "Action"
+ control.action.icon.name = "action"
+ control.action.icon.source = "qrc:/icons/action.png"
+ control.action.checkable = false
+ control.action.checked = false
+ control.action.enabled = true
+ compare(control.text, "Action") // propagates
+ compare(control.icon.name, "action") // propagates
+ compare(control.icon.source, "qrc:/icons/action.png") // propagates
+ compare(control.checkable, false) // propagates
+ compare(control.checked, false) // propagates
+ compare(control.enabled, true) // propagates
+
+ // changes via button
+ control.text = "Button"
+ control.icon.name = "button"
+ control.icon.source = "qrc:/icons/button.png"
+ control.checkable = true
+ control.checked = true
+ control.enabled = false
+ compare(control.text, "Button")
+ compare(control.icon.name, "button")
+ compare(control.icon.source, "qrc:/icons/button.png")
+ compare(control.checkable, true)
+ compare(control.checked, true)
+ compare(control.enabled, false)
+ compare(control.action.text, "Action") // does NOT propagate
+ compare(control.action.icon.name, "action") // does NOT propagate
+ compare(control.action.icon.source, "qrc:/icons/action.png") // does NOT propagate
+ compare(control.action.checkable, true) // propagates
+ compare(control.action.checked, true) // propagates
+ compare(control.action.enabled, true) // does NOT propagate
+ }
+
+ function test_trigger_data() {
+ return [
+ {tag: "click", click: true, button: true, action: true, clicked: true, triggered: true},
+ {tag: "click disabled button", click: true, button: false, action: true, clicked: false, triggered: false},
+ {tag: "click disabled action", click: true, button: true, action: false, clicked: true, triggered: false},
+ {tag: "trigger", trigger: true, button: true, action: true, clicked: true, triggered: true},
+ {tag: "trigger disabled button", trigger: true, button: false, action: true, clicked: false, triggered: true},
+ {tag: "trigger disabled action", trigger: true, button: true, action: false, clicked: false, triggered: false}
+ ]
+ }
+
+ function test_trigger(data) {
+ var control = createTemporaryObject(actionButton, testCase, {"enabled": data.button, "action.enabled": data.action})
+ verify(control)
+
+ compare(control.enabled, data.button)
+ compare(control.action.enabled, data.action)
+
+ var buttonSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"})
+ verify(buttonSpy.valid)
+
+ var actionSpy = signalSpy.createObject(control, {target: control.action, signalName: "triggered"})
+ verify(actionSpy.valid)
+
+ if (data.click)
+ mouseClick(control)
+ else if (data.trigger)
+ control.action.trigger()
+
+ compare(buttonSpy.count, data.clicked ? 1 : 0)
+ compare(actionSpy.count, data.triggered ? 1 : 0)
+ }
+
+ function test_mnemonic() {
+ if (Qt.platform.os === "osx" || Qt.platform.os === "macos")
+ skip("Mnemonics are not used on macOS")
+
+ var control = createTemporaryObject(button, testCase)
+ verify(control)
+
+ control.text = "&Hello"
+ compare(control.text, "Hello") // ### TODO: visualize mnemonics
+
+ var clickSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"})
+ verify(clickSpy.valid)
+
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 1)
+
+ control.visible = false
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 1)
+
+ control.visible = true
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 2)
+
+ control.text = "Te&st"
+ compare(control.text, "Test") // ### TODO: visualize mnemonics
+
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 2)
+
+ keyClick(Qt.Key_S, Qt.AltModifier)
+ compare(clickSpy.count, 3)
+
+ control.visible = false
+ control.text = "&Hidden"
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 3)
+
+ control.visible = true
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ compare(clickSpy.count, 4)
+
+ control.action = action.createObject(control, {text: "&Action"})
+
+ var actionSpy = signalSpy.createObject(control, {target: control.action, signalName: "triggered"})
+ verify(actionSpy.valid)
+
+ keyClick(Qt.Key_A, Qt.AltModifier)
+ compare(actionSpy.count, 1)
+ compare(clickSpy.count, 5)
+
+ // ungrab on destruction (don't crash)
+ control.Component.onDestruction.connect(function() { control = null })
+ control.destroy()
+ wait(0)
+ verify(!control)
+ keyClick(Qt.Key_H, Qt.AltModifier)
+ }
}
diff --git a/tests/auto/controls/data/tst_action.qml b/tests/auto/controls/data/tst_action.qml
new file mode 100644
index 00000000..7d057c26
--- /dev/null
+++ b/tests/auto/controls/data/tst_action.qml
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.2
+import QtTest 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Templates 2.3 as T
+
+TestCase {
+ id: testCase
+ width: 400
+ height: 400
+ visible: true
+ when: windowShown
+ name: "Action"
+
+ Component {
+ id: component
+ Action { }
+ }
+
+ Component {
+ id: signalSpy
+ SignalSpy { }
+ }
+
+ function test_enabled() {
+ var action = createTemporaryObject(component, testCase)
+ verify(action)
+
+ var spy = createTemporaryObject(signalSpy, testCase, {target: action, signalName: "triggered"})
+ verify(spy.valid)
+
+ action.trigger()
+ compare(spy.count, 1)
+
+ action.enabled = false
+ action.trigger()
+ compare(spy.count, 1)
+
+ action.enabled = undefined // reset
+ action.trigger()
+ compare(spy.count, 2)
+ }
+
+ Component {
+ id: buttonAndMenu
+ Item {
+ property alias button: button
+ property alias menu: menu
+ property alias menuItem: menuItem
+ property alias action: sharedAction
+ property var lastSource
+ Action {
+ id: sharedAction
+ text: "Shared"
+ shortcut: "Ctrl+B"
+ onTriggered: lastSource = source
+ }
+ Button {
+ id: button
+ action: sharedAction
+ Menu {
+ id: menu
+ MenuItem {
+ id: menuItem
+ action: sharedAction
+ }
+ }
+ }
+ }
+ }
+
+ function test_shared() {
+ var container = createTemporaryObject(buttonAndMenu, testCase)
+ verify(container)
+
+ keyClick(Qt.Key_B, Qt.ControlModifier)
+ compare(container.lastSource, container.button)
+
+ container.menu.open()
+ keyClick(Qt.Key_B, Qt.ControlModifier)
+ compare(container.lastSource, container.menuItem)
+
+ tryVerify(function() { return !container.menu.visible })
+ keyClick(Qt.Key_B, Qt.ControlModifier)
+ compare(container.lastSource, container.button)
+
+ container.button.visible = false
+ keyClick(Qt.Key_B, Qt.ControlModifier)
+ compare(container.lastSource, container.action)
+ }
+}
diff --git a/tests/auto/controls/data/tst_actiongroup.qml b/tests/auto/controls/data/tst_actiongroup.qml
new file mode 100644
index 00000000..6b31336d
--- /dev/null
+++ b/tests/auto/controls/data/tst_actiongroup.qml
@@ -0,0 +1,381 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.2
+import QtTest 1.0
+import QtQuick.Controls 2.3
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "ActionGroup"
+
+ Component {
+ id: actionGroup
+ ActionGroup { }
+ }
+
+ Component {
+ id: nonExclusiveGroup
+ ActionGroup { exclusive: false }
+ }
+
+ Component {
+ id: signalSpy
+ SignalSpy { }
+ }
+
+ function test_null() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+
+ group.addAction(null)
+ group.removeAction(null)
+ }
+
+ Component {
+ id: action
+ Action { }
+ }
+
+ function test_defaults() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+ compare(group.actions.length, 0)
+ compare(group.checkedAction, null)
+ compare(group.exclusive, true)
+ }
+
+ function test_current() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+
+ var checkedActionSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "checkedActionChanged"})
+ verify(checkedActionSpy.valid)
+ verify(!group.checkedAction)
+
+ var action1 = createTemporaryObject(action, testCase, {checked: true})
+ var action2 = createTemporaryObject(action, testCase, {checked: false})
+ var action3 = createTemporaryObject(action, testCase, {checked: true, objectName: "3"})
+
+ // add checked
+ group.addAction(action1)
+ compare(group.checkedAction, action1)
+ compare(action1.checked, true)
+ compare(action2.checked, false)
+ compare(action3.checked, true)
+ compare(checkedActionSpy.count, 1)
+
+ // add non-checked
+ group.addAction(action2)
+ compare(group.checkedAction, action1)
+ compare(action1.checked, true)
+ compare(action2.checked, false)
+ compare(action3.checked, true)
+ compare(checkedActionSpy.count, 1)
+
+ // add checked
+ group.addAction(action3)
+ compare(group.checkedAction, action3)
+ compare(action1.checked, false)
+ compare(action2.checked, false)
+ compare(action3.checked, true)
+ compare(checkedActionSpy.count, 2)
+
+ // change current
+ group.checkedAction = action2
+ compare(group.checkedAction, action2)
+ compare(action1.checked, false)
+ compare(action2.checked, true)
+ compare(action3.checked, false)
+ compare(checkedActionSpy.count, 3)
+
+ // check
+ action1.checked = true
+ compare(group.checkedAction, action1)
+ compare(action1.checked, true)
+ compare(action2.checked, false)
+ compare(action3.checked, false)
+ compare(checkedActionSpy.count, 4)
+
+ // remove non-checked
+ group.removeAction(action2)
+ compare(group.checkedAction, action1)
+ compare(action1.checked, true)
+ compare(action2.checked, false)
+ compare(action3.checked, false)
+ compare(checkedActionSpy.count, 4)
+
+ // remove checked
+ group.removeAction(action1)
+ verify(!group.checkedAction)
+ compare(action1.checked, false)
+ compare(action2.checked, false)
+ compare(action3.checked, false)
+ compare(checkedActionSpy.count, 5)
+ }
+
+ function test_actions() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+
+ var actionsSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "actionsChanged"})
+ verify(actionsSpy.valid)
+
+ compare(group.actions.length, 0)
+ compare(group.checkedAction, null)
+
+ var action1 = createTemporaryObject(action, testCase, {checked: true})
+ var action2 = createTemporaryObject(action, testCase, {checked: false})
+
+ group.actions = [action1, action2]
+ compare(group.actions.length, 2)
+ compare(group.actions[0], action1)
+ compare(group.actions[1], action2)
+ compare(group.checkedAction, action1)
+ compare(actionsSpy.count, 2)
+
+ var action3 = createTemporaryObject(action, testCase, {checked: true})
+
+ group.addAction(action3)
+ compare(group.actions.length, 3)
+ compare(group.actions[0], action1)
+ compare(group.actions[1], action2)
+ compare(group.actions[2], action3)
+ compare(group.checkedAction, action3)
+ compare(actionsSpy.count, 3)
+
+ group.removeAction(action1)
+ compare(group.actions.length, 2)
+ compare(group.actions[0], action2)
+ compare(group.actions[1], action3)
+ compare(group.checkedAction, action3)
+ compare(actionsSpy.count, 4)
+
+ group.actions = []
+ compare(group.actions.length, 0)
+ tryCompare(group, "checkedAction", null)
+ compare(actionsSpy.count, 5)
+ }
+
+ function test_triggered_data() {
+ return [
+ {tag: "exclusive", exclusive: true},
+ {tag: "non-exclusive", exclusive: false}
+ ]
+ }
+
+ function test_triggered(data) {
+ var group = createTemporaryObject(actionGroup, testCase, {exclusive: data.exclusive})
+ verify(group)
+
+ var triggeredSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "triggered"})
+ verify(triggeredSpy.valid)
+
+ var action1 = createTemporaryObject(action, testCase)
+ var action2 = createTemporaryObject(action, testCase)
+
+ group.addAction(action1)
+ group.addAction(action2)
+
+ action1.triggered()
+ compare(triggeredSpy.count, 1)
+ compare(triggeredSpy.signalArguments[0][0], action1)
+
+ action2.triggered()
+ compare(triggeredSpy.count, 2)
+ compare(triggeredSpy.signalArguments[1][0], action2)
+ }
+
+ Component {
+ id: attachedGroup
+ Item {
+ property ActionGroup group: ActionGroup { id: group }
+ property Action action1: Action { ActionGroup.group: group }
+ property Action action2: Action { ActionGroup.group: group }
+ property Action action3: Action { ActionGroup.group: group }
+ }
+ }
+
+ function test_attached() {
+ var container = createTemporaryObject(attachedGroup, testCase)
+ verify(container)
+
+ verify(!container.group.checkedAction)
+
+ container.action1.checked = true
+ compare(container.group.checkedAction, container.action1)
+ compare(container.action1.checked, true)
+ compare(container.action2.checked, false)
+ compare(container.action3.checked, false)
+
+ container.action2.checked = true
+ compare(container.group.checkedAction, container.action2)
+ compare(container.action1.checked, false)
+ compare(container.action2.checked, true)
+ compare(container.action3.checked, false)
+
+ container.action3.checked = true
+ compare(container.group.checkedAction, container.action3)
+ compare(container.action1.checked, false)
+ compare(container.action2.checked, false)
+ compare(container.action3.checked, true)
+ }
+
+ function test_actionDestroyed() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+
+ var actionsSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "actionsChanged"})
+ verify(actionsSpy.valid)
+
+ var action1 = createTemporaryObject(action, testCase, {objectName: "action1", checked: true})
+
+ group.addAction(action1)
+ compare(group.actions.length, 1)
+ compare(group.actions[0], action1)
+ compare(group.checkedAction, action1)
+ compare(actionsSpy.count, 1)
+
+ action1.destroy()
+ wait(0)
+ compare(group.actions.length, 0)
+ compare(group.checkedAction, null)
+ compare(actionsSpy.count, 2)
+ }
+
+ function test_nonExclusive() {
+ var group = createTemporaryObject(nonExclusiveGroup, testCase)
+ verify(group)
+
+ var action1 = createTemporaryObject(action, testCase, {checked: true})
+ group.addAction(action1)
+ compare(action1.checked, true)
+ compare(group.checkedAction, null)
+
+ var action2 = createTemporaryObject(action, testCase, {checked: true})
+ group.addAction(action2)
+ compare(action1.checked, true)
+ compare(action2.checked, true)
+ compare(group.checkedAction, null)
+
+ action1.checked = false
+ compare(action1.checked, false)
+ compare(action2.checked, true)
+ compare(group.checkedAction, null)
+
+ action2.checked = false
+ compare(action1.checked, false)
+ compare(action2.checked, false)
+ compare(group.checkedAction, null)
+
+ action1.checked = true
+ compare(action1.checked, true)
+ compare(action2.checked, false)
+ compare(group.checkedAction, null)
+
+ action2.checked = true
+ compare(action1.checked, true)
+ compare(action2.checked, true)
+ compare(group.checkedAction, null)
+ }
+
+ function test_enabled() {
+ var group = createTemporaryObject(actionGroup, testCase)
+ verify(group)
+
+ compare(group.enabled, true)
+
+ var action1 = createTemporaryObject(action, testCase)
+ var action2 = createTemporaryObject(action, testCase)
+ compare(action1.enabled, true)
+ compare(action2.enabled, true)
+
+ var action1Spy = createTemporaryObject(signalSpy, testCase, {target: action1, signalName: "enabledChanged"})
+ var action2Spy = createTemporaryObject(signalSpy, testCase, {target: action2, signalName: "enabledChanged"})
+ verify(action1Spy.valid && action2Spy.valid)
+
+ group.addAction(action1)
+ compare(action1.enabled, true)
+ compare(action2.enabled, true)
+ compare(action1Spy.count, 0)
+ compare(action2Spy.count, 0)
+
+ group.enabled = false
+ compare(action1.enabled, false)
+ compare(action2.enabled, true)
+ compare(action1Spy.count, 1)
+ compare(action1Spy.signalArguments[0][0], false)
+ compare(action2Spy.count, 0)
+
+ group.addAction(action2)
+ compare(action1.enabled, false)
+ compare(action2.enabled, false)
+ compare(action1Spy.count, 1)
+ compare(action2Spy.count, 1)
+ compare(action2Spy.signalArguments[0][0], false)
+
+ action1.enabled = false
+ compare(action1.enabled, false)
+ compare(action1Spy.count, 2)
+ compare(action1Spy.signalArguments[1][0], false)
+ compare(action2Spy.count, 1)
+
+ group.enabled = true
+ compare(action1.enabled, false)
+ compare(action2.enabled, true)
+ compare(action1Spy.count, 2)
+ compare(action2Spy.count, 2)
+ compare(action2Spy.signalArguments[1][0], true)
+ }
+}
diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml
index cf9cf64d..2cf399f4 100644
--- a/tests/auto/controls/data/tst_button.qml
+++ b/tests/auto/controls/data/tst_button.qml
@@ -50,7 +50,7 @@
import QtQuick 2.2
import QtTest 1.0
-import QtQuick.Controls 2.2
+import QtQuick.Controls 2.3
TestCase {
id: testCase
@@ -430,4 +430,83 @@ TestCase {
control.highlighted = true
verify(control.highlighted)
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(button, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem
+ // should be equal to the implicitWidth of the Text while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // That means that spacing shouldn't affect it.
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // The implicitWidth of the Button itself should, therefore, also never include spacing while no icon is set.
+ compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: Button.IconOnly },
+ { "tag": "TextOnly", display: Button.TextOnly },
+ { "tag": "TextUnderIcon", display: Button.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: Button.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: Button.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: Button.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: Button.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: Button.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(button, testCase, {
+ text: "Button",
+ display: data.display,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case Button.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case Button.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case Button.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case Button.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_buttongroup.qml b/tests/auto/controls/data/tst_buttongroup.qml
index bde655da..cbbaec5a 100644
--- a/tests/auto/controls/data/tst_buttongroup.qml
+++ b/tests/auto/controls/data/tst_buttongroup.qml
@@ -50,7 +50,7 @@
import QtQuick 2.2
import QtTest 1.0
-import QtQuick.Controls 2.2
+import QtQuick.Controls 2.3
TestCase {
id: testCase
@@ -66,6 +66,11 @@ TestCase {
}
Component {
+ id: nonExclusiveGroup
+ ButtonGroup { exclusive: false }
+ }
+
+ Component {
id: signalSpy
SignalSpy { }
}
@@ -88,6 +93,14 @@ TestCase {
QtObject { }
}
+ function test_defaults() {
+ var group = createTemporaryObject(buttonGroup, testCase)
+ verify(group)
+ compare(group.buttons.length, 0)
+ compare(group.checkedButton, null)
+ compare(group.exclusive, true)
+ }
+
function test_current() {
var group = createTemporaryObject(buttonGroup, testCase)
verify(group)
@@ -200,8 +213,15 @@ TestCase {
compare(buttonsSpy.count, 5)
}
- function test_clicked() {
- var group = createTemporaryObject(buttonGroup, testCase)
+ function test_clicked_data() {
+ return [
+ {tag: "exclusive", exclusive: true},
+ {tag: "non-exclusive", exclusive: false}
+ ]
+ }
+
+ function test_clicked(data) {
+ var group = createTemporaryObject(buttonGroup, testCase, {exclusive: data.exclusive})
verify(group)
var clickedSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "clicked"})
@@ -346,4 +366,40 @@ TestCase {
verify(container.group.checkedButton)
compare(container.group.checkedButton.objectName, "0")
}
+
+ function test_nonExclusive() {
+ var group = createTemporaryObject(nonExclusiveGroup, testCase)
+ verify(group)
+
+ var button1 = createTemporaryObject(button, testCase, {checked: true})
+ group.addButton(button1)
+ compare(button1.checked, true)
+ compare(group.checkedButton, null)
+
+ var button2 = createTemporaryObject(button, testCase, {checked: true})
+ group.addButton(button2)
+ compare(button1.checked, true)
+ compare(button2.checked, true)
+ compare(group.checkedButton, null)
+
+ button1.checked = false
+ compare(button1.checked, false)
+ compare(button2.checked, true)
+ compare(group.checkedButton, null)
+
+ button2.checked = false
+ compare(button1.checked, false)
+ compare(button2.checked, false)
+ compare(group.checkedButton, null)
+
+ button1.checked = true
+ compare(button1.checked, true)
+ compare(button2.checked, false)
+ compare(group.checkedButton, null)
+
+ button2.checked = true
+ compare(button1.checked, true)
+ compare(button2.checked, true)
+ compare(group.checkedButton, null)
+ }
}
diff --git a/tests/auto/controls/data/tst_checkdelegate.qml b/tests/auto/controls/data/tst_checkdelegate.qml
index 8933a7dd..9f92b4dc 100644
--- a/tests/auto/controls/data/tst_checkdelegate.qml
+++ b/tests/auto/controls/data/tst_checkdelegate.qml
@@ -89,4 +89,85 @@ TestCase {
verify(control);
compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset);
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(checkDelegate, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem should be
+ // equal to the implicitWidth of the Text and the check indicator + spacing while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: CheckDelegate.IconOnly },
+ { "tag": "TextOnly", display: CheckDelegate.TextOnly },
+ { "tag": "TextUnderIcon", display: CheckDelegate.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: CheckDelegate.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: CheckDelegate.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: CheckDelegate.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: CheckDelegate.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: CheckDelegate.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(checkDelegate, testCase, {
+ text: "CheckDelegate",
+ display: data.display,
+ width: 400,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ var availableWidth = control.availableWidth - control.indicator.width - control.spacing
+ var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0
+
+ switch (control.display) {
+ case CheckDelegate.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case CheckDelegate.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case CheckDelegate.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case CheckDelegate.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml
index f231ebf8..bc110de6 100644
--- a/tests/auto/controls/data/tst_combobox.qml
+++ b/tests/auto/controls/data/tst_combobox.qml
@@ -705,9 +705,6 @@ TestCase {
var activatedSpy = signalSpy.createObject(control, {target: control, signalName: "activated"})
verify(activatedSpy.valid)
- var highlightedSpy = signalSpy.createObject(control, {target: control, signalName: "highlighted"})
- verify(highlightedSpy.valid)
-
mouseClick(control)
compare(control.popup.visible, true)
@@ -717,25 +714,19 @@ TestCase {
// press - move - release outside - not activated - not closed
mousePress(content)
compare(activatedSpy.count, 0)
- compare(highlightedSpy.count, 0)
mouseMove(content, content.width * 2)
compare(activatedSpy.count, 0)
- compare(highlightedSpy.count, 0)
mouseRelease(content, content.width * 2)
compare(activatedSpy.count, 0)
- compare(highlightedSpy.count, 0)
compare(control.popup.visible, true)
// press - move - release inside - activated - closed
mousePress(content)
compare(activatedSpy.count, 0)
- compare(highlightedSpy.count, 0)
mouseMove(content, content.width / 2 + 1, content.height / 2 + 1)
compare(activatedSpy.count, 0)
- compare(highlightedSpy.count, 0)
mouseRelease(content)
compare(activatedSpy.count, 1)
- compare(highlightedSpy.count, 1)
tryCompare(control.popup, "visible", false)
}
@@ -1176,6 +1167,58 @@ TestCase {
closedSpy.target = null
}
+ function test_mouseHighlight() {
+ if ((Qt.platform.pluginName === "offscreen")
+ || (Qt.platform.pluginName === "minimal"))
+ skip("Mouse highlight not functional on offscreen/minimal platforms")
+ var control = createTemporaryObject(comboBox, testCase, {model: 20})
+ verify(control)
+
+ compare(control.highlightedIndex, -1)
+
+ var openedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "opened"})
+ verify(openedSpy.valid)
+
+ control.popup.open()
+ compare(control.highlightedIndex, 0)
+ tryCompare(openedSpy, "count", 1)
+
+ var listview = control.popup.contentItem
+ verify(listview)
+ waitForRendering(listview)
+
+ // hover-highlight through all visible list items one by one
+ var hoverIndex = -1
+ var prevHoverItem = null
+ for (var y = 0; y < listview.height; ++y) {
+ var hoverItem = listview.itemAt(0, listview.contentY + y)
+ if (!hoverItem || !hoverItem.visible || hoverItem === prevHoverItem)
+ continue
+ mouseMove(hoverItem, 0, 0)
+ tryCompare(control, "highlightedIndex", ++hoverIndex)
+ prevHoverItem = hoverItem
+ }
+
+ mouseMove(listview, listview.width / 2, listview.height / 2)
+
+ // wheel-highlight the rest of the items
+ var delta = 120
+ var prevWheelItem = null
+ while (!listview.atYEnd) {
+ var prevContentY = listview.contentY
+ mouseWheel(listview, listview.width / 2, listview.height / 2, -delta, -delta)
+ tryCompare(listview, "moving", false)
+ verify(listview.contentY > prevContentY)
+
+ var wheelItem = listview.itemAt(listview.width / 2, listview.contentY + listview.height / 2)
+ if (!wheelItem || !wheelItem.visible || wheelItem === prevWheelItem)
+ continue
+
+ tryCompare(control, "highlightedIndex", parseInt(wheelItem.text))
+ prevWheelItem = wheelItem
+ }
+ }
+
RegExpValidator {
id: regExpValidator
regExp: /(red|blue|green)?/
@@ -1417,7 +1460,6 @@ TestCase {
keyPress(Qt.Key_B)
verify(control.activeFocus)
- expectFail("", "An editable ComboBox does not yet support the Keys attached property.")
verify(control.gotit)
compare(control.editText, "a")
@@ -1466,7 +1508,7 @@ TestCase {
var control = createTemporaryObject(comboBox, testCase, { model: 1 })
verify(control)
compare(control.popup.implicitHeight, 0)
- compare(control.popup.height, 0)
+ compare(control.popup.height, control.popup.topPadding + control.popup.bottomPadding)
// Ensure that it's open so that the popup's implicitHeight changes when we increase the model count.
control.popup.open()
@@ -1482,6 +1524,6 @@ TestCase {
control.model = 0
control.popup.open()
tryCompare(control.popup, "visible", true)
- compare(control.popup.height, 0)
+ compare(control.popup.height, control.popup.topPadding + control.popup.bottomPadding)
}
}
diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml
index b8de2b08..94f22ad2 100644
--- a/tests/auto/controls/data/tst_container.qml
+++ b/tests/auto/controls/data/tst_container.qml
@@ -153,4 +153,46 @@ TestCase {
compare(control.itemAt(2).objectName, "2")
compare(control.itemAt(3).objectName, "3")
}
+
+ function test_removeTakeItem() {
+ var control = createTemporaryObject(container, testCase)
+ verify(control)
+
+ var item1 = rectangle.createObject(control)
+ var item2 = rectangle.createObject(control)
+ var item3 = rectangle.createObject(control)
+
+ item1.Component.onDestruction.connect(function() { item1 = null })
+ item2.Component.onDestruction.connect(function() { item2 = null })
+ item3.Component.onDestruction.connect(function() { item3 = null })
+
+ control.addItem(item1)
+ control.addItem(item2)
+ control.addItem(item3)
+ compare(control.count, 3)
+
+ // takeItem(int) does not destroy
+ compare(control.takeItem(1), item2)
+ compare(control.count, 2)
+ wait(1)
+ verify(item2)
+
+ // removeItem(Item) destroys
+ control.removeItem(item1)
+ compare(control.count, 1)
+ wait(1)
+ verify(!item1)
+
+ // removeItem(null) must not call removeItem(0)
+ control.removeItem(null)
+ compare(control.count, 1)
+ wait(1)
+ verify(item3)
+
+ // deprecated removeItem(int) does not destroy
+ control.removeItem(0)
+ compare(control.count, 0)
+ wait(1)
+ verify(item3)
+ }
}
diff --git a/tests/auto/controls/data/tst_dialog.qml b/tests/auto/controls/data/tst_dialog.qml
index 2f3d2a6b..e2557a04 100644
--- a/tests/auto/controls/data/tst_dialog.qml
+++ b/tests/auto/controls/data/tst_dialog.qml
@@ -99,11 +99,14 @@ TestCase {
verify(acceptedSpy.valid)
control.accept()
compare(acceptedSpy.count, 1)
+ compare(control.result, Dialog.Accepted)
tryCompare(control, "visible", false)
}
function test_reject() {
+ skip("QTBUG-62549, QTBUG-62628")
+
var control = createTemporaryObject(dialog, testCase)
var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
@@ -118,6 +121,7 @@ TestCase {
verify(rejectedSpy.valid)
control.reject()
compare(rejectedSpy.count, 1)
+ compare(control.result, Dialog.Rejected)
tryCompare(control, "visible", false)
@@ -356,4 +360,42 @@ TestCase {
- (data.header ? control.header.height + control.spacing : 0)
- (data.footer ? control.footer.height + control.spacing : 0))
}
+
+ function test_signals_data() {
+ return [
+ { tag: "Ok", standardButton: Dialog.Ok, signalName: "accepted" },
+ { tag: "Open", standardButton: Dialog.Open, signalName: "accepted" },
+ { tag: "Save", standardButton: Dialog.Save, signalName: "accepted" },
+ { tag: "Cancel", standardButton: Dialog.Cancel, signalName: "rejected" },
+ { tag: "Close", standardButton: Dialog.Close, signalName: "rejected" },
+ { tag: "Discard", standardButton: Dialog.Discard, signalName: "discarded" },
+ { tag: "Apply", standardButton: Dialog.Apply, signalName: "applied" },
+ { tag: "Reset", standardButton: Dialog.Reset, signalName: "reset" },
+ { tag: "RestoreDefaults", standardButton: Dialog.RestoreDefaults, signalName: "reset" },
+ { tag: "Help", standardButton: Dialog.Help, signalName: "helpRequested" },
+ { tag: "SaveAll", standardButton: Dialog.SaveAll, signalName: "accepted" },
+ { tag: "Yes", standardButton: Dialog.Yes, signalName: "accepted" },
+ { tag: "YesToAll", standardButton: Dialog.YesToAll, signalName: "accepted" },
+ { tag: "No", standardButton: Dialog.No, signalName: "rejected" },
+ { tag: "NoToAll", standardButton: Dialog.NoToAll, signalName: "rejected" },
+ { tag: "Abort", standardButton: Dialog.Abort, signalName: "rejected" },
+ { tag: "Retry", standardButton: Dialog.Retry, signalName: "accepted" },
+ { tag: "Ignore", standardButton: Dialog.Ignore, signalName: "accepted" }
+ ]
+ }
+
+ function test_signals(data) {
+ var control = createTemporaryObject(dialog, testCase)
+ verify(control)
+
+ control.standardButtons = data.standardButton
+ var button = control.standardButton(data.standardButton)
+ verify(button)
+
+ var buttonSpy = signalSpy.createObject(control.contentItem, {target: control, signalName: data.signalName})
+ verify(buttonSpy.valid)
+
+ button.clicked()
+ compare(buttonSpy.count, 1)
+ }
}
diff --git a/tests/auto/controls/data/tst_dialogbuttonbox.qml b/tests/auto/controls/data/tst_dialogbuttonbox.qml
index 9b3d969f..044c9593 100644
--- a/tests/auto/controls/data/tst_dialogbuttonbox.qml
+++ b/tests/auto/controls/data/tst_dialogbuttonbox.qml
@@ -159,10 +159,10 @@ TestCase {
{ tag: "Save", standardButton: DialogButtonBox.Save, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" },
{ tag: "Cancel", standardButton: DialogButtonBox.Cancel, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" },
{ tag: "Close", standardButton: DialogButtonBox.Close, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" },
- { tag: "Discard", standardButton: DialogButtonBox.Discard, buttonRole: DialogButtonBox.DestructiveRole },
- { tag: "Apply", standardButton: DialogButtonBox.Apply, buttonRole: DialogButtonBox.ApplyRole },
- { tag: "Reset", standardButton: DialogButtonBox.Reset, buttonRole: DialogButtonBox.ResetRole },
- { tag: "RestoreDefaults", standardButton: DialogButtonBox.RestoreDefaults, buttonRole: DialogButtonBox.ResetRole },
+ { tag: "Discard", standardButton: DialogButtonBox.Discard, buttonRole: DialogButtonBox.DestructiveRole, signalName: "discarded" },
+ { tag: "Apply", standardButton: DialogButtonBox.Apply, buttonRole: DialogButtonBox.ApplyRole, signalName: "applied" },
+ { tag: "Reset", standardButton: DialogButtonBox.Reset, buttonRole: DialogButtonBox.ResetRole, signalName: "reset" },
+ { tag: "RestoreDefaults", standardButton: DialogButtonBox.RestoreDefaults, buttonRole: DialogButtonBox.ResetRole, signalName: "reset" },
{ tag: "Help", standardButton: DialogButtonBox.Help, buttonRole: DialogButtonBox.HelpRole, signalName: "helpRequested" },
{ tag: "SaveAll", standardButton: DialogButtonBox.SaveAll, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" },
{ tag: "Yes", standardButton: DialogButtonBox.Yes, buttonRole: DialogButtonBox.YesRole, signalName: "accepted" },
@@ -188,11 +188,11 @@ TestCase {
var clickedSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"})
verify(clickedSpy.valid)
var roleSpy = signalSpy.createObject(control, {target: control, signalName: data.signalName})
- compare(roleSpy.valid, !!data.signalName)
+ verify(roleSpy.valid)
button.clicked()
compare(clickedSpy.count, 1)
compare(clickedSpy.signalArguments[0][0], button)
- compare(roleSpy.count, !!data.signalName ? 1 : 0)
+ compare(roleSpy.count, 1)
}
}
diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml
index a33a4bf0..5446b969 100644
--- a/tests/auto/controls/data/tst_drawer.qml
+++ b/tests/auto/controls/data/tst_drawer.qml
@@ -50,7 +50,7 @@
import QtQuick 2.2
import QtTest 1.0
-import QtQuick.Controls 2.2
+import QtQuick.Controls 2.3
TestCase {
id: testCase
@@ -70,7 +70,7 @@ TestCase {
compare(control.edge, Qt.LeftEdge)
compare(control.position, 0.0)
compare(control.dragMargin, Qt.styleHints.startDragDistance)
- compare(control.parent, ApplicationWindow.overlay)
+ compare(control.parent, Overlay.overlay)
}
function test_invalidEdge() {
diff --git a/tests/auto/controls/data/tst_itemdelegate.qml b/tests/auto/controls/data/tst_itemdelegate.qml
index 6f4bb6cb..4e4ca0c4 100644
--- a/tests/auto/controls/data/tst_itemdelegate.qml
+++ b/tests/auto/controls/data/tst_itemdelegate.qml
@@ -79,4 +79,84 @@ TestCase {
control.highlighted = true
verify(control.highlighted)
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(itemDelegate, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem
+ // should be equal to the implicitWidth of the Text while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // That means that spacing shouldn't affect it.
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // The implicitWidth of the ItemDelegate itself should, therefore, also never include spacing while no icon is set.
+ compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: ItemDelegate.IconOnly },
+ { "tag": "TextOnly", display: ItemDelegate.TextOnly },
+ { "tag": "TextUnderIcon", display: ItemDelegate.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: ItemDelegate.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: ItemDelegate.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: ItemDelegate.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: ItemDelegate.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: ItemDelegate.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(itemDelegate, testCase, {
+ text: "ItemDelegate",
+ display: data.display,
+ width: 400,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case ItemDelegate.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case ItemDelegate.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case ItemDelegate.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case ItemDelegate.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_menuitem.qml b/tests/auto/controls/data/tst_menuitem.qml
index 068e2a5c..57286002 100644
--- a/tests/auto/controls/data/tst_menuitem.qml
+++ b/tests/auto/controls/data/tst_menuitem.qml
@@ -65,6 +65,11 @@ TestCase {
MenuItem { }
}
+ Component {
+ id: menu
+ Menu { }
+ }
+
function test_baseline() {
var control = createTemporaryObject(menuItem, testCase)
verify(control)
@@ -96,4 +101,93 @@ TestCase {
control.highlighted = true
verify(control.highlighted)
}
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: MenuItem.IconOnly },
+ { "tag": "TextOnly", display: MenuItem.TextOnly },
+ { "tag": "TextUnderIcon", display: MenuItem.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: MenuItem.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: MenuItem.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: MenuItem.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: MenuItem.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: MenuItem.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(menuItem, testCase, {
+ text: "MenuItem",
+ display: data.display,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var padding = data.mirrored ? control.contentItem.rightPadding : control.contentItem.leftPadding
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case MenuItem.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, control.mirrored ? control.availableWidth - iconImage.width - padding : padding)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case MenuItem.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width - padding : padding)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case MenuItem.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, control.mirrored ? control.availableWidth - iconImage.width - (textLabel.width - iconImage.width) / 2 - padding : (textLabel.width - iconImage.width) / 2 + padding)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width - padding : padding)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case MenuItem.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
+
+ function test_menu() {
+ var control = createTemporaryObject(menu, testCase)
+ verify(control)
+
+ var item1 = createTemporaryObject(menuItem, testCase)
+ verify(item1)
+ compare(item1.menu, null)
+
+ var item2 = createTemporaryObject(menuItem, testCase)
+ verify(item2)
+ compare(item2.menu, null)
+
+ control.addItem(item1)
+ compare(item1.menu, control)
+ compare(item2.menu, null)
+
+ control.insertItem(1, item2)
+ compare(item1.menu, control)
+ compare(item2.menu, control)
+
+ control.removeItem(1)
+ compare(item1.menu, control)
+ compare(item2.menu, null)
+
+ control.removeItem(0)
+ compare(item1.menu, null)
+ compare(item2.menu, null)
+ }
}
diff --git a/tests/auto/controls/data/tst_page.qml b/tests/auto/controls/data/tst_page.qml
index 2eb11165..4fb2d089 100644
--- a/tests/auto/controls/data/tst_page.qml
+++ b/tests/auto/controls/data/tst_page.qml
@@ -150,8 +150,10 @@ TestCase {
compare(control.contentWidth, 0)
compare(control.contentHeight, 0)
- compare(control.implicitWidth, control.leftPadding + control.rightPadding)
- compare(control.implicitHeight, control.topPadding + control.bottomPadding)
+ compare(control.implicitWidth, Math.max(control.leftPadding + control.rightPadding,
+ control.background ? control.background.implicitWidth : 0))
+ compare(control.implicitHeight, Math.max(control.topPadding + control.bottomPadding,
+ control.background ? control.background.implicitHeight : 0))
}
function test_contentItem() {
diff --git a/tests/auto/controls/data/tst_pageindicator.qml b/tests/auto/controls/data/tst_pageindicator.qml
index 70813cb8..f3151882 100644
--- a/tests/auto/controls/data/tst_pageindicator.qml
+++ b/tests/auto/controls/data/tst_pageindicator.qml
@@ -96,7 +96,7 @@ TestCase {
}
function test_interactive(data) {
- var control = createTemporaryObject(pageIndicator, testCase, {count: 5, spacing: 10, padding: 10})
+ var control = createTemporaryObject(pageIndicator, testCase, {count: 5, spacing: 10, topPadding: 10, leftPadding: 10, rightPadding: 10, bottomPadding: 10})
verify(control)
verify(!control.interactive)
diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml
index bec50ad0..88ec295f 100644
--- a/tests/auto/controls/data/tst_popup.qml
+++ b/tests/auto/controls/data/tst_popup.qml
@@ -50,8 +50,8 @@
import QtQuick 2.4
import QtTest 1.0
-import QtQuick.Controls 2.2
-import QtQuick.Templates 2.2 as T
+import QtQuick.Controls 2.3
+import QtQuick.Templates 2.3 as T
TestCase {
id: testCase
@@ -361,7 +361,7 @@ TestCase {
}
function test_margins() {
- var control = createTemporaryObject(popupControl, testCase, {width: 100, height: 100})
+ var control = createTemporaryObject(popupTemplate, testCase, {width: 100, height: 100})
verify(control)
control.open()
@@ -944,6 +944,10 @@ TestCase {
compare(openedSpy.count, 1)
verify(control.visible)
+ // remove the background so that it won't affect the implicit size of the popup,
+ // so the implicit sizes tested below are entirely based on the content size
+ control.background = null
+
// implicit size of the content
control.contentItem.implicitWidth = 10
compare(control.implicitWidth, 10 + control.leftPadding + control.rightPadding)
@@ -1069,6 +1073,7 @@ TestCase {
tryCompare(window, "active", true)
compare(window.overlay.children.length, 0)
+ compare(window.overlay, window.Overlay.overlay)
var firstOverlay = findOverlay(window, window.firstDrawer)
verify(!firstOverlay)
@@ -1178,16 +1183,6 @@ TestCase {
compare(child.ApplicationWindow.window, null)
}
- SignalSpy {
- id: openedSpy
- signalName: "opened"
- }
-
- SignalSpy {
- id: closedSpy
- signalName: "closed"
- }
-
Component {
id: pausePopup
Popup {
@@ -1200,19 +1195,32 @@ TestCase {
var control = createTemporaryObject(pausePopup, testCase)
verify(control)
- openedSpy.target = control
- closedSpy.target = control
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+ var closedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "closed"})
+ verify(closedSpy.valid)
+ var openedChangeSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "openedChanged"})
+ verify(openedChangeSpy.valid)
control.open()
compare(control.visible, true)
+ compare(control.opened, false)
+ compare(openedChangeSpy.count, 0)
compare(openedSpy.count, 0)
tryCompare(openedSpy, "count", 1)
+ compare(control.opened, true)
+ compare(openedChangeSpy.count, 1)
compare(closedSpy.count, 0)
control.close()
+ compare(control.visible, true)
+ compare(control.opened, false)
+ compare(openedChangeSpy.count, 2)
compare(openedSpy.count, 1)
compare(closedSpy.count, 0)
tryCompare(closedSpy, "count", 1)
+ compare(control.opened, false)
+ compare(openedChangeSpy.count, 2)
compare(control.visible, false)
}
diff --git a/tests/auto/controls/data/tst_radiodelegate.qml b/tests/auto/controls/data/tst_radiodelegate.qml
index 8fb6f933..b1ee00db 100644
--- a/tests/auto/controls/data/tst_radiodelegate.qml
+++ b/tests/auto/controls/data/tst_radiodelegate.qml
@@ -89,4 +89,85 @@ TestCase {
verify(control);
compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset);
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(radioDelegate, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem should be
+ // equal to the implicitWidth of the Text and the radio indicator + spacing while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: RadioDelegate.IconOnly },
+ { "tag": "TextOnly", display: RadioDelegate.TextOnly },
+ { "tag": "TextUnderIcon", display: RadioDelegate.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: RadioDelegate.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: RadioDelegate.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: RadioDelegate.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: RadioDelegate.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: RadioDelegate.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(radioDelegate, testCase, {
+ text: "RadioDelegate",
+ display: data.display,
+ width: 400,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ var availableWidth = control.availableWidth - control.indicator.width - control.spacing
+ var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0
+
+ switch (control.display) {
+ case RadioDelegate.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case RadioDelegate.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case RadioDelegate.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case RadioDelegate.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml
index 791f357f..39b0c4b0 100644
--- a/tests/auto/controls/data/tst_rangeslider.qml
+++ b/tests/auto/controls/data/tst_rangeslider.qml
@@ -96,6 +96,8 @@ TestCase {
compare(control.stepSize, 0)
compare(control.snapMode, RangeSlider.NoSnap)
compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
}
function test_values() {
@@ -262,9 +264,14 @@ TestCase {
verify(control)
compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
verify(control.width > control.height)
+
control.orientation = Qt.Vertical
compare(control.orientation, Qt.Vertical)
+ compare(control.horizontal, false)
+ compare(control.vertical, true)
verify(control.width < control.height)
}
diff --git a/tests/auto/controls/data/tst_roundbutton.qml b/tests/auto/controls/data/tst_roundbutton.qml
index 7a533348..c772c85f 100644
--- a/tests/auto/controls/data/tst_roundbutton.qml
+++ b/tests/auto/controls/data/tst_roundbutton.qml
@@ -84,4 +84,83 @@ TestCase {
control.width = 10;
compare(control.radius, 5);
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(roundButton, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem
+ // should be equal to the implicitWidth of the Text while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // That means that spacing shouldn't affect it.
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // The implicitWidth of the Button itself should, therefore, also never include spacing while no icon is set.
+ compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: RoundButton.IconOnly },
+ { "tag": "TextOnly", display: RoundButton.TextOnly },
+ { "tag": "TextUnderIcon", display: RoundButton.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: RoundButton.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: RoundButton.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: RoundButton.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: RoundButton.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: RoundButton.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(roundButton, testCase, {
+ text: "RoundButton",
+ display: data.display,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case RoundButton.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case RoundButton.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case RoundButton.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case RoundButton.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml
index 3e153ebb..bc424a27 100644
--- a/tests/auto/controls/data/tst_scrollbar.qml
+++ b/tests/auto/controls/data/tst_scrollbar.qml
@@ -737,6 +737,20 @@ TestCase {
container.destroy()
}
+ function test_orientation() {
+ var control = createTemporaryObject(scrollBar, testCase)
+ verify(control)
+
+ compare(control.orientation, Qt.Vertical)
+ compare(control.horizontal, false)
+ compare(control.vertical, true)
+
+ control.orientation = Qt.Horizontal
+ compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
+ }
+
function test_flashing() {
var control = createTemporaryObject(scrollBar, testCase, {size: 0.2})
verify(control)
diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml
index 894a035d..a6275f91 100644
--- a/tests/auto/controls/data/tst_scrollindicator.qml
+++ b/tests/auto/controls/data/tst_scrollindicator.qml
@@ -223,6 +223,20 @@ TestCase {
compare(horizontal.contentItem.width, 0.2 * horizontal.availableWidth)
}
+ function test_orientation() {
+ var control = createTemporaryObject(scrollIndicator, testCase)
+ verify(control)
+
+ compare(control.orientation, Qt.Vertical)
+ compare(control.horizontal, false)
+ compare(control.vertical, true)
+
+ control.orientation = Qt.Horizontal
+ compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
+ }
+
// QTBUG-61785
function test_mouseArea() {
var ma = createTemporaryObject(mouseArea, testCase, {width: testCase.width, height: testCase.height})
diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml
index 8d696297..b70aeaab 100644
--- a/tests/auto/controls/data/tst_slider.qml
+++ b/tests/auto/controls/data/tst_slider.qml
@@ -77,6 +77,8 @@ TestCase {
compare(control.stepSize, 0)
compare(control.snapMode, Slider.NoSnap)
compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
}
function test_value() {
@@ -201,9 +203,14 @@ TestCase {
verify(control)
compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
verify(control.width > control.height)
+
control.orientation = Qt.Vertical
compare(control.orientation, Qt.Vertical)
+ compare(control.horizontal, false)
+ compare(control.vertical, true)
verify(control.width < control.height)
}
diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml
index 71f0735c..003468a1 100644
--- a/tests/auto/controls/data/tst_spinbox.qml
+++ b/tests/auto/controls/data/tst_spinbox.qml
@@ -116,15 +116,23 @@ TestCase {
compare(control.up.indicator.enabled, false)
compare(control.down.indicator.enabled, true)
+ control.wrap = true
+ compare(control.up.indicator.enabled, true)
+ compare(control.down.indicator.enabled, true)
+
control.value = -1
compare(control.value, 0)
compare(control.up.indicator.enabled, true)
- compare(control.down.indicator.enabled, false)
+ compare(control.down.indicator.enabled, true)
control.from = 25
compare(control.from, 25)
compare(control.value, 25)
compare(control.up.indicator.enabled, true)
+ compare(control.down.indicator.enabled, true)
+
+ control.wrap = false
+ compare(control.up.indicator.enabled, true)
compare(control.down.indicator.enabled, false)
control.value = 30
@@ -229,8 +237,19 @@ TestCase {
compare(valueModifiedSpy.count, data.modified)
}
- function test_keys() {
- var control = createTemporaryObject(spinBox, 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] }
+ ]
+ }
+
+ function test_keys(data) {
+ var control = createTemporaryObject(spinBox, testCase, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize})
verify(control)
var upPressedCount = 0
@@ -249,48 +268,31 @@ TestCase {
control.forceActiveFocus()
verify(control.activeFocus)
- control.value = 50
- compare(control.value, 50)
-
- for (var d1 = 1; d1 <= 10; ++d1) {
- keyPress(Qt.Key_Down)
- compare(control.down.pressed, true)
- compare(control.up.pressed, false)
- compare(downPressedSpy.count, ++downPressedCount)
- compare(valueModifiedSpy.count, ++valueModifiedCount)
-
- compare(control.value, 50 - d1)
-
- keyRelease(Qt.Key_Down)
- compare(control.down.pressed, false)
- compare(control.up.pressed, false)
- compare(downPressedSpy.count, ++downPressedCount)
- compare(valueModifiedSpy.count, valueModifiedCount)
- }
- compare(control.value, 40)
-
- for (var i1 = 1; i1 <= 10; ++i1) {
+ for (var u = 0; u < data.upSteps.length; ++u) {
+ var wasUpEnabled = control.wrap || control.value < control.to
keyPress(Qt.Key_Up)
- compare(control.up.pressed, true)
+ compare(control.up.pressed, wasUpEnabled)
compare(control.down.pressed, false)
- compare(upPressedSpy.count, ++upPressedCount)
- compare(valueModifiedSpy.count, ++valueModifiedCount)
+ if (wasUpEnabled) {
+ ++upPressedCount
+ ++valueModifiedCount
+ }
+ compare(upPressedSpy.count, upPressedCount)
+ compare(valueModifiedSpy.count, valueModifiedCount)
- compare(control.value, 40 + i1)
+ compare(control.value, data.upSteps[u])
keyRelease(Qt.Key_Up)
compare(control.down.pressed, false)
compare(control.up.pressed, false)
- compare(upPressedSpy.count, ++upPressedCount)
+ if (wasUpEnabled)
+ ++upPressedCount
+ compare(upPressedSpy.count, upPressedCount)
compare(valueModifiedSpy.count, valueModifiedCount)
}
- compare(control.value, 50)
-
- control.stepSize = 25
- compare(control.stepSize, 25)
- for (var d2 = 1; d2 <= 10; ++d2) {
- var wasDownEnabled = control.value > control.from
+ for (var d = 0; d < data.downSteps.length; ++d) {
+ var wasDownEnabled = control.wrap || control.value > control.from
keyPress(Qt.Key_Down)
compare(control.down.pressed, wasDownEnabled)
compare(control.up.pressed, false)
@@ -301,7 +303,7 @@ TestCase {
compare(downPressedSpy.count, downPressedCount)
compare(valueModifiedSpy.count, valueModifiedCount)
- compare(control.value, Math.max(0, 50 - d2 * 25))
+ compare(control.value, data.downSteps[d])
keyRelease(Qt.Key_Down)
compare(control.down.pressed, false)
@@ -311,31 +313,6 @@ TestCase {
compare(downPressedSpy.count, downPressedCount)
compare(valueModifiedSpy.count, valueModifiedCount)
}
- compare(control.value, 0)
-
- for (var i2 = 1; i2 <= 10; ++i2) {
- var wasUpEnabled = control.value < control.to
- keyPress(Qt.Key_Up)
- compare(control.up.pressed, wasUpEnabled)
- compare(control.down.pressed, false)
- if (wasUpEnabled) {
- ++upPressedCount
- ++valueModifiedCount
- }
- compare(upPressedSpy.count, upPressedCount)
- compare(valueModifiedSpy.count, valueModifiedCount)
-
- compare(control.value, Math.min(99, i2 * 25))
-
- keyRelease(Qt.Key_Up)
- compare(control.down.pressed, false)
- compare(control.up.pressed, false)
- if (wasUpEnabled)
- ++upPressedCount
- compare(upPressedSpy.count, upPressedCount)
- compare(valueModifiedSpy.count, valueModifiedCount)
- }
- compare(control.value, 99)
}
function test_locale() {
@@ -407,46 +384,46 @@ TestCase {
compare(control.value, 5)
}
+ 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] }
+ ]
+ }
+
function test_wheel(data) {
- var control = createTemporaryObject(spinBox, testCase, {wheelEnabled: true})
+ var control = createTemporaryObject(spinBox, testCase, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize, wheelEnabled: true})
verify(control)
+ var valueModifiedCount = 0
var valueModifiedSpy = signalSpy.createObject(control, {target: control, signalName: "valueModified"})
verify(valueModifiedSpy.valid)
var delta = 120
- compare(control.value, 0)
-
- mouseWheel(control, control.width / 2, control.height / 2, delta, delta)
- compare(control.value, 1)
- compare(valueModifiedSpy.count, 1)
-
- control.stepSize = 2
-
- mouseWheel(control, control.width / 2, control.height / 2, delta, delta)
- compare(control.value, 3)
- compare(valueModifiedSpy.count, 2)
-
- control.stepSize = 10
-
- mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta)
- compare(control.value, 0)
- compare(valueModifiedSpy.count, 3)
-
- control.stepSize = 5
+ for (var u = 0; u < data.upSteps.length; ++u) {
+ var wasUpEnabled = control.wrap || control.value < control.to
+ mouseWheel(control, control.width / 2, control.height / 2, delta, delta)
+ if (wasUpEnabled)
+ ++valueModifiedCount
+ compare(valueModifiedSpy.count, valueModifiedCount)
- mouseWheel(control, control.width / 2, control.height / 2, delta, delta)
- compare(control.value, 5)
- compare(valueModifiedSpy.count, 4)
+ compare(control.value, data.upSteps[u])
+ }
- mouseWheel(control, control.width / 2, control.height / 2, 0.5 * delta, 0.5 * delta)
- compare(control.value, 8)
- compare(valueModifiedSpy.count, 5)
+ for (var d = 0; d < data.downSteps.length; ++d) {
+ var wasDownEnabled = control.wrap || control.value > control.from
+ mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta)
+ if (wasDownEnabled)
+ ++valueModifiedCount
+ compare(valueModifiedSpy.count, valueModifiedCount)
- mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta)
- compare(control.value, 3)
- compare(valueModifiedSpy.count, 6)
+ compare(control.value, data.downSteps[d])
+ }
}
function test_initiallyDisabledIndicators_data() {
diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml
index 1b421b4f..f4b7fc4a 100644
--- a/tests/auto/controls/data/tst_stackview.qml
+++ b/tests/auto/controls/data/tst_stackview.qml
@@ -221,33 +221,75 @@ TestCase {
function test_depth() {
var control = createTemporaryObject(stackView, testCase)
verify(control)
+
+ var depthChanges = 0
+ var emptyChanges = 0
var depthSpy = signalSpy.createObject(control, {target: control, signalName: "depthChanged"})
+ var emptySpy = signalSpy.createObject(control, {target: control, signalName: "emptyChanged"})
verify(depthSpy.valid)
+ verify(emptySpy.valid)
compare(control.depth, 0)
+ compare(control.empty, true)
+
control.push(item, StackView.Immediate)
compare(control.depth, 1)
- compare(depthSpy.count, 1)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, ++emptyChanges)
+
control.clear()
compare(control.depth, 0)
- compare(depthSpy.count, 2)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, true)
+ compare(emptySpy.count, ++emptyChanges)
+
control.push(component, StackView.Immediate)
compare(control.depth, 1)
- compare(depthSpy.count, 3)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, ++emptyChanges)
+
control.push(component, StackView.Immediate)
compare(control.depth, 2)
- compare(depthSpy.count, 4)
- control.pop(StackView.Immediate)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, emptyChanges)
+
+ control.replace(component, StackView.Immediate)
+ compare(control.depth, 2)
+ compare(depthSpy.count, depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, emptyChanges)
+
+ control.replace([component, component], StackView.Immediate)
+ compare(control.depth, 3)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, emptyChanges)
+
+ control.pop(null, StackView.Immediate)
compare(control.depth, 1)
- compare(depthSpy.count, 5)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, emptyChanges)
+
control.pop(StackView.Immediate) // ignored
compare(control.depth, 1)
- compare(depthSpy.count, 5)
+ compare(depthSpy.count, depthChanges)
+ compare(control.empty, false)
+ compare(emptySpy.count, emptyChanges)
+
control.clear()
compare(control.depth, 0)
- compare(depthSpy.count, 6)
+ compare(depthSpy.count, ++depthChanges)
+ compare(control.empty, true)
+ compare(emptySpy.count, ++emptyChanges)
+
control.clear()
compare(control.depth, 0)
- compare(depthSpy.count, 6)
+ compare(depthSpy.count, depthChanges)
+ compare(control.empty, true)
+ compare(emptySpy.count, emptyChanges)
}
function test_size() {
@@ -510,6 +552,24 @@ TestCase {
compare(control.currentItem, item8)
}
+ function test_clear() {
+ var control = createTemporaryObject(stackView, testCase)
+ verify(control)
+
+ control.push(component, StackView.Immediate)
+
+ control.clear()
+ compare(control.depth, 0)
+ compare(control.busy, false)
+
+ control.push(component, StackView.Immediate)
+
+ control.clear(StackView.PopTransition)
+ compare(control.depth, 0)
+ compare(control.busy, true)
+ tryCompare(control, "busy", false)
+ }
+
function test_visibility_data() {
return [
{tag:"default transitions", properties: {}},
diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml
index c24f6962..d603bd7f 100644
--- a/tests/auto/controls/data/tst_swipedelegate.qml
+++ b/tests/auto/controls/data/tst_swipedelegate.qml
@@ -1569,4 +1569,84 @@ TestCase {
verify(control.behavior.enabled);
verify(control.animation.running);
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(swipeDelegateComponent, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem
+ // should be equal to the implicitWidth of the Text while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // That means that spacing shouldn't affect it.
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // The implicitWidth of the SwipeDelegate itself should, therefore, also never include spacing while no icon is set.
+ compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: SwipeDelegate.IconOnly },
+ { "tag": "TextOnly", display: SwipeDelegate.TextOnly },
+ { "tag": "TextUnderIcon", display: SwipeDelegate.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: SwipeDelegate.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: SwipeDelegate.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: SwipeDelegate.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: SwipeDelegate.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: SwipeDelegate.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(swipeDelegateComponent, testCase, {
+ text: "SwipeDelegate",
+ display: data.display,
+ width: 400,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case SwipeDelegate.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case SwipeDelegate.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case SwipeDelegate.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case SwipeDelegate.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_swipeview.qml b/tests/auto/controls/data/tst_swipeview.qml
index ff772b74..39311877 100644
--- a/tests/auto/controls/data/tst_swipeview.qml
+++ b/tests/auto/controls/data/tst_swipeview.qml
@@ -539,6 +539,8 @@ TestCase {
control.addItem(page.createObject(control, {text: i}))
compare(control.orientation, Qt.Horizontal)
+ compare(control.horizontal, true)
+ compare(control.vertical, false)
for (i = 0; i < control.count; ++i) {
control.currentIndex = i
@@ -547,6 +549,8 @@ TestCase {
control.orientation = Qt.Vertical
compare(control.orientation, Qt.Vertical)
+ compare(control.horizontal, false)
+ compare(control.vertical, true)
for (i = 0; i < control.count; ++i) {
control.currentIndex = i
diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml
index 59e29726..079bf820 100644
--- a/tests/auto/controls/data/tst_switch.qml
+++ b/tests/auto/controls/data/tst_switch.qml
@@ -201,12 +201,12 @@ TestCase {
mousePress(control, 0, 0, Qt.LeftButton)
compare(control.pressed, true)
verify(spy.success)
- mouseMove(control, control.width / 4, control.height / 4, 0, Qt.LeftButton)
+ mouseMove(control, control.width / 2, control.height / 2, 0, Qt.LeftButton)
compare(control.pressed, true)
spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }],
"released",
"clicked"]
- mouseRelease(control, control.width / 4, control.height / 4, Qt.LeftButton)
+ mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton)
compare(control.checked, false)
compare(control.pressed, false)
tryCompare(control, "position", 0) // QTBUG-57944
@@ -304,12 +304,12 @@ TestCase {
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
- touch.move(0, control, control.width / 4, control.height / 4).commit()
+ touch.move(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }],
"released",
"clicked"]
- touch.release(0, control, control.width / 4, control.height / 4).commit()
+ touch.release(0, control, control.width / 2, control.height / 2).commit()
compare(control.checked, false)
compare(control.pressed, false)
tryCompare(control, "position", 0) // QTBUG-57944
diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml
index f0c3e68b..8f240409 100644
--- a/tests/auto/controls/data/tst_switchdelegate.qml
+++ b/tests/auto/controls/data/tst_switchdelegate.qml
@@ -523,4 +523,85 @@ TestCase {
compare(control.pressed, false)
verify(spy.success)
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(switchDelegate, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem should be
+ // equal to the implicitWidth of the Text and the switch indicator + spacing while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing)
+
+ compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: SwitchDelegate.IconOnly },
+ { "tag": "TextOnly", display: SwitchDelegate.TextOnly },
+ { "tag": "TextUnderIcon", display: SwitchDelegate.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: SwitchDelegate.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: SwitchDelegate.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: SwitchDelegate.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: SwitchDelegate.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: SwitchDelegate.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(switchDelegate, testCase, {
+ text: "SwitchDelegate",
+ display: data.display,
+ width: 400,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ var availableWidth = control.availableWidth - control.indicator.width - control.spacing
+ var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0
+
+ switch (control.display) {
+ case SwitchDelegate.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case SwitchDelegate.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case SwitchDelegate.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case SwitchDelegate.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml
index 5bcd476b..adb27f78 100644
--- a/tests/auto/controls/data/tst_tabbar.qml
+++ b/tests/auto/controls/data/tst_tabbar.qml
@@ -506,47 +506,190 @@ TestCase {
function test_layout(data) {
var control = createTemporaryObject(tabBar, testCase, {spacing: data.spacing, width: 200})
- // remove the implicit size from the background so that it won't affect
- // the implicit size of the tabbar, so the implicit sizes tested below
- // are entirely based on the content size
- control.background.implicitWidth = 0
+ // remove the background so that it won't affect the implicit size of the tabbar,
+ // so the implicit sizes tested below are entirely based on the content size
+ control.background = null
var tab1 = tabButton.createObject(control, {text: "First"})
control.addItem(tab1)
tryCompare(tab1, "width", control.width)
+ compare(tab1.height, control.height)
compare(control.contentWidth, tab1.implicitWidth)
+ compare(control.contentHeight, tab1.implicitHeight)
compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding)
+ compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding)
- var tab2 = tabButton.createObject(control, {text: "Second"})
+ var tab2 = tabButton.createObject(control, {implicitHeight: tab1.implicitHeight + 10, text: "Second"})
control.addItem(tab2)
tryCompare(tab1, "width", (control.width - data.spacing) / 2)
+ compare(tab1.height, control.height)
compare(tab2.width, (control.width - data.spacing) / 2)
+ compare(tab2.height, control.height)
compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + data.spacing)
+ compare(control.contentHeight, tab2.implicitHeight)
compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding)
+ compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding)
- var tab3 = tabButton.createObject(control, {width: 50, text: "Third"})
+ var tab3 = tabButton.createObject(control, {width: 50, height: tab1.implicitHeight - 10, text: "Third"})
control.addItem(tab3)
tryCompare(tab1, "width", (control.width - 2 * data.spacing - 50) / 2)
+ compare(tab1.y, 0)
+ compare(tab1.height, control.height)
+ compare(tab2.y, 0)
compare(tab2.width, (control.width - 2 * data.spacing - 50) / 2)
+ compare(tab2.height, control.height)
+ verify(tab3.y > 0)
+ compare(tab3.y, (control.height - tab3.height) / 2)
compare(tab3.width, 50)
+ compare(tab3.height, tab1.implicitHeight - 10)
compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + tab3.width + 2 * data.spacing)
+ compare(control.contentHeight, tab2.implicitHeight)
compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding)
+ compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding)
var expectedWidth = tab3.contentItem.implicitWidth + tab3.leftPadding + tab3.rightPadding
tab3.width = tab3.implicitWidth
+ tab3.height = tab3.implicitHeight
tryCompare(tab1, "width", (control.width - 2 * data.spacing - expectedWidth) / 2)
- tryCompare(tab2, "width", (control.width - 2 * data.spacing - expectedWidth) / 2)
+ compare(tab1.height, control.height)
+ compare(tab2.width, (control.width - 2 * data.spacing - expectedWidth) / 2)
+ compare(tab2.height, control.height)
compare(tab3.width, expectedWidth)
+ compare(tab3.height, tab3.implicitHeight)
compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + tab3.implicitWidth + 2 * data.spacing)
+ compare(control.contentHeight, tab2.implicitHeight)
compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding)
+ compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding)
tab3.width = undefined
+ tab3.height = undefined
control.width = undefined
control.contentWidth = 300
+ control.contentHeight = 50
expectedWidth = (control.contentWidth - 2 * data.spacing) / 3
tryCompare(tab1, "width", expectedWidth)
- tryCompare(tab2, "width", expectedWidth)
- tryCompare(tab3, "width", expectedWidth)
+ compare(tab2.width, expectedWidth)
+ compare(tab3.width, expectedWidth)
+ compare(tab1.height, control.contentHeight)
+ compare(tab2.height, control.contentHeight)
+ compare(tab3.height, control.contentHeight)
+ }
+
+ Component {
+ id: attachedButton
+ TabButton {
+ property int index: TabBar.index
+ property TabBar tabBar: TabBar.tabBar
+ property int position: TabBar.position
+ }
+ }
+
+ function test_attached() {
+ var control = createTemporaryObject(tabBar, testCase, {position: TabBar.Footer})
+
+ // append
+ var tab1 = createTemporaryObject(attachedButton, testCase)
+ compare(tab1.index, -1)
+ compare(tab1.tabBar, null)
+ compare(tab1.position, TabBar.Header)
+
+ control.addItem(tab1)
+ compare(tab1.index, 0)
+ compare(tab1.tabBar, control)
+ compare(tab1.position, TabBar.Footer)
+
+ // insert in the beginning
+ var tab2 = createTemporaryObject(attachedButton, testCase)
+ compare(tab2.index, -1)
+ compare(tab2.tabBar, null)
+ compare(tab2.position, TabBar.Header)
+
+ control.insertItem(0, tab2)
+ compare(tab2.index, 0)
+ compare(tab2.tabBar, control)
+ compare(tab2.position, TabBar.Footer)
+
+ compare(tab1.index, 1)
+
+ // insert in the middle
+ var tab3 = createTemporaryObject(attachedButton, testCase)
+ compare(tab3.index, -1)
+ compare(tab3.tabBar, null)
+ compare(tab3.position, TabBar.Header)
+
+ control.insertItem(1, tab3)
+ compare(tab3.index, 1)
+ compare(tab3.tabBar, control)
+ compare(tab3.position, TabBar.Footer)
+
+ compare(tab2.index, 0)
+ compare(tab1.index, 2)
+
+ // insert in the end
+ var tab4 = createTemporaryObject(attachedButton, testCase)
+ compare(tab4.index, -1)
+ compare(tab4.tabBar, null)
+ compare(tab4.position, TabBar.Header)
+
+ control.insertItem(-1, tab4)
+ compare(tab4.index, 3)
+ compare(tab4.tabBar, control)
+ compare(tab4.position, TabBar.Footer)
+
+ compare(tab2.index, 0)
+ compare(tab3.index, 1)
+ compare(tab1.index, 2)
+
+ // move forwards
+ control.moveItem(0, 1)
+ compare(tab3.index, 0)
+ compare(tab2.index, 1)
+ compare(tab1.index, 2)
+ compare(tab4.index, 3)
+
+ control.moveItem(0, 2)
+ compare(tab2.index, 0)
+ compare(tab1.index, 1)
+ compare(tab3.index, 2)
+ compare(tab4.index, 3)
+
+ control.moveItem(1, 3)
+ compare(tab2.index, 0)
+ compare(tab3.index, 1)
+ compare(tab4.index, 2)
+ compare(tab1.index, 3)
+
+ // move backwards
+ control.moveItem(3, 2)
+ compare(tab2.index, 0)
+ compare(tab3.index, 1)
+ compare(tab1.index, 2)
+ compare(tab4.index, 3)
+
+ control.moveItem(3, 1)
+ compare(tab2.index, 0)
+ compare(tab4.index, 1)
+ compare(tab3.index, 2)
+ compare(tab1.index, 3)
+
+ // remove from the beginning
+ control.removeItem(0)
+ compare(tab2.index, -1)
+ compare(tab2.tabBar, null)
+ compare(tab2.position, TabBar.Header)
+
+ compare(tab4.index, 0)
+ compare(tab3.index, 1)
+ compare(tab1.index, 2)
+
+ // remove from the middle
+ control.removeItem(1)
+ compare(tab3.index, -1)
+ compare(tab3.tabBar, null)
+ compare(tab3.position, TabBar.Header)
+
+ compare(tab4.index, 0)
+ compare(tab1.index, 1)
}
}
diff --git a/tests/auto/controls/data/tst_tabbutton.qml b/tests/auto/controls/data/tst_tabbutton.qml
index 60cae927..3cb22ecd 100644
--- a/tests/auto/controls/data/tst_tabbutton.qml
+++ b/tests/auto/controls/data/tst_tabbutton.qml
@@ -95,4 +95,84 @@ TestCase {
verify(control)
compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset)
}
+
+ function test_spacing() {
+ var control = createTemporaryObject(tabButton, testCase, { text: "Some long, long, long text" })
+ verify(control)
+ if (control.background)
+ verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth)
+
+ var textLabel = findChild(control.contentItem, "label")
+ verify(textLabel)
+
+ // The implicitWidth of the IconLabel that all buttons use as their contentItem
+ // should be equal to the implicitWidth of the Text while no icon is set.
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // That means that spacing shouldn't affect it.
+ control.spacing += 100
+ compare(control.contentItem.implicitWidth, textLabel.implicitWidth)
+
+ // The implicitWidth of the TabButton itself should, therefore, also never include spacing while no icon is set.
+ compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding)
+ }
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: TabButton.IconOnly },
+ { "tag": "TextOnly", display: TabButton.TextOnly },
+ { "tag": "TextUnderIcon", display: TabButton.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: TabButton.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: TabButton.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: TabButton.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: TabButton.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: TabButton.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(tabButton, testCase, {
+ text: "TabButton",
+ display: data.display,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case TabButton.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case TabButton.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case TabButton.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case TabButton.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_textfield.qml b/tests/auto/controls/data/tst_textfield.qml
index deb4b6ff..6a40f053 100644
--- a/tests/auto/controls/data/tst_textfield.qml
+++ b/tests/auto/controls/data/tst_textfield.qml
@@ -66,6 +66,11 @@ TestCase {
}
Component {
+ id: rectangle
+ Rectangle { }
+ }
+
+ Component {
id: signalSpy
SignalSpy { }
}
@@ -82,8 +87,7 @@ TestCase {
var implicitWidthSpy = signalSpy.createObject(control, { target: control, signalName: "implicitWidthChanged"} )
var implicitHeightSpy = signalSpy.createObject(control, { target: control, signalName: "implicitHeightChanged"} )
- control.background.implicitWidth = 400
- control.background.implicitHeight = 200
+ control.background = rectangle.createObject(control, {implicitWidth: 400, implicitHeight: 200})
compare(control.implicitWidth, 400)
compare(control.implicitHeight, 200)
compare(implicitWidthSpy.count, 1)
@@ -163,14 +167,14 @@ TestCase {
if (data.textAlignment !== undefined)
compare(control.horizontalAlignment, data.textAlignment)
for (var i = 0; i < control.children.length; ++i) {
- if (control.children[i].hasOwnProperty("horizontalAlignment"))
+ if (control.children[i].hasOwnProperty("text") && control.children[i].hasOwnProperty("horizontalAlignment"))
compare(control.children[i].effectiveHorizontalAlignment, data.placeholderAlignment) // placeholder
}
control.verticalAlignment = TextField.AlignBottom
compare(control.verticalAlignment, TextField.AlignBottom)
for (var j = 0; j < control.children.length; ++j) {
- if (control.children[j].hasOwnProperty("verticalAlignment"))
+ if (control.children[j].hasOwnProperty("text") && control.children[j].hasOwnProperty("verticalAlignment"))
compare(control.children[j].verticalAlignment, Text.AlignBottom) // placeholder
}
}
diff --git a/tests/auto/controls/data/tst_toolbutton.qml b/tests/auto/controls/data/tst_toolbutton.qml
index 5eefaf59..9e79cb8c 100644
--- a/tests/auto/controls/data/tst_toolbutton.qml
+++ b/tests/auto/controls/data/tst_toolbutton.qml
@@ -181,4 +181,63 @@ TestCase {
verify(control)
compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset)
}
+
+ function test_display_data() {
+ return [
+ { "tag": "IconOnly", display: ToolButton.IconOnly },
+ { "tag": "TextOnly", display: ToolButton.TextOnly },
+ { "tag": "TextUnderIcon", display: ToolButton.TextUnderIcon },
+ { "tag": "TextBesideIcon", display: ToolButton.TextBesideIcon },
+ { "tag": "IconOnly, mirrored", display: ToolButton.IconOnly, mirrored: true },
+ { "tag": "TextOnly, mirrored", display: ToolButton.TextOnly, mirrored: true },
+ { "tag": "TextUnderIcon, mirrored", display: ToolButton.TextUnderIcon, mirrored: true },
+ { "tag": "TextBesideIcon, mirrored", display: ToolButton.TextBesideIcon, mirrored: true }
+ ]
+ }
+
+ function test_display(data) {
+ var control = createTemporaryObject(toolButton, testCase, {
+ text: "ToolButton",
+ display: data.display,
+ "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png",
+ "LayoutMirroring.enabled": !!data.mirrored
+ })
+ verify(control)
+ compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png")
+
+ var iconImage = findChild(control.contentItem, "image")
+ var textLabel = findChild(control.contentItem, "label")
+
+ switch (control.display) {
+ case ToolButton.IconOnly:
+ verify(iconImage)
+ verify(!textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ break;
+ case ToolButton.TextOnly:
+ verify(!iconImage)
+ verify(textLabel)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ case ToolButton.TextUnderIcon:
+ verify(iconImage)
+ verify(textLabel)
+ compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
+ compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
+ verify(iconImage.y < textLabel.y)
+ break;
+ case ToolButton.TextBesideIcon:
+ verify(iconImage)
+ verify(textLabel)
+ if (control.mirrored)
+ verify(textLabel.x < iconImage.x)
+ else
+ verify(iconImage.x < textLabel.x)
+ compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ break;
+ }
+ }
}
diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml
index c7973c69..bd46fabd 100644
--- a/tests/auto/controls/data/tst_tooltip.qml
+++ b/tests/auto/controls/data/tst_tooltip.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtTest 1.0
import QtQuick.Controls 2.2
@@ -283,6 +283,10 @@ TestCase {
}
function test_activateShortcutWhileToolTipVisible() {
+ if ((Qt.platform.pluginName === "offscreen")
+ || (Qt.platform.pluginName === "minimal"))
+ skip("Mouse hoovering not functional on offscreen/minimal platforms")
+
var root = createTemporaryObject(buttonAndShortcutComponent, testCase)
verify(root)
diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml
index aaf888c2..1fab0dab 100644
--- a/tests/auto/controls/data/tst_tumbler.qml
+++ b/tests/auto/controls/data/tst_tumbler.qml
@@ -123,7 +123,9 @@ TestCase {
return child;
}
- return findView(child);
+ var grandChild = findView(child);
+ if (grandChild)
+ return grandChild;
}
return null;
diff --git a/tests/auto/controls/fusion/dependencies.qml b/tests/auto/controls/fusion/dependencies.qml
new file mode 100644
index 00000000..30c32fa5
--- /dev/null
+++ b/tests/auto/controls/fusion/dependencies.qml
@@ -0,0 +1,6 @@
+import QtTest 1.0
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Fusion 2.3
+
+TestCase { }
diff --git a/tests/auto/controls/fusion/fusion.pro b/tests/auto/controls/fusion/fusion.pro
new file mode 100644
index 00000000..f3374f34
--- /dev/null
+++ b/tests/auto/controls/fusion/fusion.pro
@@ -0,0 +1,15 @@
+TEMPLATE = app
+TARGET = tst_fusion
+CONFIG += qmltestcase
+QT += quickcontrols2
+
+DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\"
+
+SOURCES += \
+ $$PWD/tst_fusion.cpp
+
+OTHER_FILES += \
+ $$PWD/../data/*.qml
+
+TESTDATA += \
+ $$PWD/../data/tst_*
diff --git a/tests/auto/controls/fusion/tst_fusion.cpp b/tests/auto/controls/fusion/tst_fusion.cpp
new file mode 100644
index 00000000..84f9c231
--- /dev/null
+++ b/tests/auto/controls/fusion/tst_fusion.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtQuickTest/quicktest.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+int main(int argc, char *argv[])
+{
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ QTEST_SET_MAIN_SOURCE_PATH
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ QQuickStyle::setStyle("Fusion");
+ return quick_test_main(argc, argv, "tst_controls::Fusion", TST_CONTROLS_DATA);
+}
diff --git a/tests/auto/controls/imagine/dependencies.qml b/tests/auto/controls/imagine/dependencies.qml
new file mode 100644
index 00000000..3811fec0
--- /dev/null
+++ b/tests/auto/controls/imagine/dependencies.qml
@@ -0,0 +1,6 @@
+import QtTest 1.0
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Imagine 2.3
+
+TestCase { }
diff --git a/tests/auto/controls/imagine/imagine.pro b/tests/auto/controls/imagine/imagine.pro
new file mode 100644
index 00000000..ab521c98
--- /dev/null
+++ b/tests/auto/controls/imagine/imagine.pro
@@ -0,0 +1,15 @@
+TEMPLATE = app
+TARGET = tst_imagine
+CONFIG += qmltestcase
+QT += quickcontrols2
+
+DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\"
+
+SOURCES += \
+ $$PWD/tst_imagine.cpp
+
+OTHER_FILES += \
+ $$PWD/../data/*.qml
+
+TESTDATA += \
+ $$PWD/../data/tst_*
diff --git a/tests/auto/controls/imagine/tst_imagine.cpp b/tests/auto/controls/imagine/tst_imagine.cpp
new file mode 100644
index 00000000..9777c9c9
--- /dev/null
+++ b/tests/auto/controls/imagine/tst_imagine.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtQuickTest/quicktest.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+int main(int argc, char *argv[])
+{
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT
+ QTEST_SET_MAIN_SOURCE_PATH
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ QQuickStyle::setStyle("Imagine");
+ return quick_test_main(argc, argv, "tst_controls::Imagine", TST_CONTROLS_DATA);
+}
diff --git a/tests/auto/cursor/tst_cursor.cpp b/tests/auto/cursor/tst_cursor.cpp
index 6256112d..0f24a29e 100644
--- a/tests/auto/cursor/tst_cursor.cpp
+++ b/tests/auto/cursor/tst_cursor.cpp
@@ -184,6 +184,11 @@ void tst_cursor::scrollBar()
const QPoint scrollBarPos(window->width() - scrollBar->width() / 2, window->height() / 2);
QTest::mouseMove(window, scrollBarPos);
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Active status behaves differently in offscreen/minimal platforms", Continue);
+
QVERIFY(scrollBar->isActive());
QCOMPARE(window->cursor().shape(), scrollBar->cursor().shape());
QCOMPARE(scrollBar->cursor().shape(), Qt::CursorShape::ArrowCursor);
diff --git a/tests/auto/font/data/font-appwindow-custom.qml b/tests/auto/font/data/font-appwindow-custom.qml
index 3d06f64a..e98b678e 100644
--- a/tests/auto/font/data/font-appwindow-custom.qml
+++ b/tests/auto/font/data/font-appwindow-custom.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/font-appwindow-default.qml b/tests/auto/font/data/font-appwindow-default.qml
index 02643c77..8337b488 100644
--- a/tests/auto/font/data/font-appwindow-default.qml
+++ b/tests/auto/font/data/font-appwindow-default.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/font-control-custom.qml b/tests/auto/font/data/font-control-custom.qml
index 92136e86..0121eca2 100644
--- a/tests/auto/font/data/font-control-custom.qml
+++ b/tests/auto/font/data/font-control-custom.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
Control {
diff --git a/tests/auto/font/data/font-control-default.qml b/tests/auto/font/data/font-control-default.qml
index 552c77d8..f3af36a2 100644
--- a/tests/auto/font/data/font-control-default.qml
+++ b/tests/auto/font/data/font-control-default.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
Control {
diff --git a/tests/auto/font/data/font-popup-custom.qml b/tests/auto/font/data/font-popup-custom.qml
index e8363a81..3982721e 100644
--- a/tests/auto/font/data/font-popup-custom.qml
+++ b/tests/auto/font/data/font-popup-custom.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
Popup {
diff --git a/tests/auto/font/data/font-popup-default.qml b/tests/auto/font/data/font-popup-default.qml
index 26c522c1..c4fab76a 100644
--- a/tests/auto/font/data/font-popup-default.qml
+++ b/tests/auto/font/data/font-popup-default.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
Popup {
diff --git a/tests/auto/font/data/inheritance-childcontrol.qml b/tests/auto/font/data/inheritance-childcontrol.qml
index 8a04dd52..7c2b0d0c 100644
--- a/tests/auto/font/data/inheritance-childcontrol.qml
+++ b/tests/auto/font/data/inheritance-childcontrol.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-childpopup.qml b/tests/auto/font/data/inheritance-childpopup.qml
index ca5cdc82..304f0486 100644
--- a/tests/auto/font/data/inheritance-childpopup.qml
+++ b/tests/auto/font/data/inheritance-childpopup.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-control.qml b/tests/auto/font/data/inheritance-control.qml
index ac9c940a..fe555237 100644
--- a/tests/auto/font/data/inheritance-control.qml
+++ b/tests/auto/font/data/inheritance-control.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-dynamicchildcontrol.qml b/tests/auto/font/data/inheritance-dynamicchildcontrol.qml
index 98c0f696..982b5611 100644
--- a/tests/auto/font/data/inheritance-dynamicchildcontrol.qml
+++ b/tests/auto/font/data/inheritance-dynamicchildcontrol.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-dynamicchildpopup.qml b/tests/auto/font/data/inheritance-dynamicchildpopup.qml
index ef4fe60c..7af10af6 100644
--- a/tests/auto/font/data/inheritance-dynamicchildpopup.qml
+++ b/tests/auto/font/data/inheritance-dynamicchildpopup.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-dynamiccontrol.qml b/tests/auto/font/data/inheritance-dynamiccontrol.qml
index a261d600..263ad38d 100644
--- a/tests/auto/font/data/inheritance-dynamiccontrol.qml
+++ b/tests/auto/font/data/inheritance-dynamiccontrol.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-dynamicpopup.qml b/tests/auto/font/data/inheritance-dynamicpopup.qml
index f0d567da..cd355682 100644
--- a/tests/auto/font/data/inheritance-dynamicpopup.qml
+++ b/tests/auto/font/data/inheritance-dynamicpopup.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/data/inheritance-popup.qml b/tests/auto/font/data/inheritance-popup.qml
index b8415e63..3219a186 100644
--- a/tests/auto/font/data/inheritance-popup.qml
+++ b/tests/auto/font/data/inheritance-popup.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/font/tst_font.cpp b/tests/auto/font/tst_font.cpp
index a851b263..660f4baf 100644
--- a/tests/auto/font/tst_font.cpp
+++ b/tests/auto/font/tst_font.cpp
@@ -255,7 +255,7 @@ void tst_font::defaultFont_data()
QTest::newRow("ToolButton") << "ToolButton" << QPlatformTheme::ToolButtonFont;
QTest::newRow("ToolSeparator") << "ToolSeparator" << QPlatformTheme::SystemFont;
QTest::newRow("ToolTip") << "ToolTip" << QPlatformTheme::TipLabelFont;
- QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::SystemFont;
+ QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::ItemViewFont;
}
void tst_font::defaultFont()
@@ -263,12 +263,14 @@ void tst_font::defaultFont()
QFETCH(QString, control);
QFETCH(QPlatformTheme::Font, fontType);
- TestFontTheme theme(QGuiApplicationPrivate::platform_theme);
-
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData(QString("import QtQuick.Controls 2.2; %1 { }").arg(control).toUtf8(), QUrl());
+ // The call to setData() above causes QQuickDefaultTheme to be set as the platform theme,
+ // so we must make sure we only set our theme afterwards.
+ TestFontTheme theme(QGuiApplicationPrivate::platform_theme);
+
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
diff --git a/tests/auto/palette/data/inheritance-childcontrol.qml b/tests/auto/palette/data/inheritance-childcontrol.qml
new file mode 100644
index 00000000..7c2b0d0c
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-childcontrol.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property alias control: control
+ property alias child: child
+ property alias grandChild: grandChild
+
+ Item {
+ Control {
+ id: control
+
+ Control {
+ id: child
+
+ Item {
+ Control {
+ id: grandChild
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-childpopup.qml b/tests/auto/palette/data/inheritance-childpopup.qml
new file mode 100644
index 00000000..304f0486
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-childpopup.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property alias control: control
+ property alias child: child
+ property alias grandChild: grandChild
+
+ Item {
+ Popup {
+ id: control
+
+ Control {
+ id: child
+
+ Item {
+ Control {
+ id: grandChild
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-control.qml b/tests/auto/palette/data/inheritance-control.qml
new file mode 100644
index 00000000..e5486edb
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-control.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ id: window
+
+ property alias control: control
+ property alias child: child
+ property alias grandChild: grandChild
+
+ Control {
+ id: control
+
+ Control {
+ id: child
+
+ Item {
+ Control {
+ id: grandChild
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml b/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml
new file mode 100644
index 00000000..982b5611
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property Control control
+ property Control child
+ property Control grandChild
+
+ Item {
+ id: childItem
+ }
+
+ Component {
+ id: component
+ Control { }
+ }
+
+ Component.onCompleted: {
+ control = component.createObject(childItem)
+ child = component.createObject(control)
+ grandChild = component.createObject(child)
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-dynamicchildpopup.qml b/tests/auto/palette/data/inheritance-dynamicchildpopup.qml
new file mode 100644
index 00000000..7af10af6
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-dynamicchildpopup.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property Popup control
+ property Control child
+ property Control grandChild
+
+ Item {
+ id: childItem
+ }
+
+ Component {
+ id: popupComponent
+ Popup { }
+ }
+
+ Component {
+ id: controlComponent
+ Control { }
+ }
+
+ Component.onCompleted: {
+ control = popupComponent.createObject(childItem)
+ child = controlComponent.createObject(control.contentItem)
+ grandChild = controlComponent.createObject(child)
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-dynamiccontrol.qml b/tests/auto/palette/data/inheritance-dynamiccontrol.qml
new file mode 100644
index 00000000..263ad38d
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-dynamiccontrol.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property Control control
+ property Control child
+ property Control grandChild
+
+ Component {
+ id: component
+ Control { }
+ }
+
+ Component.onCompleted: {
+ control = component.createObject(contentItem)
+ child = component.createObject(control)
+ grandChild = component.createObject(child)
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-dynamicpopup.qml b/tests/auto/palette/data/inheritance-dynamicpopup.qml
new file mode 100644
index 00000000..cd355682
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-dynamicpopup.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+
+ property Popup control
+ property Control child
+ property Control grandChild
+
+ Component {
+ id: popupComponent
+ Popup { }
+ }
+
+ Component {
+ id: controlComponent
+ Control { }
+ }
+
+ Component.onCompleted: {
+ control = popupComponent.createObject(window)
+ child = controlComponent.createObject(control.contentItem)
+ grandChild = controlComponent.createObject(child)
+ }
+}
diff --git a/tests/auto/palette/data/inheritance-popup.qml b/tests/auto/palette/data/inheritance-popup.qml
new file mode 100644
index 00000000..e6ac0a3a
--- /dev/null
+++ b/tests/auto/palette/data/inheritance-popup.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ id: window
+
+ property alias control: control
+ property alias child: child
+ property alias grandChild: grandChild
+
+ Popup {
+ id: control
+
+ Control {
+ id: child
+
+ Item {
+ Control {
+ id: grandChild
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/palette/data/listview.qml b/tests/auto/palette/data/listview.qml
new file mode 100644
index 00000000..7381c310
--- /dev/null
+++ b/tests/auto/palette/data/listview.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.9
+import QtQuick.Controls 2.2
+
+ApplicationWindow {
+ id: window
+ width: 200
+ height: 200
+
+ property alias listView: listView
+
+ palette.highlight: "red"
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ model: 1
+ delegate: Column {
+ property alias control: control
+ property alias label: label
+ property alias textarea: textarea
+ property alias textfield: textfield
+
+ Control { id: control }
+ Label { id: label }
+ TextArea { id: textarea }
+ TextField { id: textfield }
+ }
+ }
+}
diff --git a/tests/auto/palette/data/palette-appwindow-custom.qml b/tests/auto/palette/data/palette-appwindow-custom.qml
new file mode 100644
index 00000000..33139e48
--- /dev/null
+++ b/tests/auto/palette/data/palette-appwindow-custom.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ palette.alternateBase: "aqua"
+ palette.base: "azure"
+ palette.brightText: "beige"
+ palette.button: "bisque"
+ palette.buttonText: "chocolate"
+ palette.dark: "coral"
+ palette.highlight: "crimson"
+ palette.highlightedText: "fuchsia"
+ palette.light: "gold"
+ palette.link: "indigo"
+ palette.linkVisited: "ivory"
+ palette.mid: "khaki"
+ palette.midlight: "lavender"
+ palette.shadow: "linen"
+ palette.text: "moccasin"
+ palette.toolTipBase: "navy"
+ palette.toolTipText: "orchid"
+ palette.window: "plum"
+ palette.windowText: "salmon"
+}
diff --git a/tests/auto/palette/data/palette-appwindow-default.qml b/tests/auto/palette/data/palette-appwindow-default.qml
new file mode 100644
index 00000000..c071a0f4
--- /dev/null
+++ b/tests/auto/palette/data/palette-appwindow-default.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+}
diff --git a/tests/auto/palette/data/palette-control-custom.qml b/tests/auto/palette/data/palette-control-custom.qml
new file mode 100644
index 00000000..d3eb05bd
--- /dev/null
+++ b/tests/auto/palette/data/palette-control-custom.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+Control {
+ palette.alternateBase: "aqua"
+ palette.base: "azure"
+ palette.brightText: "beige"
+ palette.button: "bisque"
+ palette.buttonText: "chocolate"
+ palette.dark: "coral"
+ palette.highlight: "crimson"
+ palette.highlightedText: "fuchsia"
+ palette.light: "gold"
+ palette.link: "indigo"
+ palette.linkVisited: "ivory"
+ palette.mid: "khaki"
+ palette.midlight: "lavender"
+ palette.shadow: "linen"
+ palette.text: "moccasin"
+ palette.toolTipBase: "navy"
+ palette.toolTipText: "orchid"
+ palette.window: "plum"
+ palette.windowText: "salmon"
+}
diff --git a/tests/auto/palette/data/palette-control-default.qml b/tests/auto/palette/data/palette-control-default.qml
new file mode 100644
index 00000000..b747d7e2
--- /dev/null
+++ b/tests/auto/palette/data/palette-control-default.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+Control {
+}
diff --git a/tests/auto/palette/data/palette-popup-custom.qml b/tests/auto/palette/data/palette-popup-custom.qml
new file mode 100644
index 00000000..3b7cec3d
--- /dev/null
+++ b/tests/auto/palette/data/palette-popup-custom.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+Popup {
+ palette.alternateBase: "aqua"
+ palette.base: "azure"
+ palette.brightText: "beige"
+ palette.button: "bisque"
+ palette.buttonText: "chocolate"
+ palette.dark: "coral"
+ palette.highlight: "crimson"
+ palette.highlightedText: "fuchsia"
+ palette.light: "gold"
+ palette.link: "indigo"
+ palette.linkVisited: "ivory"
+ palette.mid: "khaki"
+ palette.midlight: "lavender"
+ palette.shadow: "linen"
+ palette.text: "moccasin"
+ palette.toolTipBase: "navy"
+ palette.toolTipText: "orchid"
+ palette.window: "plum"
+ palette.windowText: "salmon"
+}
diff --git a/tests/auto/palette/data/palette-popup-default.qml b/tests/auto/palette/data/palette-popup-default.qml
new file mode 100644
index 00000000..f09feae0
--- /dev/null
+++ b/tests/auto/palette/data/palette-popup-default.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+Popup {
+}
diff --git a/tests/auto/palette/palette.pro b/tests/auto/palette/palette.pro
new file mode 100644
index 00000000..c7d55d07
--- /dev/null
+++ b/tests/auto/palette/palette.pro
@@ -0,0 +1,16 @@
+CONFIG += testcase
+TARGET = tst_palette
+SOURCES += tst_palette.cpp
+
+macos:CONFIG -= app_bundle
+
+QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private quickcontrols2-private
+
+include (../shared/util.pri)
+
+RESOURCES += qtquickcontrols2.conf
+
+TESTDATA = data/*
+
+OTHER_FILES += \
+ data/*.qml
diff --git a/tests/auto/palette/qtquickcontrols2.conf b/tests/auto/palette/qtquickcontrols2.conf
new file mode 100644
index 00000000..2ffc7ecc
--- /dev/null
+++ b/tests/auto/palette/qtquickcontrols2.conf
@@ -0,0 +1,5 @@
+[Default]
+Palette\Base=#efefef
+
+[Default\Palette]
+Text=#101010
diff --git a/tests/auto/palette/tst_palette.cpp b/tests/auto/palette/tst_palette.cpp
new file mode 100644
index 00000000..f74e358a
--- /dev/null
+++ b/tests/auto/palette/tst_palette.cpp
@@ -0,0 +1,407 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtTest/qtest.h>
+#include "../shared/visualtestutil.h"
+
+#include <QtGui/qpalette.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+#include <QtQuickControls2/private/qquickproxytheme_p.h>
+
+using namespace QQuickVisualTestUtil;
+
+class tst_palette : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void palette_data();
+ void palette();
+
+ void inheritance_data();
+ void inheritance();
+
+ void defaultPalette_data();
+ void defaultPalette();
+
+ void listView_data();
+ void listView();
+};
+
+void tst_palette::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+
+ // Import QtQuick.Controls to initialize styles and themes so that
+ // QQuickControlPrivate::themePalette() returns a palette from the
+ // style's theme instead of the platform's theme.
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick.Controls 2.3; Control { }", QUrl());
+ delete component.create();
+}
+
+void tst_palette::palette_data()
+{
+ QTest::addColumn<QString>("testFile");
+ QTest::addColumn<QPalette>("expectedPalette");
+
+ QPalette defaultPalette = QQuickControlPrivate::themePalette(QPlatformTheme::SystemPalette);
+ defaultPalette.setColor(QPalette::Base, QColor("#efefef"));
+ defaultPalette.setColor(QPalette::Text, QColor("#101010"));
+
+ QTest::newRow("Control") << "palette-control-default.qml" << defaultPalette;
+ QTest::newRow("AppWindow") << "palette-appwindow-default.qml" << defaultPalette;
+ QTest::newRow("Popup") << "palette-popup-default.qml" << defaultPalette;
+
+ QPalette customPalette;
+ customPalette.setColor(QPalette::AlternateBase, QColor("aqua"));
+ customPalette.setColor(QPalette::Base, QColor("azure"));
+ customPalette.setColor(QPalette::BrightText, QColor("beige"));
+ customPalette.setColor(QPalette::Button, QColor("bisque"));
+ customPalette.setColor(QPalette::ButtonText, QColor("chocolate"));
+ customPalette.setColor(QPalette::Dark, QColor("coral"));
+ customPalette.setColor(QPalette::Highlight, QColor("crimson"));
+ customPalette.setColor(QPalette::HighlightedText, QColor("fuchsia"));
+ customPalette.setColor(QPalette::Light, QColor("gold"));
+ customPalette.setColor(QPalette::Link, QColor("indigo"));
+ customPalette.setColor(QPalette::LinkVisited, QColor("ivory"));
+ customPalette.setColor(QPalette::Mid, QColor("khaki"));
+ customPalette.setColor(QPalette::Midlight, QColor("lavender"));
+ customPalette.setColor(QPalette::Shadow, QColor("linen"));
+ customPalette.setColor(QPalette::Text, QColor("moccasin"));
+ customPalette.setColor(QPalette::ToolTipBase, QColor("navy"));
+ customPalette.setColor(QPalette::ToolTipText, QColor("orchid"));
+ customPalette.setColor(QPalette::Window, QColor("plum"));
+ customPalette.setColor(QPalette::WindowText, QColor("salmon"));
+
+ QTest::newRow("Control:custom") << "palette-control-custom.qml" << customPalette;
+ QTest::newRow("AppWindow:custom") << "palette-appwindow-custom.qml" << customPalette;
+ QTest::newRow("Popup:custom") << "palette-popup-custom.qml" << customPalette;
+}
+
+void tst_palette::palette()
+{
+ QFETCH(QString, testFile);
+ QFETCH(QPalette, expectedPalette);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl(testFile));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+ QVariant var = object->property("palette");
+ QVERIFY(var.isValid());
+
+ QPalette actualPalette = var.value<QPalette>();
+ QCOMPARE(actualPalette, expectedPalette);
+}
+
+void tst_palette::inheritance_data()
+{
+ QTest::addColumn<QString>("testFile");
+
+ QTest::newRow("Control") << "inheritance-control.qml";
+ QTest::newRow("Child Control") << "inheritance-childcontrol.qml";
+ QTest::newRow("Dynamic Control") << "inheritance-dynamiccontrol.qml";
+ QTest::newRow("Dynamic Child Control") << "inheritance-dynamicchildcontrol.qml";
+
+ QTest::newRow("Popup") << "inheritance-popup.qml";
+ QTest::newRow("Child Popup") << "inheritance-childpopup.qml";
+ QTest::newRow("Dynamic Popup") << "inheritance-dynamicpopup.qml";
+ QTest::newRow("Dynamic Child Popup") << "inheritance-dynamicchildpopup.qml";
+}
+
+void tst_palette::inheritance()
+{
+ QFETCH(QString, testFile);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl(testFile));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create()));
+ QVERIFY2(!window.isNull(), qPrintable(component.errorString()));
+
+ QObject *control = window->property("control").value<QObject *>();
+ QObject *child = window->property("child").value<QObject *>();
+ QObject *grandChild = window->property("grandChild").value<QObject *>();
+ QVERIFY(control && child && grandChild);
+
+ QPalette defaultPalette = QQuickControlPrivate::themePalette(QPlatformTheme::SystemPalette);
+ defaultPalette.setColor(QPalette::Base, QColor("#efefef"));
+ defaultPalette.setColor(QPalette::Text, QColor("#101010"));
+
+ QCOMPARE(window->palette(), defaultPalette);
+
+ QCOMPARE(control->property("palette").value<QPalette>(), defaultPalette);
+ QCOMPARE(child->property("palette").value<QPalette>(), defaultPalette);
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), defaultPalette);
+
+ QPalette childPalette(defaultPalette);
+ childPalette.setColor(QPalette::Base, Qt::red);
+ childPalette.setColor(QPalette::Text, Qt::green);
+ childPalette.setColor(QPalette::Button, Qt::blue);
+ child->setProperty("palette", childPalette);
+ QCOMPARE(child->property("palette").value<QPalette>(), childPalette);
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), childPalette);
+
+ QPalette grandChildPalette(childPalette);
+ grandChildPalette.setColor(QPalette::Base, Qt::cyan);
+ grandChildPalette.setColor(QPalette::Mid, Qt::magenta);
+ grandChild->setProperty("palette", grandChildPalette);
+ QCOMPARE(child->property("palette").value<QPalette>(), childPalette);
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette);
+
+ QPalette windowPalette(defaultPalette);
+ windowPalette.setColor(QPalette::Window, Qt::gray);
+ window->setPalette(windowPalette);
+ QCOMPARE(window->palette(), windowPalette);
+ QCOMPARE(control->property("palette").value<QPalette>(), windowPalette);
+
+ childPalette.setColor(QPalette::Window, Qt::gray);
+ QCOMPARE(child->property("palette").value<QPalette>(), childPalette);
+
+ grandChildPalette.setColor(QPalette::Window, Qt::gray);
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette);
+
+ child->setProperty("palette", QVariant());
+ QCOMPARE(child->property("palette").value<QPalette>(), windowPalette);
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette);
+
+ grandChild->setProperty("palette", QVariant());
+ QCOMPARE(grandChild->property("palette").value<QPalette>(), windowPalette);
+}
+
+class TestTheme : public QQuickProxyTheme
+{
+public:
+ TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme)
+ {
+ std::fill(palettes, palettes + QPlatformTheme::NPalettes, static_cast<QPalette *>(0));
+
+ QPalette palette = QPalette();
+ palette.setColor(QPalette::Window, Qt::gray);
+ palettes[QPlatformTheme::SystemPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::ToolTipBase, Qt::yellow);
+ palettes[QPlatformTheme::ToolTipPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::ButtonText, Qt::blue);
+ palettes[QPlatformTheme::ToolButtonPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Button, Qt::red);
+ palettes[QPlatformTheme::ButtonPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Text, Qt::green);
+ palettes[QPlatformTheme::CheckBoxPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Text, Qt::blue);
+ palettes[QPlatformTheme::RadioButtonPalette] = new QPalette(palette);
+
+ // HeaderPalette unused
+
+ palette.setColor(QPalette::Base, Qt::darkGray);
+ palettes[QPlatformTheme::ComboBoxPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Base, Qt::lightGray);
+ palettes[QPlatformTheme::ItemViewPalette] = new QPalette(palette);
+
+ // MessageBoxLabelPalette unused
+
+ palette.setColor(QPalette::ButtonText, Qt::white);
+ palettes[QPlatformTheme::TabBarPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::WindowText, Qt::darkGray);
+ palettes[QPlatformTheme::LabelPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Mid, Qt::gray);
+ palettes[QPlatformTheme::GroupBoxPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Shadow, Qt::darkYellow);
+ palettes[QPlatformTheme::MenuPalette] = new QPalette(palette);
+
+ // MenuBarPalette unused
+
+ palette.setColor(QPalette::Base, Qt::cyan);
+ palettes[QPlatformTheme::TextEditPalette] = new QPalette(palette);
+
+ palette.setColor(QPalette::Base, Qt::magenta);
+ palettes[QPlatformTheme::TextLineEditPalette] = new QPalette(palette);
+
+ QGuiApplicationPrivate::platform_theme = this;
+ }
+
+ const QPalette *palette(Palette type = SystemPalette) const override
+ {
+ return palettes[type];
+ }
+
+private:
+ QPalette *palettes[QPlatformTheme::NPalettes];
+};
+
+Q_DECLARE_METATYPE(QPlatformTheme::Palette)
+
+void tst_palette::defaultPalette_data()
+{
+ QTest::addColumn<QString>("control");
+ QTest::addColumn<QPlatformTheme::Palette>("paletteType");
+
+ QTest::newRow("AbstractButton") << "AbstractButton" << QPlatformTheme::SystemPalette;
+ QTest::newRow("ApplicationWindow") << "ApplicationWindow" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Button") << "Button" << QPlatformTheme::ButtonPalette;
+ QTest::newRow("CheckBox") << "CheckBox" << QPlatformTheme::CheckBoxPalette;
+ QTest::newRow("CheckDelegate") << "CheckDelegate" << QPlatformTheme::ItemViewPalette;
+ QTest::newRow("ComboBox") << "ComboBox" << QPlatformTheme::ComboBoxPalette;
+ QTest::newRow("Container") << "Container" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Control") << "Control" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Dial") << "Dial" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Dialog") << "Dialog" << QPlatformTheme::SystemPalette;
+ QTest::newRow("DialogButtonBox") << "DialogButtonBox" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Drawer") << "Drawer" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Frame") << "Frame" << QPlatformTheme::SystemPalette;
+ QTest::newRow("GroupBox") << "GroupBox" << QPlatformTheme::GroupBoxPalette;
+ QTest::newRow("ItemDelegate") << "ItemDelegate" << QPlatformTheme::ItemViewPalette;
+ QTest::newRow("Label") << "Label" << QPlatformTheme::LabelPalette;
+ QTest::newRow("Menu") << "Menu" << QPlatformTheme::MenuPalette;
+ QTest::newRow("MenuItem") << "MenuItem" << QPlatformTheme::MenuPalette;
+ QTest::newRow("MenuSeparator") << "MenuSeparator" << QPlatformTheme::MenuPalette;
+ QTest::newRow("Page") << "Page" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Pane") << "Pane" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Popup") << "Popup" << QPlatformTheme::SystemPalette;
+ QTest::newRow("ProgressBar") << "ProgressBar" << QPlatformTheme::SystemPalette;
+ QTest::newRow("RadioButton") << "RadioButton" << QPlatformTheme::RadioButtonPalette;
+ QTest::newRow("RadioDelegate") << "RadioDelegate" << QPlatformTheme::ItemViewPalette;
+ QTest::newRow("RangeSlider") << "RangeSlider" << QPlatformTheme::SystemPalette;
+ QTest::newRow("RoundButton") << "RoundButton" << QPlatformTheme::ButtonPalette;
+ QTest::newRow("ScrollBar") << "ScrollBar" << QPlatformTheme::SystemPalette;
+ QTest::newRow("ScrollIndicator") << "ScrollIndicator" << QPlatformTheme::SystemPalette;
+ QTest::newRow("Slider") << "Slider" << QPlatformTheme::SystemPalette;
+ QTest::newRow("SpinBox") << "SpinBox" << QPlatformTheme::TextLineEditPalette;
+ QTest::newRow("SwipeDelegate") << "SwipeDelegate" << QPlatformTheme::ItemViewPalette;
+ QTest::newRow("Switch") << "Switch" << QPlatformTheme::CheckBoxPalette; // ### TODO: add QPlatformTheme::SwitchPalette
+ QTest::newRow("SwitchDelegate") << "SwitchDelegate" << QPlatformTheme::ItemViewPalette;
+ QTest::newRow("TabBar") << "TabBar" << QPlatformTheme::TabBarPalette;
+ QTest::newRow("TabButton") << "TabButton" << QPlatformTheme::TabBarPalette;
+ QTest::newRow("TextArea") << "TextArea" << QPlatformTheme::TextEditPalette;
+ QTest::newRow("TextField") << "TextField" << QPlatformTheme::TextLineEditPalette;
+ QTest::newRow("ToolBar") << "ToolBar" << QPlatformTheme::ToolButtonPalette;
+ QTest::newRow("ToolButton") << "ToolButton" << QPlatformTheme::ToolButtonPalette;
+ QTest::newRow("ToolSeparator") << "ToolSeparator" << QPlatformTheme::ToolButtonPalette;
+ QTest::newRow("ToolTip") << "ToolTip" << QPlatformTheme::ToolTipPalette;
+ QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::ItemViewPalette;
+}
+
+void tst_palette::defaultPalette()
+{
+ QFETCH(QString, control);
+ QFETCH(QPlatformTheme::Palette, paletteType);
+
+ TestTheme theme(QGuiApplicationPrivate::platform_theme);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(QString("import QtQuick.Controls 2.3; %1 { }").arg(control).toUtf8(), QUrl());
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+ QVariant var = object->property("palette");
+ QVERIFY(var.isValid());
+
+ const QPalette *expectedPalette = theme.palette(paletteType);
+ QVERIFY(expectedPalette);
+
+ QPalette actualPalette = var.value<QPalette>();
+ QCOMPARE(actualPalette, *expectedPalette);
+}
+
+void tst_palette::listView_data()
+{
+ QTest::addColumn<QString>("objectName");
+
+ QTest::newRow("Control") << "control";
+ QTest::newRow("Label") << "label";
+ QTest::newRow("TextArea") << "textarea";
+ QTest::newRow("TextField") << "textfield";
+}
+
+void tst_palette::listView()
+{
+ QFETCH(QString, objectName);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("listview.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create()));
+ QVERIFY2(!window.isNull(), qPrintable(component.errorString()));
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QQuickItem *listView = window->property("listView").value<QQuickItem *>();
+ QVERIFY(listView);
+
+ QQuickItem *contentItem = listView->property("contentItem").value<QQuickItem *>();
+ QVERIFY(contentItem);
+
+ QVERIFY(QMetaObject::invokeMethod(listView, "forceLayout"));
+
+ QQuickItem *column = contentItem->childItems().value(0);
+ QVERIFY(column);
+
+ QQuickItem *control = column->property(objectName.toUtf8()).value<QQuickItem *>();
+ QVERIFY(control);
+
+ QCOMPARE(control->property("palette").value<QPalette>().color(QPalette::Highlight), QColor(Qt::red));
+}
+
+QTEST_MAIN(tst_palette)
+
+#include "tst_palette.moc"
diff --git a/tests/auto/qquickapplicationwindow/data/layout.qml b/tests/auto/qquickapplicationwindow/data/layout.qml
index a80b2d48..5bcffdf1 100644
--- a/tests/auto/qquickapplicationwindow/data/layout.qml
+++ b/tests/auto/qquickapplicationwindow/data/layout.qml
@@ -49,13 +49,14 @@
****************************************************************************/
import QtQuick 2.6
-import QtQuick.Controls 2.0
+import QtQuick.Controls 2.3
ApplicationWindow {
width: 200
height: 200
visible: true
+ menuBar: MenuBar { }
header: ToolBar { }
footer: ToolBar { }
}
diff --git a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
index 19a0bf3b..aeeddb10 100644
--- a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
+++ b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
@@ -412,7 +412,7 @@ void tst_QQuickApplicationWindow::attachedProperties()
QCOMPARE(childControl->window(), childAppWindow);
QCOMPARE(childControl->property("attached_window").value<QQuickApplicationWindow *>(), childAppWindow);
QCOMPARE(childControl->property("attached_contentItem").value<QQuickItem *>(), childAppWindow->contentItem());
- QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindow->activeFocusControl());
+ QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindowControl);
QCOMPARE(childControl->property("attached_header").value<QQuickItem *>(), childAppWindow->header());
QCOMPARE(childControl->property("attached_footer").value<QQuickItem *>(), childAppWindow->footer());
QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), childAppWindow->overlay());
@@ -421,7 +421,7 @@ void tst_QQuickApplicationWindow::attachedProperties()
QCOMPARE(childItem->window(), childAppWindow);
QCOMPARE(childItem->property("attached_window").value<QQuickApplicationWindow *>(), childAppWindow);
QCOMPARE(childItem->property("attached_contentItem").value<QQuickItem *>(), childAppWindow->contentItem());
- QCOMPARE(childItem->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindow->activeFocusControl());
+ QCOMPARE(childItem->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindowControl);
QCOMPARE(childItem->property("attached_header").value<QQuickItem *>(), childAppWindow->header());
QCOMPARE(childItem->property("attached_footer").value<QQuickItem *>(), childAppWindow->footer());
QCOMPARE(childItem->property("attached_overlay").value<QQuickItem *>(), childAppWindow->overlay());
@@ -443,6 +443,55 @@ void tst_QQuickApplicationWindow::attachedProperties()
QVERIFY(!childItem->property("attached_header").value<QQuickItem *>());
QVERIFY(!childItem->property("attached_footer").value<QQuickItem *>());
QVERIFY(!childItem->property("attached_overlay").value<QQuickItem *>());
+ childAppWindow->close();
+ qApp->processEvents();
+
+ childWindow->show();
+ childWindow->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(childWindow));
+
+ QVERIFY(!childWindowControl->hasActiveFocus());
+ childWindowControl->forceActiveFocus();
+ QTRY_VERIFY(childWindowControl->hasActiveFocus());
+ QCOMPARE(childWindow->activeFocusItem(), childWindowControl);
+ QCOMPARE(childWindowControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl);
+
+ childControl->setParentItem(childWindow->contentItem());
+ QCOMPARE(childControl->window(), childWindow);
+ QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>());
+ QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl);
+ QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_header").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>());
+ QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow));
+
+ childItem->setParentItem(childWindow->contentItem());
+ QCOMPARE(childItem->window(), childWindow);
+ QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>());
+ QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl);
+ QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_header").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>());
+ QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow));
+
+ childControl->setParentItem(nullptr);
+ QVERIFY(!childControl->window());
+ QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>());
+ QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_activeFocusControl").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_header").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>());
+ QVERIFY(!childControl->property("attached_overlay").value<QQuickItem *>());
+
+ childItem->setParentItem(nullptr);
+ QVERIFY(!childItem->window());
+ QVERIFY(!childItem->property("attached_window").value<QQuickWindow *>());
+ QVERIFY(!childItem->property("attached_contentItem").value<QQuickItem *>());
+ QVERIFY(!childItem->property("attached_activeFocusControl").value<QQuickItem *>());
+ QVERIFY(!childItem->property("attached_header").value<QQuickItem *>());
+ QVERIFY(!childItem->property("attached_footer").value<QQuickItem *>());
+ QVERIFY(!childItem->property("attached_overlay").value<QQuickItem *>());
+ childWindow->close();
// ### A temporary workaround to unblock the CI until the crash caused
// by https://codereview.qt-project.org/#/c/108517/ has been fixed...
@@ -506,7 +555,7 @@ void tst_QQuickApplicationWindow::font()
QCOMPARE(item6->font(), font);
}
-class TestTheme : public QQuickProxyTheme
+class TestTheme : public QQuickProxyTheme
{
public:
TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme), m_font("Courier")
@@ -778,11 +827,18 @@ void tst_QQuickApplicationWindow::layout()
QQuickItem *content = window->contentItem();
QVERIFY(content);
+ QQuickItem *menuBar = window->menuBar();
+ QVERIFY(menuBar);
QQuickItem *header = window->header();
QVERIFY(header);
QQuickItem *footer = window->footer();
QVERIFY(footer);
+ QCOMPARE(menuBar->x(), 0.0);
+ QCOMPARE(menuBar->y(), -menuBar->height() - header->height());
+ QCOMPARE(header->width(), qreal(window->width()));
+ QVERIFY(menuBar->height() > 0);
+
QCOMPARE(header->x(), 0.0);
QCOMPARE(header->y(), -header->height());
QCOMPARE(header->width(), qreal(window->width()));
@@ -794,6 +850,12 @@ void tst_QQuickApplicationWindow::layout()
QVERIFY(footer->height() > 0.0);
QCOMPARE(content->x(), 0.0);
+ QCOMPARE(content->y(), menuBar->height() + header->height());
+ QCOMPARE(content->width(), qreal(window->width()));
+ QCOMPARE(content->height(), window->height() - menuBar->height() - header->height() - footer->height());
+
+ menuBar->setVisible(false);
+ QCOMPARE(content->x(), 0.0);
QCOMPARE(content->y(), header->height());
QCOMPARE(content->width(), qreal(window->width()));
QCOMPARE(content->height(), window->height() - header->height() - footer->height());
diff --git a/tests/auto/qquickcolor/data/tst_color.qml b/tests/auto/qquickcolor/data/tst_color.qml
new file mode 100644
index 00000000..fbd74e3c
--- /dev/null
+++ b/tests/auto/qquickcolor/data/tst_color.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtTest 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+TestCase {
+ id: testCase
+ name: "Color"
+
+ function test_transparent() {
+ compare(Color.transparent("red", 0.2), Qt.rgba(1, 0, 0, 0.2))
+ compare(Color.transparent(Qt.rgba(0, 1, 0, 1), 0.2), Qt.rgba(0, 1, 0, 0.2))
+ compare(Color.transparent("#0000ff", 0.2), Qt.rgba(0, 0, 1, 0.2))
+ }
+}
diff --git a/tests/auto/qquickcolor/qquickcolor.pro b/tests/auto/qquickcolor/qquickcolor.pro
new file mode 100644
index 00000000..af562df1
--- /dev/null
+++ b/tests/auto/qquickcolor/qquickcolor.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+TARGET = tst_qquickcolor
+CONFIG += qmltestcase
+
+SOURCES += \
+ $$PWD/tst_qquickcolor.cpp
+
+OTHER_FILES += \
+ $$PWD/data/*.qml
+
+TESTDATA += \
+ $$PWD/data/tst_*
diff --git a/tests/auto/qquickcolor/tst_qquickcolor.cpp b/tests/auto/qquickcolor/tst_qquickcolor.cpp
new file mode 100644
index 00000000..94c60080
--- /dev/null
+++ b/tests/auto/qquickcolor/tst_qquickcolor.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(tst_qquickcolor)
diff --git a/tests/auto/qquickdrawer/BLACKLIST b/tests/auto/qquickdrawer/BLACKLIST
new file mode 100644
index 00000000..b302c76b
--- /dev/null
+++ b/tests/auto/qquickdrawer/BLACKLIST
@@ -0,0 +1,14 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+
+# https://bugreports.qt.io/browse/QTBUG-62628
+[multiple]
+*
+
+[touch]
+*
+
+[multiTouch]
+*
+
+[grabber]
+*
diff --git a/tests/auto/qquickiconimage/data/alignment.qml b/tests/auto/qquickiconimage/data/alignment.qml
new file mode 100644
index 00000000..487ebfd0
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/alignment.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ name: "appointment-new"
+ sourceSize: Qt.size(22, 22)
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/color.qml b/tests/auto/qquickiconimage/data/color.qml
new file mode 100644
index 00000000..d6f647e6
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/color.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ source: "qrc:/icons/testtheme/22x22/actions/color-test-original.png"
+ sourceSize: Qt.size(22, 22)
+ color: "red"
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/color-test-tinted.png"
+ fillMode: Image.Pad
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/fileSelectors.qml b/tests/auto/qquickiconimage/data/fileSelectors.qml
new file mode 100644
index 00000000..487ebfd0
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/fileSelectors.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ name: "appointment-new"
+ sourceSize: Qt.size(22, 22)
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml b/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml
new file mode 100644
index 00000000..d6c33bb3
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+IconImage {
+ name: "appointment-new"
+}
diff --git a/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml b/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml
new file mode 100644
index 00000000..487ebfd0
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ name: "appointment-new"
+ sourceSize: Qt.size(22, 22)
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml b/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml
new file mode 100644
index 00000000..c503d8cf
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+IconImage {
+ name: "appointment-new"
+ sourceSize: Qt.size(22, 22)
+ width: 16
+ height: 16
+}
diff --git a/tests/auto/qquickiconimage/data/root.qml b/tests/auto/qquickiconimage/data/root.qml
new file mode 100644
index 00000000..0a8b8db9
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/root.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.10
+
+Item {
+ width: 200
+ height: 200
+}
diff --git a/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml b/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml
new file mode 100644
index 00000000..33f4a2d3
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml
new file mode 100644
index 00000000..c246dc74
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ sourceSize: Qt.size(22, 22)
+ }
+ Image {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml
new file mode 100644
index 00000000..ecbb7f6d
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+IconImage {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ sourceSize: Qt.size(22, 22)
+ width: 16
+ height: 16
+}
diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml
new file mode 100644
index 00000000..f9e07899
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+IconImage {
+ source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png"
+ sourceSize: Qt.size(32, 32)
+}
diff --git a/tests/auto/qquickiconimage/data/svgNoSizes.qml b/tests/auto/qquickiconimage/data/svgNoSizes.qml
new file mode 100644
index 00000000..17cccd26
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/svgNoSizes.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ source: "qrc:/icons/testtheme/appointment-new.svg"
+ }
+ Image {
+ source: "qrc:/icons/testtheme/appointment-new.svg"
+ }
+}
diff --git a/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml b/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml
new file mode 100644
index 00000000..2387e98e
--- /dev/null
+++ b/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Row {
+ width: 200
+ height: 200
+
+ IconImage {
+ source: "qrc:/data/icons/testtheme/appointment-new.svg"
+ sourceSize: Qt.size(22, 22)
+ }
+ Image {
+ source: "qrc:/data/icons/testtheme/appointment-new.svg"
+ sourceSize: Qt.size(22, 22)
+ }
+}
diff --git a/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png
new file mode 100644
index 00000000..18b7c678
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new.png
new file mode 100644
index 00000000..c6ceca43
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new@2x.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new@2x.png
new file mode 100644
index 00000000..f380ebb6
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new@2x.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png
new file mode 100644
index 00000000..d676ffd4
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new@2x.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new@2x.png
new file mode 100644
index 00000000..63ae9ce7
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new@2x.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original.png
new file mode 100644
index 00000000..2d876cc1
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original@2x.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original@2x.png
new file mode 100644
index 00000000..c65fbed0
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original@2x.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted.png
new file mode 100644
index 00000000..220a313d
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted@2x.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted@2x.png
new file mode 100644
index 00000000..cd66ef69
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted@2x.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/+testselector/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/+testselector/appointment-new.png
new file mode 100644
index 00000000..f380ebb6
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/+testselector/appointment-new.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/appointment-new.png
new file mode 100644
index 00000000..63ae9ce7
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/appointment-new.png
Binary files differ
diff --git a/tests/auto/qquickiconimage/icons/testtheme/appointment-new.svg b/tests/auto/qquickiconimage/icons/testtheme/appointment-new.svg
new file mode 100644
index 00000000..4cb14f82
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/appointment-new.svg
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="90.000000"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+ width="48px"
+ height="48px"
+ id="svg11300"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions"
+ sodipodi:docname="appointment-new.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective59" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5204">
+ <stop
+ style="stop-color:#c4a000;stop-opacity:1;"
+ offset="0"
+ id="stop5206" />
+ <stop
+ style="stop-color:#c4a000;stop-opacity:0;"
+ offset="1"
+ id="stop5208" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5196">
+ <stop
+ style="stop-color:#c4a000;stop-opacity:1;"
+ offset="0"
+ id="stop5198" />
+ <stop
+ style="stop-color:#c4a000;stop-opacity:0;"
+ offset="1"
+ id="stop5200" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient12512">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop12513" />
+ <stop
+ style="stop-color:#fff520;stop-opacity:0.89108908;"
+ offset="0.50000000"
+ id="stop12517" />
+ <stop
+ style="stop-color:#fff300;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop12514" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient12512"
+ id="radialGradient278"
+ gradientUnits="userSpaceOnUse"
+ cx="55.000000"
+ cy="125.00000"
+ fx="55.000000"
+ fy="125.00000"
+ r="14.375000" />
+ <linearGradient
+ id="linearGradient10653">
+ <stop
+ style="stop-color:#f3f4ff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop10655" />
+ <stop
+ style="stop-color:#9193af;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop10657" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient42174">
+ <stop
+ style="stop-color:#a0a0a0;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop42176" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop42178" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2145">
+ <stop
+ style="stop-color:#fffffd;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2147" />
+ <stop
+ style="stop-color:#cbcbc9;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2149" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient37935">
+ <stop
+ id="stop37937"
+ offset="0.0000000"
+ style="stop-color:#9497b3;stop-opacity:1.0000000;" />
+ <stop
+ id="stop37939"
+ offset="1.0000000"
+ style="stop-color:#4c4059;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2152">
+ <stop
+ id="stop2154"
+ offset="0.0000000"
+ style="stop-color:#9aa29a;stop-opacity:1.0000000;" />
+ <stop
+ id="stop2156"
+ offset="1.0000000"
+ style="stop-color:#b5beb5;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3816">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3818" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3820" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3816"
+ id="radialGradient3822"
+ cx="31.112698"
+ cy="19.008621"
+ fx="31.112698"
+ fy="19.008621"
+ r="8.6620579"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2152"
+ id="linearGradient4307"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.123841,0.000000,0.000000,0.969691,-31.88758,-19.59492)"
+ x1="8.9156475"
+ y1="37.197018"
+ x2="9.8855033"
+ y2="52.090678" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient10653"
+ id="radialGradient4309"
+ gradientUnits="userSpaceOnUse"
+ cx="11.329200"
+ cy="10.583970"
+ fx="11.329200"
+ fy="10.583970"
+ r="15.532059" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2145"
+ id="radialGradient4311"
+ gradientUnits="userSpaceOnUse"
+ cx="11.901996"
+ cy="10.045444"
+ fx="11.901996"
+ fy="10.045444"
+ r="29.292715" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient42174"
+ id="linearGradient4313"
+ gradientUnits="userSpaceOnUse"
+ x1="6.3422160"
+ y1="7.7893324"
+ x2="22.218424"
+ y2="25.884274" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5196"
+ id="radialGradient5202"
+ cx="23.375"
+ cy="10.972863"
+ fx="23.375"
+ fy="10.972863"
+ r="3.3478092"
+ gradientTransform="matrix(3.630420,1.654030e-15,-1.608743e-15,3.742066,-61.48607,-29.18618)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5204"
+ id="linearGradient5210"
+ x1="19.667364"
+ y1="4.2570662"
+ x2="20.329933"
+ y2="5.2845874"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient37935"
+ id="radialGradient5212"
+ gradientUnits="userSpaceOnUse"
+ cx="8.7468252"
+ cy="6.8283234"
+ fx="8.7468252"
+ fy="6.8283234"
+ r="29.889715" />
+ </defs>
+ <sodipodi:namedview
+ stroke="#c4a000"
+ fill="#babdb6"
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.313708"
+ inkscape:cx="13.2248"
+ inkscape:cy="25.106052"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:showpageshadow="false"
+ inkscape:window-width="833"
+ inkscape:window-height="772"
+ inkscape:window-x="305"
+ inkscape:window-y="76" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://jimmac.musichall.cz</dc:source>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ <dc:title>New Appointment</dc:title>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>appointment</rdf:li>
+ <rdf:li>new</rdf:li>
+ <rdf:li>meeting</rdf:li>
+ <rdf:li>rvsp</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <path
+ d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z"
+ sodipodi:ry="8.6620579"
+ sodipodi:rx="8.6620579"
+ sodipodi:cy="19.008621"
+ sodipodi:cx="31.112698"
+ id="path4318"
+ style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ sodipodi:type="arc"
+ transform="matrix(2.563158,0.000000,0.000000,1.219602,-55.98414,14.04144)" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path14341"
+ d="M 18.587591,1.403729 L 4.226755,18.096665 L 5.4854717,19.339844 L 18.587591,1.403729 z "
+ style="color:#000000;fill:url(#linearGradient4307);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path18921"
+ d="M 18.467176,1.3138035 L 5.6605716,19.072612 L 7.4900985,20.687913 L 18.467176,1.3138035 z "
+ style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ transform="matrix(1.431529,0.000000,0.000000,1.431529,0.569459,-1.654618)"
+ d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
+ sodipodi:ry="14.910714"
+ sodipodi:rx="14.910714"
+ sodipodi:cy="16.910715"
+ sodipodi:cx="16.25"
+ id="path27786"
+ style="fill:url(#radialGradient5212);fill-opacity:1;fill-rule:evenodd;stroke:#605773;stroke-width:0.69855404;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(1.163838,0.000000,0.000000,1.163838,4.824801,2.777556)"
+ d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
+ sodipodi:ry="14.910714"
+ sodipodi:rx="14.910714"
+ sodipodi:cy="16.910715"
+ sodipodi:cx="16.25"
+ id="path35549"
+ style="fill:url(#radialGradient4311);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4313);stroke-width:0.71139598;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;color:#000000;fill:url(#radialGradient5202);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5210);stroke-width:0.56498736;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path4120"
+ sodipodi:cx="23.375"
+ sodipodi:cy="11.875"
+ sodipodi:rx="8.5"
+ sodipodi:ry="8.5"
+ d="M 16.679382,6.6387137 A 8.5,8.5 0 0 1 23.332691,3.3751053 L 23.375,11.875 z"
+ transform="matrix(1.769951,0.000000,0.000000,1.769951,-17.02424,1.610741)"
+ sodipodi:start="3.8052902"
+ sodipodi:end="4.7074114" />
+ <path
+ transform="matrix(2.073295,0.000000,0.000000,2.073295,-7.310224,-13.13682)"
+ d="M 16.40625 17.28125 A 1.21875 1.21875 0 1 1 13.96875,17.28125 A 1.21875 1.21875 0 1 1 16.40625 17.28125 z"
+ sodipodi:ry="1.21875"
+ sodipodi:rx="1.21875"
+ sodipodi:cy="17.28125"
+ sodipodi:cx="15.1875"
+ id="path34778"
+ style="fill:#f3f3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.48232403;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;stroke-dasharray:none"
+ sodipodi:type="arc" />
+ <path
+ id="path35559"
+ d="M 22.176614,20.718014 L 13.155702,13.140282"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ id="path35561"
+ d="M 19.408614,29.776506 L 22.368655,25.283228"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ sodipodi:nodetypes="cc" />
+ <path
+ transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,-12.40939)"
+ d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
+ sodipodi:ry="0.61871845"
+ sodipodi:rx="0.61871845"
+ sodipodi:cy="7.6932044"
+ sodipodi:cx="16.705399"
+ id="path35563"
+ style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,14.80922)"
+ d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
+ sodipodi:ry="0.61871845"
+ sodipodi:rx="0.61871845"
+ sodipodi:cy="7.6932044"
+ sodipodi:cx="16.705399"
+ id="path35565"
+ style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(2.749493,0.000000,0.000000,2.749493,-35.91004,1.199890)"
+ d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
+ sodipodi:ry="0.61871845"
+ sodipodi:rx="0.61871845"
+ sodipodi:cy="7.6932044"
+ sodipodi:cx="16.705399"
+ id="path35567"
+ style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(2.749493,0.000000,0.000000,2.749493,-8.691448,1.199890)"
+ d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z"
+ sodipodi:ry="0.61871845"
+ sodipodi:rx="0.61871845"
+ sodipodi:cy="7.6932044"
+ sodipodi:cx="16.705399"
+ id="path35569"
+ style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient4309);stroke-width:0.73656511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
+ id="path10651"
+ sodipodi:cx="16.25"
+ sodipodi:cy="16.910715"
+ sodipodi:rx="14.910714"
+ sodipodi:ry="14.910714"
+ d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z"
+ transform="matrix(1.357654,0.000000,0.000000,1.357654,1.769896,-0.493735)" />
+ <path
+ sodipodi:type="arc"
+ style="color:#000000;fill:url(#radialGradient278);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block"
+ id="path12511"
+ sodipodi:cx="55"
+ sodipodi:cy="125"
+ sodipodi:rx="14.375"
+ sodipodi:ry="14.375"
+ d="M 69.375 125 A 14.375 14.375 0 1 1 40.625,125 A 14.375 14.375 0 1 1 69.375 125 z"
+ transform="matrix(0.611127,0.000000,0.000000,0.611127,5.544052,-66.92818)"
+ inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png"
+ inkscape:export-xdpi="33.852203"
+ inkscape:export-ydpi="33.852203" />
+ </g>
+</svg>
diff --git a/tests/auto/qquickiconimage/icons/testtheme/index.theme b/tests/auto/qquickiconimage/icons/testtheme/index.theme
new file mode 100644
index 00000000..6ab6c15c
--- /dev/null
+++ b/tests/auto/qquickiconimage/icons/testtheme/index.theme
@@ -0,0 +1,21 @@
+[Icon Theme]
+Name=Test
+Comment=Test Theme
+
+Directories=16x16/actions,22x22/actions,22x22@2/actions
+
+[16x16/actions]
+Size=16
+Context=Actions
+Type=Fixed
+
+[22x22/actions]
+Size=22
+Context=Actions
+Type=Fixed
+
+[22x22@2/actions]
+Size=22
+Context=Actions
+Scale=2
+Type=Fixed
diff --git a/tests/auto/qquickiconimage/qquickiconimage.pro b/tests/auto/qquickiconimage/qquickiconimage.pro
new file mode 100644
index 00000000..1a37d4ba
--- /dev/null
+++ b/tests/auto/qquickiconimage/qquickiconimage.pro
@@ -0,0 +1,17 @@
+CONFIG += testcase
+macos:CONFIG -= app_bundle
+TARGET = tst_qquickiconimage
+
+QT += core gui qml quick testlib
+QT_PRIVATE += quick-private quickcontrols2-private
+qtHaveModule(svg): QT += svg
+
+include (../shared/util.pri)
+
+SOURCES += tst_qquickiconimage.cpp
+
+RESOURCES += resources.qrc
+
+TESTDATA += \
+ $$PWD/data/*.qml \
+ $$PWD/data/icons/*
diff --git a/tests/auto/qquickiconimage/resources.qrc b/tests/auto/qquickiconimage/resources.qrc
new file mode 100644
index 00000000..6558b039
--- /dev/null
+++ b/tests/auto/qquickiconimage/resources.qrc
@@ -0,0 +1,17 @@
+<RCC>
+ <qresource prefix="/">
+ <file>icons/testtheme/16x16/actions/appointment-new.png</file>
+ <file>icons/testtheme/22x22/actions/appointment-new.png</file>
+ <file>icons/testtheme/22x22/actions/appointment-new@2x.png</file>
+ <file>icons/testtheme/22x22@2/actions/appointment-new.png</file>
+ <file>icons/testtheme/22x22/actions/+testselector/appointment-new.png</file>
+ <file>icons/testtheme/22x22/actions/+testselector/appointment-new@2x.png</file>
+ <file>icons/testtheme/22x22@2/actions/+testselector/appointment-new.png</file>
+ <file>icons/testtheme/index.theme</file>
+ <file>icons/testtheme/appointment-new.svg</file>
+ <file>icons/testtheme/22x22/actions/color-test-original.png</file>
+ <file>icons/testtheme/22x22/actions/color-test-tinted.png</file>
+ <file>icons/testtheme/22x22/actions/color-test-original@2x.png</file>
+ <file>icons/testtheme/22x22/actions/color-test-tinted@2x.png</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qquickiconimage/tst_qquickiconimage.cpp b/tests/auto/qquickiconimage/tst_qquickiconimage.cpp
new file mode 100644
index 00000000..4e4afb13
--- /dev/null
+++ b/tests/auto/qquickiconimage/tst_qquickiconimage.cpp
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QtTest/qsignalspy.h>
+
+#include <QtCore/qmath.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlfileselector.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/qquickitemgrabresult.h>
+#include <QtQuick/private/qquickimage_p.h>
+#include <QtQuickControls2/private/qquickiconimage_p.h>
+
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_qquickiconimage : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquickiconimage();
+
+private slots:
+ void initTestCase();
+ void defaults();
+ void nameBindingSourceSize();
+ void nameBindingSourceSizeWidthHeight();
+ void nameBindingNoSizes();
+ void sourceBindingNoSizes();
+ void sourceBindingSourceSize();
+ void sourceBindingSourceSizeWidthHeight();
+ void sourceBindingSourceTooLarge();
+ void changeSourceSize();
+ void alignment_data();
+ void alignment();
+ void svgNoSizes();
+ void svgSourceBindingSourceSize();
+ void color();
+ void fileSelectors();
+
+private:
+ void setTheme();
+
+ qreal dpr;
+ int integerDpr;
+};
+
+static QImage grabItemToImage(QQuickItem *item)
+{
+ QSharedPointer<QQuickItemGrabResult> result = item->grabToImage();
+ QSignalSpy spy(result.data(), SIGNAL(ready()));
+ spy.wait();
+ return result->image();
+}
+
+#define SKIP_IF_DPR_TOO_HIGH() \
+ if (dpr > 2) \
+ QSKIP("Test does not support device pixel ratio greater than 2")
+
+tst_qquickiconimage::tst_qquickiconimage() :
+ dpr(qGuiApp->devicePixelRatio()),
+ integerDpr(qCeil(dpr))
+{
+}
+
+void tst_qquickiconimage::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ QIcon::setThemeName(QStringLiteral("testtheme"));
+}
+
+void tst_qquickiconimage::defaults()
+{
+ QQuickIconImage iconImage;
+ QCOMPARE(iconImage.fillMode(), QQuickImage::Pad);
+ QCOMPARE(iconImage.name(), QString());
+ QCOMPARE(iconImage.source(), QUrl());
+ QCOMPARE(iconImage.color(), QColor(Qt::transparent));
+}
+
+void tst_qquickiconimage::nameBindingSourceSize()
+{
+ // We can't have images for every DPR.
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("nameBindingSourceSize.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickItem *image = view.rootObject()->childItems().at(1);
+ QVERIFY(image);
+
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 22.0);
+ QCOMPARE(iconImage->height(), 22.0);
+
+ // The requested width of 16 is less than the pixmap's size on disk which
+ // is 22x22. Our default fillMode, Pad, would result in the image being clipped,
+ // so instead we change the fillMode to PreserveAspectFit. Doing so causes
+ // QQuickImage::updatePaintedGeometry() to set our implicit size to 22x16 to
+ // ensure that the aspect ratio is respected. Since we have no explicit height,
+ // the height (previously 22) becomes the implicit height (16).
+ iconImage->setWidth(16.0);
+ QCOMPARE(iconImage->fillMode(), QQuickImage::PreserveAspectFit);
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 16.0);
+ QCOMPARE(iconImage->width(), 16.0);
+ QCOMPARE(iconImage->height(), 16.0);
+}
+
+void tst_qquickiconimage::nameBindingSourceSizeWidthHeight()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("nameBindingSourceSizeWidthHeight.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject());
+ QVERIFY(iconImage);
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 16.0);
+ QCOMPARE(iconImage->height(), 16.0);
+}
+
+void tst_qquickiconimage::nameBindingNoSizes()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("nameBindingNoSizes.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject());
+ QVERIFY(iconImage);
+ // The smallest available size will be chosen.
+ QCOMPARE(iconImage->sourceSize().width(), 16);
+ QCOMPARE(iconImage->sourceSize().height(), 16);
+ QCOMPARE(iconImage->implicitWidth(), 16.0);
+ QCOMPARE(iconImage->implicitHeight(), 16.0);
+ QCOMPARE(iconImage->width(), 16.0);
+ QCOMPARE(iconImage->height(), 16.0);
+}
+
+void tst_qquickiconimage::sourceBindingNoSizes()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("sourceBindingNoSizes.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickItem *image = view.rootObject()->childItems().at(1);
+ QVERIFY(image);
+
+ QCOMPARE(iconImage->sourceSize().width(), 22 * integerDpr);
+ QCOMPARE(iconImage->sourceSize().height(), 22 * integerDpr);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 22.0);
+ QCOMPARE(iconImage->height(), 22.0);
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+}
+
+void tst_qquickiconimage::sourceBindingSourceSize()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("sourceBindingSourceSize.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickItem *image = view.rootObject()->childItems().at(1);
+ QVERIFY(image);
+
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 22.0);
+ QCOMPARE(iconImage->height(), 22.0);
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+
+ // Changing width and height should not affect sourceSize.
+ iconImage->setWidth(50);
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ iconImage->setHeight(50);
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+}
+
+void tst_qquickiconimage::sourceBindingSourceSizeWidthHeight()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("sourceBindingSourceSizeWidthHeight.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject());
+ QVERIFY(iconImage);
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 16.0);
+ QCOMPARE(iconImage->height(), 16.0);
+}
+
+void tst_qquickiconimage::sourceBindingSourceTooLarge()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("sourceBindingSourceTooLarge.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject());
+ QVERIFY(iconImage);
+ QCOMPARE(iconImage->sourceSize().width(), 32);
+ QCOMPARE(iconImage->sourceSize().height(), 32);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 22.0);
+ QCOMPARE(iconImage->height(), 22.0);
+}
+
+void tst_qquickiconimage::alignment_data()
+{
+ QTest::addColumn<QQuickImage::HAlignment>("horizontalAlignment");
+ QTest::addColumn<QQuickImage::VAlignment>("verticalAlignment");
+
+ QTest::newRow("AlignLeft,AlignTop") << QQuickImage::AlignLeft << QQuickImage::AlignTop;
+ QTest::newRow("AlignLeft,AlignVCenter") << QQuickImage::AlignLeft << QQuickImage::AlignVCenter;
+ QTest::newRow("AlignLeft,AlignBottom") << QQuickImage::AlignLeft << QQuickImage::AlignBottom;
+ QTest::newRow("AlignHCenter,AlignTop") << QQuickImage::AlignHCenter << QQuickImage::AlignTop;
+ QTest::newRow("AlignHCenter,AlignVCenter") << QQuickImage::AlignHCenter << QQuickImage::AlignVCenter;
+ QTest::newRow("AlignHCenter,AlignBottom") << QQuickImage::AlignHCenter << QQuickImage::AlignBottom;
+ QTest::newRow("AlignRight,AlignTop") << QQuickImage::AlignRight << QQuickImage::AlignTop;
+ QTest::newRow("AlignRight,AlignVCenter") << QQuickImage::AlignRight << QQuickImage::AlignVCenter;
+ QTest::newRow("AlignRight,AlignBottom") << QQuickImage::AlignRight << QQuickImage::AlignBottom;
+}
+
+void tst_qquickiconimage::alignment()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QFETCH(QQuickImage::HAlignment, horizontalAlignment);
+ QFETCH(QQuickImage::VAlignment, verticalAlignment);
+
+ QQuickView view(testFileUrl("alignment.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject()->childItems().at(1));
+ QVERIFY(image);
+
+ // The default fillMode for IconImage is Image::Pad, so these two grabs
+ // should only be equal when the device pixel ratio is 1 or 2, as there is no
+ // @3x version of the image, and hence the Image will be upscaled
+ // and therefore blurry when the ratio is higher than 2.
+ if (qGuiApp->devicePixelRatio() <= 2)
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+ else
+ QVERIFY(grabItemToImage(iconImage) != grabItemToImage(image));
+
+ // Check that the images are what we expect in different alignment configurations.
+ iconImage->setWidth(200);
+ iconImage->setHeight(100);
+ iconImage->setHorizontalAlignment(horizontalAlignment);
+ iconImage->setVerticalAlignment(verticalAlignment);
+ iconImage->setFillMode(QQuickImage::Pad);
+ image->setWidth(200);
+ image->setHeight(100);
+ image->setHorizontalAlignment(horizontalAlignment);
+ image->setVerticalAlignment(verticalAlignment);
+ image->setFillMode(QQuickImage::Pad);
+
+ if (qGuiApp->devicePixelRatio() <= 2)
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+ else
+ QVERIFY(grabItemToImage(iconImage) != grabItemToImage(image));
+}
+
+void tst_qquickiconimage::svgNoSizes()
+{
+#ifndef QT_SVG_LIB
+ QSKIP("This test requires qtsvg");
+#else
+ QQuickView view(testFileUrl("svgNoSizes.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject()->childItems().at(1));
+ QVERIFY(image);
+
+ QCOMPARE(iconImage->sourceSize().width(), 48);
+ QCOMPARE(iconImage->sourceSize().height(), 48);
+ QCOMPARE(iconImage->implicitWidth(), 48.0);
+ QCOMPARE(iconImage->implicitHeight(), 48.0);
+ QCOMPARE(iconImage->width(), 48.0);
+ QCOMPARE(iconImage->height(), 48.0);
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+#endif
+}
+
+void tst_qquickiconimage::svgSourceBindingSourceSize()
+{
+#ifndef QT_SVG_LIB
+ QSKIP("This test requires qtsvg");
+#else
+ QQuickView view(testFileUrl("alignment.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject()->childItems().at(1));
+ QVERIFY(image);
+
+ QCOMPARE(iconImage->sourceSize().width(), 22);
+ QCOMPARE(iconImage->sourceSize().height(), 22);
+ QCOMPARE(iconImage->implicitWidth(), 22.0);
+ QCOMPARE(iconImage->implicitHeight(), 22.0);
+ QCOMPARE(iconImage->width(), 22.0);
+ QCOMPARE(iconImage->height(), 22.0);
+ QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
+#endif
+}
+
+void tst_qquickiconimage::color()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view(testFileUrl("color.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject()->childItems().at(1));
+ QVERIFY(image);
+
+ QImage iconImageWindowGrab = grabItemToImage(iconImage);
+ QCOMPARE(iconImageWindowGrab, grabItemToImage(image));
+
+ // Transparent pixels should remain transparent.
+ QCOMPARE(iconImageWindowGrab.pixelColor(0, 0), QColor(0, 0, 0, 0));
+
+ // Set a color after component completion.
+ iconImage->setColor(QColor(Qt::green));
+ iconImageWindowGrab = grabItemToImage(iconImage);
+ const QPoint centerPixelPos(11, 11);
+ QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos), QColor(Qt::green));
+
+ // Set a semi-transparent color after component completion.
+ iconImage->setColor(QColor(0, 0, 255, 127));
+ iconImageWindowGrab = grabItemToImage(iconImage);
+ QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).red(), 0);
+ QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).green(), 0);
+ QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).blue(), 255);
+ QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).alpha(), 127);
+}
+
+void tst_qquickiconimage::changeSourceSize()
+{
+ QQuickView view(testFileUrl("sourceBindingSourceSize.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ // Ensure that there isn't any infinite recursion when trying to change the sourceSize.
+ QSize sourceSize = iconImage->sourceSize();
+ sourceSize.setWidth(sourceSize.width() - 1);
+ iconImage->setSourceSize(sourceSize);
+}
+
+
+void tst_qquickiconimage::fileSelectors()
+{
+ SKIP_IF_DPR_TOO_HIGH();
+
+ QQuickView view;
+ QQmlFileSelector* fileSelector = new QQmlFileSelector(view.engine());
+ fileSelector->setExtraSelectors(QStringList() << "testselector");
+ view.setSource(testFileUrl("fileSelectors.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(view.rootObject()->childItems().at(0));
+ QVERIFY(iconImage);
+
+ QQuickItem *image = view.rootObject()->childItems().at(1);
+ QVERIFY(image);
+
+ QImage iconImageWindowGrab = grabItemToImage(iconImage);
+ QCOMPARE(iconImageWindowGrab, grabItemToImage(image));
+
+ QCOMPARE(iconImageWindowGrab.pixelColor(iconImageWindowGrab.width() / 2, iconImageWindowGrab.height() / 2), QColor(Qt::blue));
+}
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+ QGuiApplication app(argc, argv);
+ Q_UNUSED(app);
+ tst_qquickiconimage test;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&test, argc, argv);
+}
+
+#include "tst_qquickiconimage.moc"
diff --git a/tests/auto/qquickiconlabel/data/colorChanges.qml b/tests/auto/qquickiconlabel/data/colorChanges.qml
new file mode 100644
index 00000000..6fc579f8
--- /dev/null
+++ b/tests/auto/qquickiconlabel/data/colorChanges.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+AbstractButton {
+ id: button
+ width: 200
+ height: 200
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png"
+ icon.color: enabled ? "transparent" : "red"
+
+ IconLabel {
+ icon: button.icon
+ text: button.text
+ }
+}
diff --git a/tests/auto/qquickiconlabel/data/iconlabel.qml b/tests/auto/qquickiconlabel/data/iconlabel.qml
new file mode 100644
index 00000000..97042107
--- /dev/null
+++ b/tests/auto/qquickiconlabel/data/iconlabel.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+AbstractButton {
+ id: button
+ width: 200
+ height: 200
+ text: "Some text"
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png"
+
+ IconLabel {
+ icon: button.icon
+ text: button.text
+ }
+}
diff --git a/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml b/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml
new file mode 100644
index 00000000..ccdb74e2
--- /dev/null
+++ b/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+AbstractButton {
+ id: button
+ width: 200
+ height: 200
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png"
+
+ IconLabel {
+ spacing: 10
+ mirrored: true
+ icon: button.icon
+ }
+}
diff --git a/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml b/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml
new file mode 100644
index 00000000..9015aa9d
--- /dev/null
+++ b/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Item {
+ width: 200
+ height: 200
+
+ IconLabel {
+ spacing: 10
+ text: "Some text"
+ }
+}
diff --git a/tests/auto/qquickiconlabel/qquickiconlabel.pro b/tests/auto/qquickiconlabel/qquickiconlabel.pro
new file mode 100644
index 00000000..6b0f73b3
--- /dev/null
+++ b/tests/auto/qquickiconlabel/qquickiconlabel.pro
@@ -0,0 +1,13 @@
+CONFIG += testcase
+macos:CONFIG -= app_bundle
+TARGET = tst_qquickiconlabel
+
+QT += core gui qml quick testlib
+QT_PRIVATE += quick-private quickcontrols2-private
+
+include (../shared/util.pri)
+
+SOURCES += tst_qquickiconlabel.cpp
+
+TESTDATA += \
+ $$PWD/data/*.qml
diff --git a/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp b/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp
new file mode 100644
index 00000000..a251b471
--- /dev/null
+++ b/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp
@@ -0,0 +1,326 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qvector.h>
+
+#include <qtest.h>
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/qquickitemgrabresult.h>
+#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+#include <QtQuickControls2/private/qquickiconimage_p.h>
+#include <QtQuickControls2/private/qquickiconlabel_p.h>
+
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_qquickiconlabel : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquickiconlabel();
+
+private slots:
+ void display_data();
+ void display();
+ void spacingWithOneDelegate_data();
+ void spacingWithOneDelegate();
+ void emptyIconSource();
+ void colorChanges();
+};
+
+tst_qquickiconlabel::tst_qquickiconlabel()
+{
+}
+
+void tst_qquickiconlabel::display_data()
+{
+ QTest::addColumn<QVector<QQuickIconLabel::Display> >("displayTypes");
+ QTest::addColumn<bool>("mirrored");
+ QTest::addColumn<qreal>("labelWidth");
+ QTest::addColumn<qreal>("labelHeight");
+ QTest::addColumn<qreal>("spacing");
+
+ typedef QVector<QQuickIconLabel::Display> DisplayVector;
+ QQuickIconLabel::Display IconOnly = QQuickIconLabel::IconOnly;
+ QQuickIconLabel::Display TextOnly = QQuickIconLabel::TextOnly;
+ QQuickIconLabel::Display TextUnderIcon = QQuickIconLabel::TextUnderIcon;
+ QQuickIconLabel::Display TextBesideIcon = QQuickIconLabel::TextBesideIcon;
+
+ QTest::addRow("IconOnly") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextOnly") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon") << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("TextBesideIcon") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("IconOnly, spacing=10") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("TextOnly, spacing=10") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("TextUnderIcon, spacing=10") << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon => IconOnly => TextUnderIcon")
+ << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon => IconOnly => TextUnderIcon, labelWidth=400")
+ << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon => TextOnly => TextUnderIcon")
+ << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon => TextOnly => TextUnderIcon, labelWidth=400")
+ << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon, spacing=10") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon")
+ << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon, labelWidth=400")
+ << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon")
+ << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon, labelWidth=400")
+ << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("IconOnly, mirrored") << (DisplayVector() << IconOnly) << true << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextOnly, mirrored") << (DisplayVector() << TextOnly) << true << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextUnderIcon, mirrored") << (DisplayVector() << TextUnderIcon) << true << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon, mirrored") << (DisplayVector() << TextBesideIcon) << true << -1.0 << -1.0 << 0.0;
+}
+
+void tst_qquickiconlabel::display()
+{
+ QFETCH(QVector<QQuickIconLabel::Display>, displayTypes);
+ QFETCH(bool, mirrored);
+ QFETCH(qreal, labelWidth);
+ QFETCH(qreal, labelHeight);
+ QFETCH(qreal, spacing);
+
+ QQuickView view(testFileUrl("iconlabel.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>();
+ QVERIFY(label);
+ QCOMPARE(label->spacing(), 0.0);
+ QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon);
+ QCOMPARE(label->isMirrored(), false);
+
+ // Setting labelWidth allows us to test the issue where the icon's
+ // width was not updated after switching between different display types.
+ if (!qFuzzyCompare(labelWidth, -1)) {
+ label->setWidth(labelWidth);
+ QCOMPARE(label->width(), labelWidth);
+ }
+ if (!qFuzzyCompare(labelHeight, -1)) {
+ label->setHeight(labelHeight);
+ QCOMPARE(label->height(), labelHeight);
+ }
+
+ label->setMirrored(mirrored);
+ QCOMPARE(label->isMirrored(), mirrored);
+
+ label->setSpacing(spacing);
+ QCOMPARE(label->spacing(), spacing);
+
+ const qreal horizontalPadding = label->leftPadding() + label->rightPadding();
+ const qreal verticalPadding = label->topPadding() + label->bottomPadding();
+
+ // Test that the icon and text are correctly positioned and sized after
+ // setting several different display types in succession.
+ for (QQuickIconLabel::Display displayType : qAsConst(displayTypes)) {
+ label->setDisplay(displayType);
+ QCOMPARE(label->display(), displayType);
+
+ QQuickIconImage *icon = label->findChild<QQuickIconImage *>();
+ QQuickText *text = label->findChild<QQuickText *>();
+
+ const qreal horizontalCenter = label->width() / 2;
+ const qreal verticalCenter = label->height() / 2;
+
+ switch (displayType) {
+ case QQuickIconLabel::IconOnly:
+ QVERIFY(icon);
+ QVERIFY(!text);
+ QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2);
+ QCOMPARE(icon->y(), verticalCenter - icon->height() / 2);
+ QCOMPARE(icon->width(), icon->implicitWidth());
+ QCOMPARE(icon->height(), icon->implicitHeight());
+ QCOMPARE(label->implicitWidth(), icon->implicitWidth() + horizontalPadding);
+ QCOMPARE(label->implicitHeight(), icon->implicitHeight() + verticalPadding);
+ break;
+ case QQuickIconLabel::TextOnly:
+ QVERIFY(!icon);
+ QVERIFY(text);
+ QCOMPARE(text->x(), horizontalCenter - text->width() / 2);
+ QCOMPARE(text->y(), verticalCenter - text->height() / 2);
+ QCOMPARE(text->width(), text->implicitWidth());
+ QCOMPARE(text->height(), text->implicitHeight());
+ QCOMPARE(label->implicitWidth(), text->implicitWidth() + horizontalPadding);
+ QCOMPARE(label->implicitHeight(), text->implicitHeight() + verticalPadding);
+ break;
+ case QQuickIconLabel::TextUnderIcon: {
+ QVERIFY(icon);
+ QVERIFY(text);
+ const qreal combinedHeight = icon->height() + label->spacing() + text->height();
+ const qreal contentY = verticalCenter - combinedHeight / 2;
+ QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2);
+ QCOMPARE(icon->y(), contentY);
+ QCOMPARE(icon->width(), icon->implicitWidth());
+ QCOMPARE(icon->height(), icon->implicitHeight());
+ QCOMPARE(text->x(), horizontalCenter - text->width() / 2);
+ QCOMPARE(text->y(), contentY + icon->height() + label->spacing());
+ QCOMPARE(text->width(), text->implicitWidth());
+ QCOMPARE(text->height(), text->implicitHeight());
+ QCOMPARE(label->implicitWidth(), qMax(icon->implicitWidth(), text->implicitWidth()) + horizontalPadding);
+ QCOMPARE(label->implicitHeight(), combinedHeight + verticalPadding);
+ break;
+ }
+ case QQuickIconLabel::TextBesideIcon:
+ default:
+ QVERIFY(icon);
+ QVERIFY(text);
+ const qreal combinedWidth = icon->width() + label->spacing() + text->width();
+ const qreal contentX = horizontalCenter - combinedWidth / 2;
+ QCOMPARE(icon->x(), contentX + (label->isMirrored() ? text->width() + label->spacing() : 0));
+ QCOMPARE(icon->y(), verticalCenter - icon->height() / 2);
+ QCOMPARE(icon->width(), icon->implicitWidth());
+ QCOMPARE(icon->height(), icon->implicitHeight());
+ QCOMPARE(text->x(), contentX + (label->isMirrored() ? 0 : icon->width() + label->spacing()));
+ QCOMPARE(text->y(), verticalCenter - text->height() / 2);
+ QCOMPARE(text->width(), text->implicitWidth());
+ QCOMPARE(text->height(), text->implicitHeight());
+ QCOMPARE(label->implicitWidth(), combinedWidth + horizontalPadding);
+ QCOMPARE(label->implicitHeight(), qMax(icon->implicitHeight(), text->implicitHeight()) + verticalPadding);
+ break;
+ }
+ }
+}
+
+void tst_qquickiconlabel::spacingWithOneDelegate_data()
+{
+ QTest::addColumn<QString>("qmlFileName");
+
+ QTest::addRow("spacingWithOnlyIcon") << QStringLiteral("spacingWithOnlyIcon.qml");
+ QTest::addRow("spacingWithOnlyText") << QStringLiteral("spacingWithOnlyText.qml");
+}
+
+void tst_qquickiconlabel::spacingWithOneDelegate()
+{
+ QFETCH(QString, qmlFileName);
+
+ QQuickView view(testFileUrl(qmlFileName));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>();
+ QVERIFY(label);
+ QQuickItem *delegate = nullptr;
+ if (!label->icon().isEmpty()) {
+ QVERIFY(!label->findChild<QQuickText *>());
+ delegate = label->findChild<QQuickIconImage *>();
+ } else {
+ QVERIFY(!label->findChild<QQuickIconImage *>());
+ delegate = label->findChild<QQuickText *>();
+ }
+
+ QVERIFY(delegate);
+ QCOMPARE(delegate->x(), 0.0);
+ QCOMPARE(delegate->width(), label->width());
+}
+
+void tst_qquickiconlabel::emptyIconSource()
+{
+ QQuickView view(testFileUrl("iconlabel.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>();
+ QVERIFY(label);
+ QCOMPARE(label->spacing(), 0.0);
+ QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon);
+ QCOMPARE(label->isMirrored(), false);
+
+ QQuickItem *icon = label->findChild<QQuickIconImage *>();
+ QVERIFY(icon);
+
+ QQuickItem *text = label->findChild<QQuickText *>();
+ QVERIFY(text);
+ qreal horizontalCenter = label->width() / 2;
+ const qreal combinedWidth = icon->width() + text->width();
+ const qreal contentX = horizontalCenter - combinedWidth / 2;
+ // The text should be positioned next to an item.
+ QCOMPARE(text->x(), contentX + icon->width() + label->spacing());
+
+ // Now give the label an explicit width large enough so that implicit size
+ // changes in its children don't affect its implicit size.
+ label->setWidth(label->implicitWidth() + 200);
+ label->setHeight(label->implicitWidth() + 100);
+ QVERIFY(icon->property("source").isValid());
+ label->setIcon(QQuickIcon());
+ QVERIFY(!label->findChild<QQuickIconImage *>());
+ horizontalCenter = label->width() / 2;
+ QCOMPARE(text->x(), horizontalCenter - text->width() / 2);
+}
+
+void tst_qquickiconlabel::colorChanges()
+{
+ QQuickView view(testFileUrl("colorChanges.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>();
+ QVERIFY(label);
+ QCOMPARE(label->spacing(), 0.0);
+ QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon);
+ QCOMPARE(label->isMirrored(), false);
+
+ QSharedPointer<QQuickItemGrabResult> grabResult = label->grabToImage();
+ QTRY_VERIFY(!grabResult->image().isNull());
+ const QImage enabledImageGrab = grabResult->image();
+
+ // The color should change to "red" when the item is disabled.
+ rootItem->setEnabled(false);
+
+ grabResult = label->grabToImage();
+ QTRY_VERIFY(!grabResult->image().isNull());
+ QVERIFY(grabResult->image() != enabledImageGrab);
+}
+
+QTEST_MAIN(tst_qquickiconlabel)
+
+#include "tst_qquickiconlabel.moc"
diff --git a/tests/auto/qquickimaginestyle/control-assets/button-background.9.png b/tests/auto/qquickimaginestyle/control-assets/button-background.9.png
new file mode 100644
index 00000000..29bd8d7c
--- /dev/null
+++ b/tests/auto/qquickimaginestyle/control-assets/button-background.9.png
Binary files differ
diff --git a/tests/auto/qquickimaginestyle/data/tst_imagine.qml b/tests/auto/qquickimaginestyle/data/tst_imagine.qml
new file mode 100644
index 00000000..7a711dcd
--- /dev/null
+++ b/tests/auto/qquickimaginestyle/data/tst_imagine.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.9
+import QtQuick.Window 2.2
+import QtTest 1.1
+import QtQuick.Templates 2.3 as T
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Imagine 2.3
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "Imagine"
+
+ Component {
+ id: implicitQrcButtonComponent
+ Button {
+ Imagine.path: ":/control-assets"
+ }
+ }
+
+ Component {
+ id: explicitQrcButtonComponent
+ Button {
+ Imagine.path: "qrc:/control-assets"
+ }
+ }
+
+ function test_qrcPaths_data() {
+ return [
+ { tag: ":/control-assets", component: implicitQrcButtonComponent },
+ { tag: "qrc:/control-assets", component: explicitQrcButtonComponent }
+ ]
+ }
+
+ function test_qrcPaths(data) {
+ if (Qt.platform.pluginName === "offscreen")
+ skip("grabImage() is not functional on the offscreen platform (QTBUG-63185)")
+
+ var control = createTemporaryObject(data.component, testCase)
+ verify(control)
+ compare(control.Imagine.path, data.tag)
+ var image = grabImage(control)
+ compare(image.pixel(control.width / 2, control.height / 2), "#ff0000")
+ }
+}
diff --git a/tests/auto/qquickimaginestyle/qquickimaginestyle.pro b/tests/auto/qquickimaginestyle/qquickimaginestyle.pro
new file mode 100644
index 00000000..c421f2dc
--- /dev/null
+++ b/tests/auto/qquickimaginestyle/qquickimaginestyle.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+TARGET = tst_qquickimaginestyle
+CONFIG += qmltestcase
+
+SOURCES += \
+ $$PWD/tst_qquickimaginestyle.cpp
+
+RESOURCES += \
+ $$PWD/qtquickcontrols2.conf \
+ $$PWD/control-assets/button-background.9.png
+
+OTHER_FILES += \
+ $$PWD/data/*.qml
+
+TESTDATA += \
+ $$PWD/data/tst_*
diff --git a/tests/auto/qquickimaginestyle/qtquickcontrols2.conf b/tests/auto/qquickimaginestyle/qtquickcontrols2.conf
new file mode 100644
index 00000000..add378d4
--- /dev/null
+++ b/tests/auto/qquickimaginestyle/qtquickcontrols2.conf
@@ -0,0 +1,2 @@
+[Controls]
+Style=Imagine
diff --git a/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp b/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp
new file mode 100644
index 00000000..cd08923a
--- /dev/null
+++ b/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(tst_qquickmaterialstyle)
diff --git a/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf
index 78634834..30cee878 100644
--- a/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf
+++ b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf
@@ -4,3 +4,7 @@ Style=Material
[Material]
Background=#444444
Foreground=Red
+Font\PixelSize=22
+
+[Material\Font]
+Family=Courier
diff --git a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp
index cc81afea..17d1ea6d 100644
--- a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp
+++ b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp
@@ -55,16 +55,22 @@ void tst_qquickmaterialstyleconf::conf()
{
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
+ QFont customFont;
+ customFont.setFamily("Courier");
+ customFont.setPixelSize(22);
+
QQuickApplicationWindow *window = helper.appWindow;
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
- // We specified a custom background color, so the window should have it.
+ // We specified a custom background color and font, so the window should have them.
QCOMPARE(window->property("color").value<QColor>(), QColor("#444444"));
+ QCOMPARE(window->property("font").value<QFont>(), customFont);
- // We specified a custom foreground color, so the label should have it.
+ // We specified a custom foreground color and font, so the label should have them.
QQuickItem *label = window->property("label").value<QQuickItem*>();
QVERIFY(label);
QCOMPARE(label->property("color").value<QColor>(), QColor("#F44336"));
+ QCOMPARE(label->property("font").value<QFont>(), customFont);
}
QTEST_MAIN(tst_qquickmaterialstyleconf)
diff --git a/tests/auto/qquickmenu/data/actions.qml b/tests/auto/qquickmenu/data/actions.qml
new file mode 100644
index 00000000..0ec9f36c
--- /dev/null
+++ b/tests/auto/qquickmenu/data/actions.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias menu: menu
+
+ Menu {
+ id: menu
+ Action { text: "action1" }
+ MenuItem { text: "menuitem2" }
+ Action { text: "action3" }
+ MenuItem { text: "menuitem4" }
+ }
+}
diff --git a/tests/auto/qquickmenu/data/mnemonics.qml b/tests/auto/qquickmenu/data/mnemonics.qml
new file mode 100644
index 00000000..de4cd215
--- /dev/null
+++ b/tests/auto/qquickmenu/data/mnemonics.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.6
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias menu: menu
+ property alias action: action
+ property alias menuItem: menuItem
+ property alias subMenu: subMenu
+ property alias subMenuItem: subMenuItem
+
+ Menu {
+ id: menu
+
+ Action {
+ id: action
+ text: "&Action"
+ }
+
+ MenuItem {
+ id: menuItem
+ text: "Menu &Item"
+ }
+
+ Menu {
+ id: subMenu
+ title: "Sub &Menu"
+
+ MenuItem {
+ id: subMenuItem
+ text: "&Sub Menu Item"
+ }
+ }
+ }
+}
diff --git a/tests/auto/qquickmenu/data/popup.qml b/tests/auto/qquickmenu/data/popup.qml
new file mode 100644
index 00000000..6040e8ba
--- /dev/null
+++ b/tests/auto/qquickmenu/data/popup.qml
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias menu: menu
+ property alias menuItem1: menuItem1
+ property alias menuItem2: menuItem2
+ property alias menuItem3: menuItem3
+ property alias button: button
+
+ function popupAtCursor() {
+ menu.popup()
+ }
+
+ function popupAtPos(pos) {
+ menu.popup(pos)
+ }
+
+ function popupAtCoord(x, y) {
+ menu.popup(x, y)
+ }
+
+ function popupItemAtCursor(item) {
+ menu.popup(item)
+ }
+
+ function popupItemAtPos(pos, item) {
+ menu.popup(pos, item)
+ }
+
+ function popupItemAtCoord(x, y, item) {
+ menu.popup(x, y, item)
+ }
+
+ function popupAtParentCursor(parent) {
+ menu.popup(parent)
+ }
+
+ function popupAtParentPos(parent, pos) {
+ menu.popup(parent, pos)
+ }
+
+ function popupAtParentCoord(parent, x, y) {
+ menu.popup(parent, x, y)
+ }
+
+ function popupItemAtParentCursor(parent, item) {
+ menu.popup(parent, item)
+ }
+
+ function popupItemAtParentPos(parent, pos, item) {
+ menu.popup(parent, pos, item)
+ }
+
+ function popupItemAtParentCoord(parent, x, y, item) {
+ menu.popup(parent, x, y, item)
+ }
+
+ Menu {
+ id: menu
+ MenuItem { id: menuItem1; text: "Foo" }
+ MenuItem { id: menuItem2; text: "Bar" }
+ MenuItem { id: menuItem3; text: "Baz" }
+ }
+
+ Button {
+ id: button
+ text: "Button"
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/qquickmenu/data/removeTakeItem.qml b/tests/auto/qquickmenu/data/removeTakeItem.qml
new file mode 100644
index 00000000..89090fb6
--- /dev/null
+++ b/tests/auto/qquickmenu/data/removeTakeItem.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 200
+ height: 200
+
+ property alias menu: menu
+ property alias menuItem1: menuItem1
+ property alias menuItem2: menuItem2
+ property alias menuItem3: menuItem3
+
+ function takeSecondItem() {
+ return menu.takeItem(1)
+ }
+
+ function removeFirstItem() {
+ menu.removeItem(menuItem1)
+ }
+
+ function removeNullItem() {
+ menu.removeItem(null)
+ }
+
+ function removeFirstIndex() {
+ menu.removeItem(0)
+ }
+
+ Menu {
+ id: menu
+ MenuItem {
+ id: menuItem1
+ }
+ MenuItem {
+ id: menuItem2
+ }
+ MenuItem {
+ id: menuItem3
+ }
+ }
+}
diff --git a/tests/auto/qquickmenu/data/subMenus.qml b/tests/auto/qquickmenu/data/subMenus.qml
new file mode 100644
index 00000000..49811bc2
--- /dev/null
+++ b/tests/auto/qquickmenu/data/subMenus.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 600
+ height: 400
+
+ property alias mainMenu: mainMenu
+ property alias subMenu1: subMenu1
+ property alias subMenu2: subMenu2
+ property alias subSubMenu1: subSubMenu1
+
+ Menu {
+ id: mainMenu
+ MenuItem { id: mainMenuItem1; text: "Main 1" }
+
+ Menu {
+ id: subMenu1
+ title: "Sub Menu 1"
+ MenuItem { id: subMenuItem1; text: "Sub 1" }
+ MenuItem { id: subMenuItem2; text: "Sub 2" }
+
+ Menu {
+ id: subSubMenu1
+ title: "Sub Sub Menu 1"
+ MenuItem { id: subSubMenuItem1; text: "Sub Sub 1" }
+ MenuItem { id: subSubMenuItem2; text: "Sub Sub 2" }
+ }
+ }
+
+ MenuItem { id: mainMenuItem2; text: "Main 2" }
+
+ Menu {
+ id: subMenu2
+ title: "Sub Menu 2"
+ MenuItem { id: subMenuItem3; text: "Sub 3" }
+ MenuItem { id: subMenuItem4; text: "Sub 4" }
+ }
+
+ MenuItem { id: mainMenuItem3; text: "Main 3" }
+ }
+}
diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp
index 717e892b..1202072b 100644
--- a/tests/auto/qquickmenu/tst_qquickmenu.cpp
+++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp
@@ -36,6 +36,7 @@
#include <qtest.h>
#include <QtTest/QSignalSpy>
+#include <QtGui/qcursor.h>
#include <QtGui/qstylehints.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -45,6 +46,7 @@
#include "../shared/util.h"
#include "../shared/visualtestutil.h"
+#include <QtQuickTemplates2/private/qquickaction_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
@@ -62,14 +64,26 @@ public:
private slots:
void defaults();
+ void count();
void mouse();
void pressAndHold();
void contextMenuKeyboard();
+ void mnemonics();
void menuButton();
void addItem();
void menuSeparator();
void repeater();
void order();
+ void popup();
+ void actions();
+ void removeTakeItem();
+ void subMenuMouse_data();
+ void subMenuMouse();
+ void subMenuKeyboard_data();
+ void subMenuKeyboard();
+ void subMenuPosition_data();
+ void subMenuPosition();
+ void addRemoveSubMenus();
};
void tst_QQuickMenu::defaults()
@@ -78,16 +92,52 @@ void tst_QQuickMenu::defaults()
QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value<QQuickMenu*>();
QCOMPARE(emptyMenu->isVisible(), false);
+ QCOMPARE(emptyMenu->currentIndex(), -1);
QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1));
+ QCOMPARE(emptyMenu->count(), 0);
+}
+
+void tst_QQuickMenu::count()
+{
+ QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
+
+ QQuickMenu *menu = helper.window->property("emptyMenu").value<QQuickMenu*>();
+ QVERIFY(menu);
+
+ QSignalSpy countSpy(menu, &QQuickMenu::countChanged);
+ QVERIFY(countSpy.isValid());
+
+ menu->addItem(new QQuickItem);
+ QCOMPARE(menu->count(), 1);
+ QCOMPARE(countSpy.count(), 1);
+
+ menu->insertItem(0, new QQuickItem);
+ QCOMPARE(menu->count(), 2);
+ QCOMPARE(countSpy.count(), 2);
+
+ menu->removeItem(menu->itemAt(1));
+ QCOMPARE(menu->count(), 1);
+ QCOMPARE(countSpy.count(), 3);
+
+ QQuickItem *item = menu->takeItem(0);
+ QVERIFY(item);
+ QCOMPARE(menu->count(), 0);
+ QCOMPARE(countSpy.count(), 4);
}
void tst_QQuickMenu::mouse()
{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
+
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
QQuickApplicationWindow *window = helper.appWindow;
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
menu->open();
@@ -103,6 +153,7 @@ void tst_QQuickMenu::mouse()
// so that the highlight acts as a way of illustrating press state.
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2));
QVERIFY(firstItem->hasActiveFocus());
+ QCOMPARE(menu->currentIndex(), 0);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
QVERIFY(menu->isVisible());
@@ -112,6 +163,7 @@ void tst_QQuickMenu::mouse()
QCOMPARE(visibleSpy.count(), 1);
QVERIFY(!menu->isVisible());
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
+ QCOMPARE(menu->currentIndex(), -1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
menu->open();
@@ -133,6 +185,21 @@ void tst_QQuickMenu::mouse()
QVERIFY(menu->isVisible());
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
+ // Hover-highlight through the menu items one by one
+ QQuickItem *prevHoverItem = nullptr;
+ QQuickItem *listView = menu->contentItem();
+ for (int y = 0; y < listView->height(); ++y) {
+ QQuickItem *hoverItem = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(listView, "itemAt", Q_RETURN_ARG(QQuickItem *, hoverItem), Q_ARG(qreal, 0), Q_ARG(qreal, listView->property("contentY").toReal() + y)));
+ if (!hoverItem || !hoverItem->isVisible() || hoverItem == prevHoverItem)
+ continue;
+ QTest::mouseMove(window, QPoint(hoverItem->x() + hoverItem->width() / 2, hoverItem->y() + hoverItem->height() / 2));
+ QTRY_VERIFY(hoverItem->property("highlighted").toBool());
+ if (prevHoverItem)
+ QVERIFY(!prevHoverItem->property("highlighted").toBool());
+ prevHoverItem = hoverItem;
+ }
+
// Try pressing within the menu and releasing outside of it; it should close.
// TODO: won't work until QQuickPopup::releasedOutside() actually gets emitted
// QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2));
@@ -183,8 +250,11 @@ void tst_QQuickMenu::contextMenuKeyboard()
window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
QVERIFY(QGuiApplication::focusWindow() == window);
+ centerOnScreen(window);
+ moveMouseAway(window);
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
+ QCOMPARE(menu->currentIndex(), -1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
QQuickMenuItem *firstItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(0));
@@ -197,12 +267,16 @@ void tst_QQuickMenu::contextMenuKeyboard()
QVERIFY(menu->isVisible());
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
QVERIFY(!firstItem->hasActiveFocus());
+ QVERIFY(!firstItem->property("highlighted").toBool());
+ QCOMPARE(menu->currentIndex(), -1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
QTest::keyClick(window, Qt::Key_Tab);
QVERIFY(firstItem->hasActiveFocus());
QVERIFY(firstItem->hasVisualFocus());
+ QVERIFY(firstItem->isHighlighted());
QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(menu->currentIndex(), 0);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
QQuickMenuItem *secondItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(1));
@@ -210,9 +284,12 @@ void tst_QQuickMenu::contextMenuKeyboard()
QTest::keyClick(window, Qt::Key_Tab);
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(secondItem->hasActiveFocus());
QVERIFY(secondItem->hasVisualFocus());
+ QVERIFY(secondItem->isHighlighted());
QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(menu->currentIndex(), 1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1));
QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered()));
@@ -223,8 +300,11 @@ void tst_QQuickMenu::contextMenuKeyboard()
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(!secondItem->hasActiveFocus());
QVERIFY(!secondItem->hasVisualFocus());
+ QVERIFY(!secondItem->isHighlighted());
+ QCOMPARE(menu->currentIndex(), -1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
menu->open();
@@ -233,18 +313,23 @@ void tst_QQuickMenu::contextMenuKeyboard()
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(!secondItem->hasActiveFocus());
QVERIFY(!secondItem->hasVisualFocus());
+ QVERIFY(!secondItem->isHighlighted());
+ QCOMPARE(menu->currentIndex(), -1);
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
QTest::keyClick(window, Qt::Key_Down);
QVERIFY(firstItem->hasActiveFocus());
QVERIFY(firstItem->hasVisualFocus());
+ QVERIFY(firstItem->isHighlighted());
QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason);
QTest::keyClick(window, Qt::Key_Down);
QVERIFY(secondItem->hasActiveFocus());
QVERIFY(secondItem->hasVisualFocus());
+ QVERIFY(secondItem->isHighlighted());
QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason);
QTest::keyClick(window, Qt::Key_Down);
@@ -252,45 +337,105 @@ void tst_QQuickMenu::contextMenuKeyboard()
QVERIFY(thirdItem);
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(!secondItem->hasActiveFocus());
QVERIFY(!secondItem->hasVisualFocus());
+ QVERIFY(!secondItem->isHighlighted());
QVERIFY(thirdItem->hasActiveFocus());
QVERIFY(thirdItem->hasVisualFocus());
+ QVERIFY(thirdItem->isHighlighted());
QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason);
// Key navigation shouldn't wrap by default.
QTest::keyClick(window, Qt::Key_Down);
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(!secondItem->hasActiveFocus());
QVERIFY(!secondItem->hasVisualFocus());
+ QVERIFY(!secondItem->isHighlighted());
QVERIFY(thirdItem->hasActiveFocus());
QVERIFY(thirdItem->hasVisualFocus());
+ QVERIFY(thirdItem->isHighlighted());
QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason);
QTest::keyClick(window, Qt::Key_Up);
QVERIFY(!firstItem->hasActiveFocus());
QVERIFY(!firstItem->hasVisualFocus());
+ QVERIFY(!firstItem->isHighlighted());
QVERIFY(secondItem->hasActiveFocus());
QVERIFY(secondItem->hasVisualFocus());
+ QVERIFY(secondItem->isHighlighted());
QCOMPARE(secondItem->focusReason(), Qt::BacktabFocusReason);
QVERIFY(!thirdItem->hasActiveFocus());
QVERIFY(!thirdItem->hasVisualFocus());
+ QVERIFY(!thirdItem->isHighlighted());
QTest::keyClick(window, Qt::Key_Backtab);
QVERIFY(firstItem->hasActiveFocus());
QVERIFY(firstItem->hasVisualFocus());
+ QVERIFY(firstItem->isHighlighted());
QCOMPARE(firstItem->focusReason(), Qt::BacktabFocusReason);
QVERIFY(!secondItem->hasActiveFocus());
QVERIFY(!secondItem->hasVisualFocus());
+ QVERIFY(!secondItem->isHighlighted());
QVERIFY(!thirdItem->hasActiveFocus());
QVERIFY(!thirdItem->hasVisualFocus());
+ QVERIFY(!thirdItem->isHighlighted());
QTest::keyClick(window, Qt::Key_Escape);
QCOMPARE(visibleSpy.count(), 4);
QVERIFY(!menu->isVisible());
}
+void tst_QQuickMenu::mnemonics()
+{
+#ifdef Q_OS_MACOS
+ QSKIP("Mnemonics are not used on macOS");
+#endif
+
+ QQuickApplicationHelper helper(this, QLatin1String("mnemonics.qml"));
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QQuickAction *action = window->property("action").value<QQuickAction *>();
+ QQuickMenuItem *menuItem = window->property("menuItem").value<QQuickMenuItem *>();
+ QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
+ QQuickMenuItem *subMenuItem = window->property("subMenuItem").value<QQuickMenuItem *>();
+ QVERIFY(menu && action && menuItem && subMenu && subMenuItem);
+
+ menu->open();
+ QTRY_VERIFY(menu->isOpened());
+
+ QSignalSpy actionSpy(action, &QQuickAction::triggered);
+ QVERIFY(actionSpy.isValid());
+ QTest::keyClick(window, Qt::Key_A, Qt::AltModifier); // "&Action"
+ QCOMPARE(actionSpy.count(), 1);
+
+ menu->open();
+ QTRY_VERIFY(menu->isOpened());
+
+ QSignalSpy menuItemSpy(menuItem, &QQuickMenuItem::triggered);
+ QVERIFY(menuItemSpy.isValid());
+ QTest::keyClick(window, Qt::Key_I, Qt::AltModifier); // "Menu &Item"
+ QCOMPARE(menuItemSpy.count(), 1);
+
+ menu->open();
+ QTRY_VERIFY(menu->isOpened());
+
+ QTest::keyClick(window, Qt::Key_M, Qt::AltModifier); // "Sub &Menu"
+ QTRY_VERIFY(subMenu->isOpened());
+
+ QSignalSpy subMenuItemSpy(subMenuItem, &QQuickMenuItem::triggered);
+ QVERIFY(subMenuItemSpy.isValid());
+ QTest::keyClick(window, Qt::Key_S, Qt::AltModifier); // "&Sub Menu Item"
+ QCOMPARE(subMenuItemSpy.count(), 1);
+}
+
void tst_QQuickMenu::menuButton()
{
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
@@ -346,6 +491,8 @@ void tst_QQuickMenu::menuSeparator()
QQuickWindow *window = helper.window;
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
QVERIFY(menu);
@@ -382,6 +529,8 @@ void tst_QQuickMenu::menuSeparator()
saveMenuItem->mapToScene(QPointF(saveMenuItem->width() / 2, saveMenuItem->height() / 2)).toPoint());
QTRY_VERIFY(!menu->isVisible());
+ moveMouseAway(window);
+
menu->open();
QVERIFY(menu->isVisible());
@@ -477,6 +626,689 @@ void tst_QQuickMenu::order()
}
}
+void tst_QQuickMenu::popup()
+{
+ QQuickApplicationHelper helper(this, QLatin1String("popup.qml"));
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+
+ QQuickMenuItem *menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>();
+ QVERIFY(menuItem1);
+
+ QQuickMenuItem *menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>();
+ QVERIFY(menuItem2);
+
+ QQuickMenuItem *menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>();
+ QVERIFY(menuItem3);
+
+ QQuickItem *button = window->property("button").value<QQuickItem *>();
+ QVERIFY(button);
+
+#if QT_CONFIG(cursor)
+ QPoint oldCursorPos = QCursor::pos();
+ QPoint cursorPos = window->mapToGlobal(QPoint(11, 22));
+ QCursor::setPos(cursorPos);
+ QTRY_COMPARE(QCursor::pos(), cursorPos);
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtCursor"));
+ QCOMPARE(menu->parentItem(), window->contentItem());
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), 11);
+ QTRY_COMPARE(menu->y(), 22);
+ menu->close();
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtPos", Q_ARG(QVariant, QPointF(33, 44))));
+ QCOMPARE(menu->parentItem(), window->contentItem());
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), 33);
+ QTRY_COMPARE(menu->y(), 44);
+ menu->close();
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, 66)));
+ QCOMPARE(menu->parentItem(), window->contentItem());
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), 55);
+ QTRY_COMPARE(menu->y(), 66);
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button))));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), button->mapFromScene(QPointF(11, 22)).x());
+ QTRY_COMPARE(menu->y(), button->mapFromScene(QPointF(11, 22)).y());
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22))));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), -11);
+ QTRY_COMPARE(menu->y(), -22);
+ QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22)));
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44)));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
+ QTRY_COMPARE(menu->x(), -33);
+ QTRY_COMPARE(menu->y(), -44);
+ QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44)));
+ menu->close();
+
+ cursorPos = window->mapToGlobal(QPoint(12, window->height() / 2));
+ QCursor::setPos(cursorPos);
+ QTRY_COMPARE(QCursor::pos(), cursorPos);
+
+ const QList<QQuickMenuItem *> menuItems = QList<QQuickMenuItem *>() << menuItem1 << menuItem2 << menuItem3;
+ for (QQuickMenuItem *menuItem : menuItems) {
+ menu->resetParentItem();
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCursor", Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), 12);
+ QTRY_COMPARE(menu->y(), window->height() / 2 + menu->topPadding() - menuItem->y());
+ menu->close();
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtPos", Q_ARG(QVariant, QPointF(33, window->height() / 3)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), 33);
+ QTRY_COMPARE(menu->y(), window->height() / 3 + menu->topPadding() - menuItem->y());
+ menu->close();
+
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, window->height() / 3 * 2), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), 55);
+ QTRY_COMPARE(menu->y(), window->height() / 3 * 2 + menu->topPadding() - menuItem->y());
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), button->mapFromScene(QPoint(12, window->height() / 2)).x());
+ QTRY_COMPARE(menu->y(), button->mapFromScene(QPoint(12, window->height() / 2)).y() + menu->topPadding() - menuItem->y());
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), -11);
+ QTRY_COMPARE(menu->y(), -22 + menu->topPadding() - menuItem->y());
+ QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22 + menu->topPadding() - menuItem->y())));
+ menu->close();
+
+ menu->setParentItem(nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
+ QCOMPARE(menu->parentItem(), button);
+ QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
+ QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
+ QTRY_COMPARE(menu->x(), -33);
+ QTRY_COMPARE(menu->y(), -44 + menu->topPadding() - menuItem->y());
+ QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44 + menu->topPadding() - menuItem->y())));
+ menu->close();
+ }
+
+ QCursor::setPos(oldCursorPos);
+ QTRY_COMPARE(QCursor::pos(), oldCursorPos);
+#endif
+}
+
+void tst_QQuickMenu::actions()
+{
+ QQuickApplicationHelper helper(this, QLatin1String("actions.qml"));
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+
+ QPointer<QQuickAction> action1 = menu->actionAt(0);
+ QVERIFY(!action1.isNull());
+
+ QPointer<QQuickAction> action3 = menu->actionAt(2);
+ QVERIFY(!action3.isNull());
+
+ QVERIFY(!menu->actionAt(1));
+ QVERIFY(!menu->actionAt(3));
+
+ QPointer<QQuickMenuItem> menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(0));
+ QVERIFY(!menuItem1.isNull());
+ QCOMPARE(menuItem1->action(), action1.data());
+ QCOMPARE(menuItem1->text(), "action1");
+
+ QPointer<QQuickMenuItem> menuItem2 = qobject_cast<QQuickMenuItem *>(menu->itemAt(1));
+ QVERIFY(!menuItem2.isNull());
+ QVERIFY(!menuItem2->action());
+ QCOMPARE(menuItem2->text(), "menuitem2");
+
+ QPointer<QQuickMenuItem> menuItem3 = qobject_cast<QQuickMenuItem *>(menu->itemAt(2));
+ QVERIFY(!menuItem3.isNull());
+ QCOMPARE(menuItem3->action(), action3.data());
+ QCOMPARE(menuItem3->text(), "action3");
+
+ QPointer<QQuickMenuItem> menuItem4 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3));
+ QVERIFY(!menuItem4.isNull());
+ QVERIFY(!menuItem4->action());
+ QCOMPARE(menuItem4->text(), "menuitem4");
+
+ // takeAction(int) does not destroy the action, but does destroy the respective item
+ QCOMPARE(menu->takeAction(0), action1.data());
+ QVERIFY(!menu->itemAt(3));
+ QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete);
+ QVERIFY(!action1.isNull());
+ QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
+ QVERIFY(menuItem1.isNull());
+
+ // takeAction(int) does not destroy an item that doesn't have an action
+ QVERIFY(!menuItem2->subMenu());
+ QVERIFY(!menu->takeAction(0));
+ QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete);
+ QVERIFY(!menuItem2.isNull());
+
+ // addAction(Action) re-creates the respective item in the menu
+ menu->addAction(action1);
+ menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3));
+ QVERIFY(!menuItem1.isNull());
+ QCOMPARE(menuItem1->action(), action1.data());
+
+ // removeAction(Action) destroys both the action and the respective item
+ menu->removeAction(action1);
+ QVERIFY(!menu->itemAt(3));
+ QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete);
+ QVERIFY(action1.isNull());
+ QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
+ QVERIFY(menuItem1.isNull());
+}
+
+void tst_QQuickMenu::removeTakeItem()
+{
+ QQuickApplicationHelper helper(this, QLatin1String("removeTakeItem.qml"));
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+
+ QPointer<QQuickMenuItem> menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>();
+ QVERIFY(!menuItem1.isNull());
+ QCOMPARE(menuItem1->menu(), menu);
+
+ QPointer<QQuickMenuItem> menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>();
+ QVERIFY(!menuItem2.isNull());
+ QCOMPARE(menuItem2->menu(), menu);
+
+ QPointer<QQuickMenuItem> menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>();
+ QVERIFY(!menuItem3.isNull());
+ QCOMPARE(menuItem3->menu(), menu);
+
+ // takeItem(int) does not destroy
+ QVariant ret;
+ QVERIFY(QMetaObject::invokeMethod(window, "takeSecondItem", Q_RETURN_ARG(QVariant, ret)));
+ QCOMPARE(ret.value<QQuickMenuItem *>(), menuItem2);
+ QVERIFY(!menuItem2->menu());
+ QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete);
+ QVERIFY(!menuItem2.isNull());
+
+ // removeItem(Item) destroys
+ QVERIFY(QMetaObject::invokeMethod(window, "removeFirstItem"));
+ QVERIFY(!menuItem1->menu());
+ QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
+ QVERIFY(menuItem1.isNull());
+
+ // removeItem(null) must not call removeItem(0)
+ QVERIFY(QMetaObject::invokeMethod(window, "removeNullItem"));
+ QCOMPARE(menuItem3->menu(), menu);
+ QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete);
+ QVERIFY(!menuItem3.isNull());
+
+ // deprecated removeItem(int) does not destroy
+ QVERIFY(QMetaObject::invokeMethod(window, "removeFirstIndex"));
+ QVERIFY(!menuItem3->menu());
+ QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete);
+ QVERIFY(!menuItem3.isNull());
+}
+
+void tst_QQuickMenu::subMenuMouse_data()
+{
+ QTest::addColumn<bool>("cascade");
+
+ QTest::newRow("cascading") << true;
+ QTest::newRow("non-cascading") << false;
+}
+
+void tst_QQuickMenu::subMenuMouse()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
+
+ QFETCH(bool, cascade);
+
+ QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
+
+ QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
+ QVERIFY(mainMenu);
+ mainMenu->setCascade(cascade);
+ QCOMPARE(mainMenu->cascade(), cascade);
+
+ QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
+ QVERIFY(subMenu1);
+
+ QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
+ QVERIFY(subMenu2);
+
+ QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
+ QVERIFY(subSubMenu1);
+
+ mainMenu->open();
+ QVERIFY(mainMenu->isVisible());
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // open the sub-menu with mouse click
+ QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
+ QVERIFY(subMenu1Item);
+ QCOMPARE(subMenu1Item->subMenu(), subMenu1);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // open the cascading sub-sub-menu with mouse hover
+ QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
+ QVERIFY(subSubMenu1Item);
+ QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
+ QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+ if (cascade)
+ QTRY_VERIFY(subSubMenu1->isVisible());
+
+ // close the sub-sub-menu with mouse hover over another parent menu item
+ QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenuItem1);
+ QVERIFY(!subMenuItem1->subMenu());
+ QTest::mouseMove(window, subMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // re-open the sub-sub-menu with mouse hover
+ QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+ if (cascade)
+ QTRY_VERIFY(subSubMenu1->isVisible());
+
+ // close sub-menu and sub-sub-menu with mouse hover in the main menu
+ QQuickMenuItem *mainMenuItem1 = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(0));
+ QVERIFY(mainMenuItem1);
+ QTest::mouseMove(window, mainMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QCOMPARE(subMenu1->isVisible(), !cascade);
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // close all menus by click triggering an item
+ QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0));
+ QVERIFY(subSubMenuItem1);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subSubMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
+ QVERIFY(!mainMenu->isVisible());
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+}
+
+void tst_QQuickMenu::subMenuKeyboard_data()
+{
+ QTest::addColumn<bool>("cascade");
+ QTest::addColumn<bool>("mirrored");
+
+ QTest::newRow("cascading") << true << false;
+ QTest::newRow("cascading,mirrored") << true << true;
+ QTest::newRow("non-cascading") << false << false;
+ QTest::newRow("non-cascading,mirrored") << false << true;
+}
+
+void tst_QQuickMenu::subMenuKeyboard()
+{
+ QFETCH(bool, cascade);
+ QFETCH(bool, mirrored);
+
+ QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
+
+ if (mirrored)
+ window->setLocale(QLocale("ar_EG"));
+
+ QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
+ QVERIFY(mainMenu);
+ mainMenu->setCascade(cascade);
+ QCOMPARE(mainMenu->cascade(), cascade);
+
+ QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
+ QVERIFY(subMenu1);
+
+ QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
+ QVERIFY(subMenu2);
+
+ QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
+ QVERIFY(subSubMenu1);
+
+ mainMenu->open();
+ QVERIFY(mainMenu->isVisible());
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // navigate to the sub-menu item and trigger it
+ QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
+ QVERIFY(subMenu1Item);
+ QVERIFY(!subMenu1Item->isHighlighted());
+ QCOMPARE(subMenu1Item->subMenu(), subMenu1);
+ QTest::keyClick(window, Qt::Key_Down);
+ QTest::keyClick(window, Qt::Key_Down);
+ QVERIFY(subMenu1Item->isHighlighted());
+ QTest::keyClick(window, Qt::Key_Space);
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // navigate to the sub-sub-menu item and open it with the arrow key
+ QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
+ QVERIFY(subSubMenu1Item);
+ QVERIFY(!subSubMenu1Item->isHighlighted());
+ QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
+ QTest::keyClick(window, Qt::Key_Down);
+ QTest::keyClick(window, Qt::Key_Down);
+ QTest::keyClick(window, Qt::Key_Down);
+ QVERIFY(subSubMenu1Item->isHighlighted());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+ QTest::keyClick(window, mirrored ? Qt::Key_Left : Qt::Key_Right);
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QCOMPARE(subMenu1->isVisible(), cascade);
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(subSubMenu1->isVisible());
+
+ // navigate within the sub-sub-menu
+ QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0));
+ QVERIFY(subSubMenuItem1);
+ QQuickMenuItem *subSubMenuItem2 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(1));
+ QVERIFY(subSubMenuItem2);
+ QVERIFY(subSubMenuItem1->isHighlighted());
+ QVERIFY(!subSubMenuItem2->isHighlighted());
+ QTest::keyClick(window, Qt::Key_Down);
+ QVERIFY(!subSubMenuItem1->isHighlighted());
+ QVERIFY(subSubMenuItem2->isHighlighted());
+
+ // navigate to the parent menu with the arrow key
+ QTest::keyClick(window, mirrored ? Qt::Key_Right : Qt::Key_Left);
+ QVERIFY(subSubMenu1Item->isHighlighted());
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // navigate within the sub-menu
+ QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenuItem1);
+ QQuickMenuItem *subMenuItem2 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(1));
+ QVERIFY(subMenuItem2);
+ QVERIFY(!subMenuItem1->isHighlighted());
+ QVERIFY(!subMenuItem2->isHighlighted());
+ QVERIFY(subSubMenu1Item->isHighlighted());
+ QTest::keyClick(window, Qt::Key_Up);
+ QVERIFY(!subMenuItem1->isHighlighted());
+ QVERIFY(subMenuItem2->isHighlighted());
+ QVERIFY(!subSubMenu1Item->isHighlighted());
+
+ // close the menus with esc
+ QTest::keyClick(window, Qt::Key_Escape);
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+ QTest::keyClick(window, Qt::Key_Escape);
+ QVERIFY(!mainMenu->isVisible());
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+}
+
+void tst_QQuickMenu::subMenuPosition_data()
+{
+ QTest::addColumn<bool>("cascade");
+ QTest::addColumn<bool>("flip");
+ QTest::addColumn<bool>("mirrored");
+ QTest::addColumn<qreal>("overlap");
+
+ QTest::newRow("cascading") << true << false << false << 0.0;
+ QTest::newRow("cascading,flip") << true << true << false << 0.0;
+ QTest::newRow("cascading,overlap") << true << false << false << 10.0;
+ QTest::newRow("cascading,flip,overlap") << true << true << false << 10.0;
+ QTest::newRow("cascading,mirrored") << true << false << true << 0.0;
+ QTest::newRow("cascading,mirrored,flip") << true << true << true << 0.0;
+ QTest::newRow("cascading,mirrored,overlap") << true << false << true << 10.0;
+ QTest::newRow("cascading,mirrored,flip,overlap") << true << true << true << 10.0;
+ QTest::newRow("non-cascading") << false << false << false << 0.0;
+}
+
+void tst_QQuickMenu::subMenuPosition()
+{
+ QFETCH(bool, cascade);
+ QFETCH(bool, flip);
+ QFETCH(bool, mirrored);
+ QFETCH(qreal, overlap);
+
+ QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
+ QQuickApplicationWindow *window = helper.appWindow;
+
+ // the default size of the window fits three menus side by side.
+ // when testing flipping, we resize the window so that the first
+ // sub-menu fits, but the second doesn't
+ if (flip)
+ window->setWidth(window->width() - 200);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ centerOnScreen(window);
+ moveMouseAway(window);
+
+ if (mirrored)
+ window->setLocale(QLocale("ar_EG"));
+
+ QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
+ QVERIFY(mainMenu);
+ mainMenu->setCascade(cascade);
+ QCOMPARE(mainMenu->cascade(), cascade);
+ mainMenu->setOverlap(overlap);
+ QCOMPARE(mainMenu->overlap(), overlap);
+
+ QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
+ QVERIFY(subMenu1);
+ subMenu1->setCascade(cascade);
+ QCOMPARE(subMenu1->cascade(), cascade);
+ subMenu1->setOverlap(overlap);
+ QCOMPARE(subMenu1->overlap(), overlap);
+
+ QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
+ QVERIFY(subMenu2);
+ subMenu2->setCascade(cascade);
+ QCOMPARE(subMenu2->cascade(), cascade);
+ subMenu2->setOverlap(overlap);
+ QCOMPARE(subMenu2->overlap(), overlap);
+
+ QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
+ QVERIFY(subSubMenu1);
+ subSubMenu1->setCascade(cascade);
+ QCOMPARE(subSubMenu1->cascade(), cascade);
+ subSubMenu1->setOverlap(overlap);
+ QCOMPARE(subSubMenu1->overlap(), overlap);
+
+ // choose the main menu position so that there's room for the
+ // sub-menus to cascade to the left when mirrored
+ if (mirrored)
+ mainMenu->setX(window->width() - 200);
+
+ mainMenu->open();
+ QVERIFY(mainMenu->isVisible());
+ QVERIFY(!subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ // open the sub-menu (never flips)
+ QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
+ QVERIFY(subMenu1Item);
+ QCOMPARE(subMenu1Item->subMenu(), subMenu1);
+ emit subMenu1Item->triggered();
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QVERIFY(subMenu1->isVisible());
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(!subSubMenu1->isVisible());
+
+ if (cascade) {
+ QCOMPARE(subMenu1->parentItem(), subMenu1Item);
+ // vertically aligned to the parent menu item
+ QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + subMenu1Item->y() - subMenu1->topPadding());
+ if (mirrored)
+ QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() - subMenu1->width() + overlap); // on the left of the parent menu
+ else
+ QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + mainMenu->width() - overlap); // on the right of the parent menu
+ } else {
+ QCOMPARE(subMenu1->parentItem(), mainMenu->parentItem());
+ // centered over the parent menu
+ QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + (mainMenu->width() - subMenu1->width()) / 2);
+ QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + (mainMenu->height() - subMenu1->height()) / 2);
+ }
+
+ // open the sub-sub-menu (can flip)
+ QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
+ QVERIFY(subSubMenu1Item);
+ QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
+ emit subSubMenu1Item->triggered();
+ QCOMPARE(mainMenu->isVisible(), cascade);
+ QCOMPARE(subMenu1->isVisible(), cascade);
+ QVERIFY(!subMenu2->isVisible());
+ QVERIFY(subSubMenu1->isVisible());
+
+ if (cascade) {
+ QCOMPARE(subSubMenu1->parentItem(), subSubMenu1Item);
+ // vertically aligned to the parent menu item
+ QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + subSubMenu1Item->y() - subSubMenu1->topPadding());
+ if (mirrored != flip)
+ QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() - subSubMenu1->width() + overlap); // on the left of the parent menu
+ else
+ QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + subMenu1->width() - overlap); // on the right of the parent menu
+ } else {
+ QCOMPARE(subSubMenu1->parentItem(), subMenu1->parentItem());
+ // centered over the parent menu
+ QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + (subMenu1->width() - subSubMenu1->width()) / 2);
+ QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + (subMenu1->height() - subSubMenu1->height()) / 2);
+ }
+}
+
+void tst_QQuickMenu::addRemoveSubMenus()
+{
+ QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
+ QVERIFY(mainMenu);
+
+ QVERIFY(!mainMenu->menuAt(0));
+
+ QPointer<QQuickMenu> subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
+ QVERIFY(!subMenu1.isNull());
+ QCOMPARE(mainMenu->menuAt(1), subMenu1.data());
+
+ QVERIFY(!mainMenu->menuAt(2));
+
+ QPointer<QQuickMenu> subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
+ QVERIFY(!subMenu2.isNull());
+ QCOMPARE(mainMenu->menuAt(3), subMenu2.data());
+
+ QVERIFY(!mainMenu->menuAt(4));
+
+ QPointer<QQuickMenu> subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
+ QVERIFY(!subSubMenu1.isNull());
+
+ // takeMenu(int) does not destroy the menu, but does destroy the respective item in the parent menu
+ QPointer<QQuickMenuItem> subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
+ QVERIFY(subSubMenu1Item);
+ QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1.data());
+ QCOMPARE(subMenu1->takeMenu(2), subSubMenu1.data());
+ QVERIFY(!subMenu1->itemAt(2));
+ QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete);
+ QVERIFY(!subSubMenu1.isNull());
+ QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete);
+ QVERIFY(subSubMenu1Item.isNull());
+
+ // takeMenu(int) does not destroy an item that doesn't present a menu
+ QPointer<QQuickMenuItem> subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenuItem1);
+ QVERIFY(!subMenuItem1->subMenu());
+ QVERIFY(!subMenu1->takeMenu(0));
+ QCoreApplication::sendPostedEvents(subMenuItem1, QEvent::DeferredDelete);
+ QVERIFY(!subMenuItem1.isNull());
+
+ // addMenu(Menu) re-creates the respective item in the parent menu
+ subMenu1->addMenu(subSubMenu1);
+ subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
+ QVERIFY(!subSubMenu1Item.isNull());
+
+ // removeMenu(Menu) destroys both the menu and the respective item in the parent menu
+ subMenu1->removeMenu(subSubMenu1);
+ QVERIFY(!subMenu1->itemAt(2));
+ QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete);
+ QVERIFY(subSubMenu1.isNull());
+ QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete);
+ QVERIFY(subSubMenu1Item.isNull());
+}
+
QTEST_MAIN(tst_QQuickMenu)
#include "tst_qquickmenu.moc"
diff --git a/tests/auto/qquickmenubar/data/empty.qml b/tests/auto/qquickmenubar/data/empty.qml
new file mode 100644
index 00000000..6ed0a141
--- /dev/null
+++ b/tests/auto/qquickmenubar/data/empty.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+MenuBar { }
diff --git a/tests/auto/qquickmenubar/data/menubar.qml b/tests/auto/qquickmenubar/data/menubar.qml
new file mode 100644
index 00000000..606dd92c
--- /dev/null
+++ b/tests/auto/qquickmenubar/data/menubar.qml
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 2.10
+import QtQuick.Controls 2.3
+
+ApplicationWindow {
+ width: 400
+ height: 400
+ visible: true
+
+ header: MenuBar {
+ MenuBarItem {
+ menu: Menu {
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+ }
+ MenuBarItem {
+ menu: Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+ }
+ MenuBarItem {
+ menu: Menu {
+ title: "&View"
+ Menu {
+ title: "&Alignment"
+ Menu {
+ title: "&Horizontal"
+ MenuItem { text: "&Left" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Right" }
+ }
+ Menu {
+ title: "&Vertical"
+ MenuItem { text: "&Top" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Bottom" }
+ }
+ }
+ }
+ }
+
+ MenuBarItem {
+ menu: Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+ }
+}
diff --git a/tests/auto/qquickmenubar/qquickmenubar.pro b/tests/auto/qquickmenubar/qquickmenubar.pro
new file mode 100644
index 00000000..b7d41f0f
--- /dev/null
+++ b/tests/auto/qquickmenubar/qquickmenubar.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+TARGET = tst_qquickmenubar
+SOURCES += tst_qquickmenubar.cpp
+
+macos:CONFIG -= app_bundle
+
+QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private
+
+include (../shared/util.pri)
+
+TESTDATA = data/*
+
+OTHER_FILES += \
+ data/*.qml
diff --git a/tests/auto/qquickmenubar/tst_qquickmenubar.cpp b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp
new file mode 100644
index 00000000..19d67eac
--- /dev/null
+++ b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtTest>
+#include <QtQml>
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+#include "../shared/qtest_quickcontrols.h"
+
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickmenu_p.h>
+#include <QtQuickTemplates2/private/qquickmenubar_p.h>
+#include <QtQuickTemplates2/private/qquickmenubaritem_p.h>
+#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
+
+using namespace QQuickVisualTestUtil;
+
+class tst_qquickmenubar : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+
+private slots:
+ void delegate();
+ void mouse();
+ void keys();
+ void mnemonics();
+ void addRemove();
+};
+
+void tst_qquickmenubar::delegate()
+{
+ QQmlApplicationEngine engine(testFileUrl("empty.qml"));
+ QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0)));
+ QVERIFY(menuBar);
+
+ QQmlComponent *delegate = menuBar->delegate();
+ QVERIFY(delegate);
+
+ QScopedPointer<QQuickMenuBarItem> item(qobject_cast<QQuickMenuBarItem *>(delegate->create()));
+ QVERIFY(item);
+}
+
+void tst_qquickmenubar::mouse()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Mouse highlight not functional on offscreen/minimal platforms");
+
+ QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ centerOnScreen(window.data());
+ moveMouseAway(window.data());
+
+ QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
+ QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
+ QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
+ QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
+ QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
+
+ QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
+ QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
+ QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
+ QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
+ QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
+
+ // highlight a menubar item
+ QTest::mouseMove(window.data(), fileMenuBarItem->mapToScene(QPointF(fileMenuBarItem->width() / 2, fileMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(fileMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarMenu->isVisible());
+
+ // highlight another menubar item
+ QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(!fileMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarMenu->isVisible());
+ QVERIFY(!editMenuBarMenu->isVisible());
+
+ // trigger a menubar item to open a menu
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+
+ // re-trigger a menubar item to hide the menu
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarItem->hasActiveFocus());
+ QTRY_VERIFY(!editMenuBarMenu->isVisible());
+
+ // re-trigger a menubar item to show the menu again
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+
+ // highlight another menubar item to open another menu
+ QTest::mouseMove(window.data(), helpMenuBarItem->mapToScene(QPointF(helpMenuBarItem->width() / 2, helpMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(!fileMenuBarItem->isHighlighted());
+ QVERIFY(!editMenuBarItem->isHighlighted());
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QVERIFY(helpMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarMenu->isVisible());
+ QVERIFY(!viewMenuBarMenu->isVisible());
+ QVERIFY(helpMenuBarMenu->isVisible());
+ QTRY_VERIFY(!editMenuBarMenu->isVisible());
+ QTRY_VERIFY(helpMenuBarMenu->isOpened());
+
+ // trigger a menu item to close the menu
+ QQuickMenuItem *aboutMenuItem = qobject_cast<QQuickMenuItem *>(helpMenuBarMenu->itemAt(0));
+ QVERIFY(aboutMenuItem);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, aboutMenuItem->mapToScene(QPointF(aboutMenuItem->width() / 2, aboutMenuItem->height() / 2)).toPoint());
+ QVERIFY(!helpMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!helpMenuBarMenu->isVisible());
+
+ // highlight a menubar item
+ QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(!helpMenuBarItem->isHighlighted());
+ QVERIFY(!editMenuBarMenu->isVisible());
+ QVERIFY(!helpMenuBarMenu->isVisible());
+
+ // trigger a menubar item to open a menu
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(!editMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(viewMenuBarMenu->isOpened());
+
+ // trigger a menu item to open a sub-menu
+ QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
+ QVERIFY(alignmentSubMenuItem);
+ QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
+ QVERIFY(alignmentSubMenu);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+ QTRY_VERIFY(alignmentSubMenu->isOpened());
+
+ // trigger a menu item to open a sub-sub-menu
+ QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1));
+ QVERIFY(verticalSubMenuItem);
+ QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu();
+ QVERIFY(verticalSubMenu);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+ QVERIFY(verticalSubMenu->isVisible());
+ QTRY_VERIFY(verticalSubMenu->isOpened());
+
+ // trigger a menu item to close the whole chain of menus
+ QQuickMenuItem *centerMenuItem = qobject_cast<QQuickMenuItem *>(verticalSubMenu->itemAt(1));
+ QVERIFY(centerMenuItem);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, centerMenuItem->mapToScene(QPointF(centerMenuItem->width() / 2, centerMenuItem->height() / 2)).toPoint());
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(!alignmentSubMenu->isVisible());
+ QTRY_VERIFY(!verticalSubMenu->isVisible());
+
+ // re-highlight the same menubar item
+ QTest::mouseMove(window.data(), viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+
+ // re-open the chain of menus
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
+ QTRY_VERIFY(viewMenuBarMenu->isOpened());
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint());
+ QTRY_VERIFY(alignmentSubMenu->isOpened());
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint());
+ QTRY_VERIFY(verticalSubMenu->isOpened());
+
+ // click outside to close the whole chain of menus
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() - 1));
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(!alignmentSubMenu->isVisible());
+ QTRY_VERIFY(!verticalSubMenu->isVisible());
+}
+
+void tst_qquickmenubar::keys()
+{
+ QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ centerOnScreen(window.data());
+ moveMouseAway(window.data());
+
+ QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
+ QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
+ QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
+ QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
+ QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
+
+ QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
+ QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
+ QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
+ QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
+ QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
+
+ // trigger a menubar item to open a menu
+ editMenuBarItem->forceActiveFocus();
+ QTest::keyClick(window.data(), Qt::Key_Space);
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+ QVERIFY(editMenuBarMenu->hasActiveFocus());
+
+ // navigate down to the menu
+ QQuickMenuItem *cutMenuItem = qobject_cast<QQuickMenuItem *>(editMenuBarMenu->itemAt(0));
+ QVERIFY(cutMenuItem);
+ QVERIFY(!cutMenuItem->isHighlighted());
+ QVERIFY(!cutMenuItem->hasActiveFocus());
+ QTest::keyClick(window.data(), Qt::Key_Down);
+ QVERIFY(cutMenuItem->isHighlighted());
+ QVERIFY(cutMenuItem->hasActiveFocus());
+
+ // navigate up, back to the menubar
+ QTest::keyClick(window.data(), Qt::Key_Up);
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarItem->hasActiveFocus());
+ QTRY_VERIFY(!editMenuBarMenu->isVisible());
+ QVERIFY(!cutMenuItem->isHighlighted());
+ QVERIFY(!cutMenuItem->hasActiveFocus());
+
+ // navigate down to re-open the menu
+ QTest::keyClick(window.data(), Qt::Key_Down);
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(!editMenuBarItem->hasActiveFocus());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+ QVERIFY(editMenuBarMenu->hasActiveFocus());
+ QVERIFY(cutMenuItem->isHighlighted());
+ QVERIFY(cutMenuItem->hasActiveFocus());
+
+ // navigate left in popup mode (menu open)
+ QTest::keyClick(window.data(), Qt::Key_Left);
+ QVERIFY(fileMenuBarItem->isHighlighted());
+ QVERIFY(!editMenuBarItem->isHighlighted());
+ QVERIFY(fileMenuBarMenu->isVisible());
+ QTRY_VERIFY(fileMenuBarMenu->isOpened());
+ QTRY_VERIFY(!editMenuBarMenu->isVisible());
+
+ // navigate left in popup mode (wrap)
+ QTest::keyClick(window.data(), Qt::Key_Left);
+ QVERIFY(helpMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarItem->isHighlighted());
+ QVERIFY(helpMenuBarMenu->isVisible());
+ QTRY_VERIFY(helpMenuBarMenu->isOpened());
+ QTRY_VERIFY(!fileMenuBarMenu->isVisible());
+
+ // navigate up to close the menu
+ QTest::keyClick(window.data(), Qt::Key_Up);
+ QVERIFY(helpMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!helpMenuBarMenu->isVisible());
+
+ // navigate right in non-popup mode (wrap)
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(fileMenuBarItem->isHighlighted());
+ QVERIFY(!helpMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarMenu->isVisible());
+ QVERIFY(!helpMenuBarMenu->isVisible());
+
+ // navigate right in non-popup mode (menu closed)
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(!fileMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(!fileMenuBarMenu->isVisible());
+ QVERIFY(!editMenuBarMenu->isVisible());
+
+ // open a menu
+ viewMenuBarItem->forceActiveFocus();
+ QTest::keyClick(window.data(), Qt::Key_Space);
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(viewMenuBarMenu->isOpened());
+ QVERIFY(!viewMenuBarItem->hasActiveFocus());
+ QVERIFY(viewMenuBarMenu->hasActiveFocus());
+
+ // open a sub-menu
+ QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
+ QVERIFY(alignmentSubMenuItem);
+ QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
+ QVERIFY(alignmentSubMenu);
+ QTest::keyClick(window.data(), Qt::Key_Down);
+ QVERIFY(alignmentSubMenuItem->isHighlighted());
+ QVERIFY(!alignmentSubMenu->isVisible());
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(alignmentSubMenu->isVisible());
+ QTRY_VERIFY(alignmentSubMenu->isOpened());
+
+ // open a sub-sub-menu
+ QQuickMenuItem *horizontalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(0));
+ QVERIFY(horizontalSubMenuItem);
+ QVERIFY(horizontalSubMenuItem->isHighlighted());
+ QQuickMenu *horizontalSubMenu = horizontalSubMenuItem->subMenu();
+ QVERIFY(horizontalSubMenu);
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+ QVERIFY(horizontalSubMenu->isVisible());
+ QTRY_VERIFY(horizontalSubMenu->isOpened());
+
+ // navigate left to close a sub-menu
+ QTest::keyClick(window.data(), Qt::Key_Left);
+ QTRY_VERIFY(!horizontalSubMenu->isVisible());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+
+ // navigate right to re-open the sub-menu
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(horizontalSubMenuItem->isHighlighted());
+ QVERIFY(horizontalSubMenu->isVisible());
+ QTRY_VERIFY(horizontalSubMenu->isOpened());
+
+ // navigate right to the next menubar menu
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QVERIFY(helpMenuBarItem->isHighlighted());
+ QVERIFY(helpMenuBarMenu->isVisible());
+ QTRY_VERIFY(!viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(!alignmentSubMenu->isVisible());
+ QTRY_VERIFY(!horizontalSubMenu->isVisible());
+ QTRY_VERIFY(helpMenuBarMenu->isOpened());
+
+ // navigate back
+ QTest::keyClick(window.data(), Qt::Key_Left);
+ QVERIFY(!helpMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(!helpMenuBarMenu->isVisible());
+ QTRY_VERIFY(viewMenuBarMenu->isOpened());
+
+ // re-open the chain of menus
+ QTest::keyClick(window.data(), Qt::Key_Down);
+ QVERIFY(alignmentSubMenuItem->isHighlighted());
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QTRY_VERIFY(alignmentSubMenu->isOpened());
+ QTest::keyClick(window.data(), Qt::Key_Right);
+ QTRY_VERIFY(horizontalSubMenu->isOpened());
+
+ // repeat escape to close the whole chain of menus one by one
+ QTest::keyClick(window.data(), Qt::Key_Escape);
+ QTRY_VERIFY(!horizontalSubMenu->isVisible());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+
+ QTest::keyClick(window.data(), Qt::Key_Escape);
+ QTRY_VERIFY(!alignmentSubMenu->isVisible());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+
+ QTest::keyClick(window.data(), Qt::Key_Escape);
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!viewMenuBarMenu->isVisible());
+}
+
+void tst_qquickmenubar::mnemonics()
+{
+#ifdef Q_OS_MACOS
+ QSKIP("Mnemonics are not used on macOS");
+#endif
+
+ QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ centerOnScreen(window.data());
+ moveMouseAway(window.data());
+
+ QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
+ QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
+ QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
+ QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
+ QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
+
+ QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
+ QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
+ QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
+ QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
+ QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
+
+ // trigger a menubar item to open a menu
+ QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(!editMenuBarItem->hasActiveFocus());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+ QVERIFY(editMenuBarMenu->hasActiveFocus());
+
+ // re-trigger a menubar item to hide the menu
+ QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarItem->hasActiveFocus());
+ QVERIFY(!editMenuBarMenu->hasActiveFocus());
+ QTRY_VERIFY(!editMenuBarMenu->isVisible());
+
+ // re-trigger a menubar item to show the menu again
+ QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
+ QVERIFY(editMenuBarItem->isHighlighted());
+ QVERIFY(editMenuBarMenu->isVisible());
+ QTRY_VERIFY(editMenuBarMenu->isOpened());
+ QVERIFY(editMenuBarMenu->hasActiveFocus());
+ QVERIFY(!editMenuBarItem->hasActiveFocus());
+
+ // trigger another menubar item to open another menu
+ QTest::keyClick(window.data(), Qt::Key_H, Qt::AltModifier); // "&Help"
+ QVERIFY(!editMenuBarItem->isHighlighted());
+ QVERIFY(helpMenuBarItem->isHighlighted());
+ QVERIFY(!viewMenuBarMenu->isVisible());
+ QVERIFY(helpMenuBarMenu->isVisible());
+ QTRY_VERIFY(helpMenuBarMenu->isOpened());
+
+ // trigger a menu item to close the menu
+ QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&About"
+ QVERIFY(!helpMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!helpMenuBarMenu->isVisible());
+
+ // trigger a menubar item to open a menu
+ QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&View"
+ QVERIFY(!editMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarItem->isHighlighted());
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(viewMenuBarMenu->isOpened());
+
+ // trigger a menu item to open a sub-menu
+ QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
+ QVERIFY(alignmentSubMenuItem);
+ QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
+ QVERIFY(alignmentSubMenu);
+ QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&Alignment"
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+ QTRY_VERIFY(alignmentSubMenu->isOpened());
+
+ // trigger a menu item to open a sub-sub-menu
+ QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1));
+ QVERIFY(verticalSubMenuItem);
+ QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu();
+ QVERIFY(verticalSubMenu);
+ QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&Vertical"
+ QVERIFY(viewMenuBarMenu->isVisible());
+ QVERIFY(alignmentSubMenu->isVisible());
+ QVERIFY(verticalSubMenu->isVisible());
+ QTRY_VERIFY(verticalSubMenu->isOpened());
+
+ // trigger a menu item to close the whole chain of menus
+ QTest::keyClick(window.data(), Qt::Key_C, Qt::AltModifier); // "&Center"
+ QVERIFY(!viewMenuBarItem->isHighlighted());
+ QTRY_VERIFY(!viewMenuBarMenu->isVisible());
+ QTRY_VERIFY(!alignmentSubMenu->isVisible());
+ QTRY_VERIFY(!verticalSubMenu->isVisible());
+}
+
+void tst_qquickmenubar::addRemove()
+{
+ QQmlApplicationEngine engine(testFileUrl("empty.qml"));
+
+ QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0)));
+ QVERIFY(menuBar);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick.Controls 2.0; Menu { }", QUrl());
+
+ QPointer<QQuickMenu> menu1(qobject_cast<QQuickMenu *>(component.create()));
+ QVERIFY(!menu1.isNull());
+ menuBar->addMenu(menu1.data());
+ QCOMPARE(menuBar->count(), 1);
+ QCOMPARE(menuBar->menuAt(0), menu1.data());
+
+ QPointer<QQuickMenuBarItem> menuBarItem1(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0)));
+ QVERIFY(menuBarItem1);
+ QCOMPARE(menuBarItem1->menu(), menu1.data());
+ QCOMPARE(menuBar->itemAt(0), menuBarItem1.data());
+
+ QScopedPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create()));
+ QVERIFY(!menu2.isNull());
+ menuBar->insertMenu(0, menu2.data());
+ QCOMPARE(menuBar->count(), 2);
+ QCOMPARE(menuBar->menuAt(0), menu2.data());
+ QCOMPARE(menuBar->menuAt(1), menu1.data());
+
+ QPointer<QQuickMenuBarItem> menuBarItem2(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0)));
+ QVERIFY(menuBarItem2);
+ QCOMPARE(menuBarItem2->menu(), menu2.data());
+ QCOMPARE(menuBar->itemAt(0), menuBarItem2.data());
+ QCOMPARE(menuBar->itemAt(1), menuBarItem1.data());
+
+ // takeMenu(int) does not destroy the menu, but does destroy the respective item in the menubar
+ QCOMPARE(menuBar->takeMenu(1), menu1.data());
+ QCOMPARE(menuBar->count(), 1);
+ QVERIFY(!menuBar->menuAt(1));
+ QVERIFY(!menuBar->itemAt(1));
+ QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
+ QVERIFY(!menu1.isNull());
+ QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
+ QVERIFY(menuBarItem1.isNull());
+
+ // addMenu(Menu) re-creates the respective item in the menubar
+ menuBar->addMenu(menu1.data());
+ QCOMPARE(menuBar->count(), 2);
+ menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
+ QVERIFY(!menuBarItem1.isNull());
+
+ // removeMenu(Menu) destroys both the menu and the respective item in the menubar
+ menuBar->removeMenu(menu1.data());
+ QCOMPARE(menuBar->count(), 1);
+ QVERIFY(!menuBar->itemAt(1));
+ QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
+ QVERIFY(menu1.isNull());
+ QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
+ QVERIFY(menuBarItem1.isNull());
+}
+
+QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar)
+
+#include "tst_qquickmenubar.moc"
diff --git a/tests/auto/qquickninepatchimage/data/foo.9.png b/tests/auto/qquickninepatchimage/data/foo.9.png
new file mode 100644
index 00000000..51246990
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/foo.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/foo@2x.9.png b/tests/auto/qquickninepatchimage/data/foo@2x.9.png
new file mode 100644
index 00000000..c8dc30a3
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/foo@2x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/foo@3x.9.png b/tests/auto/qquickninepatchimage/data/foo@3x.9.png
new file mode 100644
index 00000000..00ea4e05
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/foo@3x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/foo@4x.9.png b/tests/auto/qquickninepatchimage/data/foo@4x.9.png
new file mode 100644
index 00000000..ea73340a
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/foo@4x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-all.9.png b/tests/auto/qquickninepatchimage/data/inset-all.9.png
new file mode 100644
index 00000000..e08ef9c7
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-all.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png
new file mode 100644
index 00000000..96d1c0e8
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png
new file mode 100644
index 00000000..215ce27e
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png
new file mode 100644
index 00000000..35e53101
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png
new file mode 100644
index 00000000..c4c37dff
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png
new file mode 100644
index 00000000..3d64036f
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png
new file mode 100644
index 00000000..115184d9
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png
new file mode 100644
index 00000000..2ec7cbef
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft.9.png
new file mode 100644
index 00000000..9cc5f43d
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-topleft.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png
new file mode 100644
index 00000000..a4ca2b12
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png
new file mode 100644
index 00000000..73f3595a
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png
new file mode 100644
index 00000000..78baa463
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/ninepatchimage.qml b/tests/auto/qquickninepatchimage/data/ninepatchimage.qml
new file mode 100644
index 00000000..7ef07a1c
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/ninepatchimage.qml
@@ -0,0 +1,7 @@
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+import QtQuick.Controls.Imagine 2.3
+import QtQuick.Controls.Imagine.impl 2.3
+
+NinePatchImage {
+}
diff --git a/tests/auto/qquickninepatchimage/data/padding.9.png b/tests/auto/qquickninepatchimage/data/padding.9.png
new file mode 100644
index 00000000..5b4f0960
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/padding.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/padding@2x.9.png b/tests/auto/qquickninepatchimage/data/padding@2x.9.png
new file mode 100644
index 00000000..44eb1943
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/padding@2x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/padding@3x.9.png b/tests/auto/qquickninepatchimage/data/padding@3x.9.png
new file mode 100644
index 00000000..d1563448
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/padding@3x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/data/padding@4x.9.png b/tests/auto/qquickninepatchimage/data/padding@4x.9.png
new file mode 100644
index 00000000..e86cce69
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/data/padding@4x.9.png
Binary files differ
diff --git a/tests/auto/qquickninepatchimage/qquickninepatchimage.pro b/tests/auto/qquickninepatchimage/qquickninepatchimage.pro
new file mode 100644
index 00000000..b40a5f4c
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/qquickninepatchimage.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+macos:CONFIG -= app_bundle
+TARGET = tst_qquickninepatchimage
+
+QT += core gui qml quick testlib
+QT_PRIVATE += gui-private quick-private quickcontrols2-private
+
+include (../shared/util.pri)
+
+SOURCES += tst_qquickninepatchimage.cpp
+
+TESTDATA += \
+ $$PWD/data/*.qml \
+ $$PWD/data/*.png
diff --git a/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp b/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp
new file mode 100644
index 00000000..b5dd7f2f
--- /dev/null
+++ b/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp
@@ -0,0 +1,245 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QtTest/qsignalspy.h>
+
+#include <QtCore/qmath.h>
+#include <QtCore/qsize.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/qquickitemgrabresult.h>
+#include <QtQuick/private/qquickimage_p.h>
+
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_qquickninepatchimage : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void ninePatch_data();
+ void ninePatch();
+ void padding_data();
+ void padding();
+ void inset_data();
+ void inset();
+ void implicitSize_data();
+ void implicitSize();
+};
+
+static QImage grabItemToImage(QQuickItem *item)
+{
+ QSharedPointer<QQuickItemGrabResult> result = item->grabToImage();
+ QSignalSpy spy(result.data(), SIGNAL(ready()));
+ spy.wait();
+ return result->image();
+}
+
+void tst_qquickninepatchimage::ninePatch_data()
+{
+ QTest::addColumn<int>("dpr");
+ QTest::addColumn<QSize>("size");
+
+ // original size, downsized, stretched
+ const QList<QSize> sizes = QList<QSize>()
+ << QSize(40, 40) // original
+ << QSize(10, 40) // downsized (h)
+ << QSize(40, 10) // downsized (v)
+ << QSize(10, 10) // downsized (h & v)
+ << QSize(80, 40) // stretched (h)
+ << QSize(40, 80) // stretched (v)
+ << QSize(80, 80) // stretched (h & v)
+ << QSize(8, 8); // minimal (borders only)
+
+ for (const QSize &sz : sizes) {
+ for (int dpr = 1; dpr <= 4; ++dpr)
+ QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1, %2x%3").arg(dpr).arg(sz.width()).arg(sz.height()))) << dpr << sz;
+ }
+}
+
+void tst_qquickninepatchimage::ninePatch()
+{
+ QFETCH(int, dpr);
+ QFETCH(QSize, size);
+
+ QHighDpiScaling::setGlobalFactor(dpr);
+
+ QQuickView view(testFileUrl("ninepatchimage.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject());
+ QVERIFY(ninePatchImage);
+ ninePatchImage->setSource(testFileUrl("foo.9.png"));
+ ninePatchImage->setSize(size);
+
+ const QImage ninePatchImageGrab = grabItemToImage(ninePatchImage).scaled(size * dpr);
+
+ // Generate an image to compare against the actual 9-patch image.
+ QImage generatedImage(size * dpr, ninePatchImageGrab.format());
+ generatedImage.fill(Qt::red);
+
+ QImage blueRect(4 * dpr, 4 * dpr, ninePatchImageGrab.format());
+ blueRect.fill(Qt::blue);
+
+ QPainter painter(&generatedImage);
+ // Top-left
+ painter.drawImage(0, 0, blueRect);
+ // Top-right
+ painter.drawImage(generatedImage.width() - blueRect.width(), 0, blueRect);
+ // Bottom-right
+ painter.drawImage(generatedImage.width() - blueRect.width(), generatedImage.height() - blueRect.height(), blueRect);
+ // Bottom-left
+ painter.drawImage(0, generatedImage.height() - blueRect.height(), blueRect);
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Grabbing does not work on offscreen/minimal platforms", Abort);
+
+ QCOMPARE(ninePatchImageGrab, generatedImage);
+}
+
+void tst_qquickninepatchimage::padding_data()
+{
+ QTest::addColumn<int>("dpr");
+
+ for (int dpr = 1; dpr <= 4; ++dpr)
+ QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1").arg(dpr))) << dpr;
+}
+
+void tst_qquickninepatchimage::padding()
+{
+ QFETCH(int, dpr);
+
+ QHighDpiScaling::setGlobalFactor(dpr);
+
+ QQuickView view(testFileUrl("ninepatchimage.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject());
+ QVERIFY(ninePatchImage);
+ ninePatchImage->setSource(testFileUrl("padding.9.png"));
+
+ QCOMPARE(ninePatchImage->property("topPadding").toReal(), 8);
+ QCOMPARE(ninePatchImage->property("leftPadding").toReal(), 18);
+ QCOMPARE(ninePatchImage->property("rightPadding").toReal(), 20);
+ QCOMPARE(ninePatchImage->property("bottomPadding").toReal(), 10);
+}
+
+void tst_qquickninepatchimage::inset_data()
+{
+ QTest::addColumn<int>("dpr");
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QMarginsF>("insets");
+
+ const QStringList files = QStringList() << "inset-all.9.png" << "inset-topleft.9.png" << "inset-bottomright.9.png";
+ const QList<QMarginsF> insets = QList<QMarginsF>() << QMarginsF(2, 1, 3, 4) << QMarginsF(2, 1, 0, 0) << QMarginsF(0, 0, 3, 4);
+
+ for (int i = 0; i < files.count(); ++i) {
+ QString file = files.at(i);
+ for (int dpr = 1; dpr <= 4; ++dpr)
+ QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file).arg(dpr))) << dpr << file << insets.at(i);
+ }
+}
+
+Q_DECLARE_METATYPE(QMarginsF)
+
+void tst_qquickninepatchimage::inset()
+{
+ QFETCH(int, dpr);
+ QFETCH(QString, file);
+ QFETCH(QMarginsF, insets);
+
+ QHighDpiScaling::setGlobalFactor(dpr);
+
+ QQuickView view(testFileUrl("ninepatchimage.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject());
+ QVERIFY(ninePatchImage);
+ ninePatchImage->setSource(testFileUrl(file));
+
+ QCOMPARE(ninePatchImage->property("topInset").toReal(), insets.top());
+ QCOMPARE(ninePatchImage->property("leftInset").toReal(), insets.left());
+ QCOMPARE(ninePatchImage->property("rightInset").toReal(), insets.right());
+ QCOMPARE(ninePatchImage->property("bottomInset").toReal(), insets.bottom());
+}
+
+void tst_qquickninepatchimage::implicitSize_data()
+{
+ QTest::addColumn<int>("dpr");
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<QSizeF>("implicitSize");
+
+ const QStringList files = QStringList() << "foo.9.png" << "padding.9.png" << "inset-all.9.png" << "inset-topleft.9.png" << "inset-bottomright.9.png";
+
+ for (const QString &file : files) {
+ for (int dpr = 1; dpr <= 4; ++dpr)
+ QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file).arg(dpr))) << dpr << file << QSizeF(40, 40);
+ }
+}
+
+void tst_qquickninepatchimage::implicitSize()
+{
+ QFETCH(int, dpr);
+ QFETCH(QString, file);
+ QFETCH(QSizeF, implicitSize);
+
+ QHighDpiScaling::setGlobalFactor(dpr);
+
+ QQuickView view(testFileUrl("ninepatchimage.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject());
+ QVERIFY(ninePatchImage);
+ ninePatchImage->setSource(testFileUrl(file));
+
+ QCOMPARE(ninePatchImage->implicitWidth(), implicitSize.width());
+ QCOMPARE(ninePatchImage->implicitHeight(), implicitSize.height());
+}
+
+QTEST_MAIN(tst_qquickninepatchimage)
+
+#include "tst_qquickninepatchimage.moc"
diff --git a/tests/auto/qquickpopup/BLACKLIST b/tests/auto/qquickpopup/BLACKLIST
new file mode 100644
index 00000000..47795a8b
--- /dev/null
+++ b/tests/auto/qquickpopup/BLACKLIST
@@ -0,0 +1,10 @@
+[overlay]
+# QTBUG-62668
+*
+
+[closePolicy]
+# QTBUG-62668
+*
+
+
+
diff --git a/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml b/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml
index 53dae0f9..f41516c8 100644
--- a/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml
+++ b/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.9
+import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp
index 3f4b2d13..a1e5e246 100644
--- a/tests/auto/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp
@@ -79,6 +79,7 @@ private slots:
void cursorShape();
void componentComplete();
void closeOnEscapeWithNestedPopups();
+ void enabled();
void orientation_data();
void orientation();
};
@@ -217,6 +218,15 @@ void tst_QQuickPopup::overlay()
QQuickPopup *popup = window->property("popup").value<QQuickPopup*>();
QVERIFY(popup);
+ QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(qmlAttachedPropertiesObject<QQuickOverlay>(popup));
+ QVERIFY(overlayAttached);
+ QCOMPARE(overlayAttached->overlay(), overlay);
+
+ QSignalSpy overlayAttachedPressedSignal(overlayAttached, SIGNAL(pressed()));
+ QSignalSpy overlayAttachedReleasedSignal(overlayAttached, SIGNAL(released()));
+ QVERIFY(overlayAttachedPressedSignal.isValid());
+ QVERIFY(overlayAttachedReleasedSignal.isValid());
+
QQuickButton *button = window->property("button").value<QQuickButton*>();
QVERIFY(button);
@@ -230,10 +240,14 @@ void tst_QQuickPopup::overlay()
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
popup->close();
QVERIFY(!popup->isVisible());
@@ -251,10 +265,14 @@ void tst_QQuickPopup::overlay()
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
QVERIFY(!popup->isVisible());
QCOMPARE(overlay->isVisible(), popup->isVisible());
@@ -280,10 +298,14 @@ void tst_QQuickPopup::overlay()
QTest::touchEvent(window, device.data()).press(0, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
QTest::touchEvent(window, device.data()).release(0, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
+ QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
+ QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
QVERIFY(!popup->isVisible());
QCOMPARE(overlay->isVisible(), popup->isVisible());
@@ -387,6 +409,28 @@ void tst_QQuickPopup::windowChange()
popup.setParentItem(window.contentItem());
QCOMPARE(popup.window(), &window);
QCOMPARE(spy.count(), 3);
+
+ popup.resetParentItem();
+ QVERIFY(!popup.window());
+ QCOMPARE(spy.count(), 4);
+
+ popup.setParent(&window);
+ popup.resetParentItem();
+ QCOMPARE(popup.window(), &window);
+ QCOMPARE(spy.count(), 5);
+
+ popup.setParent(this);
+ popup.resetParentItem();
+ QVERIFY(!popup.window());
+ QCOMPARE(spy.count(), 6);
+
+ item.setParentItem(window.contentItem());
+ popup.setParent(&item);
+ popup.resetParentItem();
+ QCOMPARE(popup.window(), &window);
+ QCOMPARE(spy.count(), 7);
+
+ popup.setParent(nullptr);
}
Q_DECLARE_METATYPE(QQuickPopup::ClosePolicy)
@@ -942,6 +986,26 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
QCOMPARE(stackView->depth(), 1);
}
+void tst_QQuickPopup::enabled()
+{
+ QQuickPopup popup;
+ QVERIFY(popup.isEnabled());
+ QVERIFY(popup.popupItem()->isEnabled());
+
+ QSignalSpy enabledSpy(&popup, &QQuickPopup::enabledChanged);
+ QVERIFY(enabledSpy.isValid());
+
+ popup.setEnabled(false);
+ QVERIFY(!popup.isEnabled());
+ QVERIFY(!popup.popupItem()->isEnabled());
+ QCOMPARE(enabledSpy.count(), 1);
+
+ popup.popupItem()->setEnabled(true);
+ QVERIFY(popup.isEnabled());
+ QVERIFY(popup.popupItem()->isEnabled());
+ QCOMPARE(enabledSpy.count(), 2);
+}
+
void tst_QQuickPopup::orientation_data()
{
QTest::addColumn<Qt::ScreenOrientation>("orientation");
diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml
new file mode 100644
index 00000000..ee17c230
--- /dev/null
+++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml
@@ -0,0 +1,2 @@
+import QtQuick.Templates 2.1 as T
+T.Button { }
diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml
new file mode 100644
index 00000000..ee17c230
--- /dev/null
+++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml
@@ -0,0 +1,2 @@
+import QtQuick.Templates 2.1 as T
+T.Button { }
diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml
new file mode 100644
index 00000000..ee17c230
--- /dev/null
+++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml
@@ -0,0 +1,2 @@
+import QtQuick.Templates 2.1 as T
+T.Button { }
diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml
new file mode 100644
index 00000000..ee17c230
--- /dev/null
+++ b/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml
@@ -0,0 +1,2 @@
+import QtQuick.Templates 2.1 as T
+T.Button { }
diff --git a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp
index 598320d2..e90a8bd9 100644
--- a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp
+++ b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp
@@ -49,6 +49,8 @@ private slots:
void select_data();
void select();
+
+ void platformSelectors();
};
void tst_QQuickStyleSelector::initTestCase()
@@ -139,6 +141,24 @@ void tst_QQuickStyleSelector::select()
QCOMPARE(selector.select(file), expected);
}
+void tst_QQuickStyleSelector::platformSelectors()
+{
+ QQuickStyle::setStyle(QDir(dataDirectory()).filePath("PlatformStyle"));
+
+ QQuickStyleSelector selector;
+ selector.setBaseUrl(dataDirectoryUrl());
+
+#if defined(Q_OS_LINUX)
+ QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+linux/Button.qml").toString());
+#elif defined(Q_OS_MACOS)
+ QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+macos/Button.qml").toString());
+#elif defined(Q_OS_WIN)
+ QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+windows/Button.qml").toString());
+#else
+ QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/Button.qml").toString());
+#endif
+}
+
QTEST_MAIN(tst_QQuickStyleSelector)
#include "tst_qquickstyleselector.moc"
diff --git a/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf
index 836372c9..0ec13258 100644
--- a/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf
+++ b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf
@@ -4,3 +4,7 @@ Style=Universal
[Universal]
Background=#444444
Foreground=Red
+Font\PixelSize=22
+
+[Universal\Font]
+Family=Courier
diff --git a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp
index c6b28be3..51cc5883 100644
--- a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp
+++ b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp
@@ -55,16 +55,22 @@ void tst_qquickuniversalstyleconf::conf()
{
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
+ QFont customFont;
+ customFont.setFamily("Courier");
+ customFont.setPixelSize(22);
+
QQuickApplicationWindow *window = helper.appWindow;
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
- // We specified a custom background color, so the window should have it.
+ // We specified a custom background color and font, so the window should have them.
QCOMPARE(window->property("color").value<QColor>(), QColor("#444444"));
+ QCOMPARE(window->property("font").value<QFont>(), customFont);
- // We specified a custom foreground color, so the label should have it.
+ // We specified a custom foreground color and font, so the label should have them.
QQuickItem *label = window->property("label").value<QQuickItem*>();
QVERIFY(label);
QCOMPARE(label->property("color").value<QColor>(), QColor("#E51400"));
+ QCOMPARE(label->property("font").value<QFont>(), customFont);
}
QTEST_MAIN(tst_qquickuniversalstyleconf)
diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp
index 2988c96c..25e118e3 100644
--- a/tests/auto/sanity/tst_sanity.cpp
+++ b/tests/auto/sanity/tst_sanity.cpp
@@ -314,6 +314,7 @@ void tst_Sanity::attachedObjects_data()
QTest::addColumn<QUrl>("url");
addTestRows(&engine, "calendar", "Qt/labs/calendar");
addTestRows(&engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
+ addTestRows(&engine, "controls/fusion", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator");
addTestRows(&engine, "controls/material", "QtQuick/Controls.2/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate");
addTestRows(&engine, "controls/universal", "QtQuick/Controls.2/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator");
}
diff --git a/tests/auto/shared/qtest_quickcontrols.h b/tests/auto/shared/qtest_quickcontrols.h
new file mode 100644
index 00000000..d1fe08f6
--- /dev/null
+++ b/tests/auto/shared/qtest_quickcontrols.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 QTEST_QUICKCONTROLS_H
+#define QTEST_QUICKCONTROLS_H
+
+#include <QtTest/qtest.h>
+#include <QtTest/private/qtestresult_p.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+static QStringList testStyles()
+{
+ if (QQuickStyle::name().isEmpty())
+ return QQuickStyle::availableStyles();
+ return QStringList(QQuickStyle::name());
+}
+
+static int runTests(QObject *testObject, int argc, char *argv[])
+{
+ int res = 0;
+ QTest::qInit(testObject, argc, argv);
+ const QByteArray testObjectName = QTestResult::currentTestObjectName();
+ const QStringList styles = testStyles();
+ for (const QString &style : styles) {
+ qmlClearTypeRegistrations();
+ QQuickStyle::setStyle(style);
+ const QByteArray testName = testObjectName + "::" + style.toLocal8Bit();
+ QTestResult::setCurrentTestObject(testName);
+ res += QTest::qRun();
+ }
+ QTestResult::setCurrentTestObject(testObjectName);
+ QTest::qCleanup();
+ return res;
+}
+
+#define QTEST_QUICKCONTROLS_MAIN(TestCase) \
+QT_BEGIN_NAMESPACE \
+QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \
+QT_END_NAMESPACE \
+int main(int argc, char *argv[]) \
+{ \
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1"); \
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); \
+ QGuiApplication app(argc, argv); \
+ QTEST_ADD_GPU_BLACKLIST_SUPPORT \
+ TestCase tc; \
+ QTEST_SET_MAIN_SOURCE_PATH \
+ return runTests(&tc, argc, argv); \
+}
+
+#endif // QTEST_QUICKCONTROLS_H
diff --git a/tests/auto/shared/util.pri b/tests/auto/shared/util.pri
index 03191511..77c2cc59 100644
--- a/tests/auto/shared/util.pri
+++ b/tests/auto/shared/util.pri
@@ -1,7 +1,8 @@
-QT += core-private gui-private qml-private quick-private quicktemplates2-private
+QT += testlib-private core-private gui-private qml-private quick-private quicktemplates2-private quickcontrols2
HEADERS += $$PWD/visualtestutil.h \
- $$PWD/util.h
+ $$PWD/util.h \
+ $$PWD/qtest_quickcontrols.h
SOURCES += $$PWD/visualtestutil.cpp \
$$PWD/util.cpp
diff --git a/tests/auto/shared/visualtestutil.cpp b/tests/auto/shared/visualtestutil.cpp
index 60b8790d..c5e69812 100644
--- a/tests/auto/shared/visualtestutil.cpp
+++ b/tests/auto/shared/visualtestutil.cpp
@@ -38,6 +38,8 @@
#include <QtQuick/QQuickItem>
#include <QtCore/QDebug>
+#include <QtGui/QCursor>
+#include <QtCore/QCoreApplication>
bool QQuickVisualTestUtil::delegateVisible(QQuickItem *item)
{
@@ -69,3 +71,24 @@ void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth)
}
}
+void QQuickVisualTestUtil::moveMouseAway(QQuickWindow *window)
+{
+#if QT_CONFIG(cursor) // Get the cursor out of the way.
+ // Using "bottomRight() + QPoint(100, 100)" was causing issues on Ubuntu,
+ // where the window was positioned at the bottom right corner of the window
+ // (even after centering the window on the screen), so we use another position.
+ QCursor::setPos(window->geometry().bottomLeft() + QPoint(0, 10));
+#endif
+
+ // make sure hover events from QQuickWindowPrivate::flushFrameSynchronousEvents()
+ // do not interfere with the tests
+ QEvent leave(QEvent::Leave);
+ QCoreApplication::sendEvent(window, &leave);
+}
+
+void QQuickVisualTestUtil::centerOnScreen(QQuickWindow *window)
+{
+ const QRect screenGeometry = window->screen()->availableGeometry();
+ const QPoint offset = QPoint(window->width() / 2, window->height() / 2);
+ window->setFramePosition(screenGeometry.center() - offset);
+}
diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h
index 12f955ea..a6b52fef 100644
--- a/tests/auto/shared/visualtestutil.h
+++ b/tests/auto/shared/visualtestutil.h
@@ -54,6 +54,10 @@ namespace QQuickVisualTestUtil
bool delegateVisible(QQuickItem *item);
+ void centerOnScreen(QQuickWindow *window);
+
+ void moveMouseAway(QQuickWindow *window);
+
/*
Find an item with the specified objectName. If index is supplied then the
item must also evaluate the {index} expression equal to index