1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | #include "bookmarkfiltermodel.h" |
4 | |
5 | #include "bookmarkitem.h" |
6 | #include "bookmarkmodel.h" |
7 | |
8 | BookmarkFilterModel::BookmarkFilterModel(QObject *parent) |
9 | : QAbstractProxyModel(parent) |
10 | { |
11 | } |
12 | |
13 | void BookmarkFilterModel::setSourceModel(QAbstractItemModel *_sourceModel) |
14 | { |
15 | beginResetModel(); |
16 | |
17 | if (sourceModel) { |
18 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::dataChanged, |
19 | receiver: this, slot: &BookmarkFilterModel::changed); |
20 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsInserted, |
21 | receiver: this, slot: &BookmarkFilterModel::rowsInserted); |
22 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsAboutToBeRemoved, |
23 | receiver: this, slot: &BookmarkFilterModel::rowsAboutToBeRemoved); |
24 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsRemoved, |
25 | receiver: this, slot: &BookmarkFilterModel::rowsRemoved); |
26 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::layoutAboutToBeChanged, |
27 | receiver: this, slot: &BookmarkFilterModel::layoutAboutToBeChanged); |
28 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::layoutChanged, |
29 | receiver: this, slot: &BookmarkFilterModel::layoutChanged); |
30 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::modelAboutToBeReset, |
31 | receiver: this, slot: &BookmarkFilterModel::modelAboutToBeReset); |
32 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::modelReset, |
33 | receiver: this, slot: &BookmarkFilterModel::modelReset); |
34 | } |
35 | |
36 | sourceModel = qobject_cast<BookmarkModel*> (object: _sourceModel); |
37 | QAbstractProxyModel::setSourceModel(sourceModel); |
38 | |
39 | if (sourceModel) { |
40 | connect(sender: sourceModel, signal: &QAbstractItemModel::dataChanged, |
41 | context: this, slot: &BookmarkFilterModel::changed); |
42 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsInserted, |
43 | context: this, slot: &BookmarkFilterModel::rowsInserted); |
44 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsAboutToBeRemoved, |
45 | context: this, slot: &BookmarkFilterModel::rowsAboutToBeRemoved); |
46 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsRemoved, |
47 | context: this, slot: &BookmarkFilterModel::rowsRemoved); |
48 | connect(sender: sourceModel, signal: &QAbstractItemModel::layoutAboutToBeChanged, |
49 | context: this, slot: &BookmarkFilterModel::layoutAboutToBeChanged); |
50 | connect(sender: sourceModel, signal: &QAbstractItemModel::layoutChanged, |
51 | context: this, slot: &BookmarkFilterModel::layoutChanged); |
52 | connect(sender: sourceModel, signal: &QAbstractItemModel::modelAboutToBeReset, |
53 | context: this, slot: &BookmarkFilterModel::modelAboutToBeReset); |
54 | connect(sender: sourceModel, signal: &QAbstractItemModel::modelReset, |
55 | context: this, slot: &BookmarkFilterModel::modelReset); |
56 | |
57 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
58 | } |
59 | endResetModel(); |
60 | } |
61 | |
62 | int BookmarkFilterModel::rowCount(const QModelIndex &index) const |
63 | { |
64 | Q_UNUSED(index); |
65 | return cache.size(); |
66 | } |
67 | |
68 | int BookmarkFilterModel::columnCount(const QModelIndex &index) const |
69 | { |
70 | Q_UNUSED(index); |
71 | if (sourceModel) |
72 | return sourceModel->columnCount(); |
73 | return 0; |
74 | } |
75 | |
76 | QModelIndex BookmarkFilterModel::mapToSource(const QModelIndex &proxyIndex) const |
77 | { |
78 | const int row = proxyIndex.row(); |
79 | if (proxyIndex.isValid() && row >= 0 && row < cache.size()) |
80 | return cache[row]; |
81 | return QModelIndex(); |
82 | } |
83 | |
84 | QModelIndex BookmarkFilterModel::mapFromSource(const QModelIndex &sourceIndex) const |
85 | { |
86 | return index(row: cache.indexOf(t: sourceIndex), column: 0, parent: QModelIndex()); |
87 | } |
88 | |
89 | QModelIndex BookmarkFilterModel::parent(const QModelIndex &child) const |
90 | { |
91 | Q_UNUSED(child); |
92 | return QModelIndex(); |
93 | } |
94 | |
95 | QModelIndex BookmarkFilterModel::index(int row, int column, |
96 | const QModelIndex &index) const |
97 | { |
98 | Q_UNUSED(index); |
99 | if (row < 0 || column < 0 || cache.size() <= row |
100 | || !sourceModel || sourceModel->columnCount() <= column) { |
101 | return QModelIndex(); |
102 | } |
103 | return createIndex(arow: row, acolumn: 0); |
104 | } |
105 | |
106 | Qt::DropActions BookmarkFilterModel::supportedDropActions () const |
107 | { |
108 | if (sourceModel) |
109 | return sourceModel->supportedDropActions(); |
110 | return Qt::IgnoreAction; |
111 | } |
112 | |
113 | Qt::ItemFlags BookmarkFilterModel::flags(const QModelIndex &index) const |
114 | { |
115 | if (sourceModel) |
116 | return sourceModel->flags(index); |
117 | return Qt::NoItemFlags; |
118 | } |
119 | |
120 | QVariant BookmarkFilterModel::data(const QModelIndex &index, int role) const |
121 | { |
122 | if (sourceModel) |
123 | return sourceModel->data(index: mapToSource(proxyIndex: index), role); |
124 | return QVariant(); |
125 | } |
126 | |
127 | bool BookmarkFilterModel::setData(const QModelIndex &index, const QVariant &value, |
128 | int role) |
129 | { |
130 | if (sourceModel) |
131 | return sourceModel->setData(index: mapToSource(proxyIndex: index), value, role); |
132 | return false; |
133 | } |
134 | |
135 | void BookmarkFilterModel::filterBookmarks() |
136 | { |
137 | if (sourceModel) { |
138 | beginResetModel(); |
139 | hideBookmarks = true; |
140 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
141 | endResetModel(); |
142 | } |
143 | } |
144 | |
145 | void BookmarkFilterModel::filterBookmarkFolders() |
146 | { |
147 | if (sourceModel) { |
148 | beginResetModel(); |
149 | hideBookmarks = false; |
150 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
151 | endResetModel(); |
152 | } |
153 | } |
154 | |
155 | void BookmarkFilterModel::changed(const QModelIndex &topLeft, |
156 | const QModelIndex &bottomRight) |
157 | { |
158 | emit dataChanged(topLeft: mapFromSource(sourceIndex: topLeft), bottomRight: mapFromSource(sourceIndex: bottomRight)); |
159 | } |
160 | |
161 | void BookmarkFilterModel::rowsInserted(const QModelIndex &parent, int start, |
162 | int end) |
163 | { |
164 | if (!sourceModel) |
165 | return; |
166 | |
167 | QModelIndex cachePrevious = parent; |
168 | if (BookmarkItem *parentItem = sourceModel->itemFromIndex(index: parent)) { |
169 | BookmarkItem *newItem = parentItem->child(number: start); |
170 | |
171 | // iterate over tree hirarchie to find the previous folder |
172 | for (int i = 0; i < parentItem->childCount(); ++i) { |
173 | if (BookmarkItem *child = parentItem->child(number: i)) { |
174 | const QModelIndex &tmp = sourceModel->indexFromItem(item: child); |
175 | if (tmp.data(arole: UserRoleFolder).toBool() && child != newItem) |
176 | cachePrevious = tmp; |
177 | } |
178 | } |
179 | |
180 | const QModelIndex &newIndex = sourceModel->indexFromItem(item: newItem); |
181 | const bool isFolder = newIndex.data(arole: UserRoleFolder).toBool(); |
182 | if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) { |
183 | beginInsertRows(parent: mapFromSource(sourceIndex: parent), first: start, last: end); |
184 | const int index = cache.indexOf(t: cachePrevious) + 1; |
185 | if (cache.value(i: index, defaultValue: QPersistentModelIndex()) != newIndex) |
186 | cache.insert(i: index, t: newIndex); |
187 | endInsertRows(); |
188 | } |
189 | } |
190 | } |
191 | |
192 | void BookmarkFilterModel::rowsAboutToBeRemoved(const QModelIndex &parent, |
193 | int start, int end) |
194 | { |
195 | if (!sourceModel) |
196 | return; |
197 | |
198 | if (BookmarkItem *parentItem = sourceModel->itemFromIndex(index: parent)) { |
199 | if (BookmarkItem *child = parentItem->child(number: start)) { |
200 | indexToRemove = sourceModel->indexFromItem(item: child); |
201 | if (cache.contains(t: indexToRemove)) |
202 | beginRemoveRows(parent: mapFromSource(sourceIndex: parent), first: start, last: end); |
203 | } |
204 | } |
205 | } |
206 | |
207 | void BookmarkFilterModel::rowsRemoved(const QModelIndex &/*parent*/, int, int) |
208 | { |
209 | if (cache.contains(t: indexToRemove)) { |
210 | cache.removeAll(t: indexToRemove); |
211 | endRemoveRows(); |
212 | } |
213 | } |
214 | |
215 | void BookmarkFilterModel::layoutAboutToBeChanged() |
216 | { |
217 | // TODO: ??? |
218 | } |
219 | |
220 | void BookmarkFilterModel::layoutChanged() |
221 | { |
222 | // TODO: ??? |
223 | } |
224 | |
225 | void BookmarkFilterModel::modelAboutToBeReset() |
226 | { |
227 | beginResetModel(); |
228 | } |
229 | |
230 | void BookmarkFilterModel::modelReset() |
231 | { |
232 | if (sourceModel) |
233 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
234 | endResetModel(); |
235 | } |
236 | |
237 | void BookmarkFilterModel::setupCache(const QModelIndex &parent) |
238 | { |
239 | cache.clear(); |
240 | for (int i = 0; i < sourceModel->rowCount(index: parent); ++i) |
241 | collectItems(parent: sourceModel->index(row: i, column: 0, index: parent)); |
242 | } |
243 | |
244 | void BookmarkFilterModel::collectItems(const QModelIndex &parent) |
245 | { |
246 | if (parent.isValid()) { |
247 | bool isFolder = sourceModel->data(index: parent, role: UserRoleFolder).toBool(); |
248 | if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) |
249 | cache.append(t: parent); |
250 | |
251 | if (sourceModel->hasChildren(parent)) { |
252 | for (int i = 0; i < sourceModel->rowCount(index: parent); ++i) |
253 | collectItems(parent: sourceModel->index(row: i, column: 0, index: parent)); |
254 | } |
255 | } |
256 | } |
257 | |
258 | // -- BookmarkTreeModel |
259 | |
260 | BookmarkTreeModel::BookmarkTreeModel(QObject *parent) |
261 | : QSortFilterProxyModel(parent) |
262 | { |
263 | } |
264 | |
265 | int BookmarkTreeModel::columnCount(const QModelIndex &parent) const |
266 | { |
267 | return qMin(a: 1, b: QSortFilterProxyModel::columnCount(parent)); |
268 | } |
269 | |
270 | bool BookmarkTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const |
271 | { |
272 | Q_UNUSED(row); |
273 | BookmarkModel *model = qobject_cast<BookmarkModel*> (object: sourceModel()); |
274 | if (model->rowCount(index: parent) > 0 |
275 | && model->data(index: model->index(row, column: 0, index: parent), role: UserRoleFolder).toBool()) |
276 | return true; |
277 | return false; |
278 | } |
279 | |