diff options
Diffstat (limited to 'tests/auto')
173 files changed, 8410 insertions, 205 deletions
diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp index 4208a366..7e491b54 100644 --- a/tests/auto/accessibility/tst_accessibility.cpp +++ b/tests/auto/accessibility/tst_accessibility.cpp @@ -43,6 +43,9 @@ #include "../shared/util.h" #if QT_CONFIG(accessibility) +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> +#include <QtGui/qpa/qplatformaccessibility.h> #include <QtQuick/private/qquickaccessibleattached_p.h> #endif @@ -114,12 +117,10 @@ void tst_accessibility::a11y_data() } #if QT_CONFIG(accessibility) -static QQuickAccessibleAttached *accessibleAttached(QQuickItem *item) +static QPlatformAccessibility *platformAccessibility() { - QQuickAccessibleAttached *acc = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)); - if (!acc) - acc = item->findChild<QQuickAccessibleAttached *>(); - return acc; + QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration(); + return pfIntegration ? pfIntegration->accessibility() : nullptr; } #endif @@ -152,7 +153,7 @@ void tst_accessibility::a11y() QVERIFY(item); #if QT_CONFIG(accessibility) - QQuickAccessibleAttached *acc = accessibleAttached(item); + QQuickAccessibleAttached *acc = QQuickAccessibleAttached::attachedProperties(item); if (name != QLatin1Literal("dayofweekrow") && name != QLatin1Literal("monthgrid") && name != QLatin1Literal("weeknumbercolumn")) { @@ -160,8 +161,11 @@ void tst_accessibility::a11y() QVERIFY(acc); } else { QVERIFY(!acc); - QAccessible::setActive(true); - acc = accessibleAttached(item); + QPlatformAccessibility *accessibility = platformAccessibility(); + if (!accessibility) + QSKIP("No QPlatformAccessibility available."); + accessibility->setActive(true); + acc = QQuickAccessibleAttached::attachedProperties(item); } } QVERIFY(acc); @@ -170,8 +174,6 @@ void tst_accessibility::a11y() #else Q_UNUSED(role) Q_UNUSED(text) - QObject *acc = qmlAttachedPropertiesObject<QObject>(item, false); - QVERIFY(!acc); #endif } diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 0aeef414..7dfd552e 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -6,13 +6,20 @@ SUBDIRS += \ cursor \ focus \ font \ + palette \ platform \ pressandhold \ qquickapplicationwindow \ + qquickcolor \ qquickdrawer \ + qquickiconimage \ + qquickiconlabel \ + qquickimaginestyle \ qquickmaterialstyle \ qquickmaterialstyleconf \ qquickmenu \ + qquickmenubar \ + qquickninepatchimage \ qquickpopup \ qquickstyle \ qquickstyleselector \ @@ -21,9 +28,3 @@ SUBDIRS += \ revisions \ sanity \ snippets - -# QTBUG-60268 -boot2qt: SUBDIRS -= qquickapplicationwindow calendar controls cursor \ - qquickdrawer focus font qquickmenu platform qquickpopup qquickmaterialstyle \ - qquickmaterialstyleconf qquickuniversalstyle \ - qquickuniversalstyleconf snippets diff --git a/tests/auto/controls/controls.pro b/tests/auto/controls/controls.pro index 8f2f8e69..fd852c4b 100644 --- a/tests/auto/controls/controls.pro +++ b/tests/auto/controls/controls.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ default \ + fusion \ + imagine \ material \ universal diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index bddb952f..7579d410 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.3 TestCase { id: testCase @@ -71,6 +71,11 @@ TestCase { } Component { + id: action + Action { } + } + + Component { id: signalSpy SignalSpy { } } @@ -162,4 +167,190 @@ TestCase { keyRelease(data.key) compare(container.lastKeyRelease, data.result) } + + function test_icon() { + var control = createTemporaryObject(button, testCase) + verify(control) + compare(control.icon.name, "") + compare(control.icon.source, "") + compare(control.icon.width, 0) + compare(control.icon.height, 0) + compare(control.icon.color, "#00000000") + + var iconSpy = signalSpy.createObject(control, { target: control, signalName: "iconChanged"} ) + verify(iconSpy.valid) + + control.icon.name = "test-name" + compare(control.icon.name, "test-name") + compare(iconSpy.count, 1) + + control.icon.source = "qrc:/test-source" + compare(control.icon.source, "qrc:/test-source") + compare(iconSpy.count, 2) + + control.icon.width = 32 + compare(control.icon.width, 32) + compare(iconSpy.count, 3) + + control.icon.height = 32 + compare(control.icon.height, 32) + compare(iconSpy.count, 4) + + control.icon.color = "#ff0000" + compare(control.icon.color, "#ff0000") + compare(iconSpy.count, 5) + } + + Component { + id: actionButton + AbstractButton { + action: Action { + text: "Default" + icon.name: "default" + icon.source: "qrc:/icons/default.png" + checkable: true + checked: true + enabled: false + } + } + } + + function test_action() { + var control = createTemporaryObject(actionButton, testCase) + verify(control) + + // initial values + compare(control.text, "Default") + compare(control.icon.name, "default") + compare(control.icon.source, "qrc:/icons/default.png") + compare(control.checkable, true) + compare(control.checked, true) + compare(control.enabled, false) + + // changes via action + control.action.text = "Action" + control.action.icon.name = "action" + control.action.icon.source = "qrc:/icons/action.png" + control.action.checkable = false + control.action.checked = false + control.action.enabled = true + compare(control.text, "Action") // propagates + compare(control.icon.name, "action") // propagates + compare(control.icon.source, "qrc:/icons/action.png") // propagates + compare(control.checkable, false) // propagates + compare(control.checked, false) // propagates + compare(control.enabled, true) // propagates + + // changes via button + control.text = "Button" + control.icon.name = "button" + control.icon.source = "qrc:/icons/button.png" + control.checkable = true + control.checked = true + control.enabled = false + compare(control.text, "Button") + compare(control.icon.name, "button") + compare(control.icon.source, "qrc:/icons/button.png") + compare(control.checkable, true) + compare(control.checked, true) + compare(control.enabled, false) + compare(control.action.text, "Action") // does NOT propagate + compare(control.action.icon.name, "action") // does NOT propagate + compare(control.action.icon.source, "qrc:/icons/action.png") // does NOT propagate + compare(control.action.checkable, true) // propagates + compare(control.action.checked, true) // propagates + compare(control.action.enabled, true) // does NOT propagate + } + + function test_trigger_data() { + return [ + {tag: "click", click: true, button: true, action: true, clicked: true, triggered: true}, + {tag: "click disabled button", click: true, button: false, action: true, clicked: false, triggered: false}, + {tag: "click disabled action", click: true, button: true, action: false, clicked: true, triggered: false}, + {tag: "trigger", trigger: true, button: true, action: true, clicked: true, triggered: true}, + {tag: "trigger disabled button", trigger: true, button: false, action: true, clicked: false, triggered: true}, + {tag: "trigger disabled action", trigger: true, button: true, action: false, clicked: false, triggered: false} + ] + } + + function test_trigger(data) { + var control = createTemporaryObject(actionButton, testCase, {"enabled": data.button, "action.enabled": data.action}) + verify(control) + + compare(control.enabled, data.button) + compare(control.action.enabled, data.action) + + var buttonSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) + verify(buttonSpy.valid) + + var actionSpy = signalSpy.createObject(control, {target: control.action, signalName: "triggered"}) + verify(actionSpy.valid) + + if (data.click) + mouseClick(control) + else if (data.trigger) + control.action.trigger() + + compare(buttonSpy.count, data.clicked ? 1 : 0) + compare(actionSpy.count, data.triggered ? 1 : 0) + } + + function test_mnemonic() { + if (Qt.platform.os === "osx" || Qt.platform.os === "macos") + skip("Mnemonics are not used on macOS") + + var control = createTemporaryObject(button, testCase) + verify(control) + + control.text = "&Hello" + compare(control.text, "Hello") // ### TODO: visualize mnemonics + + var clickSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) + verify(clickSpy.valid) + + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 1) + + control.visible = false + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 1) + + control.visible = true + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 2) + + control.text = "Te&st" + compare(control.text, "Test") // ### TODO: visualize mnemonics + + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 2) + + keyClick(Qt.Key_S, Qt.AltModifier) + compare(clickSpy.count, 3) + + control.visible = false + control.text = "&Hidden" + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 3) + + control.visible = true + keyClick(Qt.Key_H, Qt.AltModifier) + compare(clickSpy.count, 4) + + control.action = action.createObject(control, {text: "&Action"}) + + var actionSpy = signalSpy.createObject(control, {target: control.action, signalName: "triggered"}) + verify(actionSpy.valid) + + keyClick(Qt.Key_A, Qt.AltModifier) + compare(actionSpy.count, 1) + compare(clickSpy.count, 5) + + // ungrab on destruction (don't crash) + control.Component.onDestruction.connect(function() { control = null }) + control.destroy() + wait(0) + verify(!control) + keyClick(Qt.Key_H, Qt.AltModifier) + } } diff --git a/tests/auto/controls/data/tst_action.qml b/tests/auto/controls/data/tst_action.qml new file mode 100644 index 00000000..7d057c26 --- /dev/null +++ b/tests/auto/controls/data/tst_action.qml @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.3 +import QtQuick.Templates 2.3 as T + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + when: windowShown + name: "Action" + + Component { + id: component + Action { } + } + + Component { + id: signalSpy + SignalSpy { } + } + + function test_enabled() { + var action = createTemporaryObject(component, testCase) + verify(action) + + var spy = createTemporaryObject(signalSpy, testCase, {target: action, signalName: "triggered"}) + verify(spy.valid) + + action.trigger() + compare(spy.count, 1) + + action.enabled = false + action.trigger() + compare(spy.count, 1) + + action.enabled = undefined // reset + action.trigger() + compare(spy.count, 2) + } + + Component { + id: buttonAndMenu + Item { + property alias button: button + property alias menu: menu + property alias menuItem: menuItem + property alias action: sharedAction + property var lastSource + Action { + id: sharedAction + text: "Shared" + shortcut: "Ctrl+B" + onTriggered: lastSource = source + } + Button { + id: button + action: sharedAction + Menu { + id: menu + MenuItem { + id: menuItem + action: sharedAction + } + } + } + } + } + + function test_shared() { + var container = createTemporaryObject(buttonAndMenu, testCase) + verify(container) + + keyClick(Qt.Key_B, Qt.ControlModifier) + compare(container.lastSource, container.button) + + container.menu.open() + keyClick(Qt.Key_B, Qt.ControlModifier) + compare(container.lastSource, container.menuItem) + + tryVerify(function() { return !container.menu.visible }) + keyClick(Qt.Key_B, Qt.ControlModifier) + compare(container.lastSource, container.button) + + container.button.visible = false + keyClick(Qt.Key_B, Qt.ControlModifier) + compare(container.lastSource, container.action) + } +} diff --git a/tests/auto/controls/data/tst_actiongroup.qml b/tests/auto/controls/data/tst_actiongroup.qml new file mode 100644 index 00000000..6b31336d --- /dev/null +++ b/tests/auto/controls/data/tst_actiongroup.qml @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.3 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "ActionGroup" + + Component { + id: actionGroup + ActionGroup { } + } + + Component { + id: nonExclusiveGroup + ActionGroup { exclusive: false } + } + + Component { + id: signalSpy + SignalSpy { } + } + + function test_null() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + + group.addAction(null) + group.removeAction(null) + } + + Component { + id: action + Action { } + } + + function test_defaults() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + compare(group.actions.length, 0) + compare(group.checkedAction, null) + compare(group.exclusive, true) + } + + function test_current() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + + var checkedActionSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "checkedActionChanged"}) + verify(checkedActionSpy.valid) + verify(!group.checkedAction) + + var action1 = createTemporaryObject(action, testCase, {checked: true}) + var action2 = createTemporaryObject(action, testCase, {checked: false}) + var action3 = createTemporaryObject(action, testCase, {checked: true, objectName: "3"}) + + // add checked + group.addAction(action1) + compare(group.checkedAction, action1) + compare(action1.checked, true) + compare(action2.checked, false) + compare(action3.checked, true) + compare(checkedActionSpy.count, 1) + + // add non-checked + group.addAction(action2) + compare(group.checkedAction, action1) + compare(action1.checked, true) + compare(action2.checked, false) + compare(action3.checked, true) + compare(checkedActionSpy.count, 1) + + // add checked + group.addAction(action3) + compare(group.checkedAction, action3) + compare(action1.checked, false) + compare(action2.checked, false) + compare(action3.checked, true) + compare(checkedActionSpy.count, 2) + + // change current + group.checkedAction = action2 + compare(group.checkedAction, action2) + compare(action1.checked, false) + compare(action2.checked, true) + compare(action3.checked, false) + compare(checkedActionSpy.count, 3) + + // check + action1.checked = true + compare(group.checkedAction, action1) + compare(action1.checked, true) + compare(action2.checked, false) + compare(action3.checked, false) + compare(checkedActionSpy.count, 4) + + // remove non-checked + group.removeAction(action2) + compare(group.checkedAction, action1) + compare(action1.checked, true) + compare(action2.checked, false) + compare(action3.checked, false) + compare(checkedActionSpy.count, 4) + + // remove checked + group.removeAction(action1) + verify(!group.checkedAction) + compare(action1.checked, false) + compare(action2.checked, false) + compare(action3.checked, false) + compare(checkedActionSpy.count, 5) + } + + function test_actions() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + + var actionsSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "actionsChanged"}) + verify(actionsSpy.valid) + + compare(group.actions.length, 0) + compare(group.checkedAction, null) + + var action1 = createTemporaryObject(action, testCase, {checked: true}) + var action2 = createTemporaryObject(action, testCase, {checked: false}) + + group.actions = [action1, action2] + compare(group.actions.length, 2) + compare(group.actions[0], action1) + compare(group.actions[1], action2) + compare(group.checkedAction, action1) + compare(actionsSpy.count, 2) + + var action3 = createTemporaryObject(action, testCase, {checked: true}) + + group.addAction(action3) + compare(group.actions.length, 3) + compare(group.actions[0], action1) + compare(group.actions[1], action2) + compare(group.actions[2], action3) + compare(group.checkedAction, action3) + compare(actionsSpy.count, 3) + + group.removeAction(action1) + compare(group.actions.length, 2) + compare(group.actions[0], action2) + compare(group.actions[1], action3) + compare(group.checkedAction, action3) + compare(actionsSpy.count, 4) + + group.actions = [] + compare(group.actions.length, 0) + tryCompare(group, "checkedAction", null) + compare(actionsSpy.count, 5) + } + + function test_triggered_data() { + return [ + {tag: "exclusive", exclusive: true}, + {tag: "non-exclusive", exclusive: false} + ] + } + + function test_triggered(data) { + var group = createTemporaryObject(actionGroup, testCase, {exclusive: data.exclusive}) + verify(group) + + var triggeredSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "triggered"}) + verify(triggeredSpy.valid) + + var action1 = createTemporaryObject(action, testCase) + var action2 = createTemporaryObject(action, testCase) + + group.addAction(action1) + group.addAction(action2) + + action1.triggered() + compare(triggeredSpy.count, 1) + compare(triggeredSpy.signalArguments[0][0], action1) + + action2.triggered() + compare(triggeredSpy.count, 2) + compare(triggeredSpy.signalArguments[1][0], action2) + } + + Component { + id: attachedGroup + Item { + property ActionGroup group: ActionGroup { id: group } + property Action action1: Action { ActionGroup.group: group } + property Action action2: Action { ActionGroup.group: group } + property Action action3: Action { ActionGroup.group: group } + } + } + + function test_attached() { + var container = createTemporaryObject(attachedGroup, testCase) + verify(container) + + verify(!container.group.checkedAction) + + container.action1.checked = true + compare(container.group.checkedAction, container.action1) + compare(container.action1.checked, true) + compare(container.action2.checked, false) + compare(container.action3.checked, false) + + container.action2.checked = true + compare(container.group.checkedAction, container.action2) + compare(container.action1.checked, false) + compare(container.action2.checked, true) + compare(container.action3.checked, false) + + container.action3.checked = true + compare(container.group.checkedAction, container.action3) + compare(container.action1.checked, false) + compare(container.action2.checked, false) + compare(container.action3.checked, true) + } + + function test_actionDestroyed() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + + var actionsSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "actionsChanged"}) + verify(actionsSpy.valid) + + var action1 = createTemporaryObject(action, testCase, {objectName: "action1", checked: true}) + + group.addAction(action1) + compare(group.actions.length, 1) + compare(group.actions[0], action1) + compare(group.checkedAction, action1) + compare(actionsSpy.count, 1) + + action1.destroy() + wait(0) + compare(group.actions.length, 0) + compare(group.checkedAction, null) + compare(actionsSpy.count, 2) + } + + function test_nonExclusive() { + var group = createTemporaryObject(nonExclusiveGroup, testCase) + verify(group) + + var action1 = createTemporaryObject(action, testCase, {checked: true}) + group.addAction(action1) + compare(action1.checked, true) + compare(group.checkedAction, null) + + var action2 = createTemporaryObject(action, testCase, {checked: true}) + group.addAction(action2) + compare(action1.checked, true) + compare(action2.checked, true) + compare(group.checkedAction, null) + + action1.checked = false + compare(action1.checked, false) + compare(action2.checked, true) + compare(group.checkedAction, null) + + action2.checked = false + compare(action1.checked, false) + compare(action2.checked, false) + compare(group.checkedAction, null) + + action1.checked = true + compare(action1.checked, true) + compare(action2.checked, false) + compare(group.checkedAction, null) + + action2.checked = true + compare(action1.checked, true) + compare(action2.checked, true) + compare(group.checkedAction, null) + } + + function test_enabled() { + var group = createTemporaryObject(actionGroup, testCase) + verify(group) + + compare(group.enabled, true) + + var action1 = createTemporaryObject(action, testCase) + var action2 = createTemporaryObject(action, testCase) + compare(action1.enabled, true) + compare(action2.enabled, true) + + var action1Spy = createTemporaryObject(signalSpy, testCase, {target: action1, signalName: "enabledChanged"}) + var action2Spy = createTemporaryObject(signalSpy, testCase, {target: action2, signalName: "enabledChanged"}) + verify(action1Spy.valid && action2Spy.valid) + + group.addAction(action1) + compare(action1.enabled, true) + compare(action2.enabled, true) + compare(action1Spy.count, 0) + compare(action2Spy.count, 0) + + group.enabled = false + compare(action1.enabled, false) + compare(action2.enabled, true) + compare(action1Spy.count, 1) + compare(action1Spy.signalArguments[0][0], false) + compare(action2Spy.count, 0) + + group.addAction(action2) + compare(action1.enabled, false) + compare(action2.enabled, false) + compare(action1Spy.count, 1) + compare(action2Spy.count, 1) + compare(action2Spy.signalArguments[0][0], false) + + action1.enabled = false + compare(action1.enabled, false) + compare(action1Spy.count, 2) + compare(action1Spy.signalArguments[1][0], false) + compare(action2Spy.count, 1) + + group.enabled = true + compare(action1.enabled, false) + compare(action2.enabled, true) + compare(action1Spy.count, 2) + compare(action2Spy.count, 2) + compare(action2Spy.signalArguments[1][0], true) + } +} diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml index cf9cf64d..2cf399f4 100644 --- a/tests/auto/controls/data/tst_button.qml +++ b/tests/auto/controls/data/tst_button.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.3 TestCase { id: testCase @@ -430,4 +430,83 @@ TestCase { control.highlighted = true verify(control.highlighted) } + + function test_spacing() { + var control = createTemporaryObject(button, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem + // should be equal to the implicitWidth of the Text while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // That means that spacing shouldn't affect it. + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // The implicitWidth of the Button itself should, therefore, also never include spacing while no icon is set. + compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: Button.IconOnly }, + { "tag": "TextOnly", display: Button.TextOnly }, + { "tag": "TextUnderIcon", display: Button.TextUnderIcon }, + { "tag": "TextBesideIcon", display: Button.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: Button.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: Button.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: Button.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: Button.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(button, testCase, { + text: "Button", + display: data.display, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case Button.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case Button.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case Button.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case Button.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_buttongroup.qml b/tests/auto/controls/data/tst_buttongroup.qml index bde655da..cbbaec5a 100644 --- a/tests/auto/controls/data/tst_buttongroup.qml +++ b/tests/auto/controls/data/tst_buttongroup.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.3 TestCase { id: testCase @@ -66,6 +66,11 @@ TestCase { } Component { + id: nonExclusiveGroup + ButtonGroup { exclusive: false } + } + + Component { id: signalSpy SignalSpy { } } @@ -88,6 +93,14 @@ TestCase { QtObject { } } + function test_defaults() { + var group = createTemporaryObject(buttonGroup, testCase) + verify(group) + compare(group.buttons.length, 0) + compare(group.checkedButton, null) + compare(group.exclusive, true) + } + function test_current() { var group = createTemporaryObject(buttonGroup, testCase) verify(group) @@ -200,8 +213,15 @@ TestCase { compare(buttonsSpy.count, 5) } - function test_clicked() { - var group = createTemporaryObject(buttonGroup, testCase) + function test_clicked_data() { + return [ + {tag: "exclusive", exclusive: true}, + {tag: "non-exclusive", exclusive: false} + ] + } + + function test_clicked(data) { + var group = createTemporaryObject(buttonGroup, testCase, {exclusive: data.exclusive}) verify(group) var clickedSpy = createTemporaryObject(signalSpy, testCase, {target: group, signalName: "clicked"}) @@ -346,4 +366,40 @@ TestCase { verify(container.group.checkedButton) compare(container.group.checkedButton.objectName, "0") } + + function test_nonExclusive() { + var group = createTemporaryObject(nonExclusiveGroup, testCase) + verify(group) + + var button1 = createTemporaryObject(button, testCase, {checked: true}) + group.addButton(button1) + compare(button1.checked, true) + compare(group.checkedButton, null) + + var button2 = createTemporaryObject(button, testCase, {checked: true}) + group.addButton(button2) + compare(button1.checked, true) + compare(button2.checked, true) + compare(group.checkedButton, null) + + button1.checked = false + compare(button1.checked, false) + compare(button2.checked, true) + compare(group.checkedButton, null) + + button2.checked = false + compare(button1.checked, false) + compare(button2.checked, false) + compare(group.checkedButton, null) + + button1.checked = true + compare(button1.checked, true) + compare(button2.checked, false) + compare(group.checkedButton, null) + + button2.checked = true + compare(button1.checked, true) + compare(button2.checked, true) + compare(group.checkedButton, null) + } } diff --git a/tests/auto/controls/data/tst_checkdelegate.qml b/tests/auto/controls/data/tst_checkdelegate.qml index 8933a7dd..9f92b4dc 100644 --- a/tests/auto/controls/data/tst_checkdelegate.qml +++ b/tests/auto/controls/data/tst_checkdelegate.qml @@ -89,4 +89,85 @@ TestCase { verify(control); compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); } + + function test_spacing() { + var control = createTemporaryObject(checkDelegate, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem should be + // equal to the implicitWidth of the Text and the check indicator + spacing while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: CheckDelegate.IconOnly }, + { "tag": "TextOnly", display: CheckDelegate.TextOnly }, + { "tag": "TextUnderIcon", display: CheckDelegate.TextUnderIcon }, + { "tag": "TextBesideIcon", display: CheckDelegate.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: CheckDelegate.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: CheckDelegate.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: CheckDelegate.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: CheckDelegate.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(checkDelegate, testCase, { + text: "CheckDelegate", + display: data.display, + width: 400, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + var availableWidth = control.availableWidth - control.indicator.width - control.spacing + var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0 + + switch (control.display) { + case CheckDelegate.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case CheckDelegate.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case CheckDelegate.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case CheckDelegate.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml index f231ebf8..bc110de6 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -705,9 +705,6 @@ TestCase { var activatedSpy = signalSpy.createObject(control, {target: control, signalName: "activated"}) verify(activatedSpy.valid) - var highlightedSpy = signalSpy.createObject(control, {target: control, signalName: "highlighted"}) - verify(highlightedSpy.valid) - mouseClick(control) compare(control.popup.visible, true) @@ -717,25 +714,19 @@ TestCase { // press - move - release outside - not activated - not closed mousePress(content) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) mouseMove(content, content.width * 2) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) mouseRelease(content, content.width * 2) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) compare(control.popup.visible, true) // press - move - release inside - activated - closed mousePress(content) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) mouseMove(content, content.width / 2 + 1, content.height / 2 + 1) compare(activatedSpy.count, 0) - compare(highlightedSpy.count, 0) mouseRelease(content) compare(activatedSpy.count, 1) - compare(highlightedSpy.count, 1) tryCompare(control.popup, "visible", false) } @@ -1176,6 +1167,58 @@ TestCase { closedSpy.target = null } + function test_mouseHighlight() { + if ((Qt.platform.pluginName === "offscreen") + ||Â (Qt.platform.pluginName === "minimal")) + skip("Mouse highlight not functional on offscreen/minimal platforms") + var control = createTemporaryObject(comboBox, testCase, {model: 20}) + verify(control) + + compare(control.highlightedIndex, -1) + + var openedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "opened"}) + verify(openedSpy.valid) + + control.popup.open() + compare(control.highlightedIndex, 0) + tryCompare(openedSpy, "count", 1) + + var listview = control.popup.contentItem + verify(listview) + waitForRendering(listview) + + // hover-highlight through all visible list items one by one + var hoverIndex = -1 + var prevHoverItem = null + for (var y = 0; y < listview.height; ++y) { + var hoverItem = listview.itemAt(0, listview.contentY + y) + if (!hoverItem || !hoverItem.visible || hoverItem === prevHoverItem) + continue + mouseMove(hoverItem, 0, 0) + tryCompare(control, "highlightedIndex", ++hoverIndex) + prevHoverItem = hoverItem + } + + mouseMove(listview, listview.width / 2, listview.height / 2) + + // wheel-highlight the rest of the items + var delta = 120 + var prevWheelItem = null + while (!listview.atYEnd) { + var prevContentY = listview.contentY + mouseWheel(listview, listview.width / 2, listview.height / 2, -delta, -delta) + tryCompare(listview, "moving", false) + verify(listview.contentY > prevContentY) + + var wheelItem = listview.itemAt(listview.width / 2, listview.contentY + listview.height / 2) + if (!wheelItem || !wheelItem.visible || wheelItem === prevWheelItem) + continue + + tryCompare(control, "highlightedIndex", parseInt(wheelItem.text)) + prevWheelItem = wheelItem + } + } + RegExpValidator { id: regExpValidator regExp: /(red|blue|green)?/ @@ -1417,7 +1460,6 @@ TestCase { keyPress(Qt.Key_B) verify(control.activeFocus) - expectFail("", "An editable ComboBox does not yet support the Keys attached property.") verify(control.gotit) compare(control.editText, "a") @@ -1466,7 +1508,7 @@ TestCase { var control = createTemporaryObject(comboBox, testCase, { model: 1 }) verify(control) compare(control.popup.implicitHeight, 0) - compare(control.popup.height, 0) + compare(control.popup.height, control.popup.topPadding + control.popup.bottomPadding) // Ensure that it's open so that the popup's implicitHeight changes when we increase the model count. control.popup.open() @@ -1482,6 +1524,6 @@ TestCase { control.model = 0 control.popup.open() tryCompare(control.popup, "visible", true) - compare(control.popup.height, 0) + compare(control.popup.height, control.popup.topPadding + control.popup.bottomPadding) } } diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml index b8de2b08..94f22ad2 100644 --- a/tests/auto/controls/data/tst_container.qml +++ b/tests/auto/controls/data/tst_container.qml @@ -153,4 +153,46 @@ TestCase { compare(control.itemAt(2).objectName, "2") compare(control.itemAt(3).objectName, "3") } + + function test_removeTakeItem() { + var control = createTemporaryObject(container, testCase) + verify(control) + + var item1 = rectangle.createObject(control) + var item2 = rectangle.createObject(control) + var item3 = rectangle.createObject(control) + + item1.Component.onDestruction.connect(function() { item1 = null }) + item2.Component.onDestruction.connect(function() { item2 = null }) + item3.Component.onDestruction.connect(function() { item3 = null }) + + control.addItem(item1) + control.addItem(item2) + control.addItem(item3) + compare(control.count, 3) + + // takeItem(int) does not destroy + compare(control.takeItem(1), item2) + compare(control.count, 2) + wait(1) + verify(item2) + + // removeItem(Item) destroys + control.removeItem(item1) + compare(control.count, 1) + wait(1) + verify(!item1) + + // removeItem(null) must not call removeItem(0) + control.removeItem(null) + compare(control.count, 1) + wait(1) + verify(item3) + + // deprecated removeItem(int) does not destroy + control.removeItem(0) + compare(control.count, 0) + wait(1) + verify(item3) + } } diff --git a/tests/auto/controls/data/tst_dialog.qml b/tests/auto/controls/data/tst_dialog.qml index 2f3d2a6b..e2557a04 100644 --- a/tests/auto/controls/data/tst_dialog.qml +++ b/tests/auto/controls/data/tst_dialog.qml @@ -99,11 +99,14 @@ TestCase { verify(acceptedSpy.valid) control.accept() compare(acceptedSpy.count, 1) + compare(control.result, Dialog.Accepted) tryCompare(control, "visible", false) } function test_reject() { + skip("QTBUG-62549, QTBUG-62628") + var control = createTemporaryObject(dialog, testCase) var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"}) @@ -118,6 +121,7 @@ TestCase { verify(rejectedSpy.valid) control.reject() compare(rejectedSpy.count, 1) + compare(control.result, Dialog.Rejected) tryCompare(control, "visible", false) @@ -356,4 +360,42 @@ TestCase { - (data.header ? control.header.height + control.spacing : 0) - (data.footer ? control.footer.height + control.spacing : 0)) } + + function test_signals_data() { + return [ + { tag: "Ok", standardButton: Dialog.Ok, signalName: "accepted" }, + { tag: "Open", standardButton: Dialog.Open, signalName: "accepted" }, + { tag: "Save", standardButton: Dialog.Save, signalName: "accepted" }, + { tag: "Cancel", standardButton: Dialog.Cancel, signalName: "rejected" }, + { tag: "Close", standardButton: Dialog.Close, signalName: "rejected" }, + { tag: "Discard", standardButton: Dialog.Discard, signalName: "discarded" }, + { tag: "Apply", standardButton: Dialog.Apply, signalName: "applied" }, + { tag: "Reset", standardButton: Dialog.Reset, signalName: "reset" }, + { tag: "RestoreDefaults", standardButton: Dialog.RestoreDefaults, signalName: "reset" }, + { tag: "Help", standardButton: Dialog.Help, signalName: "helpRequested" }, + { tag: "SaveAll", standardButton: Dialog.SaveAll, signalName: "accepted" }, + { tag: "Yes", standardButton: Dialog.Yes, signalName: "accepted" }, + { tag: "YesToAll", standardButton: Dialog.YesToAll, signalName: "accepted" }, + { tag: "No", standardButton: Dialog.No, signalName: "rejected" }, + { tag: "NoToAll", standardButton: Dialog.NoToAll, signalName: "rejected" }, + { tag: "Abort", standardButton: Dialog.Abort, signalName: "rejected" }, + { tag: "Retry", standardButton: Dialog.Retry, signalName: "accepted" }, + { tag: "Ignore", standardButton: Dialog.Ignore, signalName: "accepted" } + ] + } + + function test_signals(data) { + var control = createTemporaryObject(dialog, testCase) + verify(control) + + control.standardButtons = data.standardButton + var button = control.standardButton(data.standardButton) + verify(button) + + var buttonSpy = signalSpy.createObject(control.contentItem, {target: control, signalName: data.signalName}) + verify(buttonSpy.valid) + + button.clicked() + compare(buttonSpy.count, 1) + } } diff --git a/tests/auto/controls/data/tst_dialogbuttonbox.qml b/tests/auto/controls/data/tst_dialogbuttonbox.qml index 9b3d969f..044c9593 100644 --- a/tests/auto/controls/data/tst_dialogbuttonbox.qml +++ b/tests/auto/controls/data/tst_dialogbuttonbox.qml @@ -159,10 +159,10 @@ TestCase { { tag: "Save", standardButton: DialogButtonBox.Save, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, { tag: "Cancel", standardButton: DialogButtonBox.Cancel, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" }, { tag: "Close", standardButton: DialogButtonBox.Close, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" }, - { tag: "Discard", standardButton: DialogButtonBox.Discard, buttonRole: DialogButtonBox.DestructiveRole }, - { tag: "Apply", standardButton: DialogButtonBox.Apply, buttonRole: DialogButtonBox.ApplyRole }, - { tag: "Reset", standardButton: DialogButtonBox.Reset, buttonRole: DialogButtonBox.ResetRole }, - { tag: "RestoreDefaults", standardButton: DialogButtonBox.RestoreDefaults, buttonRole: DialogButtonBox.ResetRole }, + { tag: "Discard", standardButton: DialogButtonBox.Discard, buttonRole: DialogButtonBox.DestructiveRole, signalName: "discarded" }, + { tag: "Apply", standardButton: DialogButtonBox.Apply, buttonRole: DialogButtonBox.ApplyRole, signalName: "applied" }, + { tag: "Reset", standardButton: DialogButtonBox.Reset, buttonRole: DialogButtonBox.ResetRole, signalName: "reset" }, + { tag: "RestoreDefaults", standardButton: DialogButtonBox.RestoreDefaults, buttonRole: DialogButtonBox.ResetRole, signalName: "reset" }, { tag: "Help", standardButton: DialogButtonBox.Help, buttonRole: DialogButtonBox.HelpRole, signalName: "helpRequested" }, { tag: "SaveAll", standardButton: DialogButtonBox.SaveAll, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, { tag: "Yes", standardButton: DialogButtonBox.Yes, buttonRole: DialogButtonBox.YesRole, signalName: "accepted" }, @@ -188,11 +188,11 @@ TestCase { var clickedSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) verify(clickedSpy.valid) var roleSpy = signalSpy.createObject(control, {target: control, signalName: data.signalName}) - compare(roleSpy.valid, !!data.signalName) + verify(roleSpy.valid) button.clicked() compare(clickedSpy.count, 1) compare(clickedSpy.signalArguments[0][0], button) - compare(roleSpy.count, !!data.signalName ? 1 : 0) + compare(roleSpy.count, 1) } } diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml index a33a4bf0..5446b969 100644 --- a/tests/auto/controls/data/tst_drawer.qml +++ b/tests/auto/controls/data/tst_drawer.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.3 TestCase { id: testCase @@ -70,7 +70,7 @@ TestCase { compare(control.edge, Qt.LeftEdge) compare(control.position, 0.0) compare(control.dragMargin, Qt.styleHints.startDragDistance) - compare(control.parent, ApplicationWindow.overlay) + compare(control.parent, Overlay.overlay) } function test_invalidEdge() { diff --git a/tests/auto/controls/data/tst_itemdelegate.qml b/tests/auto/controls/data/tst_itemdelegate.qml index 6f4bb6cb..4e4ca0c4 100644 --- a/tests/auto/controls/data/tst_itemdelegate.qml +++ b/tests/auto/controls/data/tst_itemdelegate.qml @@ -79,4 +79,84 @@ TestCase { control.highlighted = true verify(control.highlighted) } + + function test_spacing() { + var control = createTemporaryObject(itemDelegate, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem + // should be equal to the implicitWidth of the Text while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // That means that spacing shouldn't affect it. + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // The implicitWidth of the ItemDelegate itself should, therefore, also never include spacing while no icon is set. + compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: ItemDelegate.IconOnly }, + { "tag": "TextOnly", display: ItemDelegate.TextOnly }, + { "tag": "TextUnderIcon", display: ItemDelegate.TextUnderIcon }, + { "tag": "TextBesideIcon", display: ItemDelegate.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: ItemDelegate.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: ItemDelegate.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: ItemDelegate.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: ItemDelegate.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(itemDelegate, testCase, { + text: "ItemDelegate", + display: data.display, + width: 400, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case ItemDelegate.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case ItemDelegate.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case ItemDelegate.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case ItemDelegate.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_menuitem.qml b/tests/auto/controls/data/tst_menuitem.qml index 068e2a5c..57286002 100644 --- a/tests/auto/controls/data/tst_menuitem.qml +++ b/tests/auto/controls/data/tst_menuitem.qml @@ -65,6 +65,11 @@ TestCase { MenuItem { } } + Component { + id: menu + Menu { } + } + function test_baseline() { var control = createTemporaryObject(menuItem, testCase) verify(control) @@ -96,4 +101,93 @@ TestCase { control.highlighted = true verify(control.highlighted) } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: MenuItem.IconOnly }, + { "tag": "TextOnly", display: MenuItem.TextOnly }, + { "tag": "TextUnderIcon", display: MenuItem.TextUnderIcon }, + { "tag": "TextBesideIcon", display: MenuItem.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: MenuItem.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: MenuItem.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: MenuItem.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: MenuItem.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(menuItem, testCase, { + text: "MenuItem", + display: data.display, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var padding = data.mirrored ? control.contentItem.rightPadding : control.contentItem.leftPadding + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case MenuItem.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, control.mirrored ? control.availableWidth - iconImage.width - padding : padding) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case MenuItem.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width - padding : padding) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case MenuItem.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, control.mirrored ? control.availableWidth - iconImage.width - (textLabel.width - iconImage.width) / 2 - padding : (textLabel.width - iconImage.width) / 2 + padding) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width - padding : padding) + verify(iconImage.y < textLabel.y) + break; + case MenuItem.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } + + function test_menu() { + var control = createTemporaryObject(menu, testCase) + verify(control) + + var item1 = createTemporaryObject(menuItem, testCase) + verify(item1) + compare(item1.menu, null) + + var item2 = createTemporaryObject(menuItem, testCase) + verify(item2) + compare(item2.menu, null) + + control.addItem(item1) + compare(item1.menu, control) + compare(item2.menu, null) + + control.insertItem(1, item2) + compare(item1.menu, control) + compare(item2.menu, control) + + control.removeItem(1) + compare(item1.menu, control) + compare(item2.menu, null) + + control.removeItem(0) + compare(item1.menu, null) + compare(item2.menu, null) + } } diff --git a/tests/auto/controls/data/tst_page.qml b/tests/auto/controls/data/tst_page.qml index 2eb11165..4fb2d089 100644 --- a/tests/auto/controls/data/tst_page.qml +++ b/tests/auto/controls/data/tst_page.qml @@ -150,8 +150,10 @@ TestCase { compare(control.contentWidth, 0) compare(control.contentHeight, 0) - compare(control.implicitWidth, control.leftPadding + control.rightPadding) - compare(control.implicitHeight, control.topPadding + control.bottomPadding) + compare(control.implicitWidth, Math.max(control.leftPadding + control.rightPadding, + control.background ? control.background.implicitWidth : 0)) + compare(control.implicitHeight, Math.max(control.topPadding + control.bottomPadding, + control.background ? control.background.implicitHeight : 0)) } function test_contentItem() { diff --git a/tests/auto/controls/data/tst_pageindicator.qml b/tests/auto/controls/data/tst_pageindicator.qml index 70813cb8..f3151882 100644 --- a/tests/auto/controls/data/tst_pageindicator.qml +++ b/tests/auto/controls/data/tst_pageindicator.qml @@ -96,7 +96,7 @@ TestCase { } function test_interactive(data) { - var control = createTemporaryObject(pageIndicator, testCase, {count: 5, spacing: 10, padding: 10}) + var control = createTemporaryObject(pageIndicator, testCase, {count: 5, spacing: 10, topPadding: 10, leftPadding: 10, rightPadding: 10, bottomPadding: 10}) verify(control) verify(!control.interactive) diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index bec50ad0..88ec295f 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -50,8 +50,8 @@ import QtQuick 2.4 import QtTest 1.0 -import QtQuick.Controls 2.2 -import QtQuick.Templates 2.2 as T +import QtQuick.Controls 2.3 +import QtQuick.Templates 2.3 as T TestCase { id: testCase @@ -361,7 +361,7 @@ TestCase { } function test_margins() { - var control = createTemporaryObject(popupControl, testCase, {width: 100, height: 100}) + var control = createTemporaryObject(popupTemplate, testCase, {width: 100, height: 100}) verify(control) control.open() @@ -944,6 +944,10 @@ TestCase { compare(openedSpy.count, 1) verify(control.visible) + // remove the background so that it won't affect the implicit size of the popup, + // so the implicit sizes tested below are entirely based on the content size + control.background = null + // implicit size of the content control.contentItem.implicitWidth = 10 compare(control.implicitWidth, 10 + control.leftPadding + control.rightPadding) @@ -1069,6 +1073,7 @@ TestCase { tryCompare(window, "active", true) compare(window.overlay.children.length, 0) + compare(window.overlay, window.Overlay.overlay) var firstOverlay = findOverlay(window, window.firstDrawer) verify(!firstOverlay) @@ -1178,16 +1183,6 @@ TestCase { compare(child.ApplicationWindow.window, null) } - SignalSpy { - id: openedSpy - signalName: "opened" - } - - SignalSpy { - id: closedSpy - signalName: "closed" - } - Component { id: pausePopup Popup { @@ -1200,19 +1195,32 @@ TestCase { var control = createTemporaryObject(pausePopup, testCase) verify(control) - openedSpy.target = control - closedSpy.target = control + var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"}) + verify(openedSpy.valid) + var closedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "closed"}) + verify(closedSpy.valid) + var openedChangeSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "openedChanged"}) + verify(openedChangeSpy.valid) control.open() compare(control.visible, true) + compare(control.opened, false) + compare(openedChangeSpy.count, 0) compare(openedSpy.count, 0) tryCompare(openedSpy, "count", 1) + compare(control.opened, true) + compare(openedChangeSpy.count, 1) compare(closedSpy.count, 0) control.close() + compare(control.visible, true) + compare(control.opened, false) + compare(openedChangeSpy.count, 2) compare(openedSpy.count, 1) compare(closedSpy.count, 0) tryCompare(closedSpy, "count", 1) + compare(control.opened, false) + compare(openedChangeSpy.count, 2) compare(control.visible, false) } diff --git a/tests/auto/controls/data/tst_radiodelegate.qml b/tests/auto/controls/data/tst_radiodelegate.qml index 8fb6f933..b1ee00db 100644 --- a/tests/auto/controls/data/tst_radiodelegate.qml +++ b/tests/auto/controls/data/tst_radiodelegate.qml @@ -89,4 +89,85 @@ TestCase { verify(control); compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); } + + function test_spacing() { + var control = createTemporaryObject(radioDelegate, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem should be + // equal to the implicitWidth of the Text and the radio indicator + spacing while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: RadioDelegate.IconOnly }, + { "tag": "TextOnly", display: RadioDelegate.TextOnly }, + { "tag": "TextUnderIcon", display: RadioDelegate.TextUnderIcon }, + { "tag": "TextBesideIcon", display: RadioDelegate.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: RadioDelegate.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: RadioDelegate.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: RadioDelegate.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: RadioDelegate.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(radioDelegate, testCase, { + text: "RadioDelegate", + display: data.display, + width: 400, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + var availableWidth = control.availableWidth - control.indicator.width - control.spacing + var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0 + + switch (control.display) { + case RadioDelegate.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case RadioDelegate.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case RadioDelegate.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case RadioDelegate.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml index 791f357f..39b0c4b0 100644 --- a/tests/auto/controls/data/tst_rangeslider.qml +++ b/tests/auto/controls/data/tst_rangeslider.qml @@ -96,6 +96,8 @@ TestCase { compare(control.stepSize, 0) compare(control.snapMode, RangeSlider.NoSnap) compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) } function test_values() { @@ -262,9 +264,14 @@ TestCase { verify(control) compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) verify(control.width > control.height) + control.orientation = Qt.Vertical compare(control.orientation, Qt.Vertical) + compare(control.horizontal, false) + compare(control.vertical, true) verify(control.width < control.height) } diff --git a/tests/auto/controls/data/tst_roundbutton.qml b/tests/auto/controls/data/tst_roundbutton.qml index 7a533348..c772c85f 100644 --- a/tests/auto/controls/data/tst_roundbutton.qml +++ b/tests/auto/controls/data/tst_roundbutton.qml @@ -84,4 +84,83 @@ TestCase { control.width = 10; compare(control.radius, 5); } + + function test_spacing() { + var control = createTemporaryObject(roundButton, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem + // should be equal to the implicitWidth of the Text while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // That means that spacing shouldn't affect it. + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // The implicitWidth of the Button itself should, therefore, also never include spacing while no icon is set. + compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: RoundButton.IconOnly }, + { "tag": "TextOnly", display: RoundButton.TextOnly }, + { "tag": "TextUnderIcon", display: RoundButton.TextUnderIcon }, + { "tag": "TextBesideIcon", display: RoundButton.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: RoundButton.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: RoundButton.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: RoundButton.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: RoundButton.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(roundButton, testCase, { + text: "RoundButton", + display: data.display, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case RoundButton.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case RoundButton.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case RoundButton.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case RoundButton.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml index 3e153ebb..bc424a27 100644 --- a/tests/auto/controls/data/tst_scrollbar.qml +++ b/tests/auto/controls/data/tst_scrollbar.qml @@ -737,6 +737,20 @@ TestCase { container.destroy() } + function test_orientation() { + var control = createTemporaryObject(scrollBar, testCase) + verify(control) + + compare(control.orientation, Qt.Vertical) + compare(control.horizontal, false) + compare(control.vertical, true) + + control.orientation = Qt.Horizontal + compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) + } + function test_flashing() { var control = createTemporaryObject(scrollBar, testCase, {size: 0.2}) verify(control) diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index 894a035d..a6275f91 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -223,6 +223,20 @@ TestCase { compare(horizontal.contentItem.width, 0.2 * horizontal.availableWidth) } + function test_orientation() { + var control = createTemporaryObject(scrollIndicator, testCase) + verify(control) + + compare(control.orientation, Qt.Vertical) + compare(control.horizontal, false) + compare(control.vertical, true) + + control.orientation = Qt.Horizontal + compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) + } + // QTBUG-61785 function test_mouseArea() { var ma = createTemporaryObject(mouseArea, testCase, {width: testCase.width, height: testCase.height}) diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml index 8d696297..b70aeaab 100644 --- a/tests/auto/controls/data/tst_slider.qml +++ b/tests/auto/controls/data/tst_slider.qml @@ -77,6 +77,8 @@ TestCase { compare(control.stepSize, 0) compare(control.snapMode, Slider.NoSnap) compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) } function test_value() { @@ -201,9 +203,14 @@ TestCase { verify(control) compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) verify(control.width > control.height) + control.orientation = Qt.Vertical compare(control.orientation, Qt.Vertical) + compare(control.horizontal, false) + compare(control.vertical, true) verify(control.width < control.height) } diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml index 71f0735c..003468a1 100644 --- a/tests/auto/controls/data/tst_spinbox.qml +++ b/tests/auto/controls/data/tst_spinbox.qml @@ -116,15 +116,23 @@ TestCase { compare(control.up.indicator.enabled, false) compare(control.down.indicator.enabled, true) + control.wrap = true + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) + control.value = -1 compare(control.value, 0) compare(control.up.indicator.enabled, true) - compare(control.down.indicator.enabled, false) + compare(control.down.indicator.enabled, true) control.from = 25 compare(control.from, 25) compare(control.value, 25) compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) + + control.wrap = false + compare(control.up.indicator.enabled, true) compare(control.down.indicator.enabled, false) control.value = 30 @@ -229,8 +237,19 @@ TestCase { compare(valueModifiedSpy.count, data.modified) } - function test_keys() { - var control = createTemporaryObject(spinBox, testCase) + function test_keys_data() { + return [ + { tag: "1", from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3,4], downSteps: [3,2,1,1] }, + { tag: "2", from: 1, to: 10, value: 10, stepSize: 2, upSteps: [10,10], downSteps: [8,6,4] }, + { tag: "25", from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,100], downSteps: [75,50,25,0,0] }, + { tag: "wrap1", wrap: true, from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3], downSteps: [2,1,10,9] }, + { tag: "wrap2", wrap: true, from: 1, to: 10, value: 10, stepSize: 2, upSteps: [1,3,5], downSteps: [3,1,10,8,6] }, + { tag: "wrap25", wrap: true, from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,0,25], downSteps: [0,100,75] } + ] + } + + function test_keys(data) { + var control = createTemporaryObject(spinBox, testCase, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize}) verify(control) var upPressedCount = 0 @@ -249,48 +268,31 @@ TestCase { control.forceActiveFocus() verify(control.activeFocus) - control.value = 50 - compare(control.value, 50) - - for (var d1 = 1; d1 <= 10; ++d1) { - keyPress(Qt.Key_Down) - compare(control.down.pressed, true) - compare(control.up.pressed, false) - compare(downPressedSpy.count, ++downPressedCount) - compare(valueModifiedSpy.count, ++valueModifiedCount) - - compare(control.value, 50 - d1) - - keyRelease(Qt.Key_Down) - compare(control.down.pressed, false) - compare(control.up.pressed, false) - compare(downPressedSpy.count, ++downPressedCount) - compare(valueModifiedSpy.count, valueModifiedCount) - } - compare(control.value, 40) - - for (var i1 = 1; i1 <= 10; ++i1) { + for (var u = 0; u < data.upSteps.length; ++u) { + var wasUpEnabled = control.wrap || control.value < control.to keyPress(Qt.Key_Up) - compare(control.up.pressed, true) + compare(control.up.pressed, wasUpEnabled) compare(control.down.pressed, false) - compare(upPressedSpy.count, ++upPressedCount) - compare(valueModifiedSpy.count, ++valueModifiedCount) + if (wasUpEnabled) { + ++upPressedCount + ++valueModifiedCount + } + compare(upPressedSpy.count, upPressedCount) + compare(valueModifiedSpy.count, valueModifiedCount) - compare(control.value, 40 + i1) + compare(control.value, data.upSteps[u]) keyRelease(Qt.Key_Up) compare(control.down.pressed, false) compare(control.up.pressed, false) - compare(upPressedSpy.count, ++upPressedCount) + if (wasUpEnabled) + ++upPressedCount + compare(upPressedSpy.count, upPressedCount) compare(valueModifiedSpy.count, valueModifiedCount) } - compare(control.value, 50) - - control.stepSize = 25 - compare(control.stepSize, 25) - for (var d2 = 1; d2 <= 10; ++d2) { - var wasDownEnabled = control.value > control.from + for (var d = 0; d < data.downSteps.length; ++d) { + var wasDownEnabled = control.wrap || control.value > control.from keyPress(Qt.Key_Down) compare(control.down.pressed, wasDownEnabled) compare(control.up.pressed, false) @@ -301,7 +303,7 @@ TestCase { compare(downPressedSpy.count, downPressedCount) compare(valueModifiedSpy.count, valueModifiedCount) - compare(control.value, Math.max(0, 50 - d2 * 25)) + compare(control.value, data.downSteps[d]) keyRelease(Qt.Key_Down) compare(control.down.pressed, false) @@ -311,31 +313,6 @@ TestCase { compare(downPressedSpy.count, downPressedCount) compare(valueModifiedSpy.count, valueModifiedCount) } - compare(control.value, 0) - - for (var i2 = 1; i2 <= 10; ++i2) { - var wasUpEnabled = control.value < control.to - keyPress(Qt.Key_Up) - compare(control.up.pressed, wasUpEnabled) - compare(control.down.pressed, false) - if (wasUpEnabled) { - ++upPressedCount - ++valueModifiedCount - } - compare(upPressedSpy.count, upPressedCount) - compare(valueModifiedSpy.count, valueModifiedCount) - - compare(control.value, Math.min(99, i2 * 25)) - - keyRelease(Qt.Key_Up) - compare(control.down.pressed, false) - compare(control.up.pressed, false) - if (wasUpEnabled) - ++upPressedCount - compare(upPressedSpy.count, upPressedCount) - compare(valueModifiedSpy.count, valueModifiedCount) - } - compare(control.value, 99) } function test_locale() { @@ -407,46 +384,46 @@ TestCase { compare(control.value, 5) } + function test_wheel_data() { + return [ + { tag: "1", from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3,4], downSteps: [3,2,1,1] }, + { tag: "2", from: 1, to: 10, value: 10, stepSize: 2, upSteps: [10,10], downSteps: [8,6,4] }, + { tag: "25", from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,100], downSteps: [75,50,25,0,0] }, + { tag: "wrap1", wrap: true, from: 1, to: 10, value: 1, stepSize: 1, upSteps: [2,3], downSteps: [2,1,10,9] }, + { tag: "wrap2", wrap: true, from: 1, to: 10, value: 10, stepSize: 2, upSteps: [1,3,5], downSteps: [3,1,10,8,6] }, + { tag: "wrap25", wrap: true, from: 0, to: 100, value: 50, stepSize: 25, upSteps: [75,100,0,25], downSteps: [0,100,75] } + ] + } + function test_wheel(data) { - var control = createTemporaryObject(spinBox, testCase, {wheelEnabled: true}) + var control = createTemporaryObject(spinBox, testCase, {wrap: data.wrap, from: data.from, to: data.to, value: data.value, stepSize: data.stepSize, wheelEnabled: true}) verify(control) + var valueModifiedCount = 0 var valueModifiedSpy = signalSpy.createObject(control, {target: control, signalName: "valueModified"}) verify(valueModifiedSpy.valid) var delta = 120 - compare(control.value, 0) - - mouseWheel(control, control.width / 2, control.height / 2, delta, delta) - compare(control.value, 1) - compare(valueModifiedSpy.count, 1) - - control.stepSize = 2 - - mouseWheel(control, control.width / 2, control.height / 2, delta, delta) - compare(control.value, 3) - compare(valueModifiedSpy.count, 2) - - control.stepSize = 10 - - mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) - compare(control.value, 0) - compare(valueModifiedSpy.count, 3) - - control.stepSize = 5 + for (var u = 0; u < data.upSteps.length; ++u) { + var wasUpEnabled = control.wrap || control.value < control.to + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + if (wasUpEnabled) + ++valueModifiedCount + compare(valueModifiedSpy.count, valueModifiedCount) - mouseWheel(control, control.width / 2, control.height / 2, delta, delta) - compare(control.value, 5) - compare(valueModifiedSpy.count, 4) + compare(control.value, data.upSteps[u]) + } - mouseWheel(control, control.width / 2, control.height / 2, 0.5 * delta, 0.5 * delta) - compare(control.value, 8) - compare(valueModifiedSpy.count, 5) + for (var d = 0; d < data.downSteps.length; ++d) { + var wasDownEnabled = control.wrap || control.value > control.from + mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) + if (wasDownEnabled) + ++valueModifiedCount + compare(valueModifiedSpy.count, valueModifiedCount) - mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) - compare(control.value, 3) - compare(valueModifiedSpy.count, 6) + compare(control.value, data.downSteps[d]) + } } function test_initiallyDisabledIndicators_data() { diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml index 1b421b4f..f4b7fc4a 100644 --- a/tests/auto/controls/data/tst_stackview.qml +++ b/tests/auto/controls/data/tst_stackview.qml @@ -221,33 +221,75 @@ TestCase { function test_depth() { var control = createTemporaryObject(stackView, testCase) verify(control) + + var depthChanges = 0 + var emptyChanges = 0 var depthSpy = signalSpy.createObject(control, {target: control, signalName: "depthChanged"}) + var emptySpy = signalSpy.createObject(control, {target: control, signalName: "emptyChanged"}) verify(depthSpy.valid) + verify(emptySpy.valid) compare(control.depth, 0) + compare(control.empty, true) + control.push(item, StackView.Immediate) compare(control.depth, 1) - compare(depthSpy.count, 1) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, false) + compare(emptySpy.count, ++emptyChanges) + control.clear() compare(control.depth, 0) - compare(depthSpy.count, 2) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, true) + compare(emptySpy.count, ++emptyChanges) + control.push(component, StackView.Immediate) compare(control.depth, 1) - compare(depthSpy.count, 3) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, false) + compare(emptySpy.count, ++emptyChanges) + control.push(component, StackView.Immediate) compare(control.depth, 2) - compare(depthSpy.count, 4) - control.pop(StackView.Immediate) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, false) + compare(emptySpy.count, emptyChanges) + + control.replace(component, StackView.Immediate) + compare(control.depth, 2) + compare(depthSpy.count, depthChanges) + compare(control.empty, false) + compare(emptySpy.count, emptyChanges) + + control.replace([component, component], StackView.Immediate) + compare(control.depth, 3) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, false) + compare(emptySpy.count, emptyChanges) + + control.pop(null, StackView.Immediate) compare(control.depth, 1) - compare(depthSpy.count, 5) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, false) + compare(emptySpy.count, emptyChanges) + control.pop(StackView.Immediate) // ignored compare(control.depth, 1) - compare(depthSpy.count, 5) + compare(depthSpy.count, depthChanges) + compare(control.empty, false) + compare(emptySpy.count, emptyChanges) + control.clear() compare(control.depth, 0) - compare(depthSpy.count, 6) + compare(depthSpy.count, ++depthChanges) + compare(control.empty, true) + compare(emptySpy.count, ++emptyChanges) + control.clear() compare(control.depth, 0) - compare(depthSpy.count, 6) + compare(depthSpy.count, depthChanges) + compare(control.empty, true) + compare(emptySpy.count, emptyChanges) } function test_size() { @@ -510,6 +552,24 @@ TestCase { compare(control.currentItem, item8) } + function test_clear() { + var control = createTemporaryObject(stackView, testCase) + verify(control) + + control.push(component, StackView.Immediate) + + control.clear() + compare(control.depth, 0) + compare(control.busy, false) + + control.push(component, StackView.Immediate) + + control.clear(StackView.PopTransition) + compare(control.depth, 0) + compare(control.busy, true) + tryCompare(control, "busy", false) + } + function test_visibility_data() { return [ {tag:"default transitions", properties: {}}, diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml index c24f6962..d603bd7f 100644 --- a/tests/auto/controls/data/tst_swipedelegate.qml +++ b/tests/auto/controls/data/tst_swipedelegate.qml @@ -1569,4 +1569,84 @@ TestCase { verify(control.behavior.enabled); verify(control.animation.running); } + + function test_spacing() { + var control = createTemporaryObject(swipeDelegateComponent, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem + // should be equal to the implicitWidth of the Text while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // That means that spacing shouldn't affect it. + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // The implicitWidth of the SwipeDelegate itself should, therefore, also never include spacing while no icon is set. + compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: SwipeDelegate.IconOnly }, + { "tag": "TextOnly", display: SwipeDelegate.TextOnly }, + { "tag": "TextUnderIcon", display: SwipeDelegate.TextUnderIcon }, + { "tag": "TextBesideIcon", display: SwipeDelegate.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: SwipeDelegate.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: SwipeDelegate.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: SwipeDelegate.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: SwipeDelegate.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(swipeDelegateComponent, testCase, { + text: "SwipeDelegate", + display: data.display, + width: 400, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case SwipeDelegate.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case SwipeDelegate.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case SwipeDelegate.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case SwipeDelegate.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_swipeview.qml b/tests/auto/controls/data/tst_swipeview.qml index ff772b74..39311877 100644 --- a/tests/auto/controls/data/tst_swipeview.qml +++ b/tests/auto/controls/data/tst_swipeview.qml @@ -539,6 +539,8 @@ TestCase { control.addItem(page.createObject(control, {text: i})) compare(control.orientation, Qt.Horizontal) + compare(control.horizontal, true) + compare(control.vertical, false) for (i = 0; i < control.count; ++i) { control.currentIndex = i @@ -547,6 +549,8 @@ TestCase { control.orientation = Qt.Vertical compare(control.orientation, Qt.Vertical) + compare(control.horizontal, false) + compare(control.vertical, true) for (i = 0; i < control.count; ++i) { control.currentIndex = i diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index 59e29726..079bf820 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -201,12 +201,12 @@ TestCase { mousePress(control, 0, 0, Qt.LeftButton) compare(control.pressed, true) verify(spy.success) - mouseMove(control, control.width / 4, control.height / 4, 0, Qt.LeftButton) + mouseMove(control, control.width / 2, control.height / 2, 0, Qt.LeftButton) compare(control.pressed, true) spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], "released", "clicked"] - mouseRelease(control, control.width / 4, control.height / 4, Qt.LeftButton) + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.checked, false) compare(control.pressed, false) tryCompare(control, "position", 0) // QTBUG-57944 @@ -304,12 +304,12 @@ TestCase { touch.press(0, control, 0, 0).commit() compare(control.pressed, true) verify(spy.success) - touch.move(0, control, control.width / 4, control.height / 4).commit() + touch.move(0, control, control.width / 2, control.height / 2).commit() compare(control.pressed, true) spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], "released", "clicked"] - touch.release(0, control, control.width / 4, control.height / 4).commit() + touch.release(0, control, control.width / 2, control.height / 2).commit() compare(control.checked, false) compare(control.pressed, false) tryCompare(control, "position", 0) // QTBUG-57944 diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml index f0c3e68b..8f240409 100644 --- a/tests/auto/controls/data/tst_switchdelegate.qml +++ b/tests/auto/controls/data/tst_switchdelegate.qml @@ -523,4 +523,85 @@ TestCase { compare(control.pressed, false) verify(spy.success) } + + function test_spacing() { + var control = createTemporaryObject(switchDelegate, testCase, { text: "Some long, long, long text" }) + verify(control) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem should be + // equal to the implicitWidth of the Text and the switch indicator + spacing while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing) + + compare(control.implicitWidth, textLabel.implicitWidth + control.indicator.width + control.spacing + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: SwitchDelegate.IconOnly }, + { "tag": "TextOnly", display: SwitchDelegate.TextOnly }, + { "tag": "TextUnderIcon", display: SwitchDelegate.TextUnderIcon }, + { "tag": "TextBesideIcon", display: SwitchDelegate.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: SwitchDelegate.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: SwitchDelegate.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: SwitchDelegate.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: SwitchDelegate.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(switchDelegate, testCase, { + text: "SwitchDelegate", + display: data.display, + width: 400, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + var availableWidth = control.availableWidth - control.indicator.width - control.spacing + var indicatorOffset = control.mirrored ? control.indicator.width + control.spacing : 0 + + switch (control.display) { + case SwitchDelegate.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case SwitchDelegate.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, control.mirrored ? control.availableWidth - textLabel.width : 0) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case SwitchDelegate.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, indicatorOffset + (availableWidth - iconImage.width) / 2) + compare(textLabel.x, indicatorOffset + (availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case SwitchDelegate.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml index 5bcd476b..adb27f78 100644 --- a/tests/auto/controls/data/tst_tabbar.qml +++ b/tests/auto/controls/data/tst_tabbar.qml @@ -506,47 +506,190 @@ TestCase { function test_layout(data) { var control = createTemporaryObject(tabBar, testCase, {spacing: data.spacing, width: 200}) - // remove the implicit size from the background so that it won't affect - // the implicit size of the tabbar, so the implicit sizes tested below - // are entirely based on the content size - control.background.implicitWidth = 0 + // remove the background so that it won't affect the implicit size of the tabbar, + // so the implicit sizes tested below are entirely based on the content size + control.background = null var tab1 = tabButton.createObject(control, {text: "First"}) control.addItem(tab1) tryCompare(tab1, "width", control.width) + compare(tab1.height, control.height) compare(control.contentWidth, tab1.implicitWidth) + compare(control.contentHeight, tab1.implicitHeight) compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) - var tab2 = tabButton.createObject(control, {text: "Second"}) + var tab2 = tabButton.createObject(control, {implicitHeight: tab1.implicitHeight + 10, text: "Second"}) control.addItem(tab2) tryCompare(tab1, "width", (control.width - data.spacing) / 2) + compare(tab1.height, control.height) compare(tab2.width, (control.width - data.spacing) / 2) + compare(tab2.height, control.height) compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + data.spacing) + compare(control.contentHeight, tab2.implicitHeight) compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) - var tab3 = tabButton.createObject(control, {width: 50, text: "Third"}) + var tab3 = tabButton.createObject(control, {width: 50, height: tab1.implicitHeight - 10, text: "Third"}) control.addItem(tab3) tryCompare(tab1, "width", (control.width - 2 * data.spacing - 50) / 2) + compare(tab1.y, 0) + compare(tab1.height, control.height) + compare(tab2.y, 0) compare(tab2.width, (control.width - 2 * data.spacing - 50) / 2) + compare(tab2.height, control.height) + verify(tab3.y > 0) + compare(tab3.y, (control.height - tab3.height) / 2) compare(tab3.width, 50) + compare(tab3.height, tab1.implicitHeight - 10) compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + tab3.width + 2 * data.spacing) + compare(control.contentHeight, tab2.implicitHeight) compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) var expectedWidth = tab3.contentItem.implicitWidth + tab3.leftPadding + tab3.rightPadding tab3.width = tab3.implicitWidth + tab3.height = tab3.implicitHeight tryCompare(tab1, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) - tryCompare(tab2, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) + compare(tab1.height, control.height) + compare(tab2.width, (control.width - 2 * data.spacing - expectedWidth) / 2) + compare(tab2.height, control.height) compare(tab3.width, expectedWidth) + compare(tab3.height, tab3.implicitHeight) compare(control.contentWidth, tab1.implicitWidth + tab2.implicitWidth + tab3.implicitWidth + 2 * data.spacing) + compare(control.contentHeight, tab2.implicitHeight) compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) tab3.width = undefined + tab3.height = undefined control.width = undefined control.contentWidth = 300 + control.contentHeight = 50 expectedWidth = (control.contentWidth - 2 * data.spacing) / 3 tryCompare(tab1, "width", expectedWidth) - tryCompare(tab2, "width", expectedWidth) - tryCompare(tab3, "width", expectedWidth) + compare(tab2.width, expectedWidth) + compare(tab3.width, expectedWidth) + compare(tab1.height, control.contentHeight) + compare(tab2.height, control.contentHeight) + compare(tab3.height, control.contentHeight) + } + + Component { + id: attachedButton + TabButton { + property int index: TabBar.index + property TabBar tabBar: TabBar.tabBar + property int position: TabBar.position + } + } + + function test_attached() { + var control = createTemporaryObject(tabBar, testCase, {position: TabBar.Footer}) + + // append + var tab1 = createTemporaryObject(attachedButton, testCase) + compare(tab1.index, -1) + compare(tab1.tabBar, null) + compare(tab1.position, TabBar.Header) + + control.addItem(tab1) + compare(tab1.index, 0) + compare(tab1.tabBar, control) + compare(tab1.position, TabBar.Footer) + + // insert in the beginning + var tab2 = createTemporaryObject(attachedButton, testCase) + compare(tab2.index, -1) + compare(tab2.tabBar, null) + compare(tab2.position, TabBar.Header) + + control.insertItem(0, tab2) + compare(tab2.index, 0) + compare(tab2.tabBar, control) + compare(tab2.position, TabBar.Footer) + + compare(tab1.index, 1) + + // insert in the middle + var tab3 = createTemporaryObject(attachedButton, testCase) + compare(tab3.index, -1) + compare(tab3.tabBar, null) + compare(tab3.position, TabBar.Header) + + control.insertItem(1, tab3) + compare(tab3.index, 1) + compare(tab3.tabBar, control) + compare(tab3.position, TabBar.Footer) + + compare(tab2.index, 0) + compare(tab1.index, 2) + + // insert in the end + var tab4 = createTemporaryObject(attachedButton, testCase) + compare(tab4.index, -1) + compare(tab4.tabBar, null) + compare(tab4.position, TabBar.Header) + + control.insertItem(-1, tab4) + compare(tab4.index, 3) + compare(tab4.tabBar, control) + compare(tab4.position, TabBar.Footer) + + compare(tab2.index, 0) + compare(tab3.index, 1) + compare(tab1.index, 2) + + // move forwards + control.moveItem(0, 1) + compare(tab3.index, 0) + compare(tab2.index, 1) + compare(tab1.index, 2) + compare(tab4.index, 3) + + control.moveItem(0, 2) + compare(tab2.index, 0) + compare(tab1.index, 1) + compare(tab3.index, 2) + compare(tab4.index, 3) + + control.moveItem(1, 3) + compare(tab2.index, 0) + compare(tab3.index, 1) + compare(tab4.index, 2) + compare(tab1.index, 3) + + // move backwards + control.moveItem(3, 2) + compare(tab2.index, 0) + compare(tab3.index, 1) + compare(tab1.index, 2) + compare(tab4.index, 3) + + control.moveItem(3, 1) + compare(tab2.index, 0) + compare(tab4.index, 1) + compare(tab3.index, 2) + compare(tab1.index, 3) + + // remove from the beginning + control.removeItem(0) + compare(tab2.index, -1) + compare(tab2.tabBar, null) + compare(tab2.position, TabBar.Header) + + compare(tab4.index, 0) + compare(tab3.index, 1) + compare(tab1.index, 2) + + // remove from the middle + control.removeItem(1) + compare(tab3.index, -1) + compare(tab3.tabBar, null) + compare(tab3.position, TabBar.Header) + + compare(tab4.index, 0) + compare(tab1.index, 1) } } diff --git a/tests/auto/controls/data/tst_tabbutton.qml b/tests/auto/controls/data/tst_tabbutton.qml index 60cae927..3cb22ecd 100644 --- a/tests/auto/controls/data/tst_tabbutton.qml +++ b/tests/auto/controls/data/tst_tabbutton.qml @@ -95,4 +95,84 @@ TestCase { verify(control) compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) } + + function test_spacing() { + var control = createTemporaryObject(tabButton, testCase, { text: "Some long, long, long text" }) + verify(control) + if (control.background) + verify(control.contentItem.implicitWidth + control.leftPadding + control.rightPadding > control.background.implicitWidth) + + var textLabel = findChild(control.contentItem, "label") + verify(textLabel) + + // The implicitWidth of the IconLabel that all buttons use as their contentItem + // should be equal to the implicitWidth of the Text while no icon is set. + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // That means that spacing shouldn't affect it. + control.spacing += 100 + compare(control.contentItem.implicitWidth, textLabel.implicitWidth) + + // The implicitWidth of the TabButton itself should, therefore, also never include spacing while no icon is set. + compare(control.implicitWidth, textLabel.implicitWidth + control.leftPadding + control.rightPadding) + } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: TabButton.IconOnly }, + { "tag": "TextOnly", display: TabButton.TextOnly }, + { "tag": "TextUnderIcon", display: TabButton.TextUnderIcon }, + { "tag": "TextBesideIcon", display: TabButton.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: TabButton.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: TabButton.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: TabButton.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: TabButton.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(tabButton, testCase, { + text: "TabButton", + display: data.display, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case TabButton.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case TabButton.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case TabButton.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case TabButton.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_textfield.qml b/tests/auto/controls/data/tst_textfield.qml index deb4b6ff..6a40f053 100644 --- a/tests/auto/controls/data/tst_textfield.qml +++ b/tests/auto/controls/data/tst_textfield.qml @@ -66,6 +66,11 @@ TestCase { } Component { + id: rectangle + Rectangle { } + } + + Component { id: signalSpy SignalSpy { } } @@ -82,8 +87,7 @@ TestCase { var implicitWidthSpy = signalSpy.createObject(control, { target: control, signalName: "implicitWidthChanged"} ) var implicitHeightSpy = signalSpy.createObject(control, { target: control, signalName: "implicitHeightChanged"} ) - control.background.implicitWidth = 400 - control.background.implicitHeight = 200 + control.background = rectangle.createObject(control, {implicitWidth: 400, implicitHeight: 200}) compare(control.implicitWidth, 400) compare(control.implicitHeight, 200) compare(implicitWidthSpy.count, 1) @@ -163,14 +167,14 @@ TestCase { if (data.textAlignment !== undefined) compare(control.horizontalAlignment, data.textAlignment) for (var i = 0; i < control.children.length; ++i) { - if (control.children[i].hasOwnProperty("horizontalAlignment")) + if (control.children[i].hasOwnProperty("text") && control.children[i].hasOwnProperty("horizontalAlignment")) compare(control.children[i].effectiveHorizontalAlignment, data.placeholderAlignment) // placeholder } control.verticalAlignment = TextField.AlignBottom compare(control.verticalAlignment, TextField.AlignBottom) for (var j = 0; j < control.children.length; ++j) { - if (control.children[j].hasOwnProperty("verticalAlignment")) + if (control.children[j].hasOwnProperty("text") && control.children[j].hasOwnProperty("verticalAlignment")) compare(control.children[j].verticalAlignment, Text.AlignBottom) // placeholder } } diff --git a/tests/auto/controls/data/tst_toolbutton.qml b/tests/auto/controls/data/tst_toolbutton.qml index 5eefaf59..9e79cb8c 100644 --- a/tests/auto/controls/data/tst_toolbutton.qml +++ b/tests/auto/controls/data/tst_toolbutton.qml @@ -181,4 +181,63 @@ TestCase { verify(control) compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) } + + function test_display_data() { + return [ + { "tag": "IconOnly", display: ToolButton.IconOnly }, + { "tag": "TextOnly", display: ToolButton.TextOnly }, + { "tag": "TextUnderIcon", display: ToolButton.TextUnderIcon }, + { "tag": "TextBesideIcon", display: ToolButton.TextBesideIcon }, + { "tag": "IconOnly, mirrored", display: ToolButton.IconOnly, mirrored: true }, + { "tag": "TextOnly, mirrored", display: ToolButton.TextOnly, mirrored: true }, + { "tag": "TextUnderIcon, mirrored", display: ToolButton.TextUnderIcon, mirrored: true }, + { "tag": "TextBesideIcon, mirrored", display: ToolButton.TextBesideIcon, mirrored: true } + ] + } + + function test_display(data) { + var control = createTemporaryObject(toolButton, testCase, { + text: "ToolButton", + display: data.display, + "icon.source": "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png", + "LayoutMirroring.enabled": !!data.mirrored + }) + verify(control) + compare(control.icon.source, "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png") + + var iconImage = findChild(control.contentItem, "image") + var textLabel = findChild(control.contentItem, "label") + + switch (control.display) { + case ToolButton.IconOnly: + verify(iconImage) + verify(!textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + break; + case ToolButton.TextOnly: + verify(!iconImage) + verify(textLabel) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + case ToolButton.TextUnderIcon: + verify(iconImage) + verify(textLabel) + compare(iconImage.x, (control.availableWidth - iconImage.width) / 2) + compare(textLabel.x, (control.availableWidth - textLabel.width) / 2) + verify(iconImage.y < textLabel.y) + break; + case ToolButton.TextBesideIcon: + verify(iconImage) + verify(textLabel) + if (control.mirrored) + verify(textLabel.x < iconImage.x) + else + verify(iconImage.x < textLabel.x) + compare(iconImage.y, (control.availableHeight - iconImage.height) / 2) + compare(textLabel.y, (control.availableHeight - textLabel.height) / 2) + break; + } + } } diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml index c7973c69..bd46fabd 100644 --- a/tests/auto/controls/data/tst_tooltip.qml +++ b/tests/auto/controls/data/tst_tooltip.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtTest 1.0 import QtQuick.Controls 2.2 @@ -283,6 +283,10 @@ TestCase { } function test_activateShortcutWhileToolTipVisible() { + if ((Qt.platform.pluginName === "offscreen") + || (Qt.platform.pluginName === "minimal")) + skip("Mouse hoovering not functional on offscreen/minimal platforms") + var root = createTemporaryObject(buttonAndShortcutComponent, testCase) verify(root) diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index aaf888c2..1fab0dab 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.qml @@ -123,7 +123,9 @@ TestCase { return child; } - return findView(child); + var grandChild = findView(child); + if (grandChild) + return grandChild; } return null; diff --git a/tests/auto/controls/fusion/dependencies.qml b/tests/auto/controls/fusion/dependencies.qml new file mode 100644 index 00000000..30c32fa5 --- /dev/null +++ b/tests/auto/controls/fusion/dependencies.qml @@ -0,0 +1,6 @@ +import QtTest 1.0 +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.Fusion 2.3 + +TestCase { } diff --git a/tests/auto/controls/fusion/fusion.pro b/tests/auto/controls/fusion/fusion.pro new file mode 100644 index 00000000..f3374f34 --- /dev/null +++ b/tests/auto/controls/fusion/fusion.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +TARGET = tst_fusion +CONFIG += qmltestcase +QT += quickcontrols2 + +DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\" + +SOURCES += \ + $$PWD/tst_fusion.cpp + +OTHER_FILES += \ + $$PWD/../data/*.qml + +TESTDATA += \ + $$PWD/../data/tst_* diff --git a/tests/auto/controls/fusion/tst_fusion.cpp b/tests/auto/controls/fusion/tst_fusion.cpp new file mode 100644 index 00000000..84f9c231 --- /dev/null +++ b/tests/auto/controls/fusion/tst_fusion.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> +#include <QtQuickControls2/qquickstyle.h> + +int main(int argc, char *argv[]) +{ + QTEST_ADD_GPU_BLACKLIST_SUPPORT + QTEST_SET_MAIN_SOURCE_PATH + qputenv("QML_NO_TOUCH_COMPRESSION", "1"); + QQuickStyle::setStyle("Fusion"); + return quick_test_main(argc, argv, "tst_controls::Fusion", TST_CONTROLS_DATA); +} diff --git a/tests/auto/controls/imagine/dependencies.qml b/tests/auto/controls/imagine/dependencies.qml new file mode 100644 index 00000000..3811fec0 --- /dev/null +++ b/tests/auto/controls/imagine/dependencies.qml @@ -0,0 +1,6 @@ +import QtTest 1.0 +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.Imagine 2.3 + +TestCase { } diff --git a/tests/auto/controls/imagine/imagine.pro b/tests/auto/controls/imagine/imagine.pro new file mode 100644 index 00000000..ab521c98 --- /dev/null +++ b/tests/auto/controls/imagine/imagine.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +TARGET = tst_imagine +CONFIG += qmltestcase +QT += quickcontrols2 + +DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\" + +SOURCES += \ + $$PWD/tst_imagine.cpp + +OTHER_FILES += \ + $$PWD/../data/*.qml + +TESTDATA += \ + $$PWD/../data/tst_* diff --git a/tests/auto/controls/imagine/tst_imagine.cpp b/tests/auto/controls/imagine/tst_imagine.cpp new file mode 100644 index 00000000..9777c9c9 --- /dev/null +++ b/tests/auto/controls/imagine/tst_imagine.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> +#include <QtQuickControls2/qquickstyle.h> + +int main(int argc, char *argv[]) +{ + QTEST_ADD_GPU_BLACKLIST_SUPPORT + QTEST_SET_MAIN_SOURCE_PATH + qputenv("QML_NO_TOUCH_COMPRESSION", "1"); + QQuickStyle::setStyle("Imagine"); + return quick_test_main(argc, argv, "tst_controls::Imagine", TST_CONTROLS_DATA); +} diff --git a/tests/auto/cursor/tst_cursor.cpp b/tests/auto/cursor/tst_cursor.cpp index 6256112d..0f24a29e 100644 --- a/tests/auto/cursor/tst_cursor.cpp +++ b/tests/auto/cursor/tst_cursor.cpp @@ -184,6 +184,11 @@ void tst_cursor::scrollBar() const QPoint scrollBarPos(window->width() - scrollBar->width() / 2, window->height() / 2); QTest::mouseMove(window, scrollBarPos); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Active status behaves differently in offscreen/minimal platforms", Continue); + QVERIFY(scrollBar->isActive()); QCOMPARE(window->cursor().shape(), scrollBar->cursor().shape()); QCOMPARE(scrollBar->cursor().shape(), Qt::CursorShape::ArrowCursor); diff --git a/tests/auto/font/data/font-appwindow-custom.qml b/tests/auto/font/data/font-appwindow-custom.qml index 3d06f64a..e98b678e 100644 --- a/tests/auto/font/data/font-appwindow-custom.qml +++ b/tests/auto/font/data/font-appwindow-custom.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/font-appwindow-default.qml b/tests/auto/font/data/font-appwindow-default.qml index 02643c77..8337b488 100644 --- a/tests/auto/font/data/font-appwindow-default.qml +++ b/tests/auto/font/data/font-appwindow-default.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/font-control-custom.qml b/tests/auto/font/data/font-control-custom.qml index 92136e86..0121eca2 100644 --- a/tests/auto/font/data/font-control-custom.qml +++ b/tests/auto/font/data/font-control-custom.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 Control { diff --git a/tests/auto/font/data/font-control-default.qml b/tests/auto/font/data/font-control-default.qml index 552c77d8..f3af36a2 100644 --- a/tests/auto/font/data/font-control-default.qml +++ b/tests/auto/font/data/font-control-default.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 Control { diff --git a/tests/auto/font/data/font-popup-custom.qml b/tests/auto/font/data/font-popup-custom.qml index e8363a81..3982721e 100644 --- a/tests/auto/font/data/font-popup-custom.qml +++ b/tests/auto/font/data/font-popup-custom.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 Popup { diff --git a/tests/auto/font/data/font-popup-default.qml b/tests/auto/font/data/font-popup-default.qml index 26c522c1..c4fab76a 100644 --- a/tests/auto/font/data/font-popup-default.qml +++ b/tests/auto/font/data/font-popup-default.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 Popup { diff --git a/tests/auto/font/data/inheritance-childcontrol.qml b/tests/auto/font/data/inheritance-childcontrol.qml index 8a04dd52..7c2b0d0c 100644 --- a/tests/auto/font/data/inheritance-childcontrol.qml +++ b/tests/auto/font/data/inheritance-childcontrol.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-childpopup.qml b/tests/auto/font/data/inheritance-childpopup.qml index ca5cdc82..304f0486 100644 --- a/tests/auto/font/data/inheritance-childpopup.qml +++ b/tests/auto/font/data/inheritance-childpopup.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-control.qml b/tests/auto/font/data/inheritance-control.qml index ac9c940a..fe555237 100644 --- a/tests/auto/font/data/inheritance-control.qml +++ b/tests/auto/font/data/inheritance-control.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-dynamicchildcontrol.qml b/tests/auto/font/data/inheritance-dynamicchildcontrol.qml index 98c0f696..982b5611 100644 --- a/tests/auto/font/data/inheritance-dynamicchildcontrol.qml +++ b/tests/auto/font/data/inheritance-dynamicchildcontrol.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-dynamicchildpopup.qml b/tests/auto/font/data/inheritance-dynamicchildpopup.qml index ef4fe60c..7af10af6 100644 --- a/tests/auto/font/data/inheritance-dynamicchildpopup.qml +++ b/tests/auto/font/data/inheritance-dynamicchildpopup.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-dynamiccontrol.qml b/tests/auto/font/data/inheritance-dynamiccontrol.qml index a261d600..263ad38d 100644 --- a/tests/auto/font/data/inheritance-dynamiccontrol.qml +++ b/tests/auto/font/data/inheritance-dynamiccontrol.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-dynamicpopup.qml b/tests/auto/font/data/inheritance-dynamicpopup.qml index f0d567da..cd355682 100644 --- a/tests/auto/font/data/inheritance-dynamicpopup.qml +++ b/tests/auto/font/data/inheritance-dynamicpopup.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/data/inheritance-popup.qml b/tests/auto/font/data/inheritance-popup.qml index b8415e63..3219a186 100644 --- a/tests/auto/font/data/inheritance-popup.qml +++ b/tests/auto/font/data/inheritance-popup.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/font/tst_font.cpp b/tests/auto/font/tst_font.cpp index a851b263..660f4baf 100644 --- a/tests/auto/font/tst_font.cpp +++ b/tests/auto/font/tst_font.cpp @@ -255,7 +255,7 @@ void tst_font::defaultFont_data() QTest::newRow("ToolButton") << "ToolButton" << QPlatformTheme::ToolButtonFont; QTest::newRow("ToolSeparator") << "ToolSeparator" << QPlatformTheme::SystemFont; QTest::newRow("ToolTip") << "ToolTip" << QPlatformTheme::TipLabelFont; - QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::SystemFont; + QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::ItemViewFont; } void tst_font::defaultFont() @@ -263,12 +263,14 @@ void tst_font::defaultFont() QFETCH(QString, control); QFETCH(QPlatformTheme::Font, fontType); - TestFontTheme theme(QGuiApplicationPrivate::platform_theme); - QQmlEngine engine; QQmlComponent component(&engine); component.setData(QString("import QtQuick.Controls 2.2; %1 { }").arg(control).toUtf8(), QUrl()); + // The call to setData() above causes QQuickDefaultTheme to be set as the platform theme, + // so we must make sure we only set our theme afterwards. + TestFontTheme theme(QGuiApplicationPrivate::platform_theme); + QScopedPointer<QObject> object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); diff --git a/tests/auto/palette/data/inheritance-childcontrol.qml b/tests/auto/palette/data/inheritance-childcontrol.qml new file mode 100644 index 00000000..7c2b0d0c --- /dev/null +++ b/tests/auto/palette/data/inheritance-childcontrol.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property alias control: control + property alias child: child + property alias grandChild: grandChild + + Item { + Control { + id: control + + Control { + id: child + + Item { + Control { + id: grandChild + } + } + } + } + } +} diff --git a/tests/auto/palette/data/inheritance-childpopup.qml b/tests/auto/palette/data/inheritance-childpopup.qml new file mode 100644 index 00000000..304f0486 --- /dev/null +++ b/tests/auto/palette/data/inheritance-childpopup.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property alias control: control + property alias child: child + property alias grandChild: grandChild + + Item { + Popup { + id: control + + Control { + id: child + + Item { + Control { + id: grandChild + } + } + } + } + } +} diff --git a/tests/auto/palette/data/inheritance-control.qml b/tests/auto/palette/data/inheritance-control.qml new file mode 100644 index 00000000..e5486edb --- /dev/null +++ b/tests/auto/palette/data/inheritance-control.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + id: window + + property alias control: control + property alias child: child + property alias grandChild: grandChild + + Control { + id: control + + Control { + id: child + + Item { + Control { + id: grandChild + } + } + } + } +} diff --git a/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml b/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml new file mode 100644 index 00000000..982b5611 --- /dev/null +++ b/tests/auto/palette/data/inheritance-dynamicchildcontrol.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property Control control + property Control child + property Control grandChild + + Item { + id: childItem + } + + Component { + id: component + Control { } + } + + Component.onCompleted: { + control = component.createObject(childItem) + child = component.createObject(control) + grandChild = component.createObject(child) + } +} diff --git a/tests/auto/palette/data/inheritance-dynamicchildpopup.qml b/tests/auto/palette/data/inheritance-dynamicchildpopup.qml new file mode 100644 index 00000000..7af10af6 --- /dev/null +++ b/tests/auto/palette/data/inheritance-dynamicchildpopup.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property Popup control + property Control child + property Control grandChild + + Item { + id: childItem + } + + Component { + id: popupComponent + Popup { } + } + + Component { + id: controlComponent + Control { } + } + + Component.onCompleted: { + control = popupComponent.createObject(childItem) + child = controlComponent.createObject(control.contentItem) + grandChild = controlComponent.createObject(child) + } +} diff --git a/tests/auto/palette/data/inheritance-dynamiccontrol.qml b/tests/auto/palette/data/inheritance-dynamiccontrol.qml new file mode 100644 index 00000000..263ad38d --- /dev/null +++ b/tests/auto/palette/data/inheritance-dynamiccontrol.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property Control control + property Control child + property Control grandChild + + Component { + id: component + Control { } + } + + Component.onCompleted: { + control = component.createObject(contentItem) + child = component.createObject(control) + grandChild = component.createObject(child) + } +} diff --git a/tests/auto/palette/data/inheritance-dynamicpopup.qml b/tests/auto/palette/data/inheritance-dynamicpopup.qml new file mode 100644 index 00000000..cd355682 --- /dev/null +++ b/tests/auto/palette/data/inheritance-dynamicpopup.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + + property Popup control + property Control child + property Control grandChild + + Component { + id: popupComponent + Popup { } + } + + Component { + id: controlComponent + Control { } + } + + Component.onCompleted: { + control = popupComponent.createObject(window) + child = controlComponent.createObject(control.contentItem) + grandChild = controlComponent.createObject(child) + } +} diff --git a/tests/auto/palette/data/inheritance-popup.qml b/tests/auto/palette/data/inheritance-popup.qml new file mode 100644 index 00000000..e6ac0a3a --- /dev/null +++ b/tests/auto/palette/data/inheritance-popup.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + id: window + + property alias control: control + property alias child: child + property alias grandChild: grandChild + + Popup { + id: control + + Control { + id: child + + Item { + Control { + id: grandChild + } + } + } + } +} diff --git a/tests/auto/palette/data/listview.qml b/tests/auto/palette/data/listview.qml new file mode 100644 index 00000000..7381c310 --- /dev/null +++ b/tests/auto/palette/data/listview.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Controls 2.2 + +ApplicationWindow { + id: window + width: 200 + height: 200 + + property alias listView: listView + + palette.highlight: "red" + + ListView { + id: listView + anchors.fill: parent + model: 1 + delegate: Column { + property alias control: control + property alias label: label + property alias textarea: textarea + property alias textfield: textfield + + Control { id: control } + Label { id: label } + TextArea { id: textarea } + TextField { id: textfield } + } + } +} diff --git a/tests/auto/palette/data/palette-appwindow-custom.qml b/tests/auto/palette/data/palette-appwindow-custom.qml new file mode 100644 index 00000000..33139e48 --- /dev/null +++ b/tests/auto/palette/data/palette-appwindow-custom.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + palette.alternateBase: "aqua" + palette.base: "azure" + palette.brightText: "beige" + palette.button: "bisque" + palette.buttonText: "chocolate" + palette.dark: "coral" + palette.highlight: "crimson" + palette.highlightedText: "fuchsia" + palette.light: "gold" + palette.link: "indigo" + palette.linkVisited: "ivory" + palette.mid: "khaki" + palette.midlight: "lavender" + palette.shadow: "linen" + palette.text: "moccasin" + palette.toolTipBase: "navy" + palette.toolTipText: "orchid" + palette.window: "plum" + palette.windowText: "salmon" +} diff --git a/tests/auto/palette/data/palette-appwindow-default.qml b/tests/auto/palette/data/palette-appwindow-default.qml new file mode 100644 index 00000000..c071a0f4 --- /dev/null +++ b/tests/auto/palette/data/palette-appwindow-default.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { +} diff --git a/tests/auto/palette/data/palette-control-custom.qml b/tests/auto/palette/data/palette-control-custom.qml new file mode 100644 index 00000000..d3eb05bd --- /dev/null +++ b/tests/auto/palette/data/palette-control-custom.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +Control { + palette.alternateBase: "aqua" + palette.base: "azure" + palette.brightText: "beige" + palette.button: "bisque" + palette.buttonText: "chocolate" + palette.dark: "coral" + palette.highlight: "crimson" + palette.highlightedText: "fuchsia" + palette.light: "gold" + palette.link: "indigo" + palette.linkVisited: "ivory" + palette.mid: "khaki" + palette.midlight: "lavender" + palette.shadow: "linen" + palette.text: "moccasin" + palette.toolTipBase: "navy" + palette.toolTipText: "orchid" + palette.window: "plum" + palette.windowText: "salmon" +} diff --git a/tests/auto/palette/data/palette-control-default.qml b/tests/auto/palette/data/palette-control-default.qml new file mode 100644 index 00000000..b747d7e2 --- /dev/null +++ b/tests/auto/palette/data/palette-control-default.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +Control { +} diff --git a/tests/auto/palette/data/palette-popup-custom.qml b/tests/auto/palette/data/palette-popup-custom.qml new file mode 100644 index 00000000..3b7cec3d --- /dev/null +++ b/tests/auto/palette/data/palette-popup-custom.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +Popup { + palette.alternateBase: "aqua" + palette.base: "azure" + palette.brightText: "beige" + palette.button: "bisque" + palette.buttonText: "chocolate" + palette.dark: "coral" + palette.highlight: "crimson" + palette.highlightedText: "fuchsia" + palette.light: "gold" + palette.link: "indigo" + palette.linkVisited: "ivory" + palette.mid: "khaki" + palette.midlight: "lavender" + palette.shadow: "linen" + palette.text: "moccasin" + palette.toolTipBase: "navy" + palette.toolTipText: "orchid" + palette.window: "plum" + palette.windowText: "salmon" +} diff --git a/tests/auto/palette/data/palette-popup-default.qml b/tests/auto/palette/data/palette-popup-default.qml new file mode 100644 index 00000000..f09feae0 --- /dev/null +++ b/tests/auto/palette/data/palette-popup-default.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +Popup { +} diff --git a/tests/auto/palette/palette.pro b/tests/auto/palette/palette.pro new file mode 100644 index 00000000..c7d55d07 --- /dev/null +++ b/tests/auto/palette/palette.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_palette +SOURCES += tst_palette.cpp + +macos:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private quickcontrols2-private + +include (../shared/util.pri) + +RESOURCES += qtquickcontrols2.conf + +TESTDATA = data/* + +OTHER_FILES += \ + data/*.qml diff --git a/tests/auto/palette/qtquickcontrols2.conf b/tests/auto/palette/qtquickcontrols2.conf new file mode 100644 index 00000000..2ffc7ecc --- /dev/null +++ b/tests/auto/palette/qtquickcontrols2.conf @@ -0,0 +1,5 @@ +[Default] +Palette\Base=#efefef + +[Default\Palette] +Text=#101010 diff --git a/tests/auto/palette/tst_palette.cpp b/tests/auto/palette/tst_palette.cpp new file mode 100644 index 00000000..f74e358a --- /dev/null +++ b/tests/auto/palette/tst_palette.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include "../shared/visualtestutil.h" + +#include <QtGui/qpalette.h> +#include <QtGui/qpa/qplatformtheme.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcomponent.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickcontrol_p.h> +#include <QtQuickTemplates2/private/qquickcontrol_p_p.h> +#include <QtQuickTemplates2/private/qquickpopup_p.h> +#include <QtQuickControls2/private/qquickproxytheme_p.h> + +using namespace QQuickVisualTestUtil; + +class tst_palette : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void palette_data(); + void palette(); + + void inheritance_data(); + void inheritance(); + + void defaultPalette_data(); + void defaultPalette(); + + void listView_data(); + void listView(); +}; + +void tst_palette::initTestCase() +{ + QQmlDataTest::initTestCase(); + + // Import QtQuick.Controls to initialize styles and themes so that + // QQuickControlPrivate::themePalette() returns a palette from the + // style's theme instead of the platform's theme. + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick.Controls 2.3; Control { }", QUrl()); + delete component.create(); +} + +void tst_palette::palette_data() +{ + QTest::addColumn<QString>("testFile"); + QTest::addColumn<QPalette>("expectedPalette"); + + QPalette defaultPalette = QQuickControlPrivate::themePalette(QPlatformTheme::SystemPalette); + defaultPalette.setColor(QPalette::Base, QColor("#efefef")); + defaultPalette.setColor(QPalette::Text, QColor("#101010")); + + QTest::newRow("Control") << "palette-control-default.qml" << defaultPalette; + QTest::newRow("AppWindow") << "palette-appwindow-default.qml" << defaultPalette; + QTest::newRow("Popup") << "palette-popup-default.qml" << defaultPalette; + + QPalette customPalette; + customPalette.setColor(QPalette::AlternateBase, QColor("aqua")); + customPalette.setColor(QPalette::Base, QColor("azure")); + customPalette.setColor(QPalette::BrightText, QColor("beige")); + customPalette.setColor(QPalette::Button, QColor("bisque")); + customPalette.setColor(QPalette::ButtonText, QColor("chocolate")); + customPalette.setColor(QPalette::Dark, QColor("coral")); + customPalette.setColor(QPalette::Highlight, QColor("crimson")); + customPalette.setColor(QPalette::HighlightedText, QColor("fuchsia")); + customPalette.setColor(QPalette::Light, QColor("gold")); + customPalette.setColor(QPalette::Link, QColor("indigo")); + customPalette.setColor(QPalette::LinkVisited, QColor("ivory")); + customPalette.setColor(QPalette::Mid, QColor("khaki")); + customPalette.setColor(QPalette::Midlight, QColor("lavender")); + customPalette.setColor(QPalette::Shadow, QColor("linen")); + customPalette.setColor(QPalette::Text, QColor("moccasin")); + customPalette.setColor(QPalette::ToolTipBase, QColor("navy")); + customPalette.setColor(QPalette::ToolTipText, QColor("orchid")); + customPalette.setColor(QPalette::Window, QColor("plum")); + customPalette.setColor(QPalette::WindowText, QColor("salmon")); + + QTest::newRow("Control:custom") << "palette-control-custom.qml" << customPalette; + QTest::newRow("AppWindow:custom") << "palette-appwindow-custom.qml" << customPalette; + QTest::newRow("Popup:custom") << "palette-popup-custom.qml" << customPalette; +} + +void tst_palette::palette() +{ + QFETCH(QString, testFile); + QFETCH(QPalette, expectedPalette); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl(testFile)); + + QScopedPointer<QObject> object(component.create()); + QVERIFY2(!object.isNull(), qPrintable(component.errorString())); + + QVariant var = object->property("palette"); + QVERIFY(var.isValid()); + + QPalette actualPalette = var.value<QPalette>(); + QCOMPARE(actualPalette, expectedPalette); +} + +void tst_palette::inheritance_data() +{ + QTest::addColumn<QString>("testFile"); + + QTest::newRow("Control") << "inheritance-control.qml"; + QTest::newRow("Child Control") << "inheritance-childcontrol.qml"; + QTest::newRow("Dynamic Control") << "inheritance-dynamiccontrol.qml"; + QTest::newRow("Dynamic Child Control") << "inheritance-dynamicchildcontrol.qml"; + + QTest::newRow("Popup") << "inheritance-popup.qml"; + QTest::newRow("Child Popup") << "inheritance-childpopup.qml"; + QTest::newRow("Dynamic Popup") << "inheritance-dynamicpopup.qml"; + QTest::newRow("Dynamic Child Popup") << "inheritance-dynamicchildpopup.qml"; +} + +void tst_palette::inheritance() +{ + QFETCH(QString, testFile); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl(testFile)); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create())); + QVERIFY2(!window.isNull(), qPrintable(component.errorString())); + + QObject *control = window->property("control").value<QObject *>(); + QObject *child = window->property("child").value<QObject *>(); + QObject *grandChild = window->property("grandChild").value<QObject *>(); + QVERIFY(control && child && grandChild); + + QPalette defaultPalette = QQuickControlPrivate::themePalette(QPlatformTheme::SystemPalette); + defaultPalette.setColor(QPalette::Base, QColor("#efefef")); + defaultPalette.setColor(QPalette::Text, QColor("#101010")); + + QCOMPARE(window->palette(), defaultPalette); + + QCOMPARE(control->property("palette").value<QPalette>(), defaultPalette); + QCOMPARE(child->property("palette").value<QPalette>(), defaultPalette); + QCOMPARE(grandChild->property("palette").value<QPalette>(), defaultPalette); + + QPalette childPalette(defaultPalette); + childPalette.setColor(QPalette::Base, Qt::red); + childPalette.setColor(QPalette::Text, Qt::green); + childPalette.setColor(QPalette::Button, Qt::blue); + child->setProperty("palette", childPalette); + QCOMPARE(child->property("palette").value<QPalette>(), childPalette); + QCOMPARE(grandChild->property("palette").value<QPalette>(), childPalette); + + QPalette grandChildPalette(childPalette); + grandChildPalette.setColor(QPalette::Base, Qt::cyan); + grandChildPalette.setColor(QPalette::Mid, Qt::magenta); + grandChild->setProperty("palette", grandChildPalette); + QCOMPARE(child->property("palette").value<QPalette>(), childPalette); + QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette); + + QPalette windowPalette(defaultPalette); + windowPalette.setColor(QPalette::Window, Qt::gray); + window->setPalette(windowPalette); + QCOMPARE(window->palette(), windowPalette); + QCOMPARE(control->property("palette").value<QPalette>(), windowPalette); + + childPalette.setColor(QPalette::Window, Qt::gray); + QCOMPARE(child->property("palette").value<QPalette>(), childPalette); + + grandChildPalette.setColor(QPalette::Window, Qt::gray); + QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette); + + child->setProperty("palette", QVariant()); + QCOMPARE(child->property("palette").value<QPalette>(), windowPalette); + QCOMPARE(grandChild->property("palette").value<QPalette>(), grandChildPalette); + + grandChild->setProperty("palette", QVariant()); + QCOMPARE(grandChild->property("palette").value<QPalette>(), windowPalette); +} + +class TestTheme : public QQuickProxyTheme +{ +public: + TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme) + { + std::fill(palettes, palettes + QPlatformTheme::NPalettes, static_cast<QPalette *>(0)); + + QPalette palette = QPalette(); + palette.setColor(QPalette::Window, Qt::gray); + palettes[QPlatformTheme::SystemPalette] = new QPalette(palette); + + palette.setColor(QPalette::ToolTipBase, Qt::yellow); + palettes[QPlatformTheme::ToolTipPalette] = new QPalette(palette); + + palette.setColor(QPalette::ButtonText, Qt::blue); + palettes[QPlatformTheme::ToolButtonPalette] = new QPalette(palette); + + palette.setColor(QPalette::Button, Qt::red); + palettes[QPlatformTheme::ButtonPalette] = new QPalette(palette); + + palette.setColor(QPalette::Text, Qt::green); + palettes[QPlatformTheme::CheckBoxPalette] = new QPalette(palette); + + palette.setColor(QPalette::Text, Qt::blue); + palettes[QPlatformTheme::RadioButtonPalette] = new QPalette(palette); + + // HeaderPalette unused + + palette.setColor(QPalette::Base, Qt::darkGray); + palettes[QPlatformTheme::ComboBoxPalette] = new QPalette(palette); + + palette.setColor(QPalette::Base, Qt::lightGray); + palettes[QPlatformTheme::ItemViewPalette] = new QPalette(palette); + + // MessageBoxLabelPalette unused + + palette.setColor(QPalette::ButtonText, Qt::white); + palettes[QPlatformTheme::TabBarPalette] = new QPalette(palette); + + palette.setColor(QPalette::WindowText, Qt::darkGray); + palettes[QPlatformTheme::LabelPalette] = new QPalette(palette); + + palette.setColor(QPalette::Mid, Qt::gray); + palettes[QPlatformTheme::GroupBoxPalette] = new QPalette(palette); + + palette.setColor(QPalette::Shadow, Qt::darkYellow); + palettes[QPlatformTheme::MenuPalette] = new QPalette(palette); + + // MenuBarPalette unused + + palette.setColor(QPalette::Base, Qt::cyan); + palettes[QPlatformTheme::TextEditPalette] = new QPalette(palette); + + palette.setColor(QPalette::Base, Qt::magenta); + palettes[QPlatformTheme::TextLineEditPalette] = new QPalette(palette); + + QGuiApplicationPrivate::platform_theme = this; + } + + const QPalette *palette(Palette type = SystemPalette) const override + { + return palettes[type]; + } + +private: + QPalette *palettes[QPlatformTheme::NPalettes]; +}; + +Q_DECLARE_METATYPE(QPlatformTheme::Palette) + +void tst_palette::defaultPalette_data() +{ + QTest::addColumn<QString>("control"); + QTest::addColumn<QPlatformTheme::Palette>("paletteType"); + + QTest::newRow("AbstractButton") << "AbstractButton" << QPlatformTheme::SystemPalette; + QTest::newRow("ApplicationWindow") << "ApplicationWindow" << QPlatformTheme::SystemPalette; + QTest::newRow("Button") << "Button" << QPlatformTheme::ButtonPalette; + QTest::newRow("CheckBox") << "CheckBox" << QPlatformTheme::CheckBoxPalette; + QTest::newRow("CheckDelegate") << "CheckDelegate" << QPlatformTheme::ItemViewPalette; + QTest::newRow("ComboBox") << "ComboBox" << QPlatformTheme::ComboBoxPalette; + QTest::newRow("Container") << "Container" << QPlatformTheme::SystemPalette; + QTest::newRow("Control") << "Control" << QPlatformTheme::SystemPalette; + QTest::newRow("Dial") << "Dial" << QPlatformTheme::SystemPalette; + QTest::newRow("Dialog") << "Dialog" << QPlatformTheme::SystemPalette; + QTest::newRow("DialogButtonBox") << "DialogButtonBox" << QPlatformTheme::SystemPalette; + QTest::newRow("Drawer") << "Drawer" << QPlatformTheme::SystemPalette; + QTest::newRow("Frame") << "Frame" << QPlatformTheme::SystemPalette; + QTest::newRow("GroupBox") << "GroupBox" << QPlatformTheme::GroupBoxPalette; + QTest::newRow("ItemDelegate") << "ItemDelegate" << QPlatformTheme::ItemViewPalette; + QTest::newRow("Label") << "Label" << QPlatformTheme::LabelPalette; + QTest::newRow("Menu") << "Menu" << QPlatformTheme::MenuPalette; + QTest::newRow("MenuItem") << "MenuItem" << QPlatformTheme::MenuPalette; + QTest::newRow("MenuSeparator") << "MenuSeparator" << QPlatformTheme::MenuPalette; + QTest::newRow("Page") << "Page" << QPlatformTheme::SystemPalette; + QTest::newRow("Pane") << "Pane" << QPlatformTheme::SystemPalette; + QTest::newRow("Popup") << "Popup" << QPlatformTheme::SystemPalette; + QTest::newRow("ProgressBar") << "ProgressBar" << QPlatformTheme::SystemPalette; + QTest::newRow("RadioButton") << "RadioButton" << QPlatformTheme::RadioButtonPalette; + QTest::newRow("RadioDelegate") << "RadioDelegate" << QPlatformTheme::ItemViewPalette; + QTest::newRow("RangeSlider") << "RangeSlider" << QPlatformTheme::SystemPalette; + QTest::newRow("RoundButton") << "RoundButton" << QPlatformTheme::ButtonPalette; + QTest::newRow("ScrollBar") << "ScrollBar" << QPlatformTheme::SystemPalette; + QTest::newRow("ScrollIndicator") << "ScrollIndicator" << QPlatformTheme::SystemPalette; + QTest::newRow("Slider") << "Slider" << QPlatformTheme::SystemPalette; + QTest::newRow("SpinBox") << "SpinBox" << QPlatformTheme::TextLineEditPalette; + QTest::newRow("SwipeDelegate") << "SwipeDelegate" << QPlatformTheme::ItemViewPalette; + QTest::newRow("Switch") << "Switch" << QPlatformTheme::CheckBoxPalette; // ### TODO: add QPlatformTheme::SwitchPalette + QTest::newRow("SwitchDelegate") << "SwitchDelegate" << QPlatformTheme::ItemViewPalette; + QTest::newRow("TabBar") << "TabBar" << QPlatformTheme::TabBarPalette; + QTest::newRow("TabButton") << "TabButton" << QPlatformTheme::TabBarPalette; + QTest::newRow("TextArea") << "TextArea" << QPlatformTheme::TextEditPalette; + QTest::newRow("TextField") << "TextField" << QPlatformTheme::TextLineEditPalette; + QTest::newRow("ToolBar") << "ToolBar" << QPlatformTheme::ToolButtonPalette; + QTest::newRow("ToolButton") << "ToolButton" << QPlatformTheme::ToolButtonPalette; + QTest::newRow("ToolSeparator") << "ToolSeparator" << QPlatformTheme::ToolButtonPalette; + QTest::newRow("ToolTip") << "ToolTip" << QPlatformTheme::ToolTipPalette; + QTest::newRow("Tumbler") << "Tumbler" << QPlatformTheme::ItemViewPalette; +} + +void tst_palette::defaultPalette() +{ + QFETCH(QString, control); + QFETCH(QPlatformTheme::Palette, paletteType); + + TestTheme theme(QGuiApplicationPrivate::platform_theme); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QString("import QtQuick.Controls 2.3; %1 { }").arg(control).toUtf8(), QUrl()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY2(!object.isNull(), qPrintable(component.errorString())); + + QVariant var = object->property("palette"); + QVERIFY(var.isValid()); + + const QPalette *expectedPalette = theme.palette(paletteType); + QVERIFY(expectedPalette); + + QPalette actualPalette = var.value<QPalette>(); + QCOMPARE(actualPalette, *expectedPalette); +} + +void tst_palette::listView_data() +{ + QTest::addColumn<QString>("objectName"); + + QTest::newRow("Control") << "control"; + QTest::newRow("Label") << "label"; + QTest::newRow("TextArea") << "textarea"; + QTest::newRow("TextField") << "textfield"; +} + +void tst_palette::listView() +{ + QFETCH(QString, objectName); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("listview.qml")); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create())); + QVERIFY2(!window.isNull(), qPrintable(component.errorString())); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickItem *listView = window->property("listView").value<QQuickItem *>(); + QVERIFY(listView); + + QQuickItem *contentItem = listView->property("contentItem").value<QQuickItem *>(); + QVERIFY(contentItem); + + QVERIFY(QMetaObject::invokeMethod(listView, "forceLayout")); + + QQuickItem *column = contentItem->childItems().value(0); + QVERIFY(column); + + QQuickItem *control = column->property(objectName.toUtf8()).value<QQuickItem *>(); + QVERIFY(control); + + QCOMPARE(control->property("palette").value<QPalette>().color(QPalette::Highlight), QColor(Qt::red)); +} + +QTEST_MAIN(tst_palette) + +#include "tst_palette.moc" diff --git a/tests/auto/qquickapplicationwindow/data/layout.qml b/tests/auto/qquickapplicationwindow/data/layout.qml index a80b2d48..5bcffdf1 100644 --- a/tests/auto/qquickapplicationwindow/data/layout.qml +++ b/tests/auto/qquickapplicationwindow/data/layout.qml @@ -49,13 +49,14 @@ ****************************************************************************/ import QtQuick 2.6 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.3 ApplicationWindow { width: 200 height: 200 visible: true + menuBar: MenuBar { } header: ToolBar { } footer: ToolBar { } } diff --git a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp index 19a0bf3b..aeeddb10 100644 --- a/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp +++ b/tests/auto/qquickapplicationwindow/tst_qquickapplicationwindow.cpp @@ -412,7 +412,7 @@ void tst_QQuickApplicationWindow::attachedProperties() QCOMPARE(childControl->window(), childAppWindow); QCOMPARE(childControl->property("attached_window").value<QQuickApplicationWindow *>(), childAppWindow); QCOMPARE(childControl->property("attached_contentItem").value<QQuickItem *>(), childAppWindow->contentItem()); - QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindow->activeFocusControl()); + QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindowControl); QCOMPARE(childControl->property("attached_header").value<QQuickItem *>(), childAppWindow->header()); QCOMPARE(childControl->property("attached_footer").value<QQuickItem *>(), childAppWindow->footer()); QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), childAppWindow->overlay()); @@ -421,7 +421,7 @@ void tst_QQuickApplicationWindow::attachedProperties() QCOMPARE(childItem->window(), childAppWindow); QCOMPARE(childItem->property("attached_window").value<QQuickApplicationWindow *>(), childAppWindow); QCOMPARE(childItem->property("attached_contentItem").value<QQuickItem *>(), childAppWindow->contentItem()); - QCOMPARE(childItem->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindow->activeFocusControl()); + QCOMPARE(childItem->property("attached_activeFocusControl").value<QQuickItem *>(), childAppWindowControl); QCOMPARE(childItem->property("attached_header").value<QQuickItem *>(), childAppWindow->header()); QCOMPARE(childItem->property("attached_footer").value<QQuickItem *>(), childAppWindow->footer()); QCOMPARE(childItem->property("attached_overlay").value<QQuickItem *>(), childAppWindow->overlay()); @@ -443,6 +443,55 @@ void tst_QQuickApplicationWindow::attachedProperties() QVERIFY(!childItem->property("attached_header").value<QQuickItem *>()); QVERIFY(!childItem->property("attached_footer").value<QQuickItem *>()); QVERIFY(!childItem->property("attached_overlay").value<QQuickItem *>()); + childAppWindow->close(); + qApp->processEvents(); + + childWindow->show(); + childWindow->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(childWindow)); + + QVERIFY(!childWindowControl->hasActiveFocus()); + childWindowControl->forceActiveFocus(); + QTRY_VERIFY(childWindowControl->hasActiveFocus()); + QCOMPARE(childWindow->activeFocusItem(), childWindowControl); + QCOMPARE(childWindowControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl); + + childControl->setParentItem(childWindow->contentItem()); + QCOMPARE(childControl->window(), childWindow); + QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>()); + QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl); + QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_header").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>()); + QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow)); + + childItem->setParentItem(childWindow->contentItem()); + QCOMPARE(childItem->window(), childWindow); + QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>()); + QCOMPARE(childControl->property("attached_activeFocusControl").value<QQuickItem *>(), childWindowControl); + QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_header").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>()); + QCOMPARE(childControl->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow)); + + childControl->setParentItem(nullptr); + QVERIFY(!childControl->window()); + QVERIFY(!childControl->property("attached_window").value<QQuickWindow *>()); + QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_activeFocusControl").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_header").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>()); + QVERIFY(!childControl->property("attached_overlay").value<QQuickItem *>()); + + childItem->setParentItem(nullptr); + QVERIFY(!childItem->window()); + QVERIFY(!childItem->property("attached_window").value<QQuickWindow *>()); + QVERIFY(!childItem->property("attached_contentItem").value<QQuickItem *>()); + QVERIFY(!childItem->property("attached_activeFocusControl").value<QQuickItem *>()); + QVERIFY(!childItem->property("attached_header").value<QQuickItem *>()); + QVERIFY(!childItem->property("attached_footer").value<QQuickItem *>()); + QVERIFY(!childItem->property("attached_overlay").value<QQuickItem *>()); + childWindow->close(); // ### A temporary workaround to unblock the CI until the crash caused // by https://codereview.qt-project.org/#/c/108517/ has been fixed... @@ -506,7 +555,7 @@ void tst_QQuickApplicationWindow::font() QCOMPARE(item6->font(), font); } -class TestTheme : public QQuickProxyTheme +class TestTheme : public QQuickProxyTheme { public: TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme), m_font("Courier") @@ -778,11 +827,18 @@ void tst_QQuickApplicationWindow::layout() QQuickItem *content = window->contentItem(); QVERIFY(content); + QQuickItem *menuBar = window->menuBar(); + QVERIFY(menuBar); QQuickItem *header = window->header(); QVERIFY(header); QQuickItem *footer = window->footer(); QVERIFY(footer); + QCOMPARE(menuBar->x(), 0.0); + QCOMPARE(menuBar->y(), -menuBar->height() - header->height()); + QCOMPARE(header->width(), qreal(window->width())); + QVERIFY(menuBar->height() > 0); + QCOMPARE(header->x(), 0.0); QCOMPARE(header->y(), -header->height()); QCOMPARE(header->width(), qreal(window->width())); @@ -794,6 +850,12 @@ void tst_QQuickApplicationWindow::layout() QVERIFY(footer->height() > 0.0); QCOMPARE(content->x(), 0.0); + QCOMPARE(content->y(), menuBar->height() + header->height()); + QCOMPARE(content->width(), qreal(window->width())); + QCOMPARE(content->height(), window->height() - menuBar->height() - header->height() - footer->height()); + + menuBar->setVisible(false); + QCOMPARE(content->x(), 0.0); QCOMPARE(content->y(), header->height()); QCOMPARE(content->width(), qreal(window->width())); QCOMPARE(content->height(), window->height() - header->height() - footer->height()); diff --git a/tests/auto/qquickcolor/data/tst_color.qml b/tests/auto/qquickcolor/data/tst_color.qml new file mode 100644 index 00000000..fbd74e3c --- /dev/null +++ b/tests/auto/qquickcolor/data/tst_color.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtTest 1.0 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +TestCase { + id: testCase + name: "Color" + + function test_transparent() { + compare(Color.transparent("red", 0.2), Qt.rgba(1, 0, 0, 0.2)) + compare(Color.transparent(Qt.rgba(0, 1, 0, 1), 0.2), Qt.rgba(0, 1, 0, 0.2)) + compare(Color.transparent("#0000ff", 0.2), Qt.rgba(0, 0, 1, 0.2)) + } +} diff --git a/tests/auto/qquickcolor/qquickcolor.pro b/tests/auto/qquickcolor/qquickcolor.pro new file mode 100644 index 00000000..af562df1 --- /dev/null +++ b/tests/auto/qquickcolor/qquickcolor.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +TARGET = tst_qquickcolor +CONFIG += qmltestcase + +SOURCES += \ + $$PWD/tst_qquickcolor.cpp + +OTHER_FILES += \ + $$PWD/data/*.qml + +TESTDATA += \ + $$PWD/data/tst_* diff --git a/tests/auto/qquickcolor/tst_qquickcolor.cpp b/tests/auto/qquickcolor/tst_qquickcolor.cpp new file mode 100644 index 00000000..94c60080 --- /dev/null +++ b/tests/auto/qquickcolor/tst_qquickcolor.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> +QUICK_TEST_MAIN(tst_qquickcolor) diff --git a/tests/auto/qquickdrawer/BLACKLIST b/tests/auto/qquickdrawer/BLACKLIST new file mode 100644 index 00000000..b302c76b --- /dev/null +++ b/tests/auto/qquickdrawer/BLACKLIST @@ -0,0 +1,14 @@ +# See qtbase/src/testlib/qtestblacklist.cpp for format + +# https://bugreports.qt.io/browse/QTBUG-62628 +[multiple] +* + +[touch] +* + +[multiTouch] +* + +[grabber] +* diff --git a/tests/auto/qquickiconimage/data/alignment.qml b/tests/auto/qquickiconimage/data/alignment.qml new file mode 100644 index 00000000..487ebfd0 --- /dev/null +++ b/tests/auto/qquickiconimage/data/alignment.qml @@ -0,0 +1,16 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + name: "appointment-new" + sourceSize: Qt.size(22, 22) + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } +} diff --git a/tests/auto/qquickiconimage/data/color.qml b/tests/auto/qquickiconimage/data/color.qml new file mode 100644 index 00000000..d6f647e6 --- /dev/null +++ b/tests/auto/qquickiconimage/data/color.qml @@ -0,0 +1,18 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + source: "qrc:/icons/testtheme/22x22/actions/color-test-original.png" + sourceSize: Qt.size(22, 22) + color: "red" + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/color-test-tinted.png" + fillMode: Image.Pad + } +} diff --git a/tests/auto/qquickiconimage/data/fileSelectors.qml b/tests/auto/qquickiconimage/data/fileSelectors.qml new file mode 100644 index 00000000..487ebfd0 --- /dev/null +++ b/tests/auto/qquickiconimage/data/fileSelectors.qml @@ -0,0 +1,16 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + name: "appointment-new" + sourceSize: Qt.size(22, 22) + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } +} diff --git a/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml b/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml new file mode 100644 index 00000000..d6c33bb3 --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingNoSizes.qml @@ -0,0 +1,7 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +IconImage { + name: "appointment-new" +} diff --git a/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml b/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml new file mode 100644 index 00000000..487ebfd0 --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingSourceSize.qml @@ -0,0 +1,16 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + name: "appointment-new" + sourceSize: Qt.size(22, 22) + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } +} diff --git a/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml b/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml new file mode 100644 index 00000000..c503d8cf --- /dev/null +++ b/tests/auto/qquickiconimage/data/nameBindingSourceSizeWidthHeight.qml @@ -0,0 +1,10 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +IconImage { + name: "appointment-new" + sourceSize: Qt.size(22, 22) + width: 16 + height: 16 +} diff --git a/tests/auto/qquickiconimage/data/root.qml b/tests/auto/qquickiconimage/data/root.qml new file mode 100644 index 00000000..0a8b8db9 --- /dev/null +++ b/tests/auto/qquickiconimage/data/root.qml @@ -0,0 +1,6 @@ +import QtQuick 2.10 + +Item { + width: 200 + height: 200 +} diff --git a/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml b/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml new file mode 100644 index 00000000..33f4a2d3 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingNoSizes.qml @@ -0,0 +1,15 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } +} diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml new file mode 100644 index 00000000..c246dc74 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSize.qml @@ -0,0 +1,16 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + sourceSize: Qt.size(22, 22) + } + Image { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + } +} diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml new file mode 100644 index 00000000..ecbb7f6d --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceSizeWidthHeight.qml @@ -0,0 +1,10 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +IconImage { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + sourceSize: Qt.size(22, 22) + width: 16 + height: 16 +} diff --git a/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml b/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml new file mode 100644 index 00000000..f9e07899 --- /dev/null +++ b/tests/auto/qquickiconimage/data/sourceBindingSourceTooLarge.qml @@ -0,0 +1,8 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +IconImage { + source: "qrc:/icons/testtheme/22x22/actions/appointment-new.png" + sourceSize: Qt.size(32, 32) +} diff --git a/tests/auto/qquickiconimage/data/svgNoSizes.qml b/tests/auto/qquickiconimage/data/svgNoSizes.qml new file mode 100644 index 00000000..17cccd26 --- /dev/null +++ b/tests/auto/qquickiconimage/data/svgNoSizes.qml @@ -0,0 +1,15 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + source: "qrc:/icons/testtheme/appointment-new.svg" + } + Image { + source: "qrc:/icons/testtheme/appointment-new.svg" + } +} diff --git a/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml b/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml new file mode 100644 index 00000000..2387e98e --- /dev/null +++ b/tests/auto/qquickiconimage/data/svgSourceBindingSourceSize.qml @@ -0,0 +1,17 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Row { + width: 200 + height: 200 + + IconImage { + source: "qrc:/data/icons/testtheme/appointment-new.svg" + sourceSize: Qt.size(22, 22) + } + Image { + source: "qrc:/data/icons/testtheme/appointment-new.svg" + sourceSize: Qt.size(22, 22) + } +} diff --git a/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/qquickiconimage/icons/testtheme/16x16/actions/appointment-new.png 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..6fc579f8 --- /dev/null +++ b/tests/auto/qquickiconlabel/data/colorChanges.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +AbstractButton { + id: button + width: 200 + height: 200 + icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png" + icon.color: enabled ? "transparent" : "red" + + IconLabel { + icon: button.icon + text: button.text + } +} diff --git a/tests/auto/qquickiconlabel/data/iconlabel.qml b/tests/auto/qquickiconlabel/data/iconlabel.qml new file mode 100644 index 00000000..97042107 --- /dev/null +++ b/tests/auto/qquickiconlabel/data/iconlabel.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +AbstractButton { + id: button + width: 200 + height: 200 + text: "Some text" + icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png" + + IconLabel { + icon: button.icon + text: button.text + } +} diff --git a/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml b/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml new file mode 100644 index 00000000..ccdb74e2 --- /dev/null +++ b/tests/auto/qquickiconlabel/data/spacingWithOnlyIcon.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +AbstractButton { + id: button + width: 200 + height: 200 + icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png" + + IconLabel { + spacing: 10 + mirrored: true + icon: button.icon + } +} diff --git a/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml b/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml new file mode 100644 index 00000000..9015aa9d --- /dev/null +++ b/tests/auto/qquickiconlabel/data/spacingWithOnlyText.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 + +Item { + width: 200 + height: 200 + + IconLabel { + spacing: 10 + text: "Some text" + } +} diff --git a/tests/auto/qquickiconlabel/qquickiconlabel.pro b/tests/auto/qquickiconlabel/qquickiconlabel.pro new file mode 100644 index 00000000..6b0f73b3 --- /dev/null +++ b/tests/auto/qquickiconlabel/qquickiconlabel.pro @@ -0,0 +1,13 @@ +CONFIG += testcase +macos:CONFIG -= app_bundle +TARGET = tst_qquickiconlabel + +QT += core gui qml quick testlib +QT_PRIVATE += quick-private quickcontrols2-private + +include (../shared/util.pri) + +SOURCES += tst_qquickiconlabel.cpp + +TESTDATA += \ + $$PWD/data/*.qml diff --git a/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp b/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp new file mode 100644 index 00000000..a251b471 --- /dev/null +++ b/tests/auto/qquickiconlabel/tst_qquickiconlabel.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qvector.h> + +#include <qtest.h> + +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitemgrabresult.h> +#include <QtQuick/private/qquicktext_p.h> +#include <QtQuickTemplates2/private/qquickicon_p.h> +#include <QtQuickControls2/private/qquickiconimage_p.h> +#include <QtQuickControls2/private/qquickiconlabel_p.h> + +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + +class tst_qquickiconlabel : public QQmlDataTest +{ + Q_OBJECT +public: + tst_qquickiconlabel(); + +private slots: + void display_data(); + void display(); + void spacingWithOneDelegate_data(); + void spacingWithOneDelegate(); + void emptyIconSource(); + void colorChanges(); +}; + +tst_qquickiconlabel::tst_qquickiconlabel() +{ +} + +void tst_qquickiconlabel::display_data() +{ + QTest::addColumn<QVector<QQuickIconLabel::Display> >("displayTypes"); + QTest::addColumn<bool>("mirrored"); + QTest::addColumn<qreal>("labelWidth"); + QTest::addColumn<qreal>("labelHeight"); + QTest::addColumn<qreal>("spacing"); + + typedef QVector<QQuickIconLabel::Display> DisplayVector; + QQuickIconLabel::Display IconOnly = QQuickIconLabel::IconOnly; + QQuickIconLabel::Display TextOnly = QQuickIconLabel::TextOnly; + QQuickIconLabel::Display TextUnderIcon = QQuickIconLabel::TextUnderIcon; + QQuickIconLabel::Display TextBesideIcon = QQuickIconLabel::TextBesideIcon; + + QTest::addRow("IconOnly") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextOnly") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon") << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 10.0; + QTest::addRow("TextBesideIcon") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 10.0; + QTest::addRow("IconOnly, spacing=10") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 10.0; + QTest::addRow("TextOnly, spacing=10") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 10.0; + QTest::addRow("TextUnderIcon, spacing=10") << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon => IconOnly => TextUnderIcon") + << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon => IconOnly => TextUnderIcon, labelWidth=400") + << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon => TextOnly => TextUnderIcon") + << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon => TextOnly => TextUnderIcon, labelWidth=400") + << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon, spacing=10") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon") + << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon, labelWidth=400") + << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon") + << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon, labelWidth=400") + << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0; + QTest::addRow("IconOnly, mirrored") << (DisplayVector() << IconOnly) << true << -1.0 << -1.0 << 0.0; + QTest::addRow("TextOnly, mirrored") << (DisplayVector() << TextOnly) << true << -1.0 << -1.0 << 0.0; + QTest::addRow("TextUnderIcon, mirrored") << (DisplayVector() << TextUnderIcon) << true << -1.0 << -1.0 << 0.0; + QTest::addRow("TextBesideIcon, mirrored") << (DisplayVector() << TextBesideIcon) << true << -1.0 << -1.0 << 0.0; +} + +void tst_qquickiconlabel::display() +{ + QFETCH(QVector<QQuickIconLabel::Display>, displayTypes); + QFETCH(bool, mirrored); + QFETCH(qreal, labelWidth); + QFETCH(qreal, labelHeight); + QFETCH(qreal, spacing); + + QQuickView view(testFileUrl("iconlabel.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem *rootItem = view.rootObject(); + QVERIFY(rootItem); + + QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); + QVERIFY(label); + QCOMPARE(label->spacing(), 0.0); + QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); + QCOMPARE(label->isMirrored(), false); + + // Setting labelWidth allows us to test the issue where the icon's + // width was not updated after switching between different display types. + if (!qFuzzyCompare(labelWidth, -1)) { + label->setWidth(labelWidth); + QCOMPARE(label->width(), labelWidth); + } + if (!qFuzzyCompare(labelHeight, -1)) { + label->setHeight(labelHeight); + QCOMPARE(label->height(), labelHeight); + } + + label->setMirrored(mirrored); + QCOMPARE(label->isMirrored(), mirrored); + + label->setSpacing(spacing); + QCOMPARE(label->spacing(), spacing); + + const qreal horizontalPadding = label->leftPadding() + label->rightPadding(); + const qreal verticalPadding = label->topPadding() + label->bottomPadding(); + + // Test that the icon and text are correctly positioned and sized after + // setting several different display types in succession. + for (QQuickIconLabel::Display displayType : qAsConst(displayTypes)) { + label->setDisplay(displayType); + QCOMPARE(label->display(), displayType); + + QQuickIconImage *icon = label->findChild<QQuickIconImage *>(); + QQuickText *text = label->findChild<QQuickText *>(); + + const qreal horizontalCenter = label->width() / 2; + const qreal verticalCenter = label->height() / 2; + + switch (displayType) { + case QQuickIconLabel::IconOnly: + QVERIFY(icon); + QVERIFY(!text); + QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2); + QCOMPARE(icon->y(), verticalCenter - icon->height() / 2); + QCOMPARE(icon->width(), icon->implicitWidth()); + QCOMPARE(icon->height(), icon->implicitHeight()); + QCOMPARE(label->implicitWidth(), icon->implicitWidth() + horizontalPadding); + QCOMPARE(label->implicitHeight(), icon->implicitHeight() + verticalPadding); + break; + case QQuickIconLabel::TextOnly: + QVERIFY(!icon); + QVERIFY(text); + QCOMPARE(text->x(), horizontalCenter - text->width() / 2); + QCOMPARE(text->y(), verticalCenter - text->height() / 2); + QCOMPARE(text->width(), text->implicitWidth()); + QCOMPARE(text->height(), text->implicitHeight()); + QCOMPARE(label->implicitWidth(), text->implicitWidth() + horizontalPadding); + QCOMPARE(label->implicitHeight(), text->implicitHeight() + verticalPadding); + break; + case QQuickIconLabel::TextUnderIcon: { + QVERIFY(icon); + QVERIFY(text); + const qreal combinedHeight = icon->height() + label->spacing() + text->height(); + const qreal contentY = verticalCenter - combinedHeight / 2; + QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2); + QCOMPARE(icon->y(), contentY); + QCOMPARE(icon->width(), icon->implicitWidth()); + QCOMPARE(icon->height(), icon->implicitHeight()); + QCOMPARE(text->x(), horizontalCenter - text->width() / 2); + QCOMPARE(text->y(), contentY + icon->height() + label->spacing()); + QCOMPARE(text->width(), text->implicitWidth()); + QCOMPARE(text->height(), text->implicitHeight()); + QCOMPARE(label->implicitWidth(), qMax(icon->implicitWidth(), text->implicitWidth()) + horizontalPadding); + QCOMPARE(label->implicitHeight(), combinedHeight + verticalPadding); + break; + } + case QQuickIconLabel::TextBesideIcon: + default: + QVERIFY(icon); + QVERIFY(text); + const qreal combinedWidth = icon->width() + label->spacing() + text->width(); + const qreal contentX = horizontalCenter - combinedWidth / 2; + QCOMPARE(icon->x(), contentX + (label->isMirrored() ? text->width() + label->spacing() : 0)); + QCOMPARE(icon->y(), verticalCenter - icon->height() / 2); + QCOMPARE(icon->width(), icon->implicitWidth()); + QCOMPARE(icon->height(), icon->implicitHeight()); + QCOMPARE(text->x(), contentX + (label->isMirrored() ? 0 : icon->width() + label->spacing())); + QCOMPARE(text->y(), verticalCenter - text->height() / 2); + QCOMPARE(text->width(), text->implicitWidth()); + QCOMPARE(text->height(), text->implicitHeight()); + QCOMPARE(label->implicitWidth(), combinedWidth + horizontalPadding); + QCOMPARE(label->implicitHeight(), qMax(icon->implicitHeight(), text->implicitHeight()) + verticalPadding); + break; + } + } +} + +void tst_qquickiconlabel::spacingWithOneDelegate_data() +{ + QTest::addColumn<QString>("qmlFileName"); + + QTest::addRow("spacingWithOnlyIcon") << QStringLiteral("spacingWithOnlyIcon.qml"); + QTest::addRow("spacingWithOnlyText") << QStringLiteral("spacingWithOnlyText.qml"); +} + +void tst_qquickiconlabel::spacingWithOneDelegate() +{ + QFETCH(QString, qmlFileName); + + QQuickView view(testFileUrl(qmlFileName)); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem *rootItem = view.rootObject(); + QVERIFY(rootItem); + + QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); + QVERIFY(label); + QQuickItem *delegate = nullptr; + if (!label->icon().isEmpty()) { + QVERIFY(!label->findChild<QQuickText *>()); + delegate = label->findChild<QQuickIconImage *>(); + } else { + QVERIFY(!label->findChild<QQuickIconImage *>()); + delegate = label->findChild<QQuickText *>(); + } + + QVERIFY(delegate); + QCOMPARE(delegate->x(), 0.0); + QCOMPARE(delegate->width(), label->width()); +} + +void tst_qquickiconlabel::emptyIconSource() +{ + QQuickView view(testFileUrl("iconlabel.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem *rootItem = view.rootObject(); + QVERIFY(rootItem); + + QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); + QVERIFY(label); + QCOMPARE(label->spacing(), 0.0); + QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); + QCOMPARE(label->isMirrored(), false); + + QQuickItem *icon = label->findChild<QQuickIconImage *>(); + QVERIFY(icon); + + QQuickItem *text = label->findChild<QQuickText *>(); + QVERIFY(text); + qreal horizontalCenter = label->width() / 2; + const qreal combinedWidth = icon->width() + text->width(); + const qreal contentX = horizontalCenter - combinedWidth / 2; + // The text should be positioned next to an item. + QCOMPARE(text->x(), contentX + icon->width() + label->spacing()); + + // Now give the label an explicit width large enough so that implicit size + // changes in its children don't affect its implicit size. + label->setWidth(label->implicitWidth() + 200); + label->setHeight(label->implicitWidth() + 100); + QVERIFY(icon->property("source").isValid()); + label->setIcon(QQuickIcon()); + QVERIFY(!label->findChild<QQuickIconImage *>()); + horizontalCenter = label->width() / 2; + QCOMPARE(text->x(), horizontalCenter - text->width() / 2); +} + +void tst_qquickiconlabel::colorChanges() +{ + QQuickView view(testFileUrl("colorChanges.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem *rootItem = view.rootObject(); + QVERIFY(rootItem); + + QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); + QVERIFY(label); + QCOMPARE(label->spacing(), 0.0); + QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); + QCOMPARE(label->isMirrored(), false); + + QSharedPointer<QQuickItemGrabResult> grabResult = label->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + const QImage enabledImageGrab = grabResult->image(); + + // The color should change to "red" when the item is disabled. + rootItem->setEnabled(false); + + grabResult = label->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + QVERIFY(grabResult->image() != enabledImageGrab); +} + +QTEST_MAIN(tst_qquickiconlabel) + +#include "tst_qquickiconlabel.moc" diff --git a/tests/auto/qquickimaginestyle/control-assets/button-background.9.png b/tests/auto/qquickimaginestyle/control-assets/button-background.9.png Binary files differnew file mode 100644 index 00000000..29bd8d7c --- /dev/null +++ b/tests/auto/qquickimaginestyle/control-assets/button-background.9.png diff --git a/tests/auto/qquickimaginestyle/data/tst_imagine.qml b/tests/auto/qquickimaginestyle/data/tst_imagine.qml new file mode 100644 index 00000000..7a711dcd --- /dev/null +++ b/tests/auto/qquickimaginestyle/data/tst_imagine.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Window 2.2 +import QtTest 1.1 +import QtQuick.Templates 2.3 as T +import QtQuick.Controls 2.3 +import QtQuick.Controls.Imagine 2.3 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "Imagine" + + Component { + id: implicitQrcButtonComponent + Button { + Imagine.path: ":/control-assets" + } + } + + Component { + id: explicitQrcButtonComponent + Button { + Imagine.path: "qrc:/control-assets" + } + } + + function test_qrcPaths_data() { + return [ + { tag: ":/control-assets", component: implicitQrcButtonComponent }, + { tag: "qrc:/control-assets", component: explicitQrcButtonComponent } + ] + } + + function test_qrcPaths(data) { + if (Qt.platform.pluginName === "offscreen") + skip("grabImage() is not functional on the offscreen platform (QTBUG-63185)") + + var control = createTemporaryObject(data.component, testCase) + verify(control) + compare(control.Imagine.path, data.tag) + var image = grabImage(control) + compare(image.pixel(control.width / 2, control.height / 2), "#ff0000") + } +} diff --git a/tests/auto/qquickimaginestyle/qquickimaginestyle.pro b/tests/auto/qquickimaginestyle/qquickimaginestyle.pro new file mode 100644 index 00000000..c421f2dc --- /dev/null +++ b/tests/auto/qquickimaginestyle/qquickimaginestyle.pro @@ -0,0 +1,16 @@ +TEMPLATE = app +TARGET = tst_qquickimaginestyle +CONFIG += qmltestcase + +SOURCES += \ + $$PWD/tst_qquickimaginestyle.cpp + +RESOURCES += \ + $$PWD/qtquickcontrols2.conf \ + $$PWD/control-assets/button-background.9.png + +OTHER_FILES += \ + $$PWD/data/*.qml + +TESTDATA += \ + $$PWD/data/tst_* diff --git a/tests/auto/qquickimaginestyle/qtquickcontrols2.conf b/tests/auto/qquickimaginestyle/qtquickcontrols2.conf new file mode 100644 index 00000000..add378d4 --- /dev/null +++ b/tests/auto/qquickimaginestyle/qtquickcontrols2.conf @@ -0,0 +1,2 @@ +[Controls] +Style=Imagine diff --git a/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp b/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp new file mode 100644 index 00000000..cd08923a --- /dev/null +++ b/tests/auto/qquickimaginestyle/tst_qquickimaginestyle.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> +QUICK_TEST_MAIN(tst_qquickmaterialstyle) diff --git a/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf index 78634834..30cee878 100644 --- a/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf +++ b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf @@ -4,3 +4,7 @@ Style=Material [Material] Background=#444444 Foreground=Red +Font\PixelSize=22 + +[Material\Font] +Family=Courier diff --git a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp index cc81afea..17d1ea6d 100644 --- a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp +++ b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp @@ -55,16 +55,22 @@ void tst_qquickmaterialstyleconf::conf() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + QFont customFont; + customFont.setFamily("Courier"); + customFont.setPixelSize(22); + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - // We specified a custom background color, so the window should have it. + // We specified a custom background color and font, so the window should have them. QCOMPARE(window->property("color").value<QColor>(), QColor("#444444")); + QCOMPARE(window->property("font").value<QFont>(), customFont); - // We specified a custom foreground color, so the label should have it. + // We specified a custom foreground color and font, so the label should have them. QQuickItem *label = window->property("label").value<QQuickItem*>(); QVERIFY(label); QCOMPARE(label->property("color").value<QColor>(), QColor("#F44336")); + QCOMPARE(label->property("font").value<QFont>(), customFont); } QTEST_MAIN(tst_qquickmaterialstyleconf) diff --git a/tests/auto/qquickmenu/data/actions.qml b/tests/auto/qquickmenu/data/actions.qml new file mode 100644 index 00000000..0ec9f36c --- /dev/null +++ b/tests/auto/qquickmenu/data/actions.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + + Menu { + id: menu + Action { text: "action1" } + MenuItem { text: "menuitem2" } + Action { text: "action3" } + MenuItem { text: "menuitem4" } + } +} diff --git a/tests/auto/qquickmenu/data/mnemonics.qml b/tests/auto/qquickmenu/data/mnemonics.qml new file mode 100644 index 00000000..de4cd215 --- /dev/null +++ b/tests/auto/qquickmenu/data/mnemonics.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + property alias action: action + property alias menuItem: menuItem + property alias subMenu: subMenu + property alias subMenuItem: subMenuItem + + Menu { + id: menu + + Action { + id: action + text: "&Action" + } + + MenuItem { + id: menuItem + text: "Menu &Item" + } + + Menu { + id: subMenu + title: "Sub &Menu" + + MenuItem { + id: subMenuItem + text: "&Sub Menu Item" + } + } + } +} diff --git a/tests/auto/qquickmenu/data/popup.qml b/tests/auto/qquickmenu/data/popup.qml new file mode 100644 index 00000000..6040e8ba --- /dev/null +++ b/tests/auto/qquickmenu/data/popup.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + property alias menuItem1: menuItem1 + property alias menuItem2: menuItem2 + property alias menuItem3: menuItem3 + property alias button: button + + function popupAtCursor() { + menu.popup() + } + + function popupAtPos(pos) { + menu.popup(pos) + } + + function popupAtCoord(x, y) { + menu.popup(x, y) + } + + function popupItemAtCursor(item) { + menu.popup(item) + } + + function popupItemAtPos(pos, item) { + menu.popup(pos, item) + } + + function popupItemAtCoord(x, y, item) { + menu.popup(x, y, item) + } + + function popupAtParentCursor(parent) { + menu.popup(parent) + } + + function popupAtParentPos(parent, pos) { + menu.popup(parent, pos) + } + + function popupAtParentCoord(parent, x, y) { + menu.popup(parent, x, y) + } + + function popupItemAtParentCursor(parent, item) { + menu.popup(parent, item) + } + + function popupItemAtParentPos(parent, pos, item) { + menu.popup(parent, pos, item) + } + + function popupItemAtParentCoord(parent, x, y, item) { + menu.popup(parent, x, y, item) + } + + Menu { + id: menu + MenuItem { id: menuItem1; text: "Foo" } + MenuItem { id: menuItem2; text: "Bar" } + MenuItem { id: menuItem3; text: "Baz" } + } + + Button { + id: button + text: "Button" + anchors.centerIn: parent + } +} diff --git a/tests/auto/qquickmenu/data/removeTakeItem.qml b/tests/auto/qquickmenu/data/removeTakeItem.qml new file mode 100644 index 00000000..89090fb6 --- /dev/null +++ b/tests/auto/qquickmenu/data/removeTakeItem.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 200 + height: 200 + + property alias menu: menu + property alias menuItem1: menuItem1 + property alias menuItem2: menuItem2 + property alias menuItem3: menuItem3 + + function takeSecondItem() { + return menu.takeItem(1) + } + + function removeFirstItem() { + menu.removeItem(menuItem1) + } + + function removeNullItem() { + menu.removeItem(null) + } + + function removeFirstIndex() { + menu.removeItem(0) + } + + Menu { + id: menu + MenuItem { + id: menuItem1 + } + MenuItem { + id: menuItem2 + } + MenuItem { + id: menuItem3 + } + } +} diff --git a/tests/auto/qquickmenu/data/subMenus.qml b/tests/auto/qquickmenu/data/subMenus.qml new file mode 100644 index 00000000..49811bc2 --- /dev/null +++ b/tests/auto/qquickmenu/data/subMenus.qml @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 600 + height: 400 + + property alias mainMenu: mainMenu + property alias subMenu1: subMenu1 + property alias subMenu2: subMenu2 + property alias subSubMenu1: subSubMenu1 + + Menu { + id: mainMenu + MenuItem { id: mainMenuItem1; text: "Main 1" } + + Menu { + id: subMenu1 + title: "Sub Menu 1" + MenuItem { id: subMenuItem1; text: "Sub 1" } + MenuItem { id: subMenuItem2; text: "Sub 2" } + + Menu { + id: subSubMenu1 + title: "Sub Sub Menu 1" + MenuItem { id: subSubMenuItem1; text: "Sub Sub 1" } + MenuItem { id: subSubMenuItem2; text: "Sub Sub 2" } + } + } + + MenuItem { id: mainMenuItem2; text: "Main 2" } + + Menu { + id: subMenu2 + title: "Sub Menu 2" + MenuItem { id: subMenuItem3; text: "Sub 3" } + MenuItem { id: subMenuItem4; text: "Sub 4" } + } + + MenuItem { id: mainMenuItem3; text: "Main 3" } + } +} diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp index 717e892b..1202072b 100644 --- a/tests/auto/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp @@ -36,6 +36,7 @@ #include <qtest.h> #include <QtTest/QSignalSpy> +#include <QtGui/qcursor.h> #include <QtGui/qstylehints.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> @@ -45,6 +46,7 @@ #include "../shared/util.h" #include "../shared/visualtestutil.h" +#include <QtQuickTemplates2/private/qquickaction_p.h> #include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> #include <QtQuickTemplates2/private/qquickoverlay_p.h> #include <QtQuickTemplates2/private/qquickbutton_p.h> @@ -62,14 +64,26 @@ public: private slots: void defaults(); + void count(); void mouse(); void pressAndHold(); void contextMenuKeyboard(); + void mnemonics(); void menuButton(); void addItem(); void menuSeparator(); void repeater(); void order(); + void popup(); + void actions(); + void removeTakeItem(); + void subMenuMouse_data(); + void subMenuMouse(); + void subMenuKeyboard_data(); + void subMenuKeyboard(); + void subMenuPosition_data(); + void subMenuPosition(); + void addRemoveSubMenus(); }; void tst_QQuickMenu::defaults() @@ -78,16 +92,52 @@ void tst_QQuickMenu::defaults() QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value<QQuickMenu*>(); QCOMPARE(emptyMenu->isVisible(), false); + QCOMPARE(emptyMenu->currentIndex(), -1); QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1)); + QCOMPARE(emptyMenu->count(), 0); +} + +void tst_QQuickMenu::count() +{ + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickMenu *menu = helper.window->property("emptyMenu").value<QQuickMenu*>(); + QVERIFY(menu); + + QSignalSpy countSpy(menu, &QQuickMenu::countChanged); + QVERIFY(countSpy.isValid()); + + menu->addItem(new QQuickItem); + QCOMPARE(menu->count(), 1); + QCOMPARE(countSpy.count(), 1); + + menu->insertItem(0, new QQuickItem); + QCOMPARE(menu->count(), 2); + QCOMPARE(countSpy.count(), 2); + + menu->removeItem(menu->itemAt(1)); + QCOMPARE(menu->count(), 1); + QCOMPARE(countSpy.count(), 3); + + QQuickItem *item = menu->takeItem(0); + QVERIFY(item); + QCOMPARE(menu->count(), 0); + QCOMPARE(countSpy.count(), 4); } void tst_QQuickMenu::mouse() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Mouse hovering not functional on offscreen/minimal platforms"); + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); QQuickMenu *menu = window->property("menu").value<QQuickMenu*>(); menu->open(); @@ -103,6 +153,7 @@ void tst_QQuickMenu::mouse() // so that the highlight acts as a way of illustrating press state. QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); QVERIFY(firstItem->hasActiveFocus()); + QCOMPARE(menu->currentIndex(), 0); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); QVERIFY(menu->isVisible()); @@ -112,6 +163,7 @@ void tst_QQuickMenu::mouse() QCOMPARE(visibleSpy.count(), 1); QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); + QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); menu->open(); @@ -133,6 +185,21 @@ void tst_QQuickMenu::mouse() QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + // Hover-highlight through the menu items one by one + QQuickItem *prevHoverItem = nullptr; + QQuickItem *listView = menu->contentItem(); + for (int y = 0; y < listView->height(); ++y) { + QQuickItem *hoverItem = nullptr; + QVERIFY(QMetaObject::invokeMethod(listView, "itemAt", Q_RETURN_ARG(QQuickItem *, hoverItem), Q_ARG(qreal, 0), Q_ARG(qreal, listView->property("contentY").toReal() + y))); + if (!hoverItem || !hoverItem->isVisible() || hoverItem == prevHoverItem) + continue; + QTest::mouseMove(window, QPoint(hoverItem->x() + hoverItem->width() / 2, hoverItem->y() + hoverItem->height() / 2)); + QTRY_VERIFY(hoverItem->property("highlighted").toBool()); + if (prevHoverItem) + QVERIFY(!prevHoverItem->property("highlighted").toBool()); + prevHoverItem = hoverItem; + } + // Try pressing within the menu and releasing outside of it; it should close. // TODO: won't work until QQuickPopup::releasedOutside() actually gets emitted // QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); @@ -183,8 +250,11 @@ void tst_QQuickMenu::contextMenuKeyboard() window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); QVERIFY(QGuiApplication::focusWindow() == window); + centerOnScreen(window); + moveMouseAway(window); QQuickMenu *menu = window->property("menu").value<QQuickMenu*>(); + QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); QQuickMenuItem *firstItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(0)); @@ -197,12 +267,16 @@ void tst_QQuickMenu::contextMenuKeyboard() QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); QVERIFY(!firstItem->hasActiveFocus()); + QVERIFY(!firstItem->property("highlighted").toBool()); + QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); QTest::keyClick(window, Qt::Key_Tab); QVERIFY(firstItem->hasActiveFocus()); QVERIFY(firstItem->hasVisualFocus()); + QVERIFY(firstItem->isHighlighted()); QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason); + QCOMPARE(menu->currentIndex(), 0); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); QQuickMenuItem *secondItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(1)); @@ -210,9 +284,12 @@ void tst_QQuickMenu::contextMenuKeyboard() QTest::keyClick(window, Qt::Key_Tab); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(secondItem->hasActiveFocus()); QVERIFY(secondItem->hasVisualFocus()); + QVERIFY(secondItem->isHighlighted()); QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason); + QCOMPARE(menu->currentIndex(), 1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1)); QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered())); @@ -223,8 +300,11 @@ void tst_QQuickMenu::contextMenuKeyboard() QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(!secondItem->hasActiveFocus()); QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!secondItem->isHighlighted()); + QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); menu->open(); @@ -233,18 +313,23 @@ void tst_QQuickMenu::contextMenuKeyboard() QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(!secondItem->hasActiveFocus()); QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!secondItem->isHighlighted()); + QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1)); QTest::keyClick(window, Qt::Key_Down); QVERIFY(firstItem->hasActiveFocus()); QVERIFY(firstItem->hasVisualFocus()); + QVERIFY(firstItem->isHighlighted()); QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason); QTest::keyClick(window, Qt::Key_Down); QVERIFY(secondItem->hasActiveFocus()); QVERIFY(secondItem->hasVisualFocus()); + QVERIFY(secondItem->isHighlighted()); QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason); QTest::keyClick(window, Qt::Key_Down); @@ -252,45 +337,105 @@ void tst_QQuickMenu::contextMenuKeyboard() QVERIFY(thirdItem); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(!secondItem->hasActiveFocus()); QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!secondItem->isHighlighted()); QVERIFY(thirdItem->hasActiveFocus()); QVERIFY(thirdItem->hasVisualFocus()); + QVERIFY(thirdItem->isHighlighted()); QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason); // Key navigation shouldn't wrap by default. QTest::keyClick(window, Qt::Key_Down); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(!secondItem->hasActiveFocus()); QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!secondItem->isHighlighted()); QVERIFY(thirdItem->hasActiveFocus()); QVERIFY(thirdItem->hasVisualFocus()); + QVERIFY(thirdItem->isHighlighted()); QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason); QTest::keyClick(window, Qt::Key_Up); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); + QVERIFY(!firstItem->isHighlighted()); QVERIFY(secondItem->hasActiveFocus()); QVERIFY(secondItem->hasVisualFocus()); + QVERIFY(secondItem->isHighlighted()); QCOMPARE(secondItem->focusReason(), Qt::BacktabFocusReason); QVERIFY(!thirdItem->hasActiveFocus()); QVERIFY(!thirdItem->hasVisualFocus()); + QVERIFY(!thirdItem->isHighlighted()); QTest::keyClick(window, Qt::Key_Backtab); QVERIFY(firstItem->hasActiveFocus()); QVERIFY(firstItem->hasVisualFocus()); + QVERIFY(firstItem->isHighlighted()); QCOMPARE(firstItem->focusReason(), Qt::BacktabFocusReason); QVERIFY(!secondItem->hasActiveFocus()); QVERIFY(!secondItem->hasVisualFocus()); + QVERIFY(!secondItem->isHighlighted()); QVERIFY(!thirdItem->hasActiveFocus()); QVERIFY(!thirdItem->hasVisualFocus()); + QVERIFY(!thirdItem->isHighlighted()); QTest::keyClick(window, Qt::Key_Escape); QCOMPARE(visibleSpy.count(), 4); QVERIFY(!menu->isVisible()); } +void tst_QQuickMenu::mnemonics() +{ +#ifdef Q_OS_MACOS + QSKIP("Mnemonics are not used on macOS"); +#endif + + QQuickApplicationHelper helper(this, QLatin1String("mnemonics.qml")); + + QQuickWindow *window = helper.window; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu *>(); + QQuickAction *action = window->property("action").value<QQuickAction *>(); + QQuickMenuItem *menuItem = window->property("menuItem").value<QQuickMenuItem *>(); + QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>(); + QQuickMenuItem *subMenuItem = window->property("subMenuItem").value<QQuickMenuItem *>(); + QVERIFY(menu && action && menuItem && subMenu && subMenuItem); + + menu->open(); + QTRY_VERIFY(menu->isOpened()); + + QSignalSpy actionSpy(action, &QQuickAction::triggered); + QVERIFY(actionSpy.isValid()); + QTest::keyClick(window, Qt::Key_A, Qt::AltModifier); // "&Action" + QCOMPARE(actionSpy.count(), 1); + + menu->open(); + QTRY_VERIFY(menu->isOpened()); + + QSignalSpy menuItemSpy(menuItem, &QQuickMenuItem::triggered); + QVERIFY(menuItemSpy.isValid()); + QTest::keyClick(window, Qt::Key_I, Qt::AltModifier); // "Menu &Item" + QCOMPARE(menuItemSpy.count(), 1); + + menu->open(); + QTRY_VERIFY(menu->isOpened()); + + QTest::keyClick(window, Qt::Key_M, Qt::AltModifier); // "Sub &Menu" + QTRY_VERIFY(subMenu->isOpened()); + + QSignalSpy subMenuItemSpy(subMenuItem, &QQuickMenuItem::triggered); + QVERIFY(subMenuItemSpy.isValid()); + QTest::keyClick(window, Qt::Key_S, Qt::AltModifier); // "&Sub Menu Item" + QCOMPARE(subMenuItemSpy.count(), 1); +} + void tst_QQuickMenu::menuButton() { if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls) @@ -346,6 +491,8 @@ void tst_QQuickMenu::menuSeparator() QQuickWindow *window = helper.window; window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); QQuickMenu *menu = window->property("menu").value<QQuickMenu*>(); QVERIFY(menu); @@ -382,6 +529,8 @@ void tst_QQuickMenu::menuSeparator() saveMenuItem->mapToScene(QPointF(saveMenuItem->width() / 2, saveMenuItem->height() / 2)).toPoint()); QTRY_VERIFY(!menu->isVisible()); + moveMouseAway(window); + menu->open(); QVERIFY(menu->isVisible()); @@ -477,6 +626,689 @@ void tst_QQuickMenu::order() } } +void tst_QQuickMenu::popup() +{ + QQuickApplicationHelper helper(this, QLatin1String("popup.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu *>(); + QVERIFY(menu); + + QQuickMenuItem *menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>(); + QVERIFY(menuItem1); + + QQuickMenuItem *menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>(); + QVERIFY(menuItem2); + + QQuickMenuItem *menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>(); + QVERIFY(menuItem3); + + QQuickItem *button = window->property("button").value<QQuickItem *>(); + QVERIFY(button); + +#if QT_CONFIG(cursor) + QPoint oldCursorPos = QCursor::pos(); + QPoint cursorPos = window->mapToGlobal(QPoint(11, 22)); + QCursor::setPos(cursorPos); + QTRY_COMPARE(QCursor::pos(), cursorPos); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtCursor")); + QCOMPARE(menu->parentItem(), window->contentItem()); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), 11); + QTRY_COMPARE(menu->y(), 22); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtPos", Q_ARG(QVariant, QPointF(33, 44)))); + QCOMPARE(menu->parentItem(), window->contentItem()); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), 33); + QTRY_COMPARE(menu->y(), 44); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, 66))); + QCOMPARE(menu->parentItem(), window->contentItem()); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), 55); + QTRY_COMPARE(menu->y(), 66); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button)))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), button->mapFromScene(QPointF(11, 22)).x()); + QTRY_COMPARE(menu->y(), button->mapFromScene(QPointF(11, 22)).y()); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22)))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), -11); + QTRY_COMPARE(menu->y(), -22); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22))); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), -1); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); + QTRY_COMPARE(menu->x(), -33); + QTRY_COMPARE(menu->y(), -44); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44))); + menu->close(); + + cursorPos = window->mapToGlobal(QPoint(12, window->height() / 2)); + QCursor::setPos(cursorPos); + QTRY_COMPARE(QCursor::pos(), cursorPos); + + const QList<QQuickMenuItem *> menuItems = QList<QQuickMenuItem *>() << menuItem1 << menuItem2 << menuItem3; + for (QQuickMenuItem *menuItem : menuItems) { + menu->resetParentItem(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCursor", Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), 12); + QTRY_COMPARE(menu->y(), window->height() / 2 + menu->topPadding() - menuItem->y()); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtPos", Q_ARG(QVariant, QPointF(33, window->height() / 3)), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), 33); + QTRY_COMPARE(menu->y(), window->height() / 3 + menu->topPadding() - menuItem->y()); + menu->close(); + + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, window->height() / 3 * 2), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), 55); + QTRY_COMPARE(menu->y(), window->height() / 3 * 2 + menu->topPadding() - menuItem->y()); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), button->mapFromScene(QPoint(12, window->height() / 2)).x()); + QTRY_COMPARE(menu->y(), button->mapFromScene(QPoint(12, window->height() / 2)).y() + menu->topPadding() - menuItem->y()); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22)), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), -11); + QTRY_COMPARE(menu->y(), -22 + menu->topPadding() - menuItem->y()); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22 + menu->topPadding() - menuItem->y()))); + menu->close(); + + menu->setParentItem(nullptr); + QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); + QCOMPARE(menu->parentItem(), button); + QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); + QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); + QTRY_COMPARE(menu->x(), -33); + QTRY_COMPARE(menu->y(), -44 + menu->topPadding() - menuItem->y()); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44 + menu->topPadding() - menuItem->y()))); + menu->close(); + } + + QCursor::setPos(oldCursorPos); + QTRY_COMPARE(QCursor::pos(), oldCursorPos); +#endif +} + +void tst_QQuickMenu::actions() +{ + QQuickApplicationHelper helper(this, QLatin1String("actions.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu *>(); + QVERIFY(menu); + + QPointer<QQuickAction> action1 = menu->actionAt(0); + QVERIFY(!action1.isNull()); + + QPointer<QQuickAction> action3 = menu->actionAt(2); + QVERIFY(!action3.isNull()); + + QVERIFY(!menu->actionAt(1)); + QVERIFY(!menu->actionAt(3)); + + QPointer<QQuickMenuItem> menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(0)); + QVERIFY(!menuItem1.isNull()); + QCOMPARE(menuItem1->action(), action1.data()); + QCOMPARE(menuItem1->text(), "action1"); + + QPointer<QQuickMenuItem> menuItem2 = qobject_cast<QQuickMenuItem *>(menu->itemAt(1)); + QVERIFY(!menuItem2.isNull()); + QVERIFY(!menuItem2->action()); + QCOMPARE(menuItem2->text(), "menuitem2"); + + QPointer<QQuickMenuItem> menuItem3 = qobject_cast<QQuickMenuItem *>(menu->itemAt(2)); + QVERIFY(!menuItem3.isNull()); + QCOMPARE(menuItem3->action(), action3.data()); + QCOMPARE(menuItem3->text(), "action3"); + + QPointer<QQuickMenuItem> menuItem4 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3)); + QVERIFY(!menuItem4.isNull()); + QVERIFY(!menuItem4->action()); + QCOMPARE(menuItem4->text(), "menuitem4"); + + // takeAction(int) does not destroy the action, but does destroy the respective item + QCOMPARE(menu->takeAction(0), action1.data()); + QVERIFY(!menu->itemAt(3)); + QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete); + QVERIFY(!action1.isNull()); + QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete); + QVERIFY(menuItem1.isNull()); + + // takeAction(int) does not destroy an item that doesn't have an action + QVERIFY(!menuItem2->subMenu()); + QVERIFY(!menu->takeAction(0)); + QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete); + QVERIFY(!menuItem2.isNull()); + + // addAction(Action) re-creates the respective item in the menu + menu->addAction(action1); + menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3)); + QVERIFY(!menuItem1.isNull()); + QCOMPARE(menuItem1->action(), action1.data()); + + // removeAction(Action) destroys both the action and the respective item + menu->removeAction(action1); + QVERIFY(!menu->itemAt(3)); + QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete); + QVERIFY(action1.isNull()); + QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete); + QVERIFY(menuItem1.isNull()); +} + +void tst_QQuickMenu::removeTakeItem() +{ + QQuickApplicationHelper helper(this, QLatin1String("removeTakeItem.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu *>(); + QVERIFY(menu); + + QPointer<QQuickMenuItem> menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>(); + QVERIFY(!menuItem1.isNull()); + QCOMPARE(menuItem1->menu(), menu); + + QPointer<QQuickMenuItem> menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>(); + QVERIFY(!menuItem2.isNull()); + QCOMPARE(menuItem2->menu(), menu); + + QPointer<QQuickMenuItem> menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>(); + QVERIFY(!menuItem3.isNull()); + QCOMPARE(menuItem3->menu(), menu); + + // takeItem(int) does not destroy + QVariant ret; + QVERIFY(QMetaObject::invokeMethod(window, "takeSecondItem", Q_RETURN_ARG(QVariant, ret))); + QCOMPARE(ret.value<QQuickMenuItem *>(), menuItem2); + QVERIFY(!menuItem2->menu()); + QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete); + QVERIFY(!menuItem2.isNull()); + + // removeItem(Item) destroys + QVERIFY(QMetaObject::invokeMethod(window, "removeFirstItem")); + QVERIFY(!menuItem1->menu()); + QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete); + QVERIFY(menuItem1.isNull()); + + // removeItem(null) must not call removeItem(0) + QVERIFY(QMetaObject::invokeMethod(window, "removeNullItem")); + QCOMPARE(menuItem3->menu(), menu); + QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete); + QVERIFY(!menuItem3.isNull()); + + // deprecated removeItem(int) does not destroy + QVERIFY(QMetaObject::invokeMethod(window, "removeFirstIndex")); + QVERIFY(!menuItem3->menu()); + QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete); + QVERIFY(!menuItem3.isNull()); +} + +void tst_QQuickMenu::subMenuMouse_data() +{ + QTest::addColumn<bool>("cascade"); + + QTest::newRow("cascading") << true; + QTest::newRow("non-cascading") << false; +} + +void tst_QQuickMenu::subMenuMouse() +{ + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Mouse hovering not functional on offscreen/minimal platforms"); + + QFETCH(bool, cascade); + + QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); + + QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>(); + QVERIFY(mainMenu); + mainMenu->setCascade(cascade); + QCOMPARE(mainMenu->cascade(), cascade); + + QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>(); + QVERIFY(subMenu1); + + QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>(); + QVERIFY(subMenu2); + + QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>(); + QVERIFY(subSubMenu1); + + mainMenu->open(); + QVERIFY(mainMenu->isVisible()); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // open the sub-menu with mouse click + QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1)); + QVERIFY(subMenu1Item); + QCOMPARE(subMenu1Item->subMenu(), subMenu1); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenu1Item->mapToScene(QPoint(1, 1)).toPoint()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // open the cascading sub-sub-menu with mouse hover + QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); + QVERIFY(subSubMenu1Item); + QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1); + QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + if (cascade) + QTRY_VERIFY(subSubMenu1->isVisible()); + + // close the sub-sub-menu with mouse hover over another parent menu item + QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0)); + QVERIFY(subMenuItem1); + QVERIFY(!subMenuItem1->subMenu()); + QTest::mouseMove(window, subMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // re-open the sub-sub-menu with mouse hover + QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + if (cascade) + QTRY_VERIFY(subSubMenu1->isVisible()); + + // close sub-menu and sub-sub-menu with mouse hover in the main menu + QQuickMenuItem *mainMenuItem1 = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(0)); + QVERIFY(mainMenuItem1); + QTest::mouseMove(window, mainMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); + QCOMPARE(mainMenu->isVisible(), cascade); + QCOMPARE(subMenu1->isVisible(), !cascade); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // close all menus by click triggering an item + QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0)); + QVERIFY(subSubMenuItem1); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subSubMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); + QVERIFY(!mainMenu->isVisible()); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); +} + +void tst_QQuickMenu::subMenuKeyboard_data() +{ + QTest::addColumn<bool>("cascade"); + QTest::addColumn<bool>("mirrored"); + + QTest::newRow("cascading") << true << false; + QTest::newRow("cascading,mirrored") << true << true; + QTest::newRow("non-cascading") << false << false; + QTest::newRow("non-cascading,mirrored") << false << true; +} + +void tst_QQuickMenu::subMenuKeyboard() +{ + QFETCH(bool, cascade); + QFETCH(bool, mirrored); + + QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); + + if (mirrored) + window->setLocale(QLocale("ar_EG")); + + QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>(); + QVERIFY(mainMenu); + mainMenu->setCascade(cascade); + QCOMPARE(mainMenu->cascade(), cascade); + + QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>(); + QVERIFY(subMenu1); + + QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>(); + QVERIFY(subMenu2); + + QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>(); + QVERIFY(subSubMenu1); + + mainMenu->open(); + QVERIFY(mainMenu->isVisible()); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // navigate to the sub-menu item and trigger it + QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1)); + QVERIFY(subMenu1Item); + QVERIFY(!subMenu1Item->isHighlighted()); + QCOMPARE(subMenu1Item->subMenu(), subMenu1); + QTest::keyClick(window, Qt::Key_Down); + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(subMenu1Item->isHighlighted()); + QTest::keyClick(window, Qt::Key_Space); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // navigate to the sub-sub-menu item and open it with the arrow key + QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); + QVERIFY(subSubMenu1Item); + QVERIFY(!subSubMenu1Item->isHighlighted()); + QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1); + QTest::keyClick(window, Qt::Key_Down); + QTest::keyClick(window, Qt::Key_Down); + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(subSubMenu1Item->isHighlighted()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + QTest::keyClick(window, mirrored ? Qt::Key_Left : Qt::Key_Right); + QCOMPARE(mainMenu->isVisible(), cascade); + QCOMPARE(subMenu1->isVisible(), cascade); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(subSubMenu1->isVisible()); + + // navigate within the sub-sub-menu + QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0)); + QVERIFY(subSubMenuItem1); + QQuickMenuItem *subSubMenuItem2 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(1)); + QVERIFY(subSubMenuItem2); + QVERIFY(subSubMenuItem1->isHighlighted()); + QVERIFY(!subSubMenuItem2->isHighlighted()); + QTest::keyClick(window, Qt::Key_Down); + QVERIFY(!subSubMenuItem1->isHighlighted()); + QVERIFY(subSubMenuItem2->isHighlighted()); + + // navigate to the parent menu with the arrow key + QTest::keyClick(window, mirrored ? Qt::Key_Right : Qt::Key_Left); + QVERIFY(subSubMenu1Item->isHighlighted()); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // navigate within the sub-menu + QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0)); + QVERIFY(subMenuItem1); + QQuickMenuItem *subMenuItem2 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(1)); + QVERIFY(subMenuItem2); + QVERIFY(!subMenuItem1->isHighlighted()); + QVERIFY(!subMenuItem2->isHighlighted()); + QVERIFY(subSubMenu1Item->isHighlighted()); + QTest::keyClick(window, Qt::Key_Up); + QVERIFY(!subMenuItem1->isHighlighted()); + QVERIFY(subMenuItem2->isHighlighted()); + QVERIFY(!subSubMenu1Item->isHighlighted()); + + // close the menus with esc + QTest::keyClick(window, Qt::Key_Escape); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + QTest::keyClick(window, Qt::Key_Escape); + QVERIFY(!mainMenu->isVisible()); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); +} + +void tst_QQuickMenu::subMenuPosition_data() +{ + QTest::addColumn<bool>("cascade"); + QTest::addColumn<bool>("flip"); + QTest::addColumn<bool>("mirrored"); + QTest::addColumn<qreal>("overlap"); + + QTest::newRow("cascading") << true << false << false << 0.0; + QTest::newRow("cascading,flip") << true << true << false << 0.0; + QTest::newRow("cascading,overlap") << true << false << false << 10.0; + QTest::newRow("cascading,flip,overlap") << true << true << false << 10.0; + QTest::newRow("cascading,mirrored") << true << false << true << 0.0; + QTest::newRow("cascading,mirrored,flip") << true << true << true << 0.0; + QTest::newRow("cascading,mirrored,overlap") << true << false << true << 10.0; + QTest::newRow("cascading,mirrored,flip,overlap") << true << true << true << 10.0; + QTest::newRow("non-cascading") << false << false << false << 0.0; +} + +void tst_QQuickMenu::subMenuPosition() +{ + QFETCH(bool, cascade); + QFETCH(bool, flip); + QFETCH(bool, mirrored); + QFETCH(qreal, overlap); + + QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml")); + QQuickApplicationWindow *window = helper.appWindow; + + // the default size of the window fits three menus side by side. + // when testing flipping, we resize the window so that the first + // sub-menu fits, but the second doesn't + if (flip) + window->setWidth(window->width() - 200); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + centerOnScreen(window); + moveMouseAway(window); + + if (mirrored) + window->setLocale(QLocale("ar_EG")); + + QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>(); + QVERIFY(mainMenu); + mainMenu->setCascade(cascade); + QCOMPARE(mainMenu->cascade(), cascade); + mainMenu->setOverlap(overlap); + QCOMPARE(mainMenu->overlap(), overlap); + + QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>(); + QVERIFY(subMenu1); + subMenu1->setCascade(cascade); + QCOMPARE(subMenu1->cascade(), cascade); + subMenu1->setOverlap(overlap); + QCOMPARE(subMenu1->overlap(), overlap); + + QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>(); + QVERIFY(subMenu2); + subMenu2->setCascade(cascade); + QCOMPARE(subMenu2->cascade(), cascade); + subMenu2->setOverlap(overlap); + QCOMPARE(subMenu2->overlap(), overlap); + + QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>(); + QVERIFY(subSubMenu1); + subSubMenu1->setCascade(cascade); + QCOMPARE(subSubMenu1->cascade(), cascade); + subSubMenu1->setOverlap(overlap); + QCOMPARE(subSubMenu1->overlap(), overlap); + + // choose the main menu position so that there's room for the + // sub-menus to cascade to the left when mirrored + if (mirrored) + mainMenu->setX(window->width() - 200); + + mainMenu->open(); + QVERIFY(mainMenu->isVisible()); + QVERIFY(!subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + // open the sub-menu (never flips) + QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1)); + QVERIFY(subMenu1Item); + QCOMPARE(subMenu1Item->subMenu(), subMenu1); + emit subMenu1Item->triggered(); + QCOMPARE(mainMenu->isVisible(), cascade); + QVERIFY(subMenu1->isVisible()); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(!subSubMenu1->isVisible()); + + if (cascade) { + QCOMPARE(subMenu1->parentItem(), subMenu1Item); + // vertically aligned to the parent menu item + QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + subMenu1Item->y() - subMenu1->topPadding()); + if (mirrored) + QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() - subMenu1->width() + overlap); // on the left of the parent menu + else + QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + mainMenu->width() - overlap); // on the right of the parent menu + } else { + QCOMPARE(subMenu1->parentItem(), mainMenu->parentItem()); + // centered over the parent menu + QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + (mainMenu->width() - subMenu1->width()) / 2); + QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + (mainMenu->height() - subMenu1->height()) / 2); + } + + // open the sub-sub-menu (can flip) + QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); + QVERIFY(subSubMenu1Item); + QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1); + emit subSubMenu1Item->triggered(); + QCOMPARE(mainMenu->isVisible(), cascade); + QCOMPARE(subMenu1->isVisible(), cascade); + QVERIFY(!subMenu2->isVisible()); + QVERIFY(subSubMenu1->isVisible()); + + if (cascade) { + QCOMPARE(subSubMenu1->parentItem(), subSubMenu1Item); + // vertically aligned to the parent menu item + QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + subSubMenu1Item->y() - subSubMenu1->topPadding()); + if (mirrored != flip) + QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() - subSubMenu1->width() + overlap); // on the left of the parent menu + else + QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + subMenu1->width() - overlap); // on the right of the parent menu + } else { + QCOMPARE(subSubMenu1->parentItem(), subMenu1->parentItem()); + // centered over the parent menu + QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + (subMenu1->width() - subSubMenu1->width()) / 2); + QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + (subMenu1->height() - subSubMenu1->height()) / 2); + } +} + +void tst_QQuickMenu::addRemoveSubMenus() +{ + QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>(); + QVERIFY(mainMenu); + + QVERIFY(!mainMenu->menuAt(0)); + + QPointer<QQuickMenu> subMenu1 = window->property("subMenu1").value<QQuickMenu *>(); + QVERIFY(!subMenu1.isNull()); + QCOMPARE(mainMenu->menuAt(1), subMenu1.data()); + + QVERIFY(!mainMenu->menuAt(2)); + + QPointer<QQuickMenu> subMenu2 = window->property("subMenu2").value<QQuickMenu *>(); + QVERIFY(!subMenu2.isNull()); + QCOMPARE(mainMenu->menuAt(3), subMenu2.data()); + + QVERIFY(!mainMenu->menuAt(4)); + + QPointer<QQuickMenu> subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>(); + QVERIFY(!subSubMenu1.isNull()); + + // takeMenu(int) does not destroy the menu, but does destroy the respective item in the parent menu + QPointer<QQuickMenuItem> subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); + QVERIFY(subSubMenu1Item); + QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1.data()); + QCOMPARE(subMenu1->takeMenu(2), subSubMenu1.data()); + QVERIFY(!subMenu1->itemAt(2)); + QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete); + QVERIFY(!subSubMenu1.isNull()); + QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete); + QVERIFY(subSubMenu1Item.isNull()); + + // takeMenu(int) does not destroy an item that doesn't present a menu + QPointer<QQuickMenuItem> subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0)); + QVERIFY(subMenuItem1); + QVERIFY(!subMenuItem1->subMenu()); + QVERIFY(!subMenu1->takeMenu(0)); + QCoreApplication::sendPostedEvents(subMenuItem1, QEvent::DeferredDelete); + QVERIFY(!subMenuItem1.isNull()); + + // addMenu(Menu) re-creates the respective item in the parent menu + subMenu1->addMenu(subSubMenu1); + subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); + QVERIFY(!subSubMenu1Item.isNull()); + + // removeMenu(Menu) destroys both the menu and the respective item in the parent menu + subMenu1->removeMenu(subSubMenu1); + QVERIFY(!subMenu1->itemAt(2)); + QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete); + QVERIFY(subSubMenu1.isNull()); + QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete); + QVERIFY(subSubMenu1Item.isNull()); +} + QTEST_MAIN(tst_QQuickMenu) #include "tst_qquickmenu.moc" diff --git a/tests/auto/qquickmenubar/data/empty.qml b/tests/auto/qquickmenubar/data/empty.qml new file mode 100644 index 00000000..6ed0a141 --- /dev/null +++ b/tests/auto/qquickmenubar/data/empty.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +MenuBar { } diff --git a/tests/auto/qquickmenubar/data/menubar.qml b/tests/auto/qquickmenubar/data/menubar.qml new file mode 100644 index 00000000..606dd92c --- /dev/null +++ b/tests/auto/qquickmenubar/data/menubar.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 400 + height: 400 + visible: true + + header: MenuBar { + MenuBarItem { + menu: Menu { + title: "&File" + MenuItem { text: "&Open..." } + MenuItem { text: "&Save" } + MenuItem { text: "Save &As..." } + MenuSeparator { } + MenuItem { text: "&Quit" } + } + } + MenuBarItem { + menu: Menu { + title: "&Edit" + MenuItem { text: "&Cut" } + MenuItem { text: "&Copy" } + MenuItem { text: "&Paste" } + } + } + MenuBarItem { + menu: Menu { + title: "&View" + Menu { + title: "&Alignment" + Menu { + title: "&Horizontal" + MenuItem { text: "&Left" } + MenuItem { text: "&Center" } + MenuItem { text: "&Right" } + } + Menu { + title: "&Vertical" + MenuItem { text: "&Top" } + MenuItem { text: "&Center" } + MenuItem { text: "&Bottom" } + } + } + } + } + + MenuBarItem { + menu: Menu { + title: "&Help" + MenuItem { text: "&About" } + } + } + } +} diff --git a/tests/auto/qquickmenubar/qquickmenubar.pro b/tests/auto/qquickmenubar/qquickmenubar.pro new file mode 100644 index 00000000..b7d41f0f --- /dev/null +++ b/tests/auto/qquickmenubar/qquickmenubar.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qquickmenubar +SOURCES += tst_qquickmenubar.cpp + +macos:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private + +include (../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += \ + data/*.qml diff --git a/tests/auto/qquickmenubar/tst_qquickmenubar.cpp b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp new file mode 100644 index 00000000..19d67eac --- /dev/null +++ b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp @@ -0,0 +1,569 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest> +#include <QtQml> +#include "../shared/util.h" +#include "../shared/visualtestutil.h" +#include "../shared/qtest_quickcontrols.h" + +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickmenu_p.h> +#include <QtQuickTemplates2/private/qquickmenubar_p.h> +#include <QtQuickTemplates2/private/qquickmenubaritem_p.h> +#include <QtQuickTemplates2/private/qquickmenuitem_p.h> + +using namespace QQuickVisualTestUtil; + +class tst_qquickmenubar : public QQmlDataTest +{ + Q_OBJECT + +public: + +private slots: + void delegate(); + void mouse(); + void keys(); + void mnemonics(); + void addRemove(); +}; + +void tst_qquickmenubar::delegate() +{ + QQmlApplicationEngine engine(testFileUrl("empty.qml")); + QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0))); + QVERIFY(menuBar); + + QQmlComponent *delegate = menuBar->delegate(); + QVERIFY(delegate); + + QScopedPointer<QQuickMenuBarItem> item(qobject_cast<QQuickMenuBarItem *>(delegate->create())); + QVERIFY(item); +} + +void tst_qquickmenubar::mouse() +{ + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Mouse highlight not functional on offscreen/minimal platforms"); + + QQmlApplicationEngine engine(testFileUrl("menubar.qml")); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0))); + QVERIFY(window); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + centerOnScreen(window.data()); + moveMouseAway(window.data()); + + QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>(); + QVERIFY(menuBar); + + QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0); + QQuickMenu *editMenuBarMenu = menuBar->menuAt(1); + QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2); + QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3); + QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); + + QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem()); + QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem()); + QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem()); + QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem()); + QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); + + // highlight a menubar item + QTest::mouseMove(window.data(), fileMenuBarItem->mapToScene(QPointF(fileMenuBarItem->width() / 2, fileMenuBarItem->height() / 2)).toPoint()); + QVERIFY(fileMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarMenu->isVisible()); + + // highlight another menubar item + QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); + QVERIFY(!fileMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarMenu->isVisible()); + QVERIFY(!editMenuBarMenu->isVisible()); + + // trigger a menubar item to open a menu + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + + // re-trigger a menubar item to hide the menu + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarItem->hasActiveFocus()); + QTRY_VERIFY(!editMenuBarMenu->isVisible()); + + // re-trigger a menubar item to show the menu again + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + + // highlight another menubar item to open another menu + QTest::mouseMove(window.data(), helpMenuBarItem->mapToScene(QPointF(helpMenuBarItem->width() / 2, helpMenuBarItem->height() / 2)).toPoint()); + QVERIFY(!fileMenuBarItem->isHighlighted()); + QVERIFY(!editMenuBarItem->isHighlighted()); + QVERIFY(!viewMenuBarItem->isHighlighted()); + QVERIFY(helpMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarMenu->isVisible()); + QVERIFY(!viewMenuBarMenu->isVisible()); + QVERIFY(helpMenuBarMenu->isVisible()); + QTRY_VERIFY(!editMenuBarMenu->isVisible()); + QTRY_VERIFY(helpMenuBarMenu->isOpened()); + + // trigger a menu item to close the menu + QQuickMenuItem *aboutMenuItem = qobject_cast<QQuickMenuItem *>(helpMenuBarMenu->itemAt(0)); + QVERIFY(aboutMenuItem); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, aboutMenuItem->mapToScene(QPointF(aboutMenuItem->width() / 2, aboutMenuItem->height() / 2)).toPoint()); + QVERIFY(!helpMenuBarItem->isHighlighted()); + QTRY_VERIFY(!helpMenuBarMenu->isVisible()); + + // highlight a menubar item + QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(!helpMenuBarItem->isHighlighted()); + QVERIFY(!editMenuBarMenu->isVisible()); + QVERIFY(!helpMenuBarMenu->isVisible()); + + // trigger a menubar item to open a menu + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); + QVERIFY(!editMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + QTRY_VERIFY(viewMenuBarMenu->isOpened()); + + // trigger a menu item to open a sub-menu + QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0)); + QVERIFY(alignmentSubMenuItem); + QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu(); + QVERIFY(alignmentSubMenu); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint()); + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + QTRY_VERIFY(alignmentSubMenu->isOpened()); + + // trigger a menu item to open a sub-sub-menu + QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1)); + QVERIFY(verticalSubMenuItem); + QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu(); + QVERIFY(verticalSubMenu); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint()); + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + QVERIFY(verticalSubMenu->isVisible()); + QTRY_VERIFY(verticalSubMenu->isOpened()); + + // trigger a menu item to close the whole chain of menus + QQuickMenuItem *centerMenuItem = qobject_cast<QQuickMenuItem *>(verticalSubMenu->itemAt(1)); + QVERIFY(centerMenuItem); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, centerMenuItem->mapToScene(QPointF(centerMenuItem->width() / 2, centerMenuItem->height() / 2)).toPoint()); + QVERIFY(!viewMenuBarItem->isHighlighted()); + QTRY_VERIFY(!viewMenuBarMenu->isVisible()); + QTRY_VERIFY(!alignmentSubMenu->isVisible()); + QTRY_VERIFY(!verticalSubMenu->isVisible()); + + // re-highlight the same menubar item + QTest::mouseMove(window.data(), viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); + QVERIFY(viewMenuBarItem->isHighlighted()); + + // re-open the chain of menus + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); + QTRY_VERIFY(viewMenuBarMenu->isOpened()); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint()); + QTRY_VERIFY(alignmentSubMenu->isOpened()); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint()); + QTRY_VERIFY(verticalSubMenu->isOpened()); + + // click outside to close the whole chain of menus + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() - 1)); + QVERIFY(!viewMenuBarItem->isHighlighted()); + QTRY_VERIFY(!viewMenuBarMenu->isVisible()); + QTRY_VERIFY(!alignmentSubMenu->isVisible()); + QTRY_VERIFY(!verticalSubMenu->isVisible()); +} + +void tst_qquickmenubar::keys() +{ + QQmlApplicationEngine engine(testFileUrl("menubar.qml")); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0))); + QVERIFY(window); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + centerOnScreen(window.data()); + moveMouseAway(window.data()); + + QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>(); + QVERIFY(menuBar); + + QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0); + QQuickMenu *editMenuBarMenu = menuBar->menuAt(1); + QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2); + QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3); + QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); + + QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem()); + QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem()); + QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem()); + QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem()); + QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); + + // trigger a menubar item to open a menu + editMenuBarItem->forceActiveFocus(); + QTest::keyClick(window.data(), Qt::Key_Space); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + QVERIFY(editMenuBarMenu->hasActiveFocus()); + + // navigate down to the menu + QQuickMenuItem *cutMenuItem = qobject_cast<QQuickMenuItem *>(editMenuBarMenu->itemAt(0)); + QVERIFY(cutMenuItem); + QVERIFY(!cutMenuItem->isHighlighted()); + QVERIFY(!cutMenuItem->hasActiveFocus()); + QTest::keyClick(window.data(), Qt::Key_Down); + QVERIFY(cutMenuItem->isHighlighted()); + QVERIFY(cutMenuItem->hasActiveFocus()); + + // navigate up, back to the menubar + QTest::keyClick(window.data(), Qt::Key_Up); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarItem->hasActiveFocus()); + QTRY_VERIFY(!editMenuBarMenu->isVisible()); + QVERIFY(!cutMenuItem->isHighlighted()); + QVERIFY(!cutMenuItem->hasActiveFocus()); + + // navigate down to re-open the menu + QTest::keyClick(window.data(), Qt::Key_Down); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(!editMenuBarItem->hasActiveFocus()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + QVERIFY(editMenuBarMenu->hasActiveFocus()); + QVERIFY(cutMenuItem->isHighlighted()); + QVERIFY(cutMenuItem->hasActiveFocus()); + + // navigate left in popup mode (menu open) + QTest::keyClick(window.data(), Qt::Key_Left); + QVERIFY(fileMenuBarItem->isHighlighted()); + QVERIFY(!editMenuBarItem->isHighlighted()); + QVERIFY(fileMenuBarMenu->isVisible()); + QTRY_VERIFY(fileMenuBarMenu->isOpened()); + QTRY_VERIFY(!editMenuBarMenu->isVisible()); + + // navigate left in popup mode (wrap) + QTest::keyClick(window.data(), Qt::Key_Left); + QVERIFY(helpMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarItem->isHighlighted()); + QVERIFY(helpMenuBarMenu->isVisible()); + QTRY_VERIFY(helpMenuBarMenu->isOpened()); + QTRY_VERIFY(!fileMenuBarMenu->isVisible()); + + // navigate up to close the menu + QTest::keyClick(window.data(), Qt::Key_Up); + QVERIFY(helpMenuBarItem->isHighlighted()); + QTRY_VERIFY(!helpMenuBarMenu->isVisible()); + + // navigate right in non-popup mode (wrap) + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(fileMenuBarItem->isHighlighted()); + QVERIFY(!helpMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarMenu->isVisible()); + QVERIFY(!helpMenuBarMenu->isVisible()); + + // navigate right in non-popup mode (menu closed) + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(!fileMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(!fileMenuBarMenu->isVisible()); + QVERIFY(!editMenuBarMenu->isVisible()); + + // open a menu + viewMenuBarItem->forceActiveFocus(); + QTest::keyClick(window.data(), Qt::Key_Space); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + QTRY_VERIFY(viewMenuBarMenu->isOpened()); + QVERIFY(!viewMenuBarItem->hasActiveFocus()); + QVERIFY(viewMenuBarMenu->hasActiveFocus()); + + // open a sub-menu + QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0)); + QVERIFY(alignmentSubMenuItem); + QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu(); + QVERIFY(alignmentSubMenu); + QTest::keyClick(window.data(), Qt::Key_Down); + QVERIFY(alignmentSubMenuItem->isHighlighted()); + QVERIFY(!alignmentSubMenu->isVisible()); + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(alignmentSubMenu->isVisible()); + QTRY_VERIFY(alignmentSubMenu->isOpened()); + + // open a sub-sub-menu + QQuickMenuItem *horizontalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(0)); + QVERIFY(horizontalSubMenuItem); + QVERIFY(horizontalSubMenuItem->isHighlighted()); + QQuickMenu *horizontalSubMenu = horizontalSubMenuItem->subMenu(); + QVERIFY(horizontalSubMenu); + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + QVERIFY(horizontalSubMenu->isVisible()); + QTRY_VERIFY(horizontalSubMenu->isOpened()); + + // navigate left to close a sub-menu + QTest::keyClick(window.data(), Qt::Key_Left); + QTRY_VERIFY(!horizontalSubMenu->isVisible()); + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + + // navigate right to re-open the sub-menu + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(horizontalSubMenuItem->isHighlighted()); + QVERIFY(horizontalSubMenu->isVisible()); + QTRY_VERIFY(horizontalSubMenu->isOpened()); + + // navigate right to the next menubar menu + QTest::keyClick(window.data(), Qt::Key_Right); + QVERIFY(!viewMenuBarItem->isHighlighted()); + QVERIFY(helpMenuBarItem->isHighlighted()); + QVERIFY(helpMenuBarMenu->isVisible()); + QTRY_VERIFY(!viewMenuBarMenu->isVisible()); + QTRY_VERIFY(!alignmentSubMenu->isVisible()); + QTRY_VERIFY(!horizontalSubMenu->isVisible()); + QTRY_VERIFY(helpMenuBarMenu->isOpened()); + + // navigate back + QTest::keyClick(window.data(), Qt::Key_Left); + QVERIFY(!helpMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + QTRY_VERIFY(!helpMenuBarMenu->isVisible()); + QTRY_VERIFY(viewMenuBarMenu->isOpened()); + + // re-open the chain of menus + QTest::keyClick(window.data(), Qt::Key_Down); + QVERIFY(alignmentSubMenuItem->isHighlighted()); + QTest::keyClick(window.data(), Qt::Key_Right); + QTRY_VERIFY(alignmentSubMenu->isOpened()); + QTest::keyClick(window.data(), Qt::Key_Right); + QTRY_VERIFY(horizontalSubMenu->isOpened()); + + // repeat escape to close the whole chain of menus one by one + QTest::keyClick(window.data(), Qt::Key_Escape); + QTRY_VERIFY(!horizontalSubMenu->isVisible()); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + + QTest::keyClick(window.data(), Qt::Key_Escape); + QTRY_VERIFY(!alignmentSubMenu->isVisible()); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + + QTest::keyClick(window.data(), Qt::Key_Escape); + QVERIFY(!viewMenuBarItem->isHighlighted()); + QTRY_VERIFY(!viewMenuBarMenu->isVisible()); +} + +void tst_qquickmenubar::mnemonics() +{ +#ifdef Q_OS_MACOS + QSKIP("Mnemonics are not used on macOS"); +#endif + + QQmlApplicationEngine engine(testFileUrl("menubar.qml")); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0))); + QVERIFY(window); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + centerOnScreen(window.data()); + moveMouseAway(window.data()); + + QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>(); + QVERIFY(menuBar); + + QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0); + QQuickMenu *editMenuBarMenu = menuBar->menuAt(1); + QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2); + QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3); + QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); + + QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem()); + QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem()); + QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem()); + QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem()); + QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); + + // trigger a menubar item to open a menu + QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit" + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(!editMenuBarItem->hasActiveFocus()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + QVERIFY(editMenuBarMenu->hasActiveFocus()); + + // re-trigger a menubar item to hide the menu + QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit" + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarItem->hasActiveFocus()); + QVERIFY(!editMenuBarMenu->hasActiveFocus()); + QTRY_VERIFY(!editMenuBarMenu->isVisible()); + + // re-trigger a menubar item to show the menu again + QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit" + QVERIFY(editMenuBarItem->isHighlighted()); + QVERIFY(editMenuBarMenu->isVisible()); + QTRY_VERIFY(editMenuBarMenu->isOpened()); + QVERIFY(editMenuBarMenu->hasActiveFocus()); + QVERIFY(!editMenuBarItem->hasActiveFocus()); + + // trigger another menubar item to open another menu + QTest::keyClick(window.data(), Qt::Key_H, Qt::AltModifier); // "&Help" + QVERIFY(!editMenuBarItem->isHighlighted()); + QVERIFY(helpMenuBarItem->isHighlighted()); + QVERIFY(!viewMenuBarMenu->isVisible()); + QVERIFY(helpMenuBarMenu->isVisible()); + QTRY_VERIFY(helpMenuBarMenu->isOpened()); + + // trigger a menu item to close the menu + QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&About" + QVERIFY(!helpMenuBarItem->isHighlighted()); + QTRY_VERIFY(!helpMenuBarMenu->isVisible()); + + // trigger a menubar item to open a menu + QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&View" + QVERIFY(!editMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarItem->isHighlighted()); + QVERIFY(viewMenuBarMenu->isVisible()); + QTRY_VERIFY(viewMenuBarMenu->isOpened()); + + // trigger a menu item to open a sub-menu + QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0)); + QVERIFY(alignmentSubMenuItem); + QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu(); + QVERIFY(alignmentSubMenu); + QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&Alignment" + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + QTRY_VERIFY(alignmentSubMenu->isOpened()); + + // trigger a menu item to open a sub-sub-menu + QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1)); + QVERIFY(verticalSubMenuItem); + QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu(); + QVERIFY(verticalSubMenu); + QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&Vertical" + QVERIFY(viewMenuBarMenu->isVisible()); + QVERIFY(alignmentSubMenu->isVisible()); + QVERIFY(verticalSubMenu->isVisible()); + QTRY_VERIFY(verticalSubMenu->isOpened()); + + // trigger a menu item to close the whole chain of menus + QTest::keyClick(window.data(), Qt::Key_C, Qt::AltModifier); // "&Center" + QVERIFY(!viewMenuBarItem->isHighlighted()); + QTRY_VERIFY(!viewMenuBarMenu->isVisible()); + QTRY_VERIFY(!alignmentSubMenu->isVisible()); + QTRY_VERIFY(!verticalSubMenu->isVisible()); +} + +void tst_qquickmenubar::addRemove() +{ + QQmlApplicationEngine engine(testFileUrl("empty.qml")); + + QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0))); + QVERIFY(menuBar); + + QQmlComponent component(&engine); + component.setData("import QtQuick.Controls 2.0; Menu { }", QUrl()); + + QPointer<QQuickMenu> menu1(qobject_cast<QQuickMenu *>(component.create())); + QVERIFY(!menu1.isNull()); + menuBar->addMenu(menu1.data()); + QCOMPARE(menuBar->count(), 1); + QCOMPARE(menuBar->menuAt(0), menu1.data()); + + QPointer<QQuickMenuBarItem> menuBarItem1(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0))); + QVERIFY(menuBarItem1); + QCOMPARE(menuBarItem1->menu(), menu1.data()); + QCOMPARE(menuBar->itemAt(0), menuBarItem1.data()); + + QScopedPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create())); + QVERIFY(!menu2.isNull()); + menuBar->insertMenu(0, menu2.data()); + QCOMPARE(menuBar->count(), 2); + QCOMPARE(menuBar->menuAt(0), menu2.data()); + QCOMPARE(menuBar->menuAt(1), menu1.data()); + + QPointer<QQuickMenuBarItem> menuBarItem2(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0))); + QVERIFY(menuBarItem2); + QCOMPARE(menuBarItem2->menu(), menu2.data()); + QCOMPARE(menuBar->itemAt(0), menuBarItem2.data()); + QCOMPARE(menuBar->itemAt(1), menuBarItem1.data()); + + // takeMenu(int) does not destroy the menu, but does destroy the respective item in the menubar + QCOMPARE(menuBar->takeMenu(1), menu1.data()); + QCOMPARE(menuBar->count(), 1); + QVERIFY(!menuBar->menuAt(1)); + QVERIFY(!menuBar->itemAt(1)); + QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete); + QVERIFY(!menu1.isNull()); + QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete); + QVERIFY(menuBarItem1.isNull()); + + // addMenu(Menu) re-creates the respective item in the menubar + menuBar->addMenu(menu1.data()); + QCOMPARE(menuBar->count(), 2); + menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1)); + QVERIFY(!menuBarItem1.isNull()); + + // removeMenu(Menu) destroys both the menu and the respective item in the menubar + menuBar->removeMenu(menu1.data()); + QCOMPARE(menuBar->count(), 1); + QVERIFY(!menuBar->itemAt(1)); + QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete); + QVERIFY(menu1.isNull()); + QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete); + QVERIFY(menuBarItem1.isNull()); +} + +QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar) + +#include "tst_qquickmenubar.moc" diff --git a/tests/auto/qquickninepatchimage/data/foo.9.png b/tests/auto/qquickninepatchimage/data/foo.9.png Binary files differnew file mode 100644 index 00000000..51246990 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/foo.9.png diff --git a/tests/auto/qquickninepatchimage/data/foo@2x.9.png b/tests/auto/qquickninepatchimage/data/foo@2x.9.png Binary files differnew file mode 100644 index 00000000..c8dc30a3 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/foo@2x.9.png diff --git a/tests/auto/qquickninepatchimage/data/foo@3x.9.png b/tests/auto/qquickninepatchimage/data/foo@3x.9.png Binary files differnew file mode 100644 index 00000000..00ea4e05 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/foo@3x.9.png diff --git a/tests/auto/qquickninepatchimage/data/foo@4x.9.png b/tests/auto/qquickninepatchimage/data/foo@4x.9.png Binary files differnew file mode 100644 index 00000000..ea73340a --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/foo@4x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-all.9.png b/tests/auto/qquickninepatchimage/data/inset-all.9.png Binary files differnew file mode 100644 index 00000000..e08ef9c7 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-all.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png Binary files differnew file mode 100644 index 00000000..96d1c0e8 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-all@2x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png Binary files differnew file mode 100644 index 00000000..215ce27e --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-all@3x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png Binary files differnew file mode 100644 index 00000000..35e53101 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-all@4x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png Binary files differnew file mode 100644 index 00000000..c4c37dff --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-bottomright.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png Binary files differnew file mode 100644 index 00000000..3d64036f --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@2x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png Binary files differnew file mode 100644 index 00000000..115184d9 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@3x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png Binary files differnew file mode 100644 index 00000000..2ec7cbef --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-bottomright@4x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft.9.png Binary files differnew file mode 100644 index 00000000..9cc5f43d --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-topleft.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png Binary files differnew file mode 100644 index 00000000..a4ca2b12 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-topleft@2x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png Binary files differnew file mode 100644 index 00000000..73f3595a --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-topleft@3x.9.png diff --git a/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png b/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png Binary files differnew file mode 100644 index 00000000..78baa463 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/inset-topleft@4x.9.png diff --git a/tests/auto/qquickninepatchimage/data/ninepatchimage.qml b/tests/auto/qquickninepatchimage/data/ninepatchimage.qml new file mode 100644 index 00000000..7ef07a1c --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/ninepatchimage.qml @@ -0,0 +1,7 @@ +import QtQuick.Controls 2.3 +import QtQuick.Controls.impl 2.3 +import QtQuick.Controls.Imagine 2.3 +import QtQuick.Controls.Imagine.impl 2.3 + +NinePatchImage { +} diff --git a/tests/auto/qquickninepatchimage/data/padding.9.png b/tests/auto/qquickninepatchimage/data/padding.9.png Binary files differnew file mode 100644 index 00000000..5b4f0960 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/padding.9.png diff --git a/tests/auto/qquickninepatchimage/data/padding@2x.9.png b/tests/auto/qquickninepatchimage/data/padding@2x.9.png Binary files differnew file mode 100644 index 00000000..44eb1943 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/padding@2x.9.png diff --git a/tests/auto/qquickninepatchimage/data/padding@3x.9.png b/tests/auto/qquickninepatchimage/data/padding@3x.9.png Binary files differnew file mode 100644 index 00000000..d1563448 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/padding@3x.9.png diff --git a/tests/auto/qquickninepatchimage/data/padding@4x.9.png b/tests/auto/qquickninepatchimage/data/padding@4x.9.png Binary files differnew file mode 100644 index 00000000..e86cce69 --- /dev/null +++ b/tests/auto/qquickninepatchimage/data/padding@4x.9.png diff --git a/tests/auto/qquickninepatchimage/qquickninepatchimage.pro b/tests/auto/qquickninepatchimage/qquickninepatchimage.pro new file mode 100644 index 00000000..b40a5f4c --- /dev/null +++ b/tests/auto/qquickninepatchimage/qquickninepatchimage.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +macos:CONFIG -= app_bundle +TARGET = tst_qquickninepatchimage + +QT += core gui qml quick testlib +QT_PRIVATE += gui-private quick-private quickcontrols2-private + +include (../shared/util.pri) + +SOURCES += tst_qquickninepatchimage.cpp + +TESTDATA += \ + $$PWD/data/*.qml \ + $$PWD/data/*.png diff --git a/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp b/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp new file mode 100644 index 00000000..b5dd7f2f --- /dev/null +++ b/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtTest/qsignalspy.h> + +#include <QtCore/qmath.h> +#include <QtCore/qsize.h> +#include <QtGui/private/qhighdpiscaling_p.h> +#include <QtQml/qqmlengine.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitemgrabresult.h> +#include <QtQuick/private/qquickimage_p.h> + +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + +class tst_qquickninepatchimage : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void ninePatch_data(); + void ninePatch(); + void padding_data(); + void padding(); + void inset_data(); + void inset(); + void implicitSize_data(); + void implicitSize(); +}; + +static QImage grabItemToImage(QQuickItem *item) +{ + QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(); + QSignalSpy spy(result.data(), SIGNAL(ready())); + spy.wait(); + return result->image(); +} + +void tst_qquickninepatchimage::ninePatch_data() +{ + QTest::addColumn<int>("dpr"); + QTest::addColumn<QSize>("size"); + + // original size, downsized, stretched + const QList<QSize> sizes = QList<QSize>() + << QSize(40, 40) // original + << QSize(10, 40) // downsized (h) + << QSize(40, 10) // downsized (v) + << QSize(10, 10) // downsized (h & v) + << QSize(80, 40) // stretched (h) + << QSize(40, 80) // stretched (v) + << QSize(80, 80) // stretched (h & v) + << QSize(8, 8); // minimal (borders only) + + for (const QSize &sz : sizes) { + for (int dpr = 1; dpr <= 4; ++dpr) + QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1, %2x%3").arg(dpr).arg(sz.width()).arg(sz.height()))) << dpr << sz; + } +} + +void tst_qquickninepatchimage::ninePatch() +{ + QFETCH(int, dpr); + QFETCH(QSize, size); + + QHighDpiScaling::setGlobalFactor(dpr); + + QQuickView view(testFileUrl("ninepatchimage.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject()); + QVERIFY(ninePatchImage); + ninePatchImage->setSource(testFileUrl("foo.9.png")); + ninePatchImage->setSize(size); + + const QImage ninePatchImageGrab = grabItemToImage(ninePatchImage).scaled(size * dpr); + + // Generate an image to compare against the actual 9-patch image. + QImage generatedImage(size * dpr, ninePatchImageGrab.format()); + generatedImage.fill(Qt::red); + + QImage blueRect(4 * dpr, 4 * dpr, ninePatchImageGrab.format()); + blueRect.fill(Qt::blue); + + QPainter painter(&generatedImage); + // Top-left + painter.drawImage(0, 0, blueRect); + // Top-right + painter.drawImage(generatedImage.width() - blueRect.width(), 0, blueRect); + // Bottom-right + painter.drawImage(generatedImage.width() - blueRect.width(), generatedImage.height() - blueRect.height(), blueRect); + // Bottom-left + painter.drawImage(0, generatedImage.height() - blueRect.height(), blueRect); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Grabbing does not work on offscreen/minimal platforms", Abort); + + QCOMPARE(ninePatchImageGrab, generatedImage); +} + +void tst_qquickninepatchimage::padding_data() +{ + QTest::addColumn<int>("dpr"); + + for (int dpr = 1; dpr <= 4; ++dpr) + QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1").arg(dpr))) << dpr; +} + +void tst_qquickninepatchimage::padding() +{ + QFETCH(int, dpr); + + QHighDpiScaling::setGlobalFactor(dpr); + + QQuickView view(testFileUrl("ninepatchimage.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject()); + QVERIFY(ninePatchImage); + ninePatchImage->setSource(testFileUrl("padding.9.png")); + + QCOMPARE(ninePatchImage->property("topPadding").toReal(), 8); + QCOMPARE(ninePatchImage->property("leftPadding").toReal(), 18); + QCOMPARE(ninePatchImage->property("rightPadding").toReal(), 20); + QCOMPARE(ninePatchImage->property("bottomPadding").toReal(), 10); +} + +void tst_qquickninepatchimage::inset_data() +{ + QTest::addColumn<int>("dpr"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QMarginsF>("insets"); + + const QStringList files = QStringList() << "inset-all.9.png" << "inset-topleft.9.png" << "inset-bottomright.9.png"; + const QList<QMarginsF> insets = QList<QMarginsF>() << QMarginsF(2, 1, 3, 4) << QMarginsF(2, 1, 0, 0) << QMarginsF(0, 0, 3, 4); + + for (int i = 0; i < files.count(); ++i) { + QString file = files.at(i); + for (int dpr = 1; dpr <= 4; ++dpr) + QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file).arg(dpr))) << dpr << file << insets.at(i); + } +} + +Q_DECLARE_METATYPE(QMarginsF) + +void tst_qquickninepatchimage::inset() +{ + QFETCH(int, dpr); + QFETCH(QString, file); + QFETCH(QMarginsF, insets); + + QHighDpiScaling::setGlobalFactor(dpr); + + QQuickView view(testFileUrl("ninepatchimage.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject()); + QVERIFY(ninePatchImage); + ninePatchImage->setSource(testFileUrl(file)); + + QCOMPARE(ninePatchImage->property("topInset").toReal(), insets.top()); + QCOMPARE(ninePatchImage->property("leftInset").toReal(), insets.left()); + QCOMPARE(ninePatchImage->property("rightInset").toReal(), insets.right()); + QCOMPARE(ninePatchImage->property("bottomInset").toReal(), insets.bottom()); +} + +void tst_qquickninepatchimage::implicitSize_data() +{ + QTest::addColumn<int>("dpr"); + QTest::addColumn<QString>("file"); + QTest::addColumn<QSizeF>("implicitSize"); + + const QStringList files = QStringList() << "foo.9.png" << "padding.9.png" << "inset-all.9.png" << "inset-topleft.9.png" << "inset-bottomright.9.png"; + + for (const QString &file : files) { + for (int dpr = 1; dpr <= 4; ++dpr) + QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file).arg(dpr))) << dpr << file << QSizeF(40, 40); + } +} + +void tst_qquickninepatchimage::implicitSize() +{ + QFETCH(int, dpr); + QFETCH(QString, file); + QFETCH(QSizeF, implicitSize); + + QHighDpiScaling::setGlobalFactor(dpr); + + QQuickView view(testFileUrl("ninepatchimage.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(view.rootObject()); + QVERIFY(ninePatchImage); + ninePatchImage->setSource(testFileUrl(file)); + + QCOMPARE(ninePatchImage->implicitWidth(), implicitSize.width()); + QCOMPARE(ninePatchImage->implicitHeight(), implicitSize.height()); +} + +QTEST_MAIN(tst_qquickninepatchimage) + +#include "tst_qquickninepatchimage.moc" diff --git a/tests/auto/qquickpopup/BLACKLIST b/tests/auto/qquickpopup/BLACKLIST new file mode 100644 index 00000000..47795a8b --- /dev/null +++ b/tests/auto/qquickpopup/BLACKLIST @@ -0,0 +1,10 @@ +[overlay] +# QTBUG-62668 +* + +[closePolicy] +# QTBUG-62668 +* + + + diff --git a/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml b/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml index 53dae0f9..f41516c8 100644 --- a/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml +++ b/tests/auto/qquickpopup/data/closeOnEscapeWithNestedPopups.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ -import QtQuick 2.9 +import QtQuick 2.10 import QtQuick.Controls 2.2 ApplicationWindow { diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index 3f4b2d13..a1e5e246 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -79,6 +79,7 @@ private slots: void cursorShape(); void componentComplete(); void closeOnEscapeWithNestedPopups(); + void enabled(); void orientation_data(); void orientation(); }; @@ -217,6 +218,15 @@ void tst_QQuickPopup::overlay() QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); QVERIFY(popup); + QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(qmlAttachedPropertiesObject<QQuickOverlay>(popup)); + QVERIFY(overlayAttached); + QCOMPARE(overlayAttached->overlay(), overlay); + + QSignalSpy overlayAttachedPressedSignal(overlayAttached, SIGNAL(pressed())); + QSignalSpy overlayAttachedReleasedSignal(overlayAttached, SIGNAL(released())); + QVERIFY(overlayAttachedPressedSignal.isValid()); + QVERIFY(overlayAttachedReleasedSignal.isValid()); + QQuickButton *button = window->property("button").value<QQuickButton*>(); QVERIFY(button); @@ -230,10 +240,14 @@ void tst_QQuickPopup::overlay() QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); popup->close(); QVERIFY(!popup->isVisible()); @@ -251,10 +265,14 @@ void tst_QQuickPopup::overlay() QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount); + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); QVERIFY(!popup->isVisible()); QCOMPARE(overlay->isVisible(), popup->isVisible()); @@ -280,10 +298,14 @@ void tst_QQuickPopup::overlay() QTest::touchEvent(window, device.data()).press(0, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); QTest::touchEvent(window, device.data()).release(0, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount); + QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); + QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); QVERIFY(!popup->isVisible()); QCOMPARE(overlay->isVisible(), popup->isVisible()); @@ -387,6 +409,28 @@ void tst_QQuickPopup::windowChange() popup.setParentItem(window.contentItem()); QCOMPARE(popup.window(), &window); QCOMPARE(spy.count(), 3); + + popup.resetParentItem(); + QVERIFY(!popup.window()); + QCOMPARE(spy.count(), 4); + + popup.setParent(&window); + popup.resetParentItem(); + QCOMPARE(popup.window(), &window); + QCOMPARE(spy.count(), 5); + + popup.setParent(this); + popup.resetParentItem(); + QVERIFY(!popup.window()); + QCOMPARE(spy.count(), 6); + + item.setParentItem(window.contentItem()); + popup.setParent(&item); + popup.resetParentItem(); + QCOMPARE(popup.window(), &window); + QCOMPARE(spy.count(), 7); + + popup.setParent(nullptr); } Q_DECLARE_METATYPE(QQuickPopup::ClosePolicy) @@ -942,6 +986,26 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups() QCOMPARE(stackView->depth(), 1); } +void tst_QQuickPopup::enabled() +{ + QQuickPopup popup; + QVERIFY(popup.isEnabled()); + QVERIFY(popup.popupItem()->isEnabled()); + + QSignalSpy enabledSpy(&popup, &QQuickPopup::enabledChanged); + QVERIFY(enabledSpy.isValid()); + + popup.setEnabled(false); + QVERIFY(!popup.isEnabled()); + QVERIFY(!popup.popupItem()->isEnabled()); + QCOMPARE(enabledSpy.count(), 1); + + popup.popupItem()->setEnabled(true); + QVERIFY(popup.isEnabled()); + QVERIFY(popup.popupItem()->isEnabled()); + QCOMPARE(enabledSpy.count(), 2); +} + void tst_QQuickPopup::orientation_data() { QTest::addColumn<Qt::ScreenOrientation>("orientation"); diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml new file mode 100644 index 00000000..ee17c230 --- /dev/null +++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+linux/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.1 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml new file mode 100644 index 00000000..ee17c230 --- /dev/null +++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+macos/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.1 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml new file mode 100644 index 00000000..ee17c230 --- /dev/null +++ b/tests/auto/qquickstyleselector/data/PlatformStyle/+windows/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.1 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml b/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml new file mode 100644 index 00000000..ee17c230 --- /dev/null +++ b/tests/auto/qquickstyleselector/data/PlatformStyle/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.1 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp index 598320d2..e90a8bd9 100644 --- a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp +++ b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp @@ -49,6 +49,8 @@ private slots: void select_data(); void select(); + + void platformSelectors(); }; void tst_QQuickStyleSelector::initTestCase() @@ -139,6 +141,24 @@ void tst_QQuickStyleSelector::select() QCOMPARE(selector.select(file), expected); } +void tst_QQuickStyleSelector::platformSelectors() +{ + QQuickStyle::setStyle(QDir(dataDirectory()).filePath("PlatformStyle")); + + QQuickStyleSelector selector; + selector.setBaseUrl(dataDirectoryUrl()); + +#if defined(Q_OS_LINUX) + QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+linux/Button.qml").toString()); +#elif defined(Q_OS_MACOS) + QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+macos/Button.qml").toString()); +#elif defined(Q_OS_WIN) + QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/+windows/Button.qml").toString()); +#else + QCOMPARE(selector.select("Button.qml"), testFileUrl("PlatformStyle/Button.qml").toString()); +#endif +} + QTEST_MAIN(tst_QQuickStyleSelector) #include "tst_qquickstyleselector.moc" diff --git a/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf index 836372c9..0ec13258 100644 --- a/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf +++ b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf @@ -4,3 +4,7 @@ Style=Universal [Universal] Background=#444444 Foreground=Red +Font\PixelSize=22 + +[Universal\Font] +Family=Courier diff --git a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp index c6b28be3..51cc5883 100644 --- a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp +++ b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp @@ -55,16 +55,22 @@ void tst_qquickuniversalstyleconf::conf() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + QFont customFont; + customFont.setFamily("Courier"); + customFont.setPixelSize(22); + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - // We specified a custom background color, so the window should have it. + // We specified a custom background color and font, so the window should have them. QCOMPARE(window->property("color").value<QColor>(), QColor("#444444")); + QCOMPARE(window->property("font").value<QFont>(), customFont); - // We specified a custom foreground color, so the label should have it. + // We specified a custom foreground color and font, so the label should have them. QQuickItem *label = window->property("label").value<QQuickItem*>(); QVERIFY(label); QCOMPARE(label->property("color").value<QColor>(), QColor("#E51400")); + QCOMPARE(label->property("font").value<QFont>(), customFont); } QTEST_MAIN(tst_qquickuniversalstyleconf) diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp index 2988c96c..25e118e3 100644 --- a/tests/auto/sanity/tst_sanity.cpp +++ b/tests/auto/sanity/tst_sanity.cpp @@ -314,6 +314,7 @@ void tst_Sanity::attachedObjects_data() QTest::addColumn<QUrl>("url"); addTestRows(&engine, "calendar", "Qt/labs/calendar"); addTestRows(&engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); + addTestRows(&engine, "controls/fusion", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SliderGroove" << "SliderHandle" << "SwitchIndicator"); addTestRows(&engine, "controls/material", "QtQuick/Controls.2/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect" << "CursorDelegate"); addTestRows(&engine, "controls/universal", "QtQuick/Controls.2/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } diff --git a/tests/auto/shared/qtest_quickcontrols.h b/tests/auto/shared/qtest_quickcontrols.h new file mode 100644 index 00000000..d1fe08f6 --- /dev/null +++ b/tests/auto/shared/qtest_quickcontrols.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEST_QUICKCONTROLS_H +#define QTEST_QUICKCONTROLS_H + +#include <QtTest/qtest.h> +#include <QtTest/private/qtestresult_p.h> +#include <QtGui/qguiapplication.h> +#include <QtQml/qqml.h> +#include <QtQuickControls2/qquickstyle.h> + +static QStringList testStyles() +{ + if (QQuickStyle::name().isEmpty()) + return QQuickStyle::availableStyles(); + return QStringList(QQuickStyle::name()); +} + +static int runTests(QObject *testObject, int argc, char *argv[]) +{ + int res = 0; + QTest::qInit(testObject, argc, argv); + const QByteArray testObjectName = QTestResult::currentTestObjectName(); + const QStringList styles = testStyles(); + for (const QString &style : styles) { + qmlClearTypeRegistrations(); + QQuickStyle::setStyle(style); + const QByteArray testName = testObjectName + "::" + style.toLocal8Bit(); + QTestResult::setCurrentTestObject(testName); + res += QTest::qRun(); + } + QTestResult::setCurrentTestObject(testObjectName); + QTest::qCleanup(); + return res; +} + +#define QTEST_QUICKCONTROLS_MAIN(TestCase) \ +QT_BEGIN_NAMESPACE \ +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ +QT_END_NAMESPACE \ +int main(int argc, char *argv[]) \ +{ \ + qputenv("QML_NO_TOUCH_COMPRESSION", "1"); \ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); \ + QGuiApplication app(argc, argv); \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + TestCase tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ + return runTests(&tc, argc, argv); \ +} + +#endif // QTEST_QUICKCONTROLS_H diff --git a/tests/auto/shared/util.pri b/tests/auto/shared/util.pri index 03191511..77c2cc59 100644 --- a/tests/auto/shared/util.pri +++ b/tests/auto/shared/util.pri @@ -1,7 +1,8 @@ -QT += core-private gui-private qml-private quick-private quicktemplates2-private +QT += testlib-private core-private gui-private qml-private quick-private quicktemplates2-private quickcontrols2 HEADERS += $$PWD/visualtestutil.h \ - $$PWD/util.h + $$PWD/util.h \ + $$PWD/qtest_quickcontrols.h SOURCES += $$PWD/visualtestutil.cpp \ $$PWD/util.cpp diff --git a/tests/auto/shared/visualtestutil.cpp b/tests/auto/shared/visualtestutil.cpp index 60b8790d..c5e69812 100644 --- a/tests/auto/shared/visualtestutil.cpp +++ b/tests/auto/shared/visualtestutil.cpp @@ -38,6 +38,8 @@ #include <QtQuick/QQuickItem> #include <QtCore/QDebug> +#include <QtGui/QCursor> +#include <QtCore/QCoreApplication> bool QQuickVisualTestUtil::delegateVisible(QQuickItem *item) { @@ -69,3 +71,24 @@ void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth) } } +void QQuickVisualTestUtil::moveMouseAway(QQuickWindow *window) +{ +#if QT_CONFIG(cursor) // Get the cursor out of the way. + // Using "bottomRight() + QPoint(100, 100)" was causing issues on Ubuntu, + // where the window was positioned at the bottom right corner of the window + // (even after centering the window on the screen), so we use another position. + QCursor::setPos(window->geometry().bottomLeft() + QPoint(0, 10)); +#endif + + // make sure hover events from QQuickWindowPrivate::flushFrameSynchronousEvents() + // do not interfere with the tests + QEvent leave(QEvent::Leave); + QCoreApplication::sendEvent(window, &leave); +} + +void QQuickVisualTestUtil::centerOnScreen(QQuickWindow *window) +{ + const QRect screenGeometry = window->screen()->availableGeometry(); + const QPoint offset = QPoint(window->width() / 2, window->height() / 2); + window->setFramePosition(screenGeometry.center() - offset); +} diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h index 12f955ea..a6b52fef 100644 --- a/tests/auto/shared/visualtestutil.h +++ b/tests/auto/shared/visualtestutil.h @@ -54,6 +54,10 @@ namespace QQuickVisualTestUtil bool delegateVisible(QQuickItem *item); + void centerOnScreen(QQuickWindow *window); + + void moveMouseAway(QQuickWindow *window); + /* Find an item with the specified objectName. If index is supplied then the item must also evaluate the {index} expression equal to index |