diff options
Diffstat (limited to 'tests/auto/customization/tst_customization.cpp')
-rw-r--r-- | tests/auto/customization/tst_customization.cpp | 456 |
1 files changed, 273 insertions, 183 deletions
diff --git a/tests/auto/customization/tst_customization.cpp b/tests/auto/customization/tst_customization.cpp index 4d68d0c5..b20b89d1 100644 --- a/tests/auto/customization/tst_customization.cpp +++ b/tests/auto/customization/tst_customization.cpp @@ -46,17 +46,81 @@ 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" }, + { "MenuItem", QStringList() << "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" } ### TODO: fix and enable deferred execution +}; + class tst_customization : public QQmlDataTest { Q_OBJECT private slots: + void initTestCase(); + void cleanupTestCase(); + void init(); void cleanup(); void creation_data(); void creation(); + void override_data(); + void override(); + void comboPopup(); private: @@ -64,7 +128,7 @@ private: void addHooks(); void removeHooks(); - QObject* createControl(const QString &type, QString *error); + QObject* createControl(const QString &type, const QString &qml, QString *error); QQmlEngine *engine = nullptr; }; @@ -73,6 +137,39 @@ 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) { @@ -86,6 +183,12 @@ extern "C" Q_DECL_EXPORT void qt_addQObject(QObject *object) 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) @@ -94,6 +197,26 @@ extern "C" Q_DECL_EXPORT void qt_removeQObject(QObject *object) 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() @@ -119,14 +242,16 @@ void tst_customization::cleanup() void tst_customization::reset() { + qt_unparentedItemCount = 0; qt_createdQObjects()->clear(); qt_destroyedQObjects()->clear(); + qt_destroyedParentQObjects()->clear(); } -QObject* tst_customization::createControl(const QString &name, QString *error) +QObject* tst_customization::createControl(const QString &name, const QString &qml, QString *error) { QQmlComponent component(engine); - component.setData("import QtQuick.Controls 2.2; " + name.toUtf8() + " { }", QUrl()); + component.setData("import QtQuick 2.9; import QtQuick.Window 2.2; import QtQuick.Controls 2.2; " + name.toUtf8() + " { " + qml.toUtf8() + " }", QUrl()); QObject *obj = component.create(); if (!obj) *error = component.errorString(); @@ -140,188 +265,24 @@ void tst_customization::creation_data() QTest::addColumn<QStringList>("delegates"); // the "empty" style does not contain any delegates - QTest::newRow("empty:AbstractButton") << "empty" << "AbstractButton"<< QStringList(); - QTest::newRow("empty:ApplicationWindow") << "empty" << "ApplicationWindow"<< QStringList(); - QTest::newRow("empty:BusyIndicator") << "empty" << "BusyIndicator"<< QStringList(); - QTest::newRow("empty:Button") << "empty" << "Button"<< QStringList(); - QTest::newRow("empty:CheckBox") << "empty" << "CheckBox" << QStringList(); - QTest::newRow("empty:CheckDelegate") << "empty" << "CheckDelegate" << QStringList(); - QTest::newRow("empty:ComboBox") << "empty" << "ComboBox" << QStringList(); - QTest::newRow("empty:Container") << "empty" << "Container"<< QStringList(); - QTest::newRow("empty:Control") << "empty" << "Control"<< QStringList(); - QTest::newRow("empty:DelayButton") << "empty" << "DelayButton"<< QStringList(); - QTest::newRow("empty:Dial") << "empty" << "Dial" << QStringList(); - QTest::newRow("empty:DialogButtonBox") << "empty" << "DialogButtonBox" << QStringList(); - QTest::newRow("empty:Frame") << "empty" << "Frame"<< QStringList(); - QTest::newRow("empty:GroupBox") << "empty" << "GroupBox"<< QStringList(); - QTest::newRow("empty:ItemDelegate") << "empty" << "ItemDelegate" << QStringList(); - QTest::newRow("empty:Label") << "empty" << "Label"<< QStringList(); - QTest::newRow("empty:MenuItem") << "empty" << "MenuItem"<< QStringList(); - QTest::newRow("empty:MenuSeparator") << "empty" << "MenuSeparator"<< QStringList(); - QTest::newRow("empty:Page") << "empty" << "Page"<< QStringList(); - QTest::newRow("empty:PageIndicator") << "empty" << "PageIndicator"<< QStringList(); - QTest::newRow("empty:Pane") << "empty" << "Pane"<< QStringList(); - QTest::newRow("empty:ProgressBar") << "empty" << "ProgressBar"<< QStringList(); - QTest::newRow("empty:RadioButton") << "empty" << "RadioButton" << QStringList(); - QTest::newRow("empty:RadioDelegate") << "empty" << "RadioDelegate" << QStringList(); - QTest::newRow("empty:RangeSlider") << "empty" << "RangeSlider" << QStringList(); - QTest::newRow("empty:RoundButton") << "empty" << "RoundButton" << QStringList(); - QTest::newRow("empty:ScrollBar") << "empty" << "ScrollBar"<< QStringList(); - QTest::newRow("empty:ScrollIndicator") << "empty" << "ScrollIndicator"<< QStringList(); - QTest::newRow("empty:ScrollView") << "empty" << "ScrollView"<< QStringList(); - QTest::newRow("empty:Slider") << "empty" << "Slider" << QStringList(); - QTest::newRow("empty:SpinBox") << "empty" << "SpinBox" << QStringList(); - QTest::newRow("empty:StackView") << "empty" << "StackView" << QStringList(); - QTest::newRow("empty:SwipeDelegate") << "empty" << "SwipeDelegate" << QStringList(); - QTest::newRow("empty:SwipeView") << "empty" << "SwipeView" << QStringList(); - QTest::newRow("empty:Switch") << "empty" << "Switch" << QStringList(); - QTest::newRow("empty:SwitchDelegate") << "empty" << "SwitchDelegate" << QStringList(); - QTest::newRow("empty:TabBar") << "empty" << "TabBar"<< QStringList(); - QTest::newRow("empty:TabButton") << "empty" << "TabButton"<< QStringList(); - QTest::newRow("empty:TextField") << "empty" << "TextField"<< QStringList(); - QTest::newRow("empty:TextArea") << "empty" << "TextArea"<< QStringList(); - QTest::newRow("empty:ToolBar") << "empty" << "ToolBar"<< QStringList(); - QTest::newRow("empty:ToolButton") << "empty" << "ToolButton"<< QStringList(); - QTest::newRow("empty:ToolSeparator") << "empty" << "ToolSeparator"<< QStringList(); - // QTest::newRow("empty:Tumbler") << "empty" << "Tumbler"<< QStringList(); // ### TODO: fix crash with contentItem-less Tumbler + 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) - QTest::newRow("incomplete:AbstractButton") << "incomplete" << "AbstractButton" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:ApplicationWindow") << "incomplete" << "ApplicationWindow" << (QStringList() << "background"); - QTest::newRow("incomplete:BusyIndicator") << "incomplete" << "BusyIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Button") << "incomplete" << "Button" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:CheckBox") << "incomplete" << "CheckBox" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:CheckDelegate") << "incomplete" << "CheckDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:ComboBox") << "incomplete" << "ComboBox" << (QStringList() << "background" << "contentItem" << "indicator"); // popup not created until needed - QTest::newRow("incomplete:Container") << "incomplete" << "Container" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Control") << "incomplete" << "Control" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:DelayButton") << "incomplete" << "DelayButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Dial") << "incomplete" << "Dial" << (QStringList() << "background" << "contentItem" << "handle"); - QTest::newRow("incomplete:DialogButtonBox") << "incomplete" << "DialogButtonBox" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Frame") << "incomplete" << "Frame"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:GroupBox") << "incomplete" << "GroupBox"<< (QStringList() << "background" << "contentItem" << "label"); - QTest::newRow("incomplete:ItemDelegate") << "incomplete" << "ItemDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Label") << "incomplete" << "Label" << (QStringList() << "background"); - QTest::newRow("incomplete:MenuItem") << "incomplete" << "MenuItem" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:MenuSeparator") << "incomplete" << "MenuSeparator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Page") << "incomplete" << "Page" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:PageIndicator") << "incomplete" << "PageIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Pane") << "incomplete" << "Pane" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ProgressBar") << "incomplete" << "ProgressBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:RadioButton") << "incomplete" << "RadioButton" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:RadioDelegate") << "incomplete" << "RadioDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:RangeSlider") << "incomplete" << "RangeSlider" << (QStringList() << "background" << "contentItem" << "first.handle" << "second.handle"); - QTest::newRow("incomplete:RoundButton") << "incomplete" << "RoundButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ScrollBar") << "incomplete" << "ScrollBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ScrollIndicator") << "incomplete" << "ScrollIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ScrollView") << "incomplete" << "ScrollView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Slider") << "incomplete" << "Slider" << (QStringList() << "background" << "contentItem" << "handle"); - QTest::newRow("incomplete:SpinBox") << "incomplete" << "SpinBox" << (QStringList() << "background" << "contentItem" << "up.indicator" << "down.indicator"); - QTest::newRow("incomplete:StackView") << "incomplete" << "StackView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:SwipeDelegate") << "incomplete" << "SwipeDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:SwipeView") << "incomplete" << "SwipeView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Switch") << "incomplete" << "Switch" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:SwitchDelegate") << "incomplete" << "SwitchDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("incomplete:TabBar") << "incomplete" << "TabBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:TabButton") << "incomplete" << "TabButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:TextField") << "incomplete" << "TextField" << (QStringList() << "background"); - QTest::newRow("incomplete:TextArea") << "incomplete" << "TextArea" << (QStringList() << "background"); - QTest::newRow("incomplete:ToolBar") << "incomplete" << "ToolBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ToolButton") << "incomplete" << "ToolButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:ToolSeparator") << "incomplete" << "ToolSeparator"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("incomplete:Tumbler") << "incomplete" << "Tumbler"<< (QStringList() << "background" << "contentItem"); + 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 - QTest::newRow("simple:AbstractButton") << "simple" << "AbstractButton" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("simple:ApplicationWindow") << "simple" << "ApplicationWindow" << (QStringList() << "background"); - QTest::newRow("simple:BusyIndicator") << "simple" << "BusyIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Button") << "simple" << "Button" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:CheckBox") << "simple" << "CheckBox" << (QStringList() << "contentItem" << "indicator"); - QTest::newRow("simple:CheckDelegate") << "simple" << "CheckDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("simple:ComboBox") << "simple" << "ComboBox" << (QStringList() << "background" << "contentItem" << "indicator"); // popup not created until needed - QTest::newRow("simple:Container") << "simple" << "Container" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Control") << "simple" << "Control" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:DelayButton") << "simple" << "DelayButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Dial") << "simple" << "Dial" << (QStringList() << "background" << "handle"); - QTest::newRow("simple:DialogButtonBox") << "simple" << "DialogButtonBox" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Frame") << "simple" << "Frame"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:GroupBox") << "simple" << "GroupBox"<< (QStringList() << "background" << "contentItem" << "label"); - QTest::newRow("simple:ItemDelegate") << "simple" << "ItemDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Label") << "simple" << "Label" << (QStringList() << "background"); - QTest::newRow("simple:MenuItem") << "simple" << "MenuItem" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("simple:MenuSeparator") << "simple" << "MenuSeparator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Page") << "simple" << "Page" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:PageIndicator") << "simple" << "PageIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Pane") << "simple" << "Pane" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ProgressBar") << "simple" << "ProgressBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:RadioButton") << "simple" << "RadioButton" << (QStringList() << "contentItem" << "indicator"); - QTest::newRow("simple:RadioDelegate") << "simple" << "RadioDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("simple:RangeSlider") << "simple" << "RangeSlider" << (QStringList() << "background" << "first.handle" << "second.handle"); - QTest::newRow("simple:RoundButton") << "simple" << "RoundButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ScrollBar") << "simple" << "ScrollBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ScrollIndicator") << "simple" << "ScrollIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ScrollView") << "simple" << "ScrollView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Slider") << "simple" << "Slider" << (QStringList() << "background" << "handle"); - QTest::newRow("simple:SpinBox") << "simple" << "SpinBox" << (QStringList() << "background" << "contentItem" << "up.indicator" << "down.indicator"); - QTest::newRow("simple:StackView") << "simple" << "StackView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:SwipeDelegate") << "simple" << "SwipeDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:SwipeView") << "simple" << "SwipeView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Switch") << "simple" << "Switch" << (QStringList() << "contentItem" << "indicator"); - QTest::newRow("simple:SwitchDelegate") << "simple" << "SwitchDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("simple:TabBar") << "simple" << "TabBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:TabButton") << "simple" << "TabButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:TextField") << "simple" << "TextField" << (QStringList() << "background"); - QTest::newRow("simple:TextArea") << "simple" << "TextArea" << (QStringList() << "background"); - QTest::newRow("simple:ToolBar") << "simple" << "ToolBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ToolButton") << "simple" << "ToolButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:ToolSeparator") << "simple" << "ToolSeparator"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("simple:Tumbler") << "simple" << "Tumbler"<< (QStringList() << "background" << "contentItem"); + 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 - QTest::newRow("override:AbstractButton") << "override" << "AbstractButton" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:ApplicationWindow") << "override" << "ApplicationWindow" << (QStringList() << "background"); - QTest::newRow("override:BusyIndicator") << "override" << "BusyIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Button") << "override" << "Button" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:CheckBox") << "override" << "CheckBox" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:CheckDelegate") << "override" << "CheckDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:ComboBox") << "override" << "ComboBox" << (QStringList() << "background" << "contentItem" << "indicator"); // popup not created until needed - QTest::newRow("override:Container") << "override" << "Container" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Control") << "override" << "Control" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:DelayButton") << "override" << "DelayButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Dial") << "override" << "Dial" << (QStringList() << "background" << "contentItem" << "handle"); - QTest::newRow("override:DialogButtonBox") << "override" << "DialogButtonBox" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Frame") << "override" << "Frame"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:GroupBox") << "override" << "GroupBox"<< (QStringList() << "background" << "contentItem" << "label"); - QTest::newRow("override:ItemDelegate") << "override" << "ItemDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Label") << "override" << "Label" << (QStringList() << "background"); - QTest::newRow("override:MenuItem") << "override" << "MenuItem" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:MenuSeparator") << "override" << "MenuSeparator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Page") << "override" << "Page" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:PageIndicator") << "override" << "PageIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Pane") << "override" << "Pane" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ProgressBar") << "override" << "ProgressBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:RadioButton") << "override" << "RadioButton" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:RadioDelegate") << "override" << "RadioDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:RangeSlider") << "override" << "RangeSlider" << (QStringList() << "background" << "contentItem" << "first.handle" << "second.handle"); - QTest::newRow("override:RoundButton") << "override" << "RoundButton" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ScrollBar") << "override" << "ScrollBar" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ScrollIndicator") << "override" << "ScrollIndicator" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ScrollView") << "override" << "ScrollView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Slider") << "override" << "Slider" << (QStringList() << "background" << "contentItem" << "handle"); - QTest::newRow("override:SpinBox") << "override" << "SpinBox" << (QStringList() << "background" << "contentItem" << "up.indicator" << "down.indicator"); - QTest::newRow("override:StackView") << "override" << "StackView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:SwipeDelegate") << "override" << "SwipeDelegate" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:SwipeView") << "override" << "SwipeView" << (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Switch") << "override" << "Switch" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:SwitchDelegate") << "override" << "SwitchDelegate" << (QStringList() << "background" << "contentItem" << "indicator"); - QTest::newRow("override:TabBar") << "override" << "TabBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:TabButton") << "override" << "TabButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:TextField") << "override" << "TextField" << (QStringList() << "background"); - QTest::newRow("override:TextArea") << "override" << "TextArea" << (QStringList() << "background"); - QTest::newRow("override:ToolBar") << "override" << "ToolBar"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ToolButton") << "override" << "ToolButton"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:ToolSeparator") << "override" << "ToolSeparator"<< (QStringList() << "background" << "contentItem"); - QTest::newRow("override:Tumbler") << "override" << "Tumbler"<< (QStringList() << "background" << "contentItem"); + for (const ControlInfo &control : ControlInfos) + QTest::newRow(qPrintable("override:" + control.type)) << "override" << control.type << control.delegates; } void tst_customization::creation() @@ -333,27 +294,156 @@ void tst_customization::creation() QQuickStyle::setStyle(testFile("styles/" + style)); QString error; - QScopedPointer<QObject> control(createControl(type, &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)) { - if (!delegate.contains("-")) - delegate.append("-" + style); + QStringList properties = delegate.split(".", QString::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("override:Tumbler", "TODO", Abort); + 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 = QStringList() << "Default" << "Material" << "Universal"; // ### TODO: QQuickStyle::availableStyles(); + 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); + + const QString testStyle = testFile("styles/" + style); + if (QDir(testStyle).exists()) + QQuickStyle::setStyle(testStyle); + else + 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(".", QString::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()) { + for (QString delegate : qAsConst(delegates)) { + if (!delegate.contains("-")) + delegate.append("-" + nonDeferred); + delegate.prepend(type.toLower() + "-"); + QVERIFY2(qt_destroyedQObjects()->removeOne(delegate), qPrintable(delegate + " was not destroyed as expected")); + } + } + + QVERIFY2(qt_destroyedQObjects()->isEmpty(), qPrintable("unexpectedly destroyed: " + qt_destroyedQObjects->join(", "))); } void tst_customization::comboPopup() |