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 QABSTRACTITEMMODEL_P_H |
5 | #define QABSTRACTITEMMODEL_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 for the convenience |
12 | // of QAbstractItemModel*. This header file may change from version |
13 | // to version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | // |
18 | |
19 | #include "QtCore/qabstractitemmodel.h" |
20 | #include "QtCore/private/qobject_p.h" |
21 | #include "QtCore/qstack.h" |
22 | #include "QtCore/qset.h" |
23 | #include "QtCore/qhash.h" |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | QT_REQUIRE_CONFIG(itemmodel); |
28 | |
29 | class QPersistentModelIndexData |
30 | { |
31 | public: |
32 | QPersistentModelIndexData() {} |
33 | QPersistentModelIndexData(const QModelIndex &idx) : index(idx) {} |
34 | QModelIndex index; |
35 | QAtomicInt ref; |
36 | static QPersistentModelIndexData *create(const QModelIndex &index); |
37 | static void destroy(QPersistentModelIndexData *data); |
38 | }; |
39 | |
40 | namespace QtPrivate { |
41 | // This class is just a wrapper so we can use the fixed qHash() function for QModelIndex. |
42 | struct QModelIndexWrapper // ### Qt 7: Remove again, use QModelIndex directly. |
43 | { |
44 | QModelIndex index; |
45 | Q_IMPLICIT QModelIndexWrapper(const QModelIndex &i) : index(i) { } |
46 | Q_IMPLICIT inline operator QModelIndex() const { return index; } |
47 | friend bool operator==(const QModelIndexWrapper &l, const QModelIndexWrapper &r) { return l.index == r.index; } |
48 | friend bool operator!=(const QModelIndexWrapper &l, const QModelIndexWrapper &r) { return !(operator==(l,r)); } |
49 | friend bool operator==(const QModelIndexWrapper &l, const QModelIndex &r) { return l.index == r; } |
50 | friend bool operator!=(const QModelIndexWrapper &l, const QModelIndex &r) { return !(operator==(lhs: l.index,rhs: r)); } |
51 | friend bool operator==(const QModelIndex &l, const QModelIndexWrapper &r) { return l == r.index; } |
52 | friend bool operator!=(const QModelIndex &l, const QModelIndexWrapper &r) { return !(operator==(lhs: l,rhs: r.index)); } |
53 | friend inline size_t qHash(const QtPrivate::QModelIndexWrapper &index, size_t seed = 0) noexcept |
54 | { |
55 | return qHashMulti(seed, args: index.index.row(), args: index.index.column(), args: index.index.internalId()); |
56 | } |
57 | }; |
58 | } |
59 | |
60 | class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate |
61 | { |
62 | Q_DECLARE_PUBLIC(QAbstractItemModel) |
63 | |
64 | public: |
65 | QAbstractItemModelPrivate(); |
66 | ~QAbstractItemModelPrivate(); |
67 | |
68 | static const QAbstractItemModelPrivate *get(const QAbstractItemModel *model) { return model->d_func(); } |
69 | |
70 | void removePersistentIndexData(QPersistentModelIndexData *data); |
71 | void movePersistentIndexes(const QList<QPersistentModelIndexData *> &indexes, int change, const QModelIndex &parent, |
72 | Qt::Orientation orientation); |
73 | void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
74 | void rowsInserted(const QModelIndex &parent, int first, int last); |
75 | void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
76 | void rowsRemoved(const QModelIndex &parent, int first, int last); |
77 | void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
78 | void columnsInserted(const QModelIndex &parent, int first, int last); |
79 | void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
80 | void columnsRemoved(const QModelIndex &parent, int first, int last); |
81 | static QAbstractItemModel *staticEmptyModel(); |
82 | static bool variantLessThan(const QVariant &v1, const QVariant &v2); |
83 | |
84 | void itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation); |
85 | void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
86 | bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
87 | |
88 | // ugly hack for QTreeModel, see QTBUG-94546 |
89 | virtual void executePendingOperations() const; |
90 | |
91 | inline QModelIndex createIndex(int row, int column, void *data = nullptr) const { |
92 | return q_func()->createIndex(arow: row, acolumn: column, adata: data); |
93 | } |
94 | |
95 | inline QModelIndex createIndex(int row, int column, int id) const { |
96 | return q_func()->createIndex(arow: row, acolumn: column, aid: id); |
97 | } |
98 | |
99 | inline bool indexValid(const QModelIndex &index) const { |
100 | return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func()); |
101 | } |
102 | |
103 | void invalidatePersistentIndexes(); |
104 | void invalidatePersistentIndex(const QModelIndex &index); |
105 | |
106 | struct Change { |
107 | constexpr Change() : parent(), first(-1), last(-1), needsAdjust(false) {} |
108 | constexpr Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {} |
109 | |
110 | QModelIndex parent; |
111 | int first, last; |
112 | |
113 | |
114 | // In cases such as this: |
115 | // - A |
116 | // - B |
117 | // - C |
118 | // - - D |
119 | // - - E |
120 | // - - F |
121 | // |
122 | // If B is moved to above E, C is the source parent in the signal and its row is 2. When the move is |
123 | // completed however, C is at row 1 and there is no row 2 at the same level in the model at all. |
124 | // The QModelIndex is adjusted to correct that in those cases before reporting it though the |
125 | // rowsMoved signal. |
126 | bool needsAdjust; |
127 | |
128 | constexpr bool isValid() const { return first >= 0 && last >= 0; } |
129 | }; |
130 | QStack<Change> changes; |
131 | |
132 | struct Persistent { |
133 | Persistent() {} |
134 | QMultiHash<QtPrivate::QModelIndexWrapper, QPersistentModelIndexData *> indexes; |
135 | QStack<QList<QPersistentModelIndexData *>> moved; |
136 | QStack<QList<QPersistentModelIndexData *>> invalidated; |
137 | void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data); |
138 | } persistent; |
139 | |
140 | bool resetting = false; |
141 | |
142 | static const QHash<int,QByteArray> &defaultRoleNames(); |
143 | static bool isVariantLessThan(const QVariant &left, const QVariant &right, |
144 | Qt::CaseSensitivity cs = Qt::CaseSensitive, bool isLocaleAware = false); |
145 | }; |
146 | Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_RELOCATABLE_TYPE); |
147 | |
148 | namespace QtPrivate { |
149 | |
150 | /*! |
151 | \internal |
152 | This is a workaround for QTBUG-75172. |
153 | |
154 | Some predefined model roles are supposed to use certain enum/flag |
155 | types (e.g. fetching Qt::TextAlignmentRole is supposed to return a |
156 | variant containing a Qt::Alignment object). |
157 | |
158 | For historical reasons, a plain `int` was used sometimes. This is |
159 | surprising to end-users and also sloppy on Qt's part; users were |
160 | forced to use `int` rather than the correct datatype. |
161 | |
162 | This function tries both the "right" type and plain `int`, for a |
163 | given QVariant. This fixes the problem (using the correct datatype) |
164 | but also keeps compatibility with existing code using `int`. |
165 | |
166 | ### Qt 7: get rid of this. Always use the correct datatype. |
167 | */ |
168 | template <typename T> |
169 | T legacyEnumValueFromModelData(const QVariant &data) |
170 | { |
171 | static_assert(std::is_enum_v<T>); |
172 | if (data.userType() == qMetaTypeId<T>()) { |
173 | return data.value<T>(); |
174 | } else if (std::is_same_v<std::underlying_type_t<T>, int> || |
175 | std::is_same_v<std::underlying_type_t<T>, uint>) { |
176 | return T(data.toInt()); |
177 | } |
178 | |
179 | return T(); |
180 | } |
181 | |
182 | template <typename T> |
183 | T legacyFlagValueFromModelData(const QVariant &data) |
184 | { |
185 | if (data.userType() == qMetaTypeId<T>()) { |
186 | return data.value<T>(); |
187 | } else if (std::is_same_v<std::underlying_type_t<typename T::enum_type>, int> || |
188 | std::is_same_v<std::underlying_type_t<typename T::enum_type>, uint>) { |
189 | return T::fromInt(data.toInt()); |
190 | } |
191 | |
192 | return T(); |
193 | } |
194 | |
195 | } // namespace QtPrivate |
196 | |
197 | |
198 | QT_END_NAMESPACE |
199 | |
200 | #endif // QABSTRACTITEMMODEL_P_H |
201 |
Definitions
- QPersistentModelIndexData
- QPersistentModelIndexData
- QPersistentModelIndexData
- QModelIndexWrapper
- QModelIndexWrapper
- operator QModelIndex
- operator==
- operator!=
- operator==
- operator!=
- operator==
- operator!=
- qHash
- QAbstractItemModelPrivate
- get
- createIndex
- createIndex
- indexValid
- Change
- Change
- Change
- isValid
- Persistent
- Persistent
- legacyEnumValueFromModelData
Learn to use CMake with our Intro Training
Find out more