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 | class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate |
41 | { |
42 | Q_DECLARE_PUBLIC(QAbstractItemModel) |
43 | |
44 | public: |
45 | QAbstractItemModelPrivate(); |
46 | ~QAbstractItemModelPrivate(); |
47 | |
48 | void removePersistentIndexData(QPersistentModelIndexData *data); |
49 | void movePersistentIndexes(const QList<QPersistentModelIndexData *> &indexes, int change, const QModelIndex &parent, |
50 | Qt::Orientation orientation); |
51 | void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
52 | void rowsInserted(const QModelIndex &parent, int first, int last); |
53 | void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
54 | void rowsRemoved(const QModelIndex &parent, int first, int last); |
55 | void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
56 | void columnsInserted(const QModelIndex &parent, int first, int last); |
57 | void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
58 | void columnsRemoved(const QModelIndex &parent, int first, int last); |
59 | static QAbstractItemModel *staticEmptyModel(); |
60 | static bool variantLessThan(const QVariant &v1, const QVariant &v2); |
61 | |
62 | void itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation); |
63 | void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
64 | bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
65 | |
66 | // ugly hack for QTreeModel, see QTBUG-94546 |
67 | virtual void executePendingOperations() const; |
68 | |
69 | inline QModelIndex createIndex(int row, int column, void *data = nullptr) const { |
70 | return q_func()->createIndex(arow: row, acolumn: column, adata: data); |
71 | } |
72 | |
73 | inline QModelIndex createIndex(int row, int column, int id) const { |
74 | return q_func()->createIndex(arow: row, acolumn: column, aid: id); |
75 | } |
76 | |
77 | inline bool indexValid(const QModelIndex &index) const { |
78 | return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func()); |
79 | } |
80 | |
81 | void invalidatePersistentIndexes(); |
82 | void invalidatePersistentIndex(const QModelIndex &index); |
83 | |
84 | struct Change { |
85 | constexpr Change() : parent(), first(-1), last(-1), needsAdjust(false) {} |
86 | constexpr Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {} |
87 | |
88 | QModelIndex parent; |
89 | int first, last; |
90 | |
91 | |
92 | // In cases such as this: |
93 | // - A |
94 | // - B |
95 | // - C |
96 | // - - D |
97 | // - - E |
98 | // - - F |
99 | // |
100 | // If B is moved to above E, C is the source parent in the signal and its row is 2. When the move is |
101 | // completed however, C is at row 1 and there is no row 2 at the same level in the model at all. |
102 | // The QModelIndex is adjusted to correct that in those cases before reporting it though the |
103 | // rowsMoved signal. |
104 | bool needsAdjust; |
105 | |
106 | constexpr bool isValid() const { return first >= 0 && last >= 0; } |
107 | }; |
108 | QStack<Change> changes; |
109 | |
110 | struct Persistent { |
111 | Persistent() {} |
112 | QMultiHash<QModelIndex, QPersistentModelIndexData *> indexes; |
113 | QStack<QList<QPersistentModelIndexData *>> moved; |
114 | QStack<QList<QPersistentModelIndexData *>> invalidated; |
115 | void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data); |
116 | } persistent; |
117 | |
118 | static const QHash<int,QByteArray> &defaultRoleNames(); |
119 | static bool isVariantLessThan(const QVariant &left, const QVariant &right, |
120 | Qt::CaseSensitivity cs = Qt::CaseSensitive, bool isLocaleAware = false); |
121 | }; |
122 | Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_RELOCATABLE_TYPE); |
123 | |
124 | namespace QtPrivate { |
125 | |
126 | /*! |
127 | \internal |
128 | This is a workaround for QTBUG-75172. |
129 | |
130 | Some predefined model roles are supposed to use certain enum/flag |
131 | types (e.g. fetching Qt::TextAlignmentRole is supposed to return a |
132 | variant containing a Qt::Alignment object). |
133 | |
134 | For historical reasons, a plain `int` was used sometimes. This is |
135 | surprising to end-users and also sloppy on Qt's part; users were |
136 | forced to use `int` rather than the correct datatype. |
137 | |
138 | This function tries both the "right" type and plain `int`, for a |
139 | given QVariant. This fixes the problem (using the correct datatype) |
140 | but also keeps compatibility with existing code using `int`. |
141 | |
142 | ### Qt 7: get rid of this. Always use the correct datatype. |
143 | */ |
144 | template <typename T> |
145 | T legacyEnumValueFromModelData(const QVariant &data) |
146 | { |
147 | static_assert(std::is_enum_v<T>); |
148 | if (data.userType() == qMetaTypeId<T>()) { |
149 | return data.value<T>(); |
150 | } else if (std::is_same_v<std::underlying_type_t<T>, int> || |
151 | std::is_same_v<std::underlying_type_t<T>, uint>) { |
152 | return T(data.toInt()); |
153 | } |
154 | |
155 | return T(); |
156 | } |
157 | |
158 | template <typename T> |
159 | T legacyFlagValueFromModelData(const QVariant &data) |
160 | { |
161 | if (data.userType() == qMetaTypeId<T>()) { |
162 | return data.value<T>(); |
163 | } else if (std::is_same_v<std::underlying_type_t<typename T::enum_type>, int> || |
164 | std::is_same_v<std::underlying_type_t<typename T::enum_type>, uint>) { |
165 | return T::fromInt(data.toInt()); |
166 | } |
167 | |
168 | return T(); |
169 | } |
170 | |
171 | } // namespace QtPrivate |
172 | |
173 | |
174 | QT_END_NAMESPACE |
175 | |
176 | #endif // QABSTRACTITEMMODEL_P_H |
177 | |