Allow DelegateModel-based views to support multiple delegate types

This patch adds a specific abstract QQmlComponent subclass,
QQmlAbstractDelegateComponent, and a default implementation,
DelegateChooser, that, together with the type DelegateChoice
allows determining the delegate type by role and/or index.

The patch also adds QQmlAbstractDelegateComponent support
to QQmlTableInstanceModel, that is a simplified version of
the delegate model, currently only used in the new table view.

DelegateChoosers are intended to behave just like Components
in the context of the view. This means that they can be declared
outside of the view, and also in separate files, and the same
delegate component can be used at the same time in multiple views.

[ChangeLog][QtQuick][Item Views] Added a DelegateChooser Component
to host DelegateChoice instances to choose different delegates in
an Item View (e.g. TableView) depending on model roles.

Done-with: Michael Brasser <michael.brasser@live.com>
Task-number: QTBUG-26681
Change-Id: Ibe24a31daf9142c8a9ff45ef6c65da0aec8a14dc
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Paolo Angelelli 2018-05-09 17:16:59 +02:00 committed by Shawn Rutledge
parent 36c6b727c5
commit 607ced5bfd
28 changed files with 1144 additions and 30 deletions

View File

@ -0,0 +1,8 @@
TEMPLATE = app
QT += quick qml
SOURCES += main.cpp
RESOURCES += qml.qrc ../shared/shared.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/quick/delegatechooser
INSTALLS += target

View File

@ -0,0 +1,145 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples 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.12
import QtQml.Models 2.12
import QtQuick.Layouts 1.12
import Qt.labs.qmlmodels 1.0
Rectangle {
visible: true
width: 640
height: 640
ListModel {
id: listModel
ListElement { dataType: "rect"; color: "green" }
ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" }
ListElement { dataType: "rect"; color: "green" }
ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
}
ListModel {
id: listModel2
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "green" }
ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" }
ListElement { dataType: "rect"; color: "green" }
ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "rect"; color: "lightsteelblue" }
ListElement { dataType: "rect"; color: "fuchsia" }
ListElement { dataType: "rect"; color: "lime" }
}
DelegateChooser {
id: fancyDelegate
role: "dataType"
DelegateChoice {
roleValue: "rect"
delegate: DelegateChooser {
DelegateChoice {
row: 0
Rectangle {
width: parent.width
height: 50
color: "red"
border.color: "black"
border.width: 1
}
}
DelegateChoice {
Rectangle {
width: parent.width
height: 50
color: model.color
border.color: "black"
border.width: 1
}
}
}
}
DelegateChoice {
roleValue: "image"
delegate: Image {
width: parent.width
height: 100
source: model.source
fillMode: Image.PreserveAspectFit
}
}
}
Item {
anchors.fill: parent
id: ite
RowLayout {
ListView {
Layout.preferredHeight: ite.height
Layout.preferredWidth: ite.width * 0.5
model: listModel
delegate: fancyDelegate
}
ListView {
Layout.preferredHeight: ite.height
Layout.preferredWidth: ite.width * 0.5
model: listModel2
delegate: fancyDelegate
}
}
}
}

View File

@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples 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$
**
****************************************************************************/
#include "../shared/shared.h"
DECLARATIVE_EXAMPLE_MAIN(delegatechooser)

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>delegatechooser.qml</file>
</qresource>
</RCC>

View File

@ -25,6 +25,7 @@ SUBDIRS = quick-accessibility \
imageresponseprovider \
window \
particles \
delegatechooser \
shapes
#OpenGL Support Required

View File

@ -4,7 +4,8 @@ SUBDIRS += \
builtins \
qtqml \
folderlistmodel \
models
models \
labsmodels
qtHaveModule(sql): SUBDIRS += localstorage
qtConfig(settings): SUBDIRS += settings

View File

@ -0,0 +1,11 @@
CXX_MODULE = qml
TARGET = labsmodelsplugin
TARGETPATH = Qt/labs/qmlmodels
IMPORT_VERSION = 1.0
SOURCES += \
plugin.cpp
QT = qml-private
load(qml_plugin)

View File

@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** 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-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <private/qqmlmodelsmodule_p.h>
QT_BEGIN_NAMESPACE
/*!
\qmlmodule Qt.labs.qmlmodels 1.0
\title Qt QML Models experimental QML Types
\ingroup qmlmodules
\brief Provides QML experimental types for data models
\since 5.12
This QML module contains experimental QML types related to data models.
To use the types in this module, import the module with the following line:
\code
import Qt.labs.qmlmodels 1.0
\endcode
*/
//![class decl]
class QtQmlLabsModelsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQmlLabsModelsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.qmlmodels"));
Q_UNUSED(uri);
QQmlModelsModule::defineLabsModule();
qmlRegisterModule(uri, 1, 0);
}
};
//![class decl]
QT_END_NAMESPACE
#include "plugin.moc"

View File

@ -0,0 +1,3 @@
module Qt.labs.qmlmodels
plugin labsmodelsplugin
classname QtQmlLabsModelsPlugin

View File

@ -44,6 +44,7 @@
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmldelegatecomponent_p.h>
#define COMPILE_EXCEPTION(token, desc) \
{ \
@ -804,13 +805,21 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
auto *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
Q_ASSERT(tr);
if (tr->type.isValid()) {
if (tr->type.metaObject() == &QQmlComponent::staticMetaObject)
continue;
} else if (tr->compilationUnit) {
if (tr->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
continue;
}
const QMetaObject *firstMetaObject = nullptr;
if (tr->type.isValid())
firstMetaObject = tr->type.metaObject();
else if (tr->compilationUnit)
firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
// 1: test for QQmlComponent
if (firstMetaObject && firstMetaObject == &QQmlComponent::staticMetaObject)
continue;
// 2: test for QQmlAbstractDelegateComponent
while (firstMetaObject && firstMetaObject != &QQmlAbstractDelegateComponent::staticMetaObject)
firstMetaObject = firstMetaObject->superClass();
if (firstMetaObject)
continue;
// if here, not a QQmlComponent or a QQmlAbstractDelegateComponent, so needs wrapping
QQmlPropertyData *pd = nullptr;
if (binding->propertyNameIndex != quint32(0)) {

View File

@ -88,7 +88,7 @@ public:
void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
void incubateObject(
virtual void incubateObject(
QQmlIncubator *incubationTask,
QQmlComponent *component,
QQmlEngine *engine,

View File

@ -0,0 +1,285 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** 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-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qqmldelegatecomponent_p.h"
#include <QtQml/private/qqmladaptormodel_p.h>
QT_BEGIN_NAMESPACE
QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
: QQmlComponent(parent)
{
}
QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
{
}
QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
{
if (!adaptorModel)
return QVariant();
return adaptorModel->value(adaptorModel->indexAt(row, column), role);
}
/*!
\qmltype DelegateChoice
\instantiates QQmlDelegateChoice
\inqmlmodule Qt.labs.qmlmodels
\brief Encapsulates a delegate and when to use it
The DelegateChoice type wraps a delegate and defines the circumstances
in which it should be chosen.
DelegateChoices can be nested inside a DelegateChooser.
\sa DelegateChooser
*/
/*!
\qmlproperty string QtQml.Models::DelegateChoice::roleValue
This property holds the value used to match the role data for the role provided by \l DefaultDelegateChooser::role.
*/
QVariant QQmlDelegateChoice::roleValue() const
{
return m_value;
}
void QQmlDelegateChoice::setRoleValue(const QVariant &value)
{
if (m_value == value)
return;
m_value = value;
emit roleValueChanged();
emit changed();
}
/*!
\qmlproperty index QtQml.Models::DelegateChoice::row
This property holds the value used to match the row value of model elements.
With models that have only the index property (and thus only one column), this property
should be intended as index, and set to the desired index value.
\note Setting both row and index has undefined behavior. The two are equivalent and only
one should be used.
\sa QtQml.Models::DelegateChoice::index
*/
/*!
\qmlproperty index QtQml.Models::DelegateChoice::index
This property holds the value used to match the index value of model elements.
This is effectively an alias for \l QtQml.Models::DelegateChoice::row
\sa QtQml.Models::DelegateChoice::row
*/
int QQmlDelegateChoice::row() const
{
return m_row;
}
void QQmlDelegateChoice::setRow(int r)
{
if (m_row == r)
return;
m_row = r;
emit rowChanged();
emit indexChanged();
emit changed();
}
/*!
\qmlproperty index QtQml.Models::DelegateChoice::column
This property holds the value used to match the column value of model elements.
*/
int QQmlDelegateChoice::column() const
{
return m_column;
}
void QQmlDelegateChoice::setColumn(int c)
{
if (m_column == c)
return;
m_column = c;
emit columnChanged();
emit changed();
}
QQmlComponent *QQmlDelegateChoice::delegate() const
{
return m_delegate;
}
/*!
\qmlproperty Component QtQml.Models::DelegateChoice::delegate
This property holds the delegate to use if this choice matches the model item.
*/
void QQmlDelegateChoice::setDelegate(QQmlComponent *delegate)
{
if (m_delegate == delegate)
return;
QQmlAbstractDelegateComponent *adc = static_cast<QQmlAbstractDelegateComponent *>(m_delegate);
if (adc)
disconnect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
m_delegate = delegate;
adc = static_cast<QQmlAbstractDelegateComponent *>(delegate);
if (adc)
connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
emit delegateChanged();
emit changed();
}
bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
{
if (!m_value.isValid() && m_row < 0 && m_column < 0)
return true;
const bool roleMatched = (m_value.isValid()) ? value == m_value : true;
const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
return roleMatched && rowMatched && columnMatched;
}
/*!
\qmltype QQmlDelegateChooser
\instantiates QQmlDelegateChooser
\inqmlmodule Qt.labs.qmlmodels
\brief Allows a view to use different delegates for different types of items in the model.
The DelegateChooser is a special \l Component type intended for those scenarios where a Component is required
by a view and used as a delegate.
DelegateChooser encapsulates a set of \l DelegateChoices.
These choices are used determine the delegate that will be instantiated for each
item in the model.
The selection of the choice is performed based on the value that a model item has for \l role,
and also based on index.
\note This type is intended to transparently work only with TableView and any DelegateModel-based view.
Views (including user-defined views) that aren't internally based on a DelegateModel need to explicitly support
this type of component to make it function as described.
\sa DelegateChoice
*/
/*!
\qmlproperty string QtQml.Models::DelegateChooser::role
This property holds the role used to determine the delegate for a given model item.
\sa DelegateChoice
*/
void QQmlDelegateChooser::setRole(const QString &role)
{
if (m_role == role)
return;
m_role = role;
emit roleChanged();
}
/*!
\qmlproperty list<DelegateChoice> QtQml.Models::DelegateChooser::choices
\default
The list of DelegateChoices for the chooser.
The list is treated as an ordered list, where the first DelegateChoice to match
will be used be a view.
It should not generally be necessary to refer to the \c choices property,
as it is the default property for DefaultDelegateChooser and thus all child items are
automatically assigned to this property.
*/
QQmlListProperty<QQmlDelegateChoice> QQmlDelegateChooser::choices()
{
return QQmlListProperty<QQmlDelegateChoice>(this, nullptr,
QQmlDelegateChooser::choices_append,
QQmlDelegateChooser::choices_count,
QQmlDelegateChooser::choices_at,
QQmlDelegateChooser::choices_clear);
}
void QQmlDelegateChooser::choices_append(QQmlListProperty<QQmlDelegateChoice> *prop, QQmlDelegateChoice *choice)
{
QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
q->m_choices.append(choice);
connect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
q->delegateChanged();
}
int QQmlDelegateChooser::choices_count(QQmlListProperty<QQmlDelegateChoice> *prop)
{
QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
return q->m_choices.count();
}
QQmlDelegateChoice *QQmlDelegateChooser::choices_at(QQmlListProperty<QQmlDelegateChoice> *prop, int index)
{
QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
return q->m_choices.at(index);
}
void QQmlDelegateChooser::choices_clear(QQmlListProperty<QQmlDelegateChoice> *prop)
{
QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
for (QQmlDelegateChoice *choice : q->m_choices)
disconnect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
q->m_choices.clear();
q->delegateChanged();
}
QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const
{
QVariant v;
if (!m_role.isNull())
v = value(adaptorModel, row, column, m_role);
if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
v = value(adaptorModel, row, column, QStringLiteral("modelData"));
if (v.isValid())
v = v.toMap().value(m_role);
}
// loop through choices, finding first one that fits
for (int i = 0; i < m_choices.count(); ++i) {
const QQmlDelegateChoice *choice = m_choices.at(i);
if (choice->match(row, column, v))
return choice->delegate();
}
return nullptr;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,155 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 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.LGPL3 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-3.0.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 (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** 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-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QQMLDELEGATECOMPONENT_P_H
#define QQMLDELEGATECOMPONENT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qtqmlglobal_p.h>
#include <qqmlcomponent.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
// TODO: consider making QQmlAbstractDelegateComponent public API
class QQmlAbstractDelegateComponentPrivate;
class QQmlAdaptorModel;
class Q_QML_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
{
Q_OBJECT
public:
QQmlAbstractDelegateComponent(QObject *parent = nullptr);
~QQmlAbstractDelegateComponent() override;
virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
signals:
void delegateChanged();
protected:
QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
private:
Q_DECLARE_PRIVATE(QQmlAbstractDelegateComponent)
Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
};
class Q_QML_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged)
Q_PROPERTY(int index READ row WRITE setRow NOTIFY indexChanged)
Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
public:
QVariant roleValue() const;
void setRoleValue(const QVariant &roleValue);
int row() const;
void setRow(int r);
int column() const;
void setColumn(int c);
QQmlComponent *delegate() const;
void setDelegate(QQmlComponent *delegate);
virtual bool match(int row, int column, const QVariant &value) const;
signals:
void roleValueChanged();
void rowChanged();
void indexChanged();
void columnChanged();
void delegateChanged();
void changed();
private:
QVariant m_value;
int m_row = -1;
int m_column = -1;
QQmlComponent *m_delegate = nullptr;
};
class Q_QML_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
{
Q_OBJECT
Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
Q_PROPERTY(QQmlListProperty<QQmlDelegateChoice> choices READ choices CONSTANT)
Q_CLASSINFO("DefaultProperty", "choices")
public:
QString role() const { return m_role; }
void setRole(const QString &role);
virtual QQmlListProperty<QQmlDelegateChoice> choices();
static void choices_append(QQmlListProperty<QQmlDelegateChoice> *, QQmlDelegateChoice *);
static int choices_count(QQmlListProperty<QQmlDelegateChoice> *);
static QQmlDelegateChoice *choices_at(QQmlListProperty<QQmlDelegateChoice> *, int);
static void choices_clear(QQmlListProperty<QQmlDelegateChoice> *);
QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = -1) const override;
signals:
void roleChanged();
private:
QString m_role;
QList<QQmlDelegateChoice *> m_choices;
};
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlDelegateChoice)
QML_DECLARE_TYPE(QQmlDelegateChooser)
#endif // QQMLDELEGATECOMPONENT_P_H

View File

@ -38,6 +38,7 @@
****************************************************************************/
#include "qqmldelegatemodel_p_p.h"
#include "qqmldelegatecomponent_p.h"
#include <QtQml/qqmlinfo.h>
@ -200,7 +201,8 @@ QQmlDelegateModelParts::QQmlDelegateModelParts(QQmlDelegateModel *parent)
*/
QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt)
: m_cacheMetaType(nullptr)
: m_delegateChooser(nullptr)
, m_cacheMetaType(nullptr)
, m_context(ctxt)
, m_parts(nullptr)
, m_filterGroup(QStringLiteral("items"))
@ -454,6 +456,8 @@ void QQmlDelegateModel::setModel(const QVariant &model)
The delegate provides a template defining each item instantiated by a view.
The index is exposed as an accessible \c index property. Properties of the
model are also available depending upon the type of \l {qml-data-models}{Data Model}.
\sa DelegateComponent
*/
QQmlComponent *QQmlDelegateModel::delegate() const
{
@ -468,22 +472,25 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated.");
return;
}
if (d->m_delegate == delegate)
return;
bool wasValid = d->m_delegate != nullptr;
d->m_delegate.setObject(delegate, this);
d->m_delegateValidated = false;
if (wasValid && d->m_complete) {
for (int i = 1; i < d->m_groupCount; ++i) {
QQmlDelegateModelGroupPrivate::get(d->m_groups[i])->changeSet.remove(
0, d->m_compositor.count(Compositor::Group(i)));
if (d->m_delegateChooser)
QObject::disconnect(d->m_delegateChooserChanged);
d->m_delegateChooser = nullptr;
if (delegate) {
QQmlAbstractDelegateComponent *adc =
qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
if (adc) {
d->m_delegateChooser = adc;
d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
[d](){ d->delegateChanged(); });
}
}
if (d->m_complete && d->m_delegate) {
for (int i = 1; i < d->m_groupCount; ++i) {
QQmlDelegateModelGroupPrivate::get(d->m_groups[i])->changeSet.insert(
0, d->m_compositor.count(Compositor::Group(i)));
}
}
d->emitChanges();
d->delegateChanged(d->m_delegate, wasValid);
}
/*!
@ -1042,7 +1049,18 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
cacheItem->incubationTask->forceCompletion();
}
} else if (!cacheItem->object) {
QQmlContext *creationContext = m_delegate->creationContext();
QQmlComponent *delegate = nullptr;
if (m_delegateChooser) {
QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
do {
delegate = chooser->delegate(&m_adaptorModel, index);
chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
} while (chooser);
}
if (!delegate)
delegate = m_delegate;
QQmlContext *creationContext = delegate->creationContext();
cacheItem->scriptRef += 1;
@ -1067,10 +1085,10 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
}
}
QQmlComponentPrivate *cp = QQmlComponentPrivate::get(m_delegate);
QQmlComponentPrivate *cp = QQmlComponentPrivate::get(delegate);
cp->incubateObject(
cacheItem->incubationTask,
m_delegate,
delegate,
m_context->engine(),
ctxt,
QQmlContextData::get(m_context));
@ -1568,6 +1586,32 @@ void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet,
emit q->countChanged();
}
void QQmlDelegateModelPrivate::delegateChanged(bool add, bool remove)
{
Q_Q(QQmlDelegateModel);
if (!m_complete)
return;
if (m_transaction) {
qmlWarning(q) << QQmlDelegateModel::tr("The delegates of a DelegateModel cannot be changed within onUpdated.");
return;
}
if (remove) {
for (int i = 1; i < m_groupCount; ++i) {
QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(
0, m_compositor.count(Compositor::Group(i)));
}
}
if (add) {
for (int i = 1; i < m_groupCount; ++i) {
QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(
0, m_compositor.count(Compositor::Group(i)));
}
}
emitChanges();
}
void QQmlDelegateModelPrivate::emitChanges()
{
if (m_transaction || !m_complete || !m_context || !m_context->isValid())

View File

@ -67,7 +67,6 @@ QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
class QQmlChangeSet;
class QQmlComponent;
class QQuickPackage;
class QQmlV4Function;
class QQmlDelegateModelGroup;

View File

@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE
typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
class QQmlAbstractDelegateComponent;
class Q_QML_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
{
@ -303,6 +304,7 @@ public:
void itemsChanged(const QVector<Compositor::Change> &changes);
void emitChanges();
void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
void delegateChanged(bool add = true, bool remove = true);
bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
@ -319,6 +321,8 @@ public:
QQmlAdaptorModel m_adaptorModel;
QQmlListCompositor m_compositor;
QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
QQmlAbstractDelegateComponent *m_delegateChooser;
QMetaObject::Connection m_delegateChooserChanged;
QQmlDelegateModelItemMetaType *m_cacheMetaType;
QPointer<QQmlContext> m_context;
QQmlDelegateModelParts *m_parts;

View File

@ -44,6 +44,7 @@
#endif
#if QT_CONFIG(qml_delegate_model)
#include <private/qqmldelegatemodel_p.h>
#include <private/qqmldelegatecomponent_p.h>
#endif
#include <private/qqmlobjectmodel_p.h>
@ -67,4 +68,13 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
}
void QQmlModelsModule::defineLabsModule()
{
const char uri[] = "Qt.labs.qmlmodels";
qmlRegisterUncreatableType<QQmlAbstractDelegateComponent>(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent."));
qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
}
QT_END_NAMESPACE

View File

@ -59,6 +59,7 @@ class Q_QML_PRIVATE_EXPORT QQmlModelsModule
{
public:
static void defineModule();
static void defineLabsModule();
};
QT_END_NAMESPACE

View File

@ -38,7 +38,7 @@
****************************************************************************/
#include "qqmltableinstancemodel_p.h"
#include "qqmltableinstancemodel_p.h"
#include "qqmldelegatecomponent_p.h"
#include <QtCore/QTimer>
@ -107,6 +107,23 @@ QQmlTableInstanceModel::~QQmlTableInstanceModel()
drainReusableItemsPool(0);
}
QQmlComponent *QQmlTableInstanceModel::resolveDelegate(int index)
{
QQmlComponent *delegate = nullptr;
if (m_delegateChooser) {
const int row = m_adaptorModel.rowAt(index);
const int column = m_adaptorModel.columnAt(index);
QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
do {
delegate = chooser->delegate(&m_adaptorModel, row, column);
chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
} while (chooser);
}
if (!delegate)
delegate = m_delegate;
return delegate;
}
QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
{
// Check if an item for the given index is already loaded and ready
@ -114,7 +131,7 @@ QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
if (modelItem)
return modelItem;
QQmlComponent *delegate = m_delegate;
QQmlComponent *delegate = resolveDelegate(index);
// Check if the pool contains an item that can be reused
modelItem = takeFromReusableItemsPool(delegate);
@ -478,6 +495,17 @@ QQmlComponent *QQmlTableInstanceModel::delegate() const
void QQmlTableInstanceModel::setDelegate(QQmlComponent *delegate)
{
if (m_delegate == delegate)
return;
m_delegateChooser = nullptr;
if (delegate) {
QQmlAbstractDelegateComponent *adc =
qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
if (adc)
m_delegateChooser = adc;
}
m_delegate = delegate;
}

View File

@ -57,6 +57,7 @@
QT_BEGIN_NAMESPACE
class QQmlTableInstanceModel;
class QQmlAbstractDelegateComponent;
class QQmlTableInstanceModelIncubationTask : public QQDMIncubationTask
{
@ -128,8 +129,11 @@ Q_SIGNALS:
void itemReused(int index, QObject *object);
private:
QQmlComponent *m_delegate = nullptr;
QQmlComponent *resolveDelegate(int index);
QQmlAdaptorModel m_adaptorModel;
QQmlAbstractDelegateComponent *m_delegateChooser = nullptr;
QQmlComponent *m_delegate = nullptr;
QPointer<QQmlContext> m_qmlContext;
QQmlDelegateModelItemMetaType *m_metaType;

View File

@ -34,11 +34,13 @@ qtConfig(qml-list-model) {
qtConfig(qml-delegate-model) {
SOURCES += \
$$PWD/qqmldelegatemodel.cpp
$$PWD/qqmldelegatemodel.cpp \
$$PWD/qqmldelegatecomponent.cpp
HEADERS += \
$$PWD/qqmldelegatemodel_p.h \
$$PWD/qqmldelegatemodel_p_p.h
$$PWD/qqmldelegatemodel_p_p.h \
$$PWD/qqmldelegatecomponent_p.h
}
qtConfig(qml-animation) {

View File

@ -1005,6 +1005,11 @@ int QQmlAdaptorModel::columnAt(int index) const
return count <= 0 ? -1 : index / count;
}
int QQmlAdaptorModel::indexAt(int row, int column) const
{
return column * rowCount() + row;
}
void QQmlAdaptorModel::objectDestroyed(QObject *)
{
setModel(QVariant(), nullptr, nullptr);

View File

@ -123,6 +123,7 @@ public:
int columnCount() const;
int rowAt(int index) const;
int columnAt(int index) const;
int indexAt(int row, int column) const;
inline bool adaptsAim() const { return qobject_cast<QAbstractItemModel *>(object()); }
inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); }

View File

@ -0,0 +1,106 @@
/****************************************************************************
**
** Copyright (C) 2018 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.12
import QtQml.Models 2.12
import Qt.labs.qmlmodels 1.0
ListView {
width: 400
height: 400
model: ListModel {
ListElement { dataType: "rect"; color: "red" }
ListElement { dataType: "image"; source: "logo.png" }
ListElement { dataType: "text"; text: "Hello" }
ListElement { dataType: "text"; text: "World" }
ListElement { dataType: "rect"; color: "green" }
ListElement { dataType: "image"; source: "logo.png" }
ListElement { dataType: "rect"; color: "blue" }
ListElement { dataType: "" }
}
delegate: DelegateChooser {
role: "dataType"
DelegateChoice {
roleValue: "image"
delegate: Image {
width: parent.width
height: 50
fillMode: Image.PreserveAspectFit
source: model.source
}
}
DelegateChoice {
roleValue: "rect"
delegate: Rectangle {
width: parent.width
height: 50
color: model.color
}
}
DelegateChoice {
roleValue: "text"
delegate: Text {
width: parent.width
height: 50
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: model.text
}
}
DelegateChoice {
delegate: Item {
width: parent.width
height: 50
}
}
}
}

View File

@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2018 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.12
import QtQml.Models 2.12
import Qt.labs.qmlmodels 1.0
ListView {
width: 400
height: 400
model: 8
delegate: DelegateChooser {
DelegateChoice {
index: 0
delegate: Item {
property string choiceType: "1"
width: parent.width
height: 50
}
}
DelegateChoice {
index: 1
delegate: Item {
property string choiceType: "2"
width: parent.width
height: 50
}
}
DelegateChoice {
index: 2
delegate: Item {
property string choiceType: "3"
width: parent.width
height: 50
}
}
DelegateChoice {
index: 5
delegate: Item {
property string choiceType: "3"
width: parent.width
height: 50
}
}
DelegateChoice {
delegate: Item {
property string choiceType: "4"
width: parent.width
height: 50
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1 +1,2 @@
CONFIG += qmltestcase
DISTFILES += $$PWD/tst_listview.qml $$files($$PWD/data/*.qml)

View File

@ -50,6 +50,7 @@
import QtQuick 2.1
import QtTest 1.1
import "data"
Item {
id: top
@ -204,6 +205,14 @@ Item {
ListElement { component: "data/asynclistviewloader.qml" }
}
MultiDelegate {
id: multiDelegate
}
MultiDelegate2 {
id: multiDelegate2
}
TestCase {
name: "ListView"
when: windowShown
@ -363,5 +372,47 @@ Item {
function test_viewWithAction() {
compare(viewWithActionModel.funcResult, "one")
}
function test_multipleDelegates_data() {
return [
{ y: 25, type: "Rectangle", value: "red" },
{ y: 75, type: "Image", value: Qt.resolvedUrl("data/logo.png") },
{ y: 125, type: "Text", value: "Hello" },
{ y: 175, type: "Text", value: "World" },
{ y: 225, type: "Rectangle", value: "green" },
{ y: 275, type: "Image", value: Qt.resolvedUrl("data/logo.png") },
{ y: 325, type: "Rectangle", value: "blue" },
{ y: 375, type: "Item", value: "" }
]
}
function test_multipleDelegates(row) {
var delegate = multiDelegate.itemAt(10, row.y)
verify(delegate.toString().includes(row.type))
switch (row.type) {
case "Rectangle": verify(Qt.colorEqual(delegate.color, row.value)); break
case "Text": compare(delegate.text, row.value); break
case "Image": compare(delegate.source, row.value); break
case "Item": break
}
}
function test_multipleDelegates2_data() {
return [
{ y: 25, type: "1" },
{ y: 75, type: "2" },
{ y: 125, type: "3" },
{ y: 175, type: "4" },
{ y: 225, type: "4" },
{ y: 275, type: "3" },
{ y: 325, type: "4" },
{ y: 375, type: "4" }
]
}
function test_multipleDelegates2(row) {
var delegate = multiDelegate2.itemAt(10, row.y)
compare(delegate.choiceType, row.type)
}
}
}