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 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | class QObject; |
17 | struct 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 | |
23 | template<typename T> |
24 | class QQmlListProperty { |
25 | public: |
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 | |
112 | private: |
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 | |
180 | class QQmlEngine; |
181 | class QQmlListReferencePrivate; |
182 | class Q_QML_EXPORT QQmlListReference |
183 | { |
184 | public: |
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 | |
225 | private: |
226 | friend class QQmlListReferencePrivate; |
227 | QQmlListReferencePrivate* d; |
228 | }; |
229 | |
230 | namespace QtPrivate { |
231 | template<typename T> |
232 | inline constexpr bool IsQmlListType<QQmlListProperty<T>> = true; |
233 | } |
234 | |
235 | QT_END_NAMESPACE |
236 | |
237 | Q_DECLARE_METATYPE(QQmlListReference) |
238 | |
239 | #endif // QQMLLIST_H |
240 | |