1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLLIST_H
5#define QQMLLIST_H
6
7#include <QtQml/qtqmlglobal.h>
8
9#include <QtCore/qcontainerinfo.h>
10#include <QtCore/qlist.h>
11#include <QtCore/qmetatype.h>
12#include <QtCore/qvariant.h>
13
14QT_BEGIN_NAMESPACE
15
16class QObject;
17struct QMetaObject;
18
19#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Append")
20#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT Q_CLASSINFO("QML.ListPropertyAssignBehavior", "ReplaceIfNotDefault")
21#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Replace")
22
23template<typename T>
24class QQmlListProperty {
25public:
26 using value_type = T*;
27
28 using AppendFunction = void (*)(QQmlListProperty<T> *, T *);
29 using CountFunction = qsizetype (*)(QQmlListProperty<T> *);
30 using AtFunction = T *(*)(QQmlListProperty<T> *, qsizetype);
31 using ClearFunction = void (*)(QQmlListProperty<T> *);
32 using ReplaceFunction = void (*)(QQmlListProperty<T> *, qsizetype, T *);
33 using RemoveLastFunction = void (*)(QQmlListProperty<T> *);
34
35 QQmlListProperty() = default;
36
37 QQmlListProperty(QObject *o, QList<T *> *list)
38 : object(o), data(list), append(qlist_append), count(qlist_count), at(qlist_at),
39 clear(qlist_clear), replace(qlist_replace), removeLast(qlist_removeLast)
40 {}
41
42 QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
43 ClearFunction r )
44 : object(o),
45 data(d),
46 append(a),
47 count(c),
48 at(t),
49 clear(r),
50 replace((a && c && t && r) ? qslow_replace : nullptr),
51 removeLast((a && c && t && r) ? qslow_removeLast : nullptr)
52 {}
53
54 QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
55 ClearFunction r, ReplaceFunction s, RemoveLastFunction p)
56 : object(o),
57 data(d),
58 append(a),
59 count(c),
60 at(t),
61 clear((!r && p && c) ? qslow_clear : r),
62 replace((!s && a && c && t && (r || p)) ? qslow_replace : s),
63 removeLast((!p && a && c && t && r) ? qslow_removeLast : p)
64 {}
65
66 QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction a)
67 : object(o), data(d), count(c), at(a)
68 {}
69
70 bool operator==(const QQmlListProperty &o) const {
71 return object == o.object &&
72 data == o.data &&
73 append == o.append &&
74 count == o.count &&
75 at == o.at &&
76 clear == o.clear &&
77 replace == o.replace &&
78 removeLast == o.removeLast;
79 }
80
81 QObject *object = nullptr;
82 void *data = nullptr;
83
84 AppendFunction append = nullptr;
85 CountFunction count = nullptr;
86 AtFunction at = nullptr;
87 ClearFunction clear = nullptr;
88 ReplaceFunction replace = nullptr;
89 RemoveLastFunction removeLast = nullptr;
90
91 template<typename List>
92 List toList()
93 {
94 if constexpr (std::is_same_v<List, QList<T *>>) {
95 if (append == qlist_append)
96 return *static_cast<QList<T *> *>(data);
97 }
98
99 const qsizetype size = count(this);
100
101 List result;
102 if constexpr (QContainerInfo::has_reserve_v<List>)
103 result.reserve(size);
104
105 static_assert(QContainerInfo::has_push_back_v<List>);
106 for (qsizetype i = 0; i < size; ++i)
107 result.push_back(at(this, i));
108
109 return result;
110 }
111
112private:
113 static void qlist_append(QQmlListProperty *p, T *v) {
114 static_cast<QList<T *> *>(p->data)->append(v);
115 }
116 static qsizetype qlist_count(QQmlListProperty *p) {
117 return static_cast<QList<T *> *>(p->data)->size();
118 }
119 static T *qlist_at(QQmlListProperty *p, qsizetype idx) {
120 return static_cast<QList<T *> *>(p->data)->at(idx);
121 }
122 static void qlist_clear(QQmlListProperty *p) {
123 return static_cast<QList<T *> *>(p->data)->clear();
124 }
125 static void qlist_replace(QQmlListProperty *p, qsizetype idx, T *v) {
126 return static_cast<QList<T *> *>(p->data)->replace(idx, v);
127 }
128 static void qlist_removeLast(QQmlListProperty *p) {
129 return static_cast<QList<T *> *>(p->data)->removeLast();
130 }
131
132 static void qslow_replace(QQmlListProperty<T> *list, qsizetype idx, T *v)
133 {
134 const qsizetype length = list->count(list);
135 if (idx < 0 || idx >= length)
136 return;
137
138 QVector<T *> stash;
139 if (list->clear != qslow_clear) {
140 stash.reserve(length);
141 for (qsizetype i = 0; i < length; ++i)
142 stash.append(i == idx ? v : list->at(list, i));
143 list->clear(list);
144 for (T *item : std::as_const(stash))
145 list->append(list, item);
146 } else {
147 stash.reserve(length - idx - 1);
148 for (qsizetype i = length - 1; i > idx; --i) {
149 stash.append(list->at(list, i));
150 list->removeLast(list);
151 }
152 list->removeLast(list);
153 list->append(list, v);
154 while (!stash.isEmpty())
155 list->append(list, stash.takeLast());
156 }
157 }
158
159 static void qslow_clear(QQmlListProperty<T> *list)
160 {
161 for (qsizetype i = 0, end = list->count(list); i < end; ++i)
162 list->removeLast(list);
163 }
164
165 static void qslow_removeLast(QQmlListProperty<T> *list)
166 {
167 const qsizetype length = list->count(list) - 1;
168 if (length < 0)
169 return;
170 QVector<T *> stash;
171 stash.reserve(length);
172 for (qsizetype i = 0; i < length; ++i)
173 stash.append(list->at(list, i));
174 list->clear(list);
175 for (T *item : std::as_const(stash))
176 list->append(list, item);
177 }
178};
179
180class QQmlEngine;
181class QQmlListReferencePrivate;
182class Q_QML_EXPORT QQmlListReference
183{
184public:
185 QQmlListReference();
186
187#if QT_DEPRECATED_SINCE(6, 4)
188 QT_DEPRECATED_X("Drop the QQmlEngine* argument")
189 QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine);
190
191 QT_DEPRECATED_X("Drop the QQmlEngine* argument")
192 QQmlListReference(QObject *o, const char *property, [[maybe_unused]] QQmlEngine *engine);
193#endif
194
195 explicit QQmlListReference(const QVariant &variant);
196 QQmlListReference(QObject *o, const char *property);
197 QQmlListReference(const QQmlListReference &);
198 QQmlListReference &operator=(const QQmlListReference &);
199 ~QQmlListReference();
200
201 bool isValid() const;
202
203 QObject *object() const;
204 const QMetaObject *listElementType() const;
205
206 bool canAppend() const;
207 bool canAt() const;
208 bool canClear() const;
209 bool canCount() const;
210 bool canReplace() const;
211 bool canRemoveLast() const;
212
213 bool isManipulable() const;
214 bool isReadable() const;
215
216 bool append(QObject *) const;
217 QObject *at(qsizetype) const;
218 bool clear() const;
219 qsizetype count() const;
220 qsizetype size() const { return count(); }
221 bool replace(qsizetype, QObject *) const;
222 bool removeLast() const;
223 bool operator==(const QQmlListReference &other) const {return d == other.d;}
224
225private:
226 friend class QQmlListReferencePrivate;
227 QQmlListReferencePrivate* d;
228};
229
230namespace QtPrivate {
231template<typename T>
232inline constexpr bool IsQmlListType<QQmlListProperty<T>> = true;
233}
234
235QT_END_NAMESPACE
236
237Q_DECLARE_METATYPE(QQmlListReference)
238
239#endif // QQMLLIST_H
240

source code of qtdeclarative/src/qml/qml/qqmllist.h