1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #ifndef QABSTRACTITEMMODEL_P_H |
43 | #define QABSTRACTITEMMODEL_P_H |
44 | |
45 | // |
46 | // W A R N I N G |
47 | // ------------- |
48 | // |
49 | // This file is not part of the Qt API. It exists for the convenience |
50 | // of QAbstractItemModel*. This header file may change from version |
51 | // to version without notice, or even be removed. |
52 | // |
53 | // We mean it. |
54 | // |
55 | // |
56 | |
57 | #include "private/qobject_p.h" |
58 | #include "QtCore/qstack.h" |
59 | #include "QtCore/qset.h" |
60 | #include "QtCore/qhash.h" |
61 | |
62 | QT_BEGIN_NAMESPACE |
63 | |
64 | class QPersistentModelIndexData |
65 | { |
66 | public: |
67 | QPersistentModelIndexData() : model(0) {} |
68 | QPersistentModelIndexData(const QModelIndex &idx) : index(idx), model(idx.model()) {} |
69 | QModelIndex index; |
70 | QAtomicInt ref; |
71 | const QAbstractItemModel *model; |
72 | static QPersistentModelIndexData *create(const QModelIndex &index); |
73 | static void destroy(QPersistentModelIndexData *data); |
74 | }; |
75 | |
76 | class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate |
77 | { |
78 | Q_DECLARE_PUBLIC(QAbstractItemModel) |
79 | |
80 | public: |
81 | QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1), roleNames(defaultRoleNames()) {} |
82 | void removePersistentIndexData(QPersistentModelIndexData *data); |
83 | void movePersistentIndexes(QVector<QPersistentModelIndexData *> indexes, int change, const QModelIndex &parent, Qt::Orientation orientation); |
84 | void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
85 | void rowsInserted(const QModelIndex &parent, int first, int last); |
86 | void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
87 | void rowsRemoved(const QModelIndex &parent, int first, int last); |
88 | void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last); |
89 | void columnsInserted(const QModelIndex &parent, int first, int last); |
90 | void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); |
91 | void columnsRemoved(const QModelIndex &parent, int first, int last); |
92 | static QAbstractItemModel *staticEmptyModel(); |
93 | static bool variantLessThan(const QVariant &v1, const QVariant &v2); |
94 | |
95 | void itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation); |
96 | void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
97 | bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation); |
98 | |
99 | inline QModelIndex createIndex(int row, int column, void *data = 0) const { |
100 | return q_func()->createIndex(row, column, data); |
101 | } |
102 | |
103 | inline QModelIndex createIndex(int row, int column, int id) const { |
104 | return q_func()->createIndex(row, column, id); |
105 | } |
106 | |
107 | inline bool indexValid(const QModelIndex &index) const { |
108 | return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func()); |
109 | } |
110 | |
111 | inline void invalidatePersistentIndexes() { |
112 | foreach (QPersistentModelIndexData *data, persistent.indexes) { |
113 | data->index = QModelIndex(); |
114 | data->model = 0; |
115 | } |
116 | persistent.indexes.clear(); |
117 | } |
118 | |
119 | /*! |
120 | \internal |
121 | clean the QPersistentModelIndex relative to the index if there is one. |
122 | To be used before an index is invalided |
123 | */ |
124 | inline void invalidatePersistentIndex(const QModelIndex &index) { |
125 | QHash<QModelIndex, QPersistentModelIndexData *>::iterator it = persistent.indexes.find(index); |
126 | if(it != persistent.indexes.end()) { |
127 | QPersistentModelIndexData *data = *it; |
128 | persistent.indexes.erase(it); |
129 | data->index = QModelIndex(); |
130 | data->model = 0; |
131 | } |
132 | } |
133 | |
134 | struct Change { |
135 | Change() : first(-1), last(-1) {} |
136 | Change(const Change &c) : parent(c.parent), first(c.first), last(c.last), needsAdjust(c.needsAdjust) {} |
137 | Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {} |
138 | QModelIndex parent; |
139 | int first, last; |
140 | |
141 | |
142 | // In cases such as this: |
143 | // - A |
144 | // - B |
145 | // - C |
146 | // - - D |
147 | // - - E |
148 | // - - F |
149 | // |
150 | // If B is moved to above E, C is the source parent in the signal and its row is 2. When the move is |
151 | // completed however, C is at row 1 and there is no row 2 at the same level in the model at all. |
152 | // The QModelIndex is adjusted to correct that in those cases before reporting it though the |
153 | // rowsMoved signal. |
154 | bool needsAdjust; |
155 | |
156 | bool isValid() { return first >= 0 && last >= 0; } |
157 | }; |
158 | QStack<Change> changes; |
159 | |
160 | struct Persistent { |
161 | Persistent() {} |
162 | QHash<QModelIndex, QPersistentModelIndexData *> indexes; |
163 | QStack<QVector<QPersistentModelIndexData *> > moved; |
164 | QStack<QVector<QPersistentModelIndexData *> > invalidated; |
165 | void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data); |
166 | } persistent; |
167 | |
168 | Qt::DropActions supportedDragActions; |
169 | |
170 | QHash<int,QByteArray> roleNames; |
171 | static const QHash<int,QByteArray> &defaultRoleNames(); |
172 | }; |
173 | |
174 | QT_END_NAMESPACE |
175 | |
176 | #endif // QABSTRACTITEMMODEL_P_H |
177 | |