diff options
Diffstat (limited to 'tests')
99 files changed, 5667 insertions, 436 deletions
diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp index 4208a366..614566e6 100644 --- a/tests/auto/accessibility/tst_accessibility.cpp +++ b/tests/auto/accessibility/tst_accessibility.cpp @@ -113,16 +113,6 @@ void tst_accessibility::a11y_data() QTest::newRow("WeekNumberColumn") << "weeknumbercolumn" << 0x0 << "WeekNumberColumn"; //QAccessible::NoRole } -#if QT_CONFIG(accessibility) -static QQuickAccessibleAttached *accessibleAttached(QQuickItem *item) -{ - QQuickAccessibleAttached *acc = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)); - if (!acc) - acc = item->findChild<QQuickAccessibleAttached *>(); - return acc; -} -#endif - void tst_accessibility::a11y() { QFETCH(QString, name); @@ -152,7 +142,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")) { @@ -161,7 +151,7 @@ void tst_accessibility::a11y() } else { QVERIFY(!acc); QAccessible::setActive(true); - acc = accessibleAttached(item); + acc = QQuickAccessibleAttached::attachedProperties(item); } } QVERIFY(acc); @@ -170,8 +160,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/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index 61f84673..60160afe 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -504,7 +504,7 @@ void tst_applicationwindow::font() QCOMPARE(item6->font(), font); } -class TestTheme : public QQuickProxyTheme +class TestTheme : public QQuickProxyTheme { public: TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme), m_font("Courier") diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 048eabed..9295fc21 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -9,9 +9,13 @@ SUBDIRS += \ focus \ font \ menu \ + palette \ platform \ popup \ pressandhold \ + qquickcolor \ + qquickiconimage \ + qquickiconlabel \ qquickmaterialstyle \ qquickmaterialstyleconf \ qquickstyle \ @@ -24,6 +28,7 @@ SUBDIRS += \ # QTBUG-60268 boot2qt: SUBDIRS -= applicationwindow calendar controls cursor \ - drawer focus font menu platform popup qquickmaterialstyle \ - qquickmaterialstyleconf qquickuniversalstyle \ - qquickuniversalstyleconf snippets + drawer focus font menu platform palette popup \ + qquickmaterialstyle qquickmaterialstyleconf \ + qquickuniversalstyle qquickuniversalstyleconf \ + snippets diff --git a/tests/auto/controls/controls.pro b/tests/auto/controls/controls.pro index 8f2f8e69..c61dff0e 100644 --- a/tests/auto/controls/controls.pro +++ b/tests/auto/controls/controls.pro @@ -1,5 +1,6 @@ TEMPLATE = subdirs SUBDIRS += \ default \ + fusion \ material \ universal diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index bddb952f..a7f4ab8a 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 @@ -162,4 +162,131 @@ 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) + } } 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 07e49e70..4f969106 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -707,7 +707,7 @@ TestCase { compare(highlightedSpy.count, 0) mouseMove(content, content.width / 2 + 1, content.height / 2 + 1) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) + compare(highlightedSpy.count, 1) mouseRelease(content) compare(activatedSpy.count, 1) compare(highlightedSpy.count, 1) @@ -1151,6 +1151,55 @@ TestCase { closedSpy.target = null } + function test_mouseHighlight() { + 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)?/ @@ -1441,7 +1490,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() @@ -1457,6 +1506,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 049982fb..44d8e67a 100644 --- a/tests/auto/controls/data/tst_container.qml +++ b/tests/auto/controls/data/tst_container.qml @@ -126,4 +126,46 @@ TestCase { compare(control1.currentIndex, 1) compare(control2.currentIndex, 1) } + + 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..5ad3e81a 100644 --- a/tests/auto/controls/data/tst_dialog.qml +++ b/tests/auto/controls/data/tst_dialog.qml @@ -99,6 +99,7 @@ TestCase { verify(acceptedSpy.valid) control.accept() compare(acceptedSpy.count, 1) + compare(control.result, Dialog.Accepted) tryCompare(control, "visible", false) } @@ -118,6 +119,7 @@ TestCase { verify(rejectedSpy.valid) control.reject() compare(rejectedSpy.count, 1) + compare(control.result, Dialog.Rejected) tryCompare(control, "visible", false) @@ -356,4 +358,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_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_popup.qml b/tests/auto/controls/data/tst_popup.qml index bec50ad0..c8b3985c 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -1178,16 +1178,6 @@ TestCase { compare(child.ApplicationWindow.window, null) } - SignalSpy { - id: openedSpy - signalName: "opened" - } - - SignalSpy { - id: closedSpy - signalName: "closed" - } - Component { id: pausePopup Popup { @@ -1200,19 +1190,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 6697de88..ec0be3f8 100644 --- a/tests/auto/controls/data/tst_scrollbar.qml +++ b/tests/auto/controls/data/tst_scrollbar.qml @@ -736,4 +736,18 @@ 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) + } } diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index 54cd7159..1e28c4f5 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -217,4 +217,18 @@ TestCase { compare(horizontal.contentItem.x, horizontal.leftPadding + 0.8 * horizontal.availableWidth) 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) + } } 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 4b2e38b3..17e4b592 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 @@ -276,8 +284,19 @@ TestCase { compare(valueModifiedSpy.count, 2) } - 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 @@ -296,48 +315,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) @@ -348,7 +350,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) @@ -358,31 +360,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() { @@ -454,46 +431,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 3328c84f..097180b8 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_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..5c9905d5 100644 --- a/tests/auto/controls/data/tst_tabbar.qml +++ b/tests/auto/controls/data/tst_tabbar.qml @@ -514,39 +514,183 @@ TestCase { 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_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/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/menu/data/actions.qml b/tests/auto/menu/data/actions.qml new file mode 100644 index 00000000..7cb1215c --- /dev/null +++ b/tests/auto/menu/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.9 +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/menu/data/popup.qml b/tests/auto/menu/data/popup.qml new file mode 100644 index 00000000..4e21bf1f --- /dev/null +++ b/tests/auto/menu/data/popup.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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.3 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + property alias menuItem1: menuItem1 + property alias menuItem2: menuItem2 + property alias menuItem3: menuItem3 + + 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) + } + + Menu { + id: menu + MenuItem { id: menuItem1; text: "Foo" } + MenuItem { id: menuItem2; text: "Bar" } + MenuItem { id: menuItem3; text: "Baz" } + } +} diff --git a/tests/auto/menu/data/removeTakeItem.qml b/tests/auto/menu/data/removeTakeItem.qml new file mode 100644 index 00000000..9a2914ed --- /dev/null +++ b/tests/auto/menu/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.9 +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/menu/tst_menu.cpp b/tests/auto/menu/tst_menu.cpp index 1e6eaceb..f788d5ee 100644 --- a/tests/auto/menu/tst_menu.cpp +++ b/tests/auto/menu/tst_menu.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> @@ -69,6 +70,9 @@ private slots: void menuSeparator(); void repeater(); void order(); + void popup(); + void actions(); + void removeTakeItem(); }; void tst_menu::defaults() @@ -132,6 +136,21 @@ void tst_menu::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)); @@ -174,16 +193,20 @@ void tst_menu::contextMenuKeyboard() QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); QTest::keyClick(window, Qt::Key_Tab); QVERIFY(firstItem->hasActiveFocus()); + QVERIFY(firstItem->property("highlighted").toBool()); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); QQuickItem *secondItem = menu->itemAt(1); QTest::keyClick(window, Qt::Key_Tab); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QVERIFY(secondItem->hasActiveFocus()); + QVERIFY(secondItem->property("highlighted").toBool()); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1)); QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered())); @@ -193,7 +216,9 @@ void tst_menu::contextMenuKeyboard() QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->property("highlighted").toBool()); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); menu->open(); @@ -201,26 +226,36 @@ void tst_menu::contextMenuKeyboard() QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->property("highlighted").toBool()); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); QTest::keyClick(window, Qt::Key_Down); QVERIFY(firstItem->hasActiveFocus()); + QVERIFY(firstItem->property("highlighted").toBool()); QTest::keyClick(window, Qt::Key_Down); QVERIFY(secondItem->hasActiveFocus()); + QVERIFY(secondItem->property("highlighted").toBool()); QTest::keyClick(window, Qt::Key_Down); QQuickItem *thirdItem = menu->itemAt(2); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->property("highlighted").toBool()); QVERIFY(thirdItem->hasActiveFocus()); + QVERIFY(thirdItem->property("highlighted").toBool()); // Key navigation shouldn't wrap by default. QTest::keyClick(window, Qt::Key_Down); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); QVERIFY(!secondItem->hasActiveFocus()); + QVERIFY(!secondItem->property("highlighted").toBool()); QVERIFY(thirdItem->hasActiveFocus()); + QVERIFY(thirdItem->property("highlighted").toBool()); QTest::keyClick(window, Qt::Key_Escape); QCOMPARE(visibleSpy.count(), 4); @@ -384,6 +419,155 @@ void tst_menu::order() } } +void tst_menu::popup() +{ + QQuickApplicationHelper helper(this, QLatin1String("popup.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(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); + +#if QT_CONFIG(cursor) + QPoint cursorPos = window->mapToGlobal(QPoint(11, 22)); + QCursor::setPos(cursorPos); + QTRY_COMPARE(QCursor::pos(), cursorPos); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtCursor")); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->property("x").toInt(), 11); + QTRY_COMPARE(menu->property("y").toInt(), 22); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtPos", Q_ARG(QVariant, QPointF(33, 44)))); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->property("x").toInt(), 33); + QTRY_COMPARE(menu->property("y").toInt(), 44); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, 66))); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->property("x").toInt(), 55); + QTRY_COMPARE(menu->property("y").toInt(), 66); + 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) { + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCursor", Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->property("x").toInt(), 12); + QTRY_COMPARE(menu->property("y").toInt(), 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->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->property("x").toInt(), 33); + QTRY_COMPARE(menu->property("y").toInt(), 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->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->property("x").toInt(), 55); + QTRY_COMPARE(menu->property("y").toInt(), window->height() / 3 * 2 + menu->topPadding() - menuItem->y()); + menu->close(); + } +#endif +} + +void tst_menu::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); + + QQuickMenuItem *menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(0)); + QVERIFY(menuItem1); + QVERIFY(menuItem1->action()); + QCOMPARE(menuItem1->text(), "action1"); + + QQuickMenuItem *menuItem2 = qobject_cast<QQuickMenuItem *>(menu->itemAt(1)); + QVERIFY(menuItem2); + QVERIFY(!menuItem2->action()); + QCOMPARE(menuItem2->text(), "menuitem2"); + + QQuickMenuItem *menuItem3 = qobject_cast<QQuickMenuItem *>(menu->itemAt(2)); + QVERIFY(menuItem3); + QVERIFY(menuItem3->action()); + QCOMPARE(menuItem3->text(), "action3"); + + QQuickMenuItem *menuItem4 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3)); + QVERIFY(menuItem4); + QVERIFY(!menuItem4->action()); + QCOMPARE(menuItem4->text(), "menuitem4"); +} + +void tst_menu::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()); +} + QTEST_MAIN(tst_menu) #include "tst_menu.moc" diff --git a/tests/auto/palette/data/inheritance-control.qml b/tests/auto/palette/data/inheritance-control.qml new file mode 100644 index 00000000..860d9b0c --- /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.9 +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-popup.qml b/tests/auto/palette/data/inheritance-popup.qml new file mode 100644 index 00000000..aceff6f2 --- /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.9 +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/palette-appwindow-custom.qml b/tests/auto/palette/data/palette-appwindow-custom.qml new file mode 100644 index 00000000..90b07605 --- /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.9 +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..97376690 --- /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.9 +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..eeefec3d --- /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.9 +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..91f38843 --- /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.9 +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..55b24fc9 --- /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.9 +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..6cff3efd --- /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.9 +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..2d125725 --- /dev/null +++ b/tests/auto/palette/tst_palette.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** 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/qquickpopup_p.h> +#include <QtQuickControls2/private/qquickproxytheme_p.h> + +using namespace QQuickVisualTestUtil; + +class tst_palette : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void palette_data(); + void palette(); + + void inheritance_data(); + void inheritance(); + + void defaultPalette_data(); + void defaultPalette(); +}; + +void tst_palette::palette_data() +{ + QTest::addColumn<QString>("testFile"); + QTest::addColumn<QPalette>("expectedPalette"); + + QPalette defaultPalette; + 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("Popup") << "inheritance-popup.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; + 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::SystemPalette; +} + +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); +} + +QTEST_MAIN(tst_palette) + +#include "tst_palette.moc" diff --git a/tests/auto/qquickcolor/data/tst_color.qml b/tests/auto/qquickcolor/data/tst_color.qml new file mode 100644 index 00000000..ab398ea4 --- /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.9 +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/qquickiconimage/data/alignment.qml b/tests/auto/qquickiconimage/data/alignment.qml new file mode 100644 index 00000000..e3ed3857 --- /dev/null +++ b/tests/auto/qquickiconimage/data/alignment.qml @@ -0,0 +1,16 @@ +import QtQuick 2.9 +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..39d94259 --- /dev/null +++ b/tests/auto/qquickiconimage/data/color.qml @@ -0,0 +1,18 @@ +import QtQuick 2.9 +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..e3ed3857 --- /dev/null +++ b/tests/auto/qquickiconimage/data/fileSelectors.qml @@ -0,0 +1,16 @@ +import QtQuick 2.9 +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..440e8d1f --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml @@ -0,0 +1,7 @@ +import QtQuick 2.9 +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..e3ed3857 --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml @@ -0,0 +1,16 @@ +import QtQuick 2.9 +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..fe24e94a --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml @@ -0,0 +1,10 @@ +import QtQuick 2.9 +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..ba65d9df --- /dev/null +++ b/tests/auto/qquickiconimage/data/root.qml @@ -0,0 +1,6 @@ +import QtQuick 2.9 + +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..51cf6498 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml @@ -0,0 +1,15 @@ +import QtQuick 2.9 +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..f4fc424f --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml @@ -0,0 +1,16 @@ +import QtQuick 2.9 +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..65e9b5f7 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml @@ -0,0 +1,10 @@ +import QtQuick 2.9 +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..a3ea3323 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml @@ -0,0 +1,8 @@ +import QtQuick 2.9 +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..40ae3247 --- /dev/null +++ b/tests/auto/qquickiconimage/data/svgNoSizes.qml @@ -0,0 +1,15 @@ +import QtQuick 2.9 +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..da52c561 --- /dev/null +++ b/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml @@ -0,0 +1,17 @@ +import QtQuick 2.9 +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 Binary files differnew file mode 100644 index 00000000..18b7c678 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png 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 Binary files differnew file mode 100644 index 00000000..c6ceca43 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new.png 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 Binary files differnew file mode 100644 index 00000000..f380ebb6 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/+testselector/appointment-new@2x.png diff --git a/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png Binary files differnew file mode 100644 index 00000000..d676ffd4 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new.png 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 Binary files differnew file mode 100644 index 00000000..63ae9ce7 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/appointment-new@2x.png 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 Binary files differnew file mode 100644 index 00000000..2d876cc1 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original.png 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 Binary files differnew file mode 100644 index 00000000..c65fbed0 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-original@2x.png 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 Binary files differnew file mode 100644 index 00000000..220a313d --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted.png 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 Binary files differnew file mode 100644 index 00000000..cd66ef69 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22/actions/color-test-tinted@2x.png 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 Binary files differnew file mode 100644 index 00000000..f380ebb6 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/+testselector/appointment-new.png 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 Binary files differnew file mode 100644 index 00000000..63ae9ce7 --- /dev/null +++ b/tests/auto/qquickiconimage/icons/testtheme/22x22@2/actions/appointment-new.png 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..e60c32c8 --- /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.9 +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..7a1bafdf --- /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.9 +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..858f84b2 --- /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.9 +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..82eb5aee --- /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.9 +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/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/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/benchmarks/objectcount/tst_objectcount.cpp b/tests/benchmarks/objectcount/tst_objectcount.cpp index d12f3293..551d2009 100644 --- a/tests/benchmarks/objectcount/tst_objectcount.cpp +++ b/tests/benchmarks/objectcount/tst_objectcount.cpp @@ -124,6 +124,7 @@ static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QSt static void initTestRows(QQmlEngine *engine) { addTestRows(engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); + addTestRows(engine, "controls/fusion", "QtQuick/Controls.2/Fusion", QStringList() << "ButtonPanel" << "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/manual/testbench/testbench.qml b/tests/manual/testbench/testbench.qml index 2ebb9923..3bb38fe8 100644 --- a/tests/manual/testbench/testbench.qml +++ b/tests/manual/testbench/testbench.qml @@ -66,8 +66,11 @@ ApplicationWindow { y = Screen.height / 2 - height / 2 } - Material.theme: themeSwitch.checked ? Material.Dark : Material.Light - Universal.theme: themeSwitch.checked ? Universal.Dark : Universal.Light + LayoutMirroring.childrenInherit: true + LayoutMirroring.enabled: mirroredMenuItem.checked + + Material.theme: darkMenuItem.checked ? Material.Dark : Material.Light + Universal.theme: darkMenuItem.checked ? Universal.Dark : Universal.Light property int controlSpacing: 10 @@ -82,95 +85,157 @@ ApplicationWindow { RowLayout { anchors.fill: parent + RowLayout { + enabled: enabledMenuItem.checked + + ToolButton { + text: "ToolButton" + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered + } + ToolButton { + text: "Pressed" + down: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered + } + ToolButton { + text: "Checked" + checkable: true + checked: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered + } + ToolButton { + text: "Highlighted" + highlighted: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered + } + ToolButton { + text: "Disabled" + enabled: false + } + + ToolSeparator {} + + ToolButton { + text: "1" + } + ToolButton { + text: "2" + } + + ToolSeparator {} + + ToolButton { + id: menuButton + text: "Menu" + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered + checked: menu.visible + checkable: true + + Menu { + id: menu + x: 1 + y: 1 + parent.height + visible: menuButton.checked + closePolicy: Popup.CloseOnPressOutsideParent + + MenuItem { + text: "MenuItem" + } + MenuItem { + text: "Pressed" + down: true + } + MenuItem { + text: "Disabled" + enabled: false + } + + MenuSeparator {} + + MenuItem { + text: "Checked" + checked: true + } + MenuItem { + text: "CH+PR" + checked: true + down: true + } + MenuItem { + text: "CH+DIS" + checked: true + enabled: false + } + } + } + } + + Item { + Layout.fillWidth: true + } + ToolButton { - text: "Normal" - hoverEnabled: true - ToolTip.text: text - ToolTip.delay: 1000 - ToolTip.visible: hovered - onClicked: menu.visible ? menu.close() : menu.open() + id: optionsMenuButton + text: "\u22EE" // VERTICAL ELLIPSIS + checked: optionsMenu.visible + checkable: true Menu { - id: menu + id: optionsMenu x: 1 y: 1 + parent.height + visible: optionsMenuButton.checked + closePolicy: Popup.CloseOnPressOutsideParent MenuItem { - text: "Option 1" + id: enabledMenuItem + text: "Enabled" checkable: true + checked: true } + MenuItem { - text: "Option 2" + id: mirroredMenuItem + text: "Mirrored" checkable: true } + MenuItem { - text: "Option 3" + id: darkMenuItem + text: "Dark" checkable: true } MenuSeparator {} MenuItem { - text: "Option A" + text: "Quit" + onTriggered: Qt.quit() } } } - ToolButton { - text: "Pressed" - down: true - hoverEnabled: true - ToolTip.text: text - ToolTip.delay: 1000 - ToolTip.visible: hovered - } - ToolButton { - text: "Checked" - checkable: true - checked: true - hoverEnabled: true - ToolTip.text: text - ToolTip.delay: 1000 - ToolTip.visible: hovered - } - ToolButton { - text: "Highlighted" - highlighted: true - hoverEnabled: true - ToolTip.text: text - ToolTip.delay: 1000 - ToolTip.visible: hovered - } - ToolButton { - text: "Disabled" - enabled: false - } - - ToolSeparator {} - - ToolButton { - text: "1" - } - ToolButton { - text: "2" - } - - ToolSeparator {} - - Item { - Layout.fillWidth: true - } - Label { - text: "Light/Dark" - } - Switch { - id: themeSwitch - } } } footer: TabBar { + enabled: enabledMenuItem.checked TabButton { - text: "Normal" + text: "TabButton" } TabButton { text: "Pressed" @@ -193,12 +258,13 @@ ApplicationWindow { id: flow width: parent.width spacing: 30 + enabled: enabledMenuItem.checked RowLayout { spacing: window.controlSpacing Button { - text: "Normal" + text: "Button" } Button { text: "Pressed" @@ -263,36 +329,6 @@ ApplicationWindow { RowLayout { spacing: window.controlSpacing * 2 - Button { - text: "Normal" - } - Button { - text: "Pressed" - down: true - } - Button { - text: "Checked" - checked: true - } - Button { - text: "CH + PR" - checked: true - down: true - } - Button { - text: "Disabled" - enabled: false - } - Button { - text: "CH + DIS" - enabled: false - checked: true - } - } - - RowLayout { - spacing: window.controlSpacing * 2 - ColumnLayout { RoundButton { highlighted: true @@ -364,7 +400,7 @@ ApplicationWindow { RowLayout { CheckBox { - text: "Normal" + text: "CheckBox" } CheckBox { text: "Pressed" @@ -391,8 +427,42 @@ ApplicationWindow { } RowLayout { + CheckBox { + text: "Tri-state\nCheckBox" + tristate: true + } + CheckBox { + text: "Pressed" + down: true + tristate: true + } + CheckBox { + text: "Partially\nChecked" + tristate: true + checkState: Qt.PartiallyChecked + } + CheckBox { + text: "CH + PR" + tristate: true + checkState: Qt.PartiallyChecked + down: true + } + CheckBox { + text: "Disabled" + tristate: true + enabled: false + } + CheckBox { + text: "CH + DIS" + tristate: true + checkState: Qt.PartiallyChecked + enabled: false + } + } + + RowLayout { RadioButton { - text: "Normal" + text: "RadioButton" } RadioButton { text: "Pressed" @@ -420,7 +490,7 @@ ApplicationWindow { RowLayout { Switch { - text: "Normal" + text: "Switch" } Switch { text: "Pressed" @@ -439,11 +509,16 @@ ApplicationWindow { text: "Disabled" enabled: false } + Switch { + text: "CH + DIS" + checked: true + enabled: false + } } RowLayout { ProgressBar { - value: 0.5 + value: slider.value } ProgressBar { value: 0.5 @@ -457,6 +532,7 @@ ApplicationWindow { RowLayout { Slider { + id: slider value: 0.5 } Slider { @@ -487,149 +563,110 @@ ApplicationWindow { } RowLayout { - Item { - implicitWidth: normalGroupBox.width - implicitHeight: normalTextArea.implicitHeight + spacing: window.controlSpacing * 2 - TextArea { - id: normalTextArea - text: "Normal" - } + TextArea { + text: "TextArea" + Layout.preferredWidth: normalGroupBox.implicitWidth } - Item { - implicitWidth: normalGroupBox.width - implicitHeight: normalTextArea.implicitHeight - TextArea { - placeholderText: "Placeholder" - } + TextArea { + placeholderText: "Placeholder" + Layout.preferredWidth: normalGroupBox.implicitWidth } - Item { - implicitWidth: normalGroupBox.width - implicitHeight: normalTextArea.implicitHeight - TextArea { - text: "Disabled" - enabled: false - } + TextArea { + text: "Disabled" + enabled: false + Layout.preferredWidth: normalGroupBox.implicitWidth } } RowLayout { - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalTextField.implicitHeight + spacing: window.controlSpacing * 2 - TextField { - id: normalTextField - text: "Normal" - } + TextField { + text: "TextField" } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalTextField.implicitHeight - - TextField { - placeholderText: "Placeholder" - } + TextField { + placeholderText: "Placeholder" } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalTextField.implicitHeight - - TextField { - text: "Disabled" - enabled: false - } + TextField { + text: "Disabled" + enabled: false } } RowLayout { - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalSpinBox.implicitHeight + spacing: window.controlSpacing * 2 - SpinBox { - id: normalSpinBox - } + SpinBox { + id: normalSpinBox } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalSpinBox.implicitHeight - - SpinBox { - up.pressed: true - } + SpinBox { + up.pressed: true } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalSpinBox.implicitHeight - - SpinBox { - enabled: false - } + SpinBox { + editable: true + } + SpinBox { + enabled: false } } RowLayout { - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalComboBox.implicitHeight + spacing: window.controlSpacing * 2 - ComboBox { - id: normalComboBox - model: 5 - } + ComboBox { + model: 5 } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalComboBox.implicitHeight + ComboBox { + pressed: true + model: ["Pressed"] + } - ComboBox { - pressed: true - model: ListModel { - ListElement { text: "Pressed" } - } + ComboBox { + editable: true + model: ListModel { + id: fruitModel + ListElement { text: "Banana" } + ListElement { text: "Apple" } + ListElement { text: "Coconut" } + } + onAccepted: { + if (find(editText) === -1) + fruitModel.append({text: editText}) } } - Item { - implicitWidth: normalGroupBox.implicitWidth - implicitHeight: normalComboBox.implicitHeight - - ComboBox { - enabled: false - model: ["Disabled"] - } + ComboBox { + enabled: false + model: ["Disabled"] } } RowLayout { GroupBox { id: normalGroupBox - title: "Normal" + title: "GroupBox" - Item { - implicitWidth: 200 - implicitHeight: 100 + contentWidth: 200 + contentHeight: 100 - BusyIndicator { - anchors.centerIn: parent - } + BusyIndicator { + anchors.centerIn: parent } } GroupBox { enabled: false title: "Disabled" - Item { - implicitWidth: 200 - implicitHeight: 100 + contentWidth: 200 + contentHeight: 100 - BusyIndicator { - anchors.centerIn: parent - } + BusyIndicator { + anchors.centerIn: parent } } GroupBox { @@ -637,16 +674,14 @@ ApplicationWindow { title: "." label.visible: false - Item { - implicitWidth: 200 - implicitHeight: 100 + contentWidth: 200 + contentHeight: 100 - PageIndicator { - count: 5 - enabled: false - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - } + PageIndicator { + count: 5 + enabled: false + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter } } } @@ -655,79 +690,77 @@ ApplicationWindow { Frame { id: scrollBarFrame - Item { - implicitWidth: 200 - implicitHeight: 100 + padding: 0 + contentWidth: 200 + contentHeight: 100 - Label { - text: "Normal" - anchors.centerIn: parent - } + Label { + text: "ScrollBar" + anchors.centerIn: parent + } - ScrollBar { - size: 0.3 - position: 0.2 - active: true - orientation: Qt.Vertical - height: parent.height - anchors.right: parent.right - } + ScrollBar { + size: 0.6 + position: 0.1 + policy: ScrollBar.AlwaysOn + orientation: Qt.Vertical + height: parent.height + anchors.right: parent.right } } Frame { - Item { - implicitWidth: 200 - implicitHeight: 100 + padding: 0 + contentWidth: 200 + contentHeight: 100 - Label { - text: "Pressed" - anchors.centerIn: parent - } + Label { + text: "Pressed" + anchors.centerIn: parent + } - ScrollBar { - size: 0.3 - position: 0.2 - active: true - orientation: Qt.Vertical - height: parent.height - anchors.right: parent.right - pressed: true - } + ScrollBar { + size: 0.6 + position: 0.1 + policy: ScrollBar.AlwaysOn + orientation: Qt.Vertical + height: parent.height + anchors.right: parent.right + pressed: true } } Frame { - Item { - implicitWidth: 200 - implicitHeight: 100 - enabled: false + padding: 0 + contentWidth: 200 + contentHeight: 100 + enabled: false - Label { - text: "Disabled" - anchors.centerIn: parent - } + Label { + text: "Disabled" + anchors.centerIn: parent + } - ScrollBar { - size: 0.3 - position: 0.2 - active: true - orientation: Qt.Vertical - height: parent.height - anchors.right: parent.right - } + ScrollBar { + size: 0.6 + position: 0.1 + policy: ScrollBar.AlwaysOn + orientation: Qt.Vertical + height: parent.height + anchors.right: parent.right } } } RowLayout { Frame { + padding: 0 Layout.preferredWidth: 100 Layout.preferredHeight: 100 ScrollIndicator { - size: 0.3 - position: 0.2 + size: 0.6 + position: 0.1 active: true orientation: Qt.Vertical height: parent.height @@ -736,12 +769,13 @@ ApplicationWindow { } Frame { + padding: 0 Layout.preferredWidth: 100 Layout.preferredHeight: 100 ScrollIndicator { - size: 0.3 - position: 0.2 + size: 0.6 + position: 0.1 active: true orientation: Qt.Vertical height: parent.height @@ -771,10 +805,12 @@ ApplicationWindow { RowLayout { Dial { + value: 0.5 implicitWidth: 100 implicitHeight: 100 } Dial { + value: 0.5 implicitWidth: 100 implicitHeight: 100 enabled: false @@ -783,11 +819,11 @@ ApplicationWindow { ListModel { id: checkableDelegateModel - ListElement { label: "Normal" } ListElement { label: "Pressed"; press: true } ListElement { label: "Checked"; check: true } ListElement { label: "CH + PR"; check: true; press: true } ListElement { label: "Disabled"; disabled: true } + ListElement { label: "CH + DIS"; check: true; disabled: true } } RowLayout { @@ -795,6 +831,12 @@ ApplicationWindow { Column { width: 200 + CheckDelegate { + text: "CheckDelegate" + width: parent.width + focusPolicy: Qt.StrongFocus + } + Repeater { model: checkableDelegateModel delegate: CheckDelegate { @@ -803,20 +845,22 @@ ApplicationWindow { down: press checked: check enabled: !disabled - ButtonGroup.group: radioButtonGroup + focusPolicy: Qt.StrongFocus } } } } - ButtonGroup { - id: radioButtonGroup - } - Frame { Column { width: 200 + RadioDelegate { + text: "RadioDelegate" + width: parent.width + focusPolicy: Qt.StrongFocus + } + Repeater { model: checkableDelegateModel delegate: RadioDelegate { @@ -825,7 +869,7 @@ ApplicationWindow { width: parent.width checked: check enabled: !disabled - ButtonGroup.group: radioButtonGroup + focusPolicy: Qt.StrongFocus } } } @@ -835,6 +879,12 @@ ApplicationWindow { Column { width: 200 + SwitchDelegate { + text: "SwitchDelegate" + width: parent.width + focusPolicy: Qt.StrongFocus + } + Repeater { model: checkableDelegateModel delegate: SwitchDelegate { @@ -843,6 +893,7 @@ ApplicationWindow { checked: check down: press enabled: !disabled + focusPolicy: Qt.StrongFocus } } } @@ -851,7 +902,6 @@ ApplicationWindow { ListModel { id: regularDelegateModel - ListElement { label: "Normal" } ListElement { label: "Pressed"; press: true } ListElement { label: "Disabled"; disabled: true } } @@ -861,6 +911,12 @@ ApplicationWindow { Column { width: 200 + ItemDelegate { + text: "ItemDelegate" + width: parent.width + focusPolicy: Qt.StrongFocus + } + Repeater { model: regularDelegateModel delegate: ItemDelegate { @@ -868,6 +924,7 @@ ApplicationWindow { width: parent.width down: press enabled: !disabled + focusPolicy: Qt.StrongFocus } } } @@ -878,41 +935,55 @@ ApplicationWindow { width: 200 clip: true + SwipeDelegate { + text: "SwipeDelegate" + width: parent.width + swipe.left: removeComponent + swipe.right: removeComponent + focusPolicy: Qt.StrongFocus + } + Repeater { model: regularDelegateModel delegate: SwipeDelegate { - id: swipeDelegate text: label width: parent.width down: press enabled: !disabled - - Component { - id: removeComponent - - Rectangle { - color: swipeDelegate.swipe.complete && swipeDelegate.pressed ? "#333" : "#444" - width: parent.width - height: parent.height - clip: true - - Label { - font.pixelSize: swipeDelegate.font.pixelSize - text: "Boop" - color: "white" - anchors.centerIn: parent - } - } - } + focusPolicy: Qt.StrongFocus swipe.left: removeComponent swipe.right: removeComponent } } + + Component { + id: removeComponent + + Rectangle { + color: parent.swipe.complete && parent.pressed ? "#333" : "#444" + width: parent.width + height: parent.height + clip: true + + Label { + font.pixelSize: parent.parent.font.pixelSize + text: "Boop" + color: "white" + anchors.centerIn: parent + } + } + } } } } } + + ScrollBar.vertical: ScrollBar { + parent: window.contentItem + x: parent.width - width + height: parent.height + } } } } |