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 QQMLLISTCOMPOSITOR_P_H
5#define QQMLLISTCOMPOSITOR_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qglobal.h>
19#include <QtCore/qvector.h>
20
21#include <private/qqmlchangeset_p.h>
22
23#include <QtCore/qdebug.h>
24
25QT_BEGIN_NAMESPACE
26
27class Q_AUTOTEST_EXPORT QQmlListCompositor
28{
29public:
30 enum { MinimumGroupCount = 3, MaximumGroupCount = 11 };
31
32 enum Group
33 {
34 Cache = 0,
35 Default = 1,
36 Persisted = 2
37 };
38
39 enum Flag
40 {
41 CacheFlag = 1 << Cache,
42 DefaultFlag = 1 << Default,
43 PersistedFlag = 1 << Persisted,
44 PrependFlag = 0x10000000,
45 AppendFlag = 0x20000000,
46 UnresolvedFlag = 0x40000000,
47 MovedFlag = 0x80000000,
48 GroupMask = ~(PrependFlag | AppendFlag | UnresolvedFlag | MovedFlag | CacheFlag)
49 };
50
51 class Range
52 {
53 public:
54 Range() : next(this), previous(this) {}
55 Range(Range *next, void *list, int index, int count, uint flags)
56 : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) {
57 next->previous = this; previous->next = this; }
58
59 Range *next;
60 Range *previous;
61 void *list = nullptr;
62 int index = 0;
63 int count = 0;
64 uint flags = 0;
65
66 inline int start() const { return index; }
67 inline int end() const { return index + count; }
68
69 inline int groups() const { return flags & GroupMask; }
70
71 inline bool inGroup() const { return flags & GroupMask; }
72 inline bool inCache() const { return flags & CacheFlag; }
73 inline bool inGroup(int group) const { return flags & (1 << group); }
74 inline bool isUnresolved() const { return flags & UnresolvedFlag; }
75
76 inline bool prepend() const { return flags & PrependFlag; }
77 inline bool append() const { return flags & AppendFlag; }
78 };
79
80 class Q_AUTOTEST_EXPORT iterator
81 {
82 public:
83 inline iterator() = default;
84 inline iterator(Range *range, int offset, Group group, int groupCount);
85
86 bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; }
87 bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; }
88
89 bool operator ==(Group group) const { return range->flags & (1 << group); }
90 bool operator !=(Group group) const { return !(range->flags & (1 << group)); }
91
92 Range *&operator *() { return range; }
93 Range * const &operator *() const { return range; }
94 Range *operator ->() { return range; }
95 const Range *operator ->() const { return range; }
96
97 iterator &operator +=(int difference);
98
99 template<typename T> T *list() const { return static_cast<T *>(range->list); }
100 int modelIndex() const { return range->index + offset; }
101
102 void incrementIndexes(int difference) { incrementIndexes(difference, flags: range->flags); }
103 void decrementIndexes(int difference) { decrementIndexes(difference, flags: range->flags); }
104
105 inline void incrementIndexes(int difference, uint flags);
106 inline void decrementIndexes(int difference, uint flags);
107
108 void setGroup(Group g) { group = g; groupFlag = 1 << g; }
109
110 Range *range = nullptr;
111 int offset = 0;
112 Group group = Default;
113 int groupFlag = 0;
114 int groupCount = 0;
115 int index[MaximumGroupCount] = { 0 };
116
117 int cacheIndex() const {
118 return index[Cache];
119 }
120
121 void setCacheIndex(int cacheIndex) {
122 index[Cache] = cacheIndex;
123 }
124 };
125
126 class Q_AUTOTEST_EXPORT insert_iterator : public iterator
127 {
128 public:
129 inline insert_iterator() {}
130 inline insert_iterator(const iterator &it) : iterator(it) {}
131 inline insert_iterator(Range *, int, Group, int);
132 inline ~insert_iterator() {}
133
134 insert_iterator &operator +=(int difference);
135 };
136
137 struct Change
138 {
139 inline Change() = default;
140 inline Change(const iterator &it, int count, uint flags, int moveId = -1);
141 int count = 0;
142 uint flags = 0;
143 int moveId = 0;
144 int index[MaximumGroupCount] = { 0 };
145
146 int cacheIndex() const {
147 return index[Cache];
148 }
149
150 void setCacheIndex(int cacheIndex) {
151 index[Cache] = cacheIndex;
152 }
153
154 inline bool isMove() const { return moveId >= 0; }
155 inline bool inCache() const { return flags & CacheFlag; }
156 inline bool inGroup() const { return flags & GroupMask; }
157 inline bool inGroup(int group) const { return flags & (CacheFlag << group); }
158
159 inline int groups() const { return flags & GroupMask; }
160 };
161
162 struct Insert : public Change
163 {
164 Insert() {}
165 Insert(const iterator &it, int count, uint flags, int moveId = -1)
166 : Change(it, count, flags, moveId) {}
167 };
168
169 struct Remove : public Change
170 {
171 Remove() {}
172 Remove(const iterator &it, int count, uint flags, int moveId = -1)
173 : Change(it, count, flags, moveId) {}
174 };
175
176 QQmlListCompositor();
177 ~QQmlListCompositor();
178
179 int defaultGroups() const { return m_defaultFlags & ~PrependFlag; }
180 void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
181 void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
182 void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
183 void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
184 void setGroupCount(int count);
185
186 int count(Group group) const;
187 iterator find(Group group, int index);
188 iterator find(Group group, int index) const;
189 insert_iterator findInsertPosition(Group group, int index);
190
191 const iterator &end() { return m_end; }
192
193 void append(void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
194 void insert(Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
195 iterator insert(iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
196
197 void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts = nullptr);
198 void setFlags(iterator from, int count, Group group, uint flags, QVector<Insert> *inserts = nullptr);
199 void setFlags(Group fromGroup, int from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
200 setFlags(fromGroup, from, count, group: fromGroup, flags, inserts); }
201 void setFlags(const iterator from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
202 setFlags(from, count, group: from.group, flags, inserts); }
203
204 void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
205 void clearFlags(iterator from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
206 void clearFlags(Group fromGroup, int from, int count, uint flags, QVector<Remove> *removals = nullptr) {
207 clearFlags(fromGroup, from, count, group: fromGroup, flags, removals); }
208 void clearFlags(const iterator &from, int count, uint flags, QVector<Remove> *removals = nullptr) {
209 clearFlags(from, count, group: from.group, flags, removals); }
210
211 bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const;
212
213 void move(
214 Group fromGroup,
215 int from,
216 Group toGroup,
217 int to,
218 int count,
219 Group group,
220 QVector<Remove> *removals = nullptr,
221 QVector<Insert> *inserts = nullptr);
222 void clear();
223
224 void listItemsInserted(void *list, int index, int count, QVector<Insert> *inserts);
225 void listItemsRemoved(void *list, int index, int count, QVector<Remove> *removals);
226 void listItemsMoved(void *list, int from, int to, int count, QVector<Remove> *removals, QVector<Insert> *inserts);
227 void listItemsChanged(void *list, int index, int count, QVector<Change> *changes);
228
229 void transition(
230 Group from,
231 Group to,
232 QVector<QQmlChangeSet::Change> *removes,
233 QVector<QQmlChangeSet::Change> *inserts);
234
235private:
236 Range m_ranges;
237 iterator m_end;
238 iterator m_cacheIt;
239 int m_groupCount;
240 int m_defaultFlags;
241 int m_removeFlags;
242 int m_moveId;
243
244 inline Range *insert(Range *before, void *list, int index, int count, uint flags);
245 inline Range *erase(Range *range);
246
247 struct MovedFlags
248 {
249 MovedFlags() {}
250 MovedFlags(int moveId, uint flags) : moveId(moveId), flags(flags) {}
251
252 int moveId;
253 uint flags;
254 };
255
256 void listItemsRemoved(
257 QVector<Remove> *translatedRemovals,
258 void *list,
259 QVector<QQmlChangeSet::Change> *removals,
260 QVector<QQmlChangeSet::Change> *insertions = nullptr,
261 QVector<MovedFlags> *movedFlags = nullptr);
262 void listItemsInserted(
263 QVector<Insert> *translatedInsertions,
264 void *list,
265 const QVector<QQmlChangeSet::Change> &insertions,
266 const QVector<MovedFlags> *movedFlags = nullptr);
267 void listItemsChanged(
268 QVector<Change> *translatedChanges,
269 void *list,
270 const QVector<QQmlChangeSet::Change> &changes);
271
272 friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
273};
274
275Q_DECLARE_TYPEINFO(QQmlListCompositor::Change, Q_PRIMITIVE_TYPE);
276Q_DECLARE_TYPEINFO(QQmlListCompositor::Remove, Q_PRIMITIVE_TYPE);
277Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
278
279QT_WARNING_PUSH
280// GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(),
281// right in front of the loops, and it didn't help, so we disable the warning:
282QT_WARNING_DISABLE_GCC("-Warray-bounds")
283inline QQmlListCompositor::iterator::iterator(
284 Range *range, int offset, Group group, int groupCount)
285 : range(range)
286 , offset(offset)
287 , group(group)
288 , groupFlag(1 << group)
289 , groupCount(groupCount)
290{
291 for (int i = 0; i < groupCount; ++i)
292 index[i] = 0;
293}
294
295inline void QQmlListCompositor::iterator::incrementIndexes(int difference, uint flags)
296{
297 for (int i = 0; i < groupCount; ++i) {
298 if (flags & (1 << i))
299 index[i] += difference;
300 }
301}
302
303inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint flags)
304{
305 for (int i = 0; i < groupCount; ++i) {
306 if (flags & (1 << i))
307 index[i] -= difference;
308 }
309}
310QT_WARNING_POP // -Warray-bounds
311
312inline QQmlListCompositor::insert_iterator::insert_iterator(
313 Range *range, int offset, Group group, int groupCount)
314 : iterator(range, offset, group, groupCount) {}
315
316inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId)
317 : count(count), flags(flags), moveId(moveId)
318{
319 for (int i = 0; i < MaximumGroupCount; ++i)
320 index[i] = it.index[i];
321}
322
323Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group);
324Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range);
325Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it);
326Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change);
327Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove);
328Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert);
329Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
330
331QT_END_NAMESPACE
332
333#endif
334

source code of qtdeclarative/src/qmlmodels/qqmllistcompositor_p.h