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
25QT_BEGIN_NAMESPACE
26
27QT_REQUIRE_CONFIG(itemmodel);
28
29class QPersistentModelIndexData
30{
31public:
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
40class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
41{
42 Q_DECLARE_PUBLIC(QAbstractItemModel)
43
44public:
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};
122Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_RELOCATABLE_TYPE);
123
124namespace 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*/
144template <typename T>
145T 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
158template <typename T>
159T 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
174QT_END_NAMESPACE
175
176#endif // QABSTRACTITEMMODEL_P_H
177

source code of qtbase/src/corelib/itemmodels/qabstractitemmodel_p.h