aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldmlistaccessordata.cpp
blob: bfd353771c5cc4054b53d7ac41f37fafe73e4748 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include <private/qqmldmlistaccessordata_p.h>

QT_BEGIN_NAMESPACE

QQmlDMListAccessorData::QQmlDMListAccessorData(
        const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
        VDMListDelegateDataType *dataType,
        int index, int row, int column, const QVariant &value)
    : QQmlDelegateModelItem(metaType, dataType, index, row, column)
    , cachedData(value)
{
    QObjectPrivate::get(this)->metaObject = dataType;
    dataType->addref();
}

QQmlDMListAccessorData::~QQmlDMListAccessorData()
{
    QObjectPrivate *d = QObjectPrivate::get(this);
    static_cast<VDMListDelegateDataType *>(d->metaObject)->release();
    d->metaObject = nullptr;
}

void QQmlDMListAccessorData::setModelData(const QVariant &data) {
    if (data == cachedData)
        return;

    cachedData = data;
    cachedDataClean = false;
    static_cast<const VDMListDelegateDataType *>(QObjectPrivate::get(this)->metaObject)
            ->emitAllSignals(this);
}

void QQmlDMListAccessorData::setValue(const QString &role, const QVariant &value)
{
    // Used only for initialization of the cached data. Does not have to emit change signals.
    Q_ASSERT(!cachedDataClean);

    if (role == QLatin1String("modelData") || role.isEmpty())
        cachedData = value;
    else
        VDMListDelegateDataType::setValue(&cachedData, role, value);
}

bool QQmlDMListAccessorData::resolveIndex(const QQmlAdaptorModel &model, int idx)
{
    if (index == -1) {
        index = idx;
        setModelData(model.list.at(idx));
        emit modelIndexChanged();
        return true;
    } else {
        return false;
    }
}

void VDMListDelegateDataType::emitAllSignals(QQmlDMListAccessorData *accessor) const
{
    for (int i = propertyOffset, end = propertyCount(); i != end; ++i)
        QMetaObject::activate(accessor, this, i - propertyOffset, nullptr);
    emit accessor->modelDataChanged();
}

int VDMListDelegateDataType::metaCall(
        QObject *object, QMetaObject::Call call, int id, void **arguments)
{
    Q_ASSERT(qobject_cast<QQmlDMListAccessorData *>(object));
    QQmlDMListAccessorData *accessor = static_cast<QQmlDMListAccessorData *>(object);

    switch (call) {
    case QMetaObject::ReadProperty: {
        if (id < propertyOffset)
            break;

        QVariant *result = static_cast<QVariant *>(arguments[0]);
        const QByteArray name = property(id).name();
        const QVariant data = accessor->index == -1
                ? accessor->modelData()
                : model->list.at(accessor->index);
        *result = value(&data, name);
        return -1;
    }
    case QMetaObject::WriteProperty: {
        if (id < propertyOffset)
            break;

        const QVariant &argument = *static_cast<QVariant *>(arguments[0]);
        const QByteArray name = property(id).name();
        QVariant data = accessor->index == -1
                ? accessor->modelData()
                : model->list.at(accessor->index);
        if (argument == value(&data, name))
            return -1;
        setValue(&data, name, argument);
        if (accessor->index == -1) {
            accessor->cachedData = data;
            accessor->cachedDataClean = false;
        } else {
            model->list.set(accessor->index, data);
        }
        QMetaObject::activate(accessor, this, id - propertyOffset, nullptr);
        emit accessor->modelDataChanged();
        return -1;
    }
    default:
        break;
    }

    return accessor->qt_metacall(call, id, arguments);
}

int VDMListDelegateDataType::createProperty(const char *name, const char *)
{
    const int propertyIndex = propertyCount() - propertyOffset;

    // We use QVariant because the types may be different in the different objects.
    QQmlAdaptorModelEngineData::addProperty(
            &builder, propertyIndex, name, QByteArrayLiteral("QVariant"));

    metaObject.reset(builder.toMetaObject());
    *static_cast<QMetaObject *>(this) = *metaObject;
    return propertyIndex + propertyOffset;
}

QMetaObject *VDMListDelegateDataType::toDynamicMetaObject(QObject *object)
{
    if (const QQmlRefPointer<QQmlContextData> &contextData
            = static_cast<QQmlDMListAccessorData *>(object)->contextData) {
        if (contextData->contextObject() == object) {
            // We are using context properties. There should be a propertyCache so that row and
            // column are hidden. We shall also return the static metaObject in that case.

            if (!propertyCache) {
                propertyCache = QQmlPropertyCache::createStandalone(
                        &QQmlDMListAccessorData::staticMetaObject, model->modelItemRevision);
                if (QQmlData *ddata = QQmlData::get(object, true))
                    ddata->propertyCache = propertyCache;
            }

            // ### Qt 7: Return const from toDynamicMetaObject() and drop the const_cast.
            return const_cast<QMetaObject *>(&QQmlDMListAccessorData::staticMetaObject);
        }
    }

    // If the context object is not the model object, we are using required properties.
    // In that case, create any extra properties.
    QQmlDMListAccessorData *data = static_cast<QQmlDMListAccessorData *>(object);
    if (!data->cachedDataClean) {
        createMissingProperties(&data->cachedData);
        data->cachedDataClean = true;
    }
    return this;
}

QT_END_NAMESPACE