aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quickcontrols2/customization/tst_customization.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quickcontrols2/customization/tst_customization.cpp')
-rw-r--r--tests/auto/quickcontrols2/customization/tst_customization.cpp534
1 files changed, 0 insertions, 534 deletions
diff --git a/tests/auto/quickcontrols2/customization/tst_customization.cpp b/tests/auto/quickcontrols2/customization/tst_customization.cpp
deleted file mode 100644
index 02c75978..00000000
--- a/tests/auto/quickcontrols2/customization/tst_customization.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-/****************************************************************************
-**
-** 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 <QtCore/private/qhooks_p.h>
-#include <QtCore/qregularexpression.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlcomponent.h>
-#include <QtQuick/qquickitem.h>
-#include <QtQuick/qquickwindow.h>
-#include <QtQuickControls2/qquickstyle.h>
-#include <QtQuickControls2/private/qquickstyle_p.h>
-#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
-#include "../shared/visualtestutil.h"
-
-using namespace QQuickVisualTestUtil;
-
-struct ControlInfo
-{
- QString type;
- QStringList delegates;
-};
-
-static const ControlInfo ControlInfos[] = {
- { "AbstractButton", QStringList() << "background" << "contentItem" << "indicator" },
- { "ApplicationWindow", QStringList() << "background" },
- { "BusyIndicator", QStringList() << "background" << "contentItem" },
- { "Button", QStringList() << "background" << "contentItem" },
- { "CheckBox", QStringList() << "contentItem" << "indicator" },
- { "CheckDelegate", QStringList() << "background" << "contentItem" << "indicator" },
- { "ComboBox", QStringList() << "background" << "contentItem" << "indicator" }, // popup not created until needed
- { "Container", QStringList() << "background" << "contentItem" },
- { "Control", QStringList() << "background" << "contentItem" },
- { "DelayButton", QStringList() << "background" << "contentItem" },
- { "Dial", QStringList() << "background" << "handle" },
- { "Dialog", QStringList() << "background" << "contentItem" },
- { "DialogButtonBox", QStringList() << "background" << "contentItem" },
- { "Drawer", QStringList() << "background" << "contentItem" },
- { "Frame", QStringList() << "background" << "contentItem" },
- { "GroupBox", QStringList() << "background" << "contentItem" << "label" },
- { "ItemDelegate", QStringList() << "background" << "contentItem" },
- { "Label", QStringList() << "background" },
- { "Menu", QStringList() << "background" << "contentItem" },
- { "MenuBar", QStringList() << "background" << "contentItem" },
- { "MenuBarItem", QStringList() << "background" << "contentItem" },
- { "MenuItem", QStringList() << "arrow" << "background" << "contentItem" << "indicator" },
- { "MenuSeparator", QStringList() << "background" << "contentItem" },
- { "Page", QStringList() << "background" << "contentItem" },
- { "PageIndicator", QStringList() << "background" << "contentItem" },
- { "Pane", QStringList() << "background" << "contentItem" },
- { "Popup", QStringList() << "background" << "contentItem" },
- { "ProgressBar", QStringList() << "background" << "contentItem" },
- { "RadioButton", QStringList() << "contentItem" << "indicator" },
- { "RadioDelegate", QStringList() << "background" << "contentItem" << "indicator" },
- { "RangeSlider", QStringList() << "background" << "first.handle" << "second.handle" },
- { "RoundButton", QStringList() << "background" << "contentItem" },
- { "ScrollBar", QStringList() << "background" << "contentItem" },
- { "ScrollIndicator", QStringList() << "background" << "contentItem" },
- { "ScrollView", QStringList() << "background" },
- { "Slider", QStringList() << "background" << "handle" },
- { "SpinBox", QStringList() << "background" << "contentItem" << "up.indicator" << "down.indicator" },
- { "StackView", QStringList() << "background" << "contentItem" },
- { "SwipeDelegate", QStringList() << "background" << "contentItem" },
- { "SwipeView", QStringList() << "background" << "contentItem" },
- { "Switch", QStringList() << "contentItem" << "indicator" },
- { "SwitchDelegate", QStringList() << "background" << "contentItem" << "indicator" },
- { "TabBar", QStringList() << "background" << "contentItem" },
- { "TabButton", QStringList() << "background" << "contentItem" },
- { "TextField", QStringList() << "background" },
- { "TextArea", QStringList() << "background" },
- { "ToolBar", QStringList() << "background" << "contentItem" },
- { "ToolButton", QStringList() << "background" << "contentItem" },
- { "ToolSeparator", QStringList() << "background" << "contentItem" },
- { "ToolTip", QStringList() << "background" << "contentItem" },
- { "Tumbler", QStringList() << "background" << "contentItem" }
-};
-
-class tst_customization : public QQmlDataTest
-{
- Q_OBJECT
-
-private slots:
- void initTestCase() override;
- void cleanupTestCase();
-
- void init();
- void cleanup();
-
- void creation_data();
- void creation();
-
- void override_data();
- void override();
-
- void comboPopup();
-
-private:
- void reset();
- void addHooks();
- void removeHooks();
-
- QObject* createControl(const QString &type, const QString &qml, QString *error);
-
- QQmlEngine *engine = nullptr;
-};
-
-typedef QHash<QObject *, QString> QObjectNameHash;
-Q_GLOBAL_STATIC(QObjectNameHash, qt_objectNames)
-Q_GLOBAL_STATIC(QStringList, qt_createdQObjects)
-Q_GLOBAL_STATIC(QStringList, qt_destroyedQObjects)
-Q_GLOBAL_STATIC(QStringList, qt_destroyedParentQObjects)
-static int qt_unparentedItemCount = 0;
-
-class ItemParentListener : public QQuickItem
-{
- Q_OBJECT
-
-public:
- ItemParentListener()
- {
- m_slotIndex = metaObject()->indexOfSlot("onParentChanged()");
- m_signalIndex = QMetaObjectPrivate::signalIndex(QMetaMethod::fromSignal(&QQuickItem::parentChanged));
- }
-
- int signalIndex() const { return m_signalIndex; }
- int slotIndex() const { return m_slotIndex; }
-
-public slots:
- void onParentChanged()
- {
- const QQuickItem *item = qobject_cast<QQuickItem *>(sender());
- if (!item)
- return;
-
- if (!item->parentItem())
- ++qt_unparentedItemCount;
- }
-
-private:
- int m_slotIndex;
- int m_signalIndex;
-};
-static ItemParentListener *qt_itemParentListener = nullptr;
-
-extern "C" Q_DECL_EXPORT void qt_addQObject(QObject *object)
-{
- // objectName is not set at construction time
- QObject::connect(object, &QObject::objectNameChanged, [object](const QString &objectName) {
- QString oldObjectName = qt_objectNames()->value(object);
- if (!oldObjectName.isEmpty())
- qt_createdQObjects()->removeOne(oldObjectName);
- // Only track object names from our QML files,
- // not e.g. contentItem object names (like "ApplicationWindow").
- if (objectName.contains("-")) {
- qt_createdQObjects()->append(objectName);
- qt_objectNames()->insert(object, objectName);
- }
- });
-
- if (qt_itemParentListener) {
- static const int signalIndex = qt_itemParentListener->signalIndex();
- static const int slotIndex = qt_itemParentListener->slotIndex();
- QMetaObject::connect(object, signalIndex, qt_itemParentListener, slotIndex);
- }
-}
-
-extern "C" Q_DECL_EXPORT void qt_removeQObject(QObject *object)
-{
- QString objectName = object->objectName();
- if (!objectName.isEmpty())
- qt_destroyedQObjects()->append(objectName);
- qt_objectNames()->remove(object);
-
- QObject *parent = object->parent();
- if (parent) {
- QString parentName = parent->objectName();
- if (!parentName.isEmpty())
- qt_destroyedParentQObjects()->append(parentName);
- }
-}
-
-void tst_customization::initTestCase()
-{
- QQmlDataTest::initTestCase();
-
- qt_itemParentListener = new ItemParentListener;
-}
-
-void tst_customization::cleanupTestCase()
-{
- delete qt_itemParentListener;
- qt_itemParentListener = nullptr;
-}
-
-void tst_customization::init()
-{
- engine = new QQmlEngine(this);
- engine->addImportPath(testFile("styles"));
-
- qtHookData[QHooks::AddQObject] = reinterpret_cast<quintptr>(&qt_addQObject);
- qtHookData[QHooks::RemoveQObject] = reinterpret_cast<quintptr>(&qt_removeQObject);
-}
-
-void tst_customization::cleanup()
-{
- qtHookData[QHooks::AddQObject] = 0;
- qtHookData[QHooks::RemoveQObject] = 0;
-
- delete engine;
- engine = nullptr;
-
- qmlClearTypeRegistrations();
-
- reset();
-}
-
-void tst_customization::reset()
-{
- qt_unparentedItemCount = 0;
- qt_createdQObjects()->clear();
- qt_destroyedQObjects()->clear();
- qt_destroyedParentQObjects()->clear();
-}
-
-QObject* tst_customization::createControl(const QString &name, const QString &qml, QString *error)
-{
- QQmlComponent component(engine);
- component.setData("import QtQuick; import QtQuick.Window; import QtQuick.Controls; " + name.toUtf8() + " { " + qml.toUtf8() + " }", QUrl());
- QObject *obj = component.create();
- if (!obj)
- *error = component.errorString();
- return obj;
-}
-
-void tst_customization::creation_data()
-{
- QTest::addColumn<QString>("style");
- QTest::addColumn<QString>("type");
- QTest::addColumn<QStringList>("delegates");
-
- // the "empty" style does not contain any delegates
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("empty:" + control.type)) << "empty" << control.type << QStringList();
-
- // the "incomplete" style is missing bindings to the delegates (must be created regardless)
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("incomplete:" + control.type)) << "incomplete" << control.type << control.delegates;
-
- // the "identified" style has IDs in the delegates (prevents deferred execution)
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("identified:" + control.type)) << "identified" << control.type << control.delegates;
-
- // the "simple" style simulates a proper style and contains bindings to/in delegates
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("simple:" + control.type)) << "simple" << control.type << control.delegates;
-
- // the "override" style overrides all delegates in the "simple" style
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("override:" + control.type)) << "override" << control.type << control.delegates;
-}
-
-void tst_customization::creation()
-{
- QFETCH(QString, style);
- QFETCH(QString, type);
- QFETCH(QStringList, delegates);
-
- QQuickStyle::setStyle(style);
-
- QString error;
- QScopedPointer<QObject> control(createControl(type, "", &error));
- QVERIFY2(control, qPrintable(error));
-
- QByteArray templateType = "QQuick" + type.toUtf8();
- QVERIFY2(control->inherits(templateType), qPrintable(type + " does not inherit " + templateType + " (" + control->metaObject()->className() + ")"));
-
- // <control>-<style>
- QString controlName = type.toLower() + "-" + style;
- QCOMPARE(control->objectName(), controlName);
- QVERIFY2(qt_createdQObjects()->removeOne(controlName), qPrintable(controlName + " was not created as expected"));
-
- for (QString delegate : qAsConst(delegates)) {
- QStringList properties = delegate.split(".", Qt::SkipEmptyParts);
-
- // <control>-<delegate>-<style>(-<override>)
- delegate.append("-" + style);
- delegate.prepend(type.toLower() + "-");
-
- QVERIFY2(qt_createdQObjects()->removeOne(delegate), qPrintable(delegate + " was not created as expected"));
-
- // verify that the delegate instance has the expected object name
- // in case of grouped properties, we must query the properties step by step
- QObject *instance = control.data();
- while (!properties.isEmpty()) {
- QString property = properties.takeFirst();
- instance = instance->property(property.toUtf8()).value<QObject *>();
- QVERIFY2(instance, qPrintable("property was null: " + property));
- }
- QCOMPARE(instance->objectName(), delegate);
- }
-
- QEXPECT_FAIL("identified:ComboBox", "ComboBox::popup with an ID is created at construction time", Continue);
-
- QVERIFY2(qt_createdQObjects()->isEmpty(), qPrintable("unexpectedly created: " + qt_createdQObjects->join(", ")));
- QVERIFY2(qt_destroyedQObjects()->isEmpty(), qPrintable("unexpectedly destroyed: " + qt_destroyedQObjects->join(", ") + " were unexpectedly destroyed"));
-
- QVERIFY2(qt_destroyedParentQObjects()->isEmpty(), qPrintable("delegates/children of: " + qt_destroyedParentQObjects->join(", ") + " were unexpectedly destroyed"));
-}
-
-void tst_customization::override_data()
-{
- QTest::addColumn<QString>("style");
- QTest::addColumn<QString>("type");
- QTest::addColumn<QStringList>("delegates");
- QTest::addColumn<QString>("nonDeferred");
- QTest::addColumn<bool>("identify");
-
- // NOTE: delegates with IDs prevent deferred execution
-
- // default delegates with IDs, override with custom delegates with no IDs
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("identified:" + control.type)) << "identified" << control.type << control.delegates << "identified" << false;
-
- // default delegates with no IDs, override with custom delegates with IDs
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("simple:" + control.type)) << "simple" << control.type << control.delegates << "" << true;
-
- // default delegates with IDs, override with custom delegates with IDs
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable("overidentified:" + control.type)) << "identified" << control.type << control.delegates << "identified" << true;
-
-#ifndef Q_OS_MACOS // QTBUG-65671
-
- // test that the built-in styles don't have undesired IDs in their delegates
- const QStringList styles = QQuickStylePrivate::builtInStyles();
- for (const QString &style : styles) {
- for (const ControlInfo &control : ControlInfos)
- QTest::newRow(qPrintable(style + ":" + control.type)) << style << control.type << control.delegates << "" << false;
- }
-
-#endif
-}
-
-void tst_customization::override()
-{
- QFETCH(QString, style);
- QFETCH(QString, type);
- QFETCH(QStringList, delegates);
- QFETCH(QString, nonDeferred);
- QFETCH(bool, identify);
-
- QQuickStyle::setStyle(style);
-
- QString qml;
- qml += QString("objectName: '%1-%2-override'; ").arg(type.toLower()).arg(style);
- for (const QString &delegate : delegates) {
- QString id = identify ? QString("id: %1;").arg(delegate) : QString();
- qml += QString("%1: Item { %2 objectName: '%3-%1-%4-override' } ").arg(delegate).arg(id.replace(".", "")).arg(type.toLower()).arg(style);
- }
-
- QString error;
- QScopedPointer<QObject> control(createControl(type, qml, &error));
- QVERIFY2(control, qPrintable(error));
-
- // If there are no intentional IDs in the default delegates nor in the overridden custom
- // delegates, no item should get un-parented during the creation process. An item being
- // unparented means that a delegate got destroyed, so there must be an internal ID in one
- // of the delegates in the tested style.
- if (!identify && nonDeferred.isEmpty()) {
- QEXPECT_FAIL("Universal:ApplicationWindow", "ApplicationWindow.qml contains an intentionally unparented FocusRectangle", Continue);
- QCOMPARE(qt_unparentedItemCount, 0);
- }
-
- // <control>-<style>-override
- QString controlName = type.toLower() + "-" + style + "-override";
- QCOMPARE(control->objectName(), controlName);
- QVERIFY2(qt_createdQObjects()->removeOne(controlName), qPrintable(controlName + " was not created as expected"));
-
- for (QString delegate : qAsConst(delegates)) {
- QStringList properties = delegate.split(".", Qt::SkipEmptyParts);
-
- // <control>-<delegate>-<style>(-override)
- delegate.append("-" + style);
- delegate.prepend(type.toLower() + "-");
-
- if (!nonDeferred.isEmpty())
- QVERIFY2(qt_createdQObjects()->removeOne(delegate), qPrintable(delegate + " was not created as expected"));
-
- delegate.append("-override");
- QVERIFY2(qt_createdQObjects()->removeOne(delegate), qPrintable(delegate + " was not created as expected"));
-
- // verify that the delegate instance has the expected object name
- // in case of grouped properties, we must query the properties step by step
- QObject *instance = control.data();
- while (!properties.isEmpty()) {
- QString property = properties.takeFirst();
- instance = instance->property(property.toUtf8()).value<QObject *>();
- QVERIFY2(instance, qPrintable("property was null: " + property));
- }
- QCOMPARE(instance->objectName(), delegate);
- }
-
- QEXPECT_FAIL("identified:ComboBox", "ComboBox::popup with an ID is created at construction time", Continue);
- QEXPECT_FAIL("overidentified:ComboBox", "ComboBox::popup with an ID is created at construction time", Continue);
- QVERIFY2(qt_createdQObjects()->isEmpty(), qPrintable("unexpectedly created: " + qt_createdQObjects->join(", ")));
-
- if (!nonDeferred.isEmpty()) {
- // There were items for which deferred execution was not possible.
- for (QString delegateName : qAsConst(delegates)) {
- if (!delegateName.contains("-"))
- delegateName.append("-" + nonDeferred);
- delegateName.prepend(type.toLower() + "-");
-
- const int delegateIndex = qt_destroyedQObjects()->indexOf(delegateName);
- QVERIFY2(delegateIndex == -1, qPrintable(delegateName + " was unexpectedly destroyed"));
-
- const auto controlChildren = control->children();
- const auto childIt = std::find_if(controlChildren.constBegin(), controlChildren.constEnd(), [delegateName](const QObject *child) {
- return child->objectName() == delegateName;
- });
- // We test other delegates (like the background) here, so make sure we don't end up with XPASSes by using the wrong delegate.
- if (delegateName.contains(QLatin1String("handle"))) {
- QEXPECT_FAIL("identified:RangeSlider", "For some reason, items that are belong to grouped properties fail here", Abort);
- QEXPECT_FAIL("overidentified:RangeSlider", "For some reason, items that are belong to grouped properties fail here", Abort);
- }
- if (delegateName.contains(QLatin1String("indicator"))) {
- QEXPECT_FAIL("identified:SpinBox", "For some reason, items that are belong to grouped properties fail here", Abort);
- QEXPECT_FAIL("overidentified:SpinBox", "For some reason, items that are belong to grouped properties fail here", Abort);
- }
- QVERIFY2(childIt != controlChildren.constEnd(), qPrintable(QString::fromLatin1(
- "Expected delegate \"%1\" to still be a QObject child of \"%2\"").arg(delegateName).arg(controlName)));
-
- const auto *delegate = qobject_cast<QQuickItem*>(*childIt);
- // Ensure that the item is hidden, etc.
- QVERIFY(delegate);
- QCOMPARE(delegate->isVisible(), false);
- QCOMPARE(delegate->parentItem(), nullptr);
- }
- }
-
- QVERIFY2(qt_destroyedQObjects()->isEmpty(), qPrintable("unexpectedly destroyed: " + qt_destroyedQObjects->join(", ")));
-}
-
-void tst_customization::comboPopup()
-{
- QQuickStyle::setStyle("simple");
-
- {
- // test that ComboBox::popup is created when accessed
- QQmlComponent component(engine);
- component.setData("import QtQuick.Controls; ComboBox { }", QUrl());
- QScopedPointer<QQuickItem> comboBox(qobject_cast<QQuickItem *>(component.create()));
- QVERIFY(comboBox);
-
- QVERIFY(!qt_createdQObjects()->contains("combobox-popup-simple"));
-
- QObject *popup = comboBox->property("popup").value<QObject *>();
- QVERIFY(popup);
- QVERIFY(qt_createdQObjects()->contains("combobox-popup-simple"));
- }
-
- reset();
-
- {
- // test that ComboBox::popup is created when it becomes visible
- QQuickWindow window;
- window.resize(300, 300);
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
- QQmlComponent component(engine);
- component.setData("import QtQuick.Controls; ComboBox { }", QUrl());
- QScopedPointer<QQuickItem> comboBox(qobject_cast<QQuickItem *>(component.create()));
- QVERIFY(comboBox);
-
- comboBox->setParentItem(window.contentItem());
- QVERIFY(!qt_createdQObjects()->contains("combobox-popup-simple"));
-
- QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
- QVERIFY(qt_createdQObjects()->contains("combobox-popup-simple"));
- }
-
- reset();
-
- {
- // test that ComboBox::popup is completed upon component completion (if appropriate)
- QQmlComponent component(engine);
- component.setData("import QtQuick; import QtQuick.Controls; ComboBox { id: control; contentItem: Item { visible: !control.popup.visible } popup: Popup { property bool wasCompleted: false; Component.onCompleted: wasCompleted = true } }", QUrl());
- QScopedPointer<QQuickItem> comboBox(qobject_cast<QQuickItem *>(component.create()));
- QVERIFY(comboBox);
-
- QObject *popup = comboBox->property("popup").value<QObject *>();
- QVERIFY(popup);
- QCOMPARE(popup->property("wasCompleted"), QVariant(true));
- }
-}
-
-QTEST_MAIN(tst_customization)
-
-#include "tst_customization.moc"