1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Assistant of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #include "bookmarkfiltermodel.h" |
29 | |
30 | #include "bookmarkitem.h" |
31 | #include "bookmarkmodel.h" |
32 | |
33 | BookmarkFilterModel::BookmarkFilterModel(QObject *parent) |
34 | : QAbstractProxyModel(parent) |
35 | { |
36 | } |
37 | |
38 | void BookmarkFilterModel::setSourceModel(QAbstractItemModel *_sourceModel) |
39 | { |
40 | beginResetModel(); |
41 | |
42 | if (sourceModel) { |
43 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::dataChanged, |
44 | receiver: this, slot: &BookmarkFilterModel::changed); |
45 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsInserted, |
46 | receiver: this, slot: &BookmarkFilterModel::rowsInserted); |
47 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsAboutToBeRemoved, |
48 | receiver: this, slot: &BookmarkFilterModel::rowsAboutToBeRemoved); |
49 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::rowsRemoved, |
50 | receiver: this, slot: &BookmarkFilterModel::rowsRemoved); |
51 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::layoutAboutToBeChanged, |
52 | receiver: this, slot: &BookmarkFilterModel::layoutAboutToBeChanged); |
53 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::layoutChanged, |
54 | receiver: this, slot: &BookmarkFilterModel::layoutChanged); |
55 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::modelAboutToBeReset, |
56 | receiver: this, slot: &BookmarkFilterModel::modelAboutToBeReset); |
57 | disconnect(sender: sourceModel, signal: &QAbstractItemModel::modelReset, |
58 | receiver: this, slot: &BookmarkFilterModel::modelReset); |
59 | } |
60 | |
61 | sourceModel = qobject_cast<BookmarkModel*> (object: _sourceModel); |
62 | QAbstractProxyModel::setSourceModel(sourceModel); |
63 | |
64 | if (sourceModel) { |
65 | connect(sender: sourceModel, signal: &QAbstractItemModel::dataChanged, |
66 | receiver: this, slot: &BookmarkFilterModel::changed); |
67 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsInserted, |
68 | receiver: this, slot: &BookmarkFilterModel::rowsInserted); |
69 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsAboutToBeRemoved, |
70 | receiver: this, slot: &BookmarkFilterModel::rowsAboutToBeRemoved); |
71 | connect(sender: sourceModel, signal: &QAbstractItemModel::rowsRemoved, |
72 | receiver: this, slot: &BookmarkFilterModel::rowsRemoved); |
73 | connect(sender: sourceModel, signal: &QAbstractItemModel::layoutAboutToBeChanged, |
74 | receiver: this, slot: &BookmarkFilterModel::layoutAboutToBeChanged); |
75 | connect(sender: sourceModel, signal: &QAbstractItemModel::layoutChanged, |
76 | receiver: this, slot: &BookmarkFilterModel::layoutChanged); |
77 | connect(sender: sourceModel, signal: &QAbstractItemModel::modelAboutToBeReset, |
78 | receiver: this, slot: &BookmarkFilterModel::modelAboutToBeReset); |
79 | connect(sender: sourceModel, signal: &QAbstractItemModel::modelReset, |
80 | receiver: this, slot: &BookmarkFilterModel::modelReset); |
81 | |
82 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
83 | } |
84 | endResetModel(); |
85 | } |
86 | |
87 | int BookmarkFilterModel::rowCount(const QModelIndex &index) const |
88 | { |
89 | Q_UNUSED(index); |
90 | return cache.count(); |
91 | } |
92 | |
93 | int BookmarkFilterModel::columnCount(const QModelIndex &index) const |
94 | { |
95 | Q_UNUSED(index); |
96 | if (sourceModel) |
97 | return sourceModel->columnCount(); |
98 | return 0; |
99 | } |
100 | |
101 | QModelIndex BookmarkFilterModel::mapToSource(const QModelIndex &proxyIndex) const |
102 | { |
103 | const int row = proxyIndex.row(); |
104 | if (proxyIndex.isValid() && row >= 0 && row < cache.count()) |
105 | return cache[row]; |
106 | return QModelIndex(); |
107 | } |
108 | |
109 | QModelIndex BookmarkFilterModel::mapFromSource(const QModelIndex &sourceIndex) const |
110 | { |
111 | return index(row: cache.indexOf(t: sourceIndex), column: 0, parent: QModelIndex()); |
112 | } |
113 | |
114 | QModelIndex BookmarkFilterModel::parent(const QModelIndex &child) const |
115 | { |
116 | Q_UNUSED(child); |
117 | return QModelIndex(); |
118 | } |
119 | |
120 | QModelIndex BookmarkFilterModel::index(int row, int column, |
121 | const QModelIndex &index) const |
122 | { |
123 | Q_UNUSED(index); |
124 | if (row < 0 || column < 0 || cache.count() <= row |
125 | || !sourceModel || sourceModel->columnCount() <= column) { |
126 | return QModelIndex(); |
127 | } |
128 | return createIndex(arow: row, acolumn: 0); |
129 | } |
130 | |
131 | Qt::DropActions BookmarkFilterModel::supportedDropActions () const |
132 | { |
133 | if (sourceModel) |
134 | return sourceModel->supportedDropActions(); |
135 | return Qt::IgnoreAction; |
136 | } |
137 | |
138 | Qt::ItemFlags BookmarkFilterModel::flags(const QModelIndex &index) const |
139 | { |
140 | if (sourceModel) |
141 | return sourceModel->flags(index); |
142 | return Qt::NoItemFlags; |
143 | } |
144 | |
145 | QVariant BookmarkFilterModel::data(const QModelIndex &index, int role) const |
146 | { |
147 | if (sourceModel) |
148 | return sourceModel->data(index: mapToSource(proxyIndex: index), role); |
149 | return QVariant(); |
150 | } |
151 | |
152 | bool BookmarkFilterModel::setData(const QModelIndex &index, const QVariant &value, |
153 | int role) |
154 | { |
155 | if (sourceModel) |
156 | return sourceModel->setData(index: mapToSource(proxyIndex: index), value, role); |
157 | return false; |
158 | } |
159 | |
160 | void BookmarkFilterModel::filterBookmarks() |
161 | { |
162 | if (sourceModel) { |
163 | beginResetModel(); |
164 | hideBookmarks = true; |
165 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
166 | endResetModel(); |
167 | } |
168 | } |
169 | |
170 | void BookmarkFilterModel::filterBookmarkFolders() |
171 | { |
172 | if (sourceModel) { |
173 | beginResetModel(); |
174 | hideBookmarks = false; |
175 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
176 | endResetModel(); |
177 | } |
178 | } |
179 | |
180 | void BookmarkFilterModel::changed(const QModelIndex &topLeft, |
181 | const QModelIndex &bottomRight) |
182 | { |
183 | emit dataChanged(topLeft: mapFromSource(sourceIndex: topLeft), bottomRight: mapFromSource(sourceIndex: bottomRight)); |
184 | } |
185 | |
186 | void BookmarkFilterModel::rowsInserted(const QModelIndex &parent, int start, |
187 | int end) |
188 | { |
189 | if (!sourceModel) |
190 | return; |
191 | |
192 | QModelIndex cachePrevious = parent; |
193 | if (BookmarkItem *parentItem = sourceModel->itemFromIndex(index: parent)) { |
194 | BookmarkItem *newItem = parentItem->child(number: start); |
195 | |
196 | // iterate over tree hirarchie to find the previous folder |
197 | for (int i = 0; i < parentItem->childCount(); ++i) { |
198 | if (BookmarkItem *child = parentItem->child(number: i)) { |
199 | const QModelIndex &tmp = sourceModel->indexFromItem(item: child); |
200 | if (tmp.data(arole: UserRoleFolder).toBool() && child != newItem) |
201 | cachePrevious = tmp; |
202 | } |
203 | } |
204 | |
205 | const QModelIndex &newIndex = sourceModel->indexFromItem(item: newItem); |
206 | const bool isFolder = newIndex.data(arole: UserRoleFolder).toBool(); |
207 | if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) { |
208 | beginInsertRows(parent: mapFromSource(sourceIndex: parent), first: start, last: end); |
209 | const int index = cache.indexOf(t: cachePrevious) + 1; |
210 | if (cache.value(i: index, defaultValue: QPersistentModelIndex()) != newIndex) |
211 | cache.insert(i: index, t: newIndex); |
212 | endInsertRows(); |
213 | } |
214 | } |
215 | } |
216 | |
217 | void BookmarkFilterModel::rowsAboutToBeRemoved(const QModelIndex &parent, |
218 | int start, int end) |
219 | { |
220 | if (!sourceModel) |
221 | return; |
222 | |
223 | if (BookmarkItem *parentItem = sourceModel->itemFromIndex(index: parent)) { |
224 | if (BookmarkItem *child = parentItem->child(number: start)) { |
225 | indexToRemove = sourceModel->indexFromItem(item: child); |
226 | if (cache.contains(t: indexToRemove)) |
227 | beginRemoveRows(parent: mapFromSource(sourceIndex: parent), first: start, last: end); |
228 | } |
229 | } |
230 | } |
231 | |
232 | void BookmarkFilterModel::rowsRemoved(const QModelIndex &/*parent*/, int, int) |
233 | { |
234 | if (cache.contains(t: indexToRemove)) { |
235 | cache.removeAll(t: indexToRemove); |
236 | endRemoveRows(); |
237 | } |
238 | } |
239 | |
240 | void BookmarkFilterModel::layoutAboutToBeChanged() |
241 | { |
242 | // TODO: ??? |
243 | } |
244 | |
245 | void BookmarkFilterModel::layoutChanged() |
246 | { |
247 | // TODO: ??? |
248 | } |
249 | |
250 | void BookmarkFilterModel::modelAboutToBeReset() |
251 | { |
252 | beginResetModel(); |
253 | } |
254 | |
255 | void BookmarkFilterModel::modelReset() |
256 | { |
257 | if (sourceModel) |
258 | setupCache(sourceModel->index(row: 0, column: 0, index: QModelIndex()).parent()); |
259 | endResetModel(); |
260 | } |
261 | |
262 | void BookmarkFilterModel::setupCache(const QModelIndex &parent) |
263 | { |
264 | cache.clear(); |
265 | for (int i = 0; i < sourceModel->rowCount(index: parent); ++i) |
266 | collectItems(parent: sourceModel->index(row: i, column: 0, index: parent)); |
267 | } |
268 | |
269 | void BookmarkFilterModel::collectItems(const QModelIndex &parent) |
270 | { |
271 | if (parent.isValid()) { |
272 | bool isFolder = sourceModel->data(index: parent, role: UserRoleFolder).toBool(); |
273 | if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) |
274 | cache.append(t: parent); |
275 | |
276 | if (sourceModel->hasChildren(parent)) { |
277 | for (int i = 0; i < sourceModel->rowCount(index: parent); ++i) |
278 | collectItems(parent: sourceModel->index(row: i, column: 0, index: parent)); |
279 | } |
280 | } |
281 | } |
282 | |
283 | // -- BookmarkTreeModel |
284 | |
285 | BookmarkTreeModel::BookmarkTreeModel(QObject *parent) |
286 | : QSortFilterProxyModel(parent) |
287 | { |
288 | } |
289 | |
290 | int BookmarkTreeModel::columnCount(const QModelIndex &parent) const |
291 | { |
292 | return qMin(a: 1, b: QSortFilterProxyModel::columnCount(parent)); |
293 | } |
294 | |
295 | bool BookmarkTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const |
296 | { |
297 | Q_UNUSED(row); |
298 | BookmarkModel *model = qobject_cast<BookmarkModel*> (object: sourceModel()); |
299 | if (model->rowCount(index: parent) > 0 |
300 | && model->data(index: model->index(row, column: 0, index: parent), role: UserRoleFolder).toBool()) |
301 | return true; |
302 | return false; |
303 | } |
304 | |