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 
BookmarkFilterModel(QObject * parent)33 BookmarkFilterModel::BookmarkFilterModel(QObject *parent)
34     : QAbstractProxyModel(parent)
35 {
36 }
37 
setSourceModel(QAbstractItemModel * _sourceModel)38 void BookmarkFilterModel::setSourceModel(QAbstractItemModel *_sourceModel)
39 {
40     beginResetModel();
41 
42     if (sourceModel) {
43         disconnect(sourceModel, &QAbstractItemModel::dataChanged,
44                 this, &BookmarkFilterModel::changed);
45         disconnect(sourceModel, &QAbstractItemModel::rowsInserted,
46                 this, &BookmarkFilterModel::rowsInserted);
47         disconnect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
48                 this, &BookmarkFilterModel::rowsAboutToBeRemoved);
49         disconnect(sourceModel, &QAbstractItemModel::rowsRemoved,
50                 this, &BookmarkFilterModel::rowsRemoved);
51         disconnect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged,
52                 this, &BookmarkFilterModel::layoutAboutToBeChanged);
53         disconnect(sourceModel, &QAbstractItemModel::layoutChanged,
54                 this, &BookmarkFilterModel::layoutChanged);
55         disconnect(sourceModel, &QAbstractItemModel::modelAboutToBeReset,
56                 this, &BookmarkFilterModel::modelAboutToBeReset);
57         disconnect(sourceModel, &QAbstractItemModel::modelReset,
58                 this, &BookmarkFilterModel::modelReset);
59     }
60 
61     sourceModel = qobject_cast<BookmarkModel*> (_sourceModel);
62     QAbstractProxyModel::setSourceModel(sourceModel);
63 
64     if (sourceModel) {
65         connect(sourceModel, &QAbstractItemModel::dataChanged,
66                 this, &BookmarkFilterModel::changed);
67         connect(sourceModel, &QAbstractItemModel::rowsInserted,
68                 this, &BookmarkFilterModel::rowsInserted);
69         connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
70                 this, &BookmarkFilterModel::rowsAboutToBeRemoved);
71         connect(sourceModel, &QAbstractItemModel::rowsRemoved,
72                 this, &BookmarkFilterModel::rowsRemoved);
73         connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged,
74                 this, &BookmarkFilterModel::layoutAboutToBeChanged);
75         connect(sourceModel, &QAbstractItemModel::layoutChanged,
76                 this, &BookmarkFilterModel::layoutChanged);
77         connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset,
78                 this, &BookmarkFilterModel::modelAboutToBeReset);
79         connect(sourceModel, &QAbstractItemModel::modelReset,
80                 this, &BookmarkFilterModel::modelReset);
81 
82         setupCache(sourceModel->index(0, 0, QModelIndex()).parent());
83     }
84     endResetModel();
85 }
86 
rowCount(const QModelIndex & index) const87 int BookmarkFilterModel::rowCount(const QModelIndex &index) const
88 {
89     Q_UNUSED(index);
90     return cache.count();
91 }
92 
columnCount(const QModelIndex & index) const93 int BookmarkFilterModel::columnCount(const QModelIndex &index) const
94 {
95     Q_UNUSED(index);
96     if (sourceModel)
97         return sourceModel->columnCount();
98     return 0;
99 }
100 
mapToSource(const QModelIndex & proxyIndex) const101 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 
mapFromSource(const QModelIndex & sourceIndex) const109 QModelIndex BookmarkFilterModel::mapFromSource(const QModelIndex &sourceIndex) const
110 {
111     return index(cache.indexOf(sourceIndex), 0, QModelIndex());
112 }
113 
parent(const QModelIndex & child) const114 QModelIndex BookmarkFilterModel::parent(const QModelIndex &child) const
115 {
116     Q_UNUSED(child);
117     return QModelIndex();
118 }
119 
index(int row,int column,const QModelIndex & index) const120 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(row, 0);
129 }
130 
supportedDropActions() const131 Qt::DropActions BookmarkFilterModel::supportedDropActions () const
132 {
133     if (sourceModel)
134         return sourceModel->supportedDropActions();
135     return Qt::IgnoreAction;
136 }
137 
flags(const QModelIndex & index) const138 Qt::ItemFlags BookmarkFilterModel::flags(const QModelIndex &index) const
139 {
140     if (sourceModel)
141         return sourceModel->flags(index);
142     return Qt::NoItemFlags;
143 }
144 
data(const QModelIndex & index,int role) const145 QVariant BookmarkFilterModel::data(const QModelIndex &index, int role) const
146 {
147     if (sourceModel)
148         return sourceModel->data(mapToSource(index), role);
149     return QVariant();
150 }
151 
setData(const QModelIndex & index,const QVariant & value,int role)152 bool BookmarkFilterModel::setData(const QModelIndex &index, const QVariant &value,
153     int role)
154 {
155     if (sourceModel)
156         return sourceModel->setData(mapToSource(index), value, role);
157     return false;
158 }
159 
filterBookmarks()160 void BookmarkFilterModel::filterBookmarks()
161 {
162     if (sourceModel) {
163         beginResetModel();
164         hideBookmarks = true;
165         setupCache(sourceModel->index(0, 0, QModelIndex()).parent());
166         endResetModel();
167     }
168 }
169 
filterBookmarkFolders()170 void BookmarkFilterModel::filterBookmarkFolders()
171 {
172     if (sourceModel) {
173         beginResetModel();
174         hideBookmarks = false;
175         setupCache(sourceModel->index(0, 0, QModelIndex()).parent());
176         endResetModel();
177     }
178 }
179 
changed(const QModelIndex & topLeft,const QModelIndex & bottomRight)180 void BookmarkFilterModel::changed(const QModelIndex &topLeft,
181     const QModelIndex &bottomRight)
182 {
183     emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight));
184 }
185 
rowsInserted(const QModelIndex & parent,int start,int end)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(parent)) {
194         BookmarkItem *newItem = parentItem->child(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(i)) {
199                 const QModelIndex &tmp = sourceModel->indexFromItem(child);
200                 if (tmp.data(UserRoleFolder).toBool() && child != newItem)
201                     cachePrevious = tmp;
202             }
203         }
204 
205         const QModelIndex &newIndex = sourceModel->indexFromItem(newItem);
206         const bool isFolder = newIndex.data(UserRoleFolder).toBool();
207         if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) {
208             beginInsertRows(mapFromSource(parent), start, end);
209             const int index = cache.indexOf(cachePrevious) + 1;
210             if (cache.value(index, QPersistentModelIndex()) != newIndex)
211                 cache.insert(index, newIndex);
212             endInsertRows();
213         }
214     }
215 }
216 
rowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)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(parent)) {
224         if (BookmarkItem *child = parentItem->child(start)) {
225             indexToRemove = sourceModel->indexFromItem(child);
226             if (cache.contains(indexToRemove))
227                 beginRemoveRows(mapFromSource(parent), start, end);
228         }
229     }
230 }
231 
rowsRemoved(const QModelIndex &,int,int)232 void BookmarkFilterModel::rowsRemoved(const QModelIndex &/*parent*/, int, int)
233 {
234     if (cache.contains(indexToRemove)) {
235         cache.removeAll(indexToRemove);
236         endRemoveRows();
237     }
238 }
239 
layoutAboutToBeChanged()240 void BookmarkFilterModel::layoutAboutToBeChanged()
241 {
242     // TODO: ???
243 }
244 
layoutChanged()245 void BookmarkFilterModel::layoutChanged()
246 {
247     // TODO: ???
248 }
249 
modelAboutToBeReset()250 void BookmarkFilterModel::modelAboutToBeReset()
251 {
252     beginResetModel();
253 }
254 
modelReset()255 void BookmarkFilterModel::modelReset()
256 {
257     if (sourceModel)
258         setupCache(sourceModel->index(0, 0, QModelIndex()).parent());
259     endResetModel();
260 }
261 
setupCache(const QModelIndex & parent)262 void BookmarkFilterModel::setupCache(const QModelIndex &parent)
263 {
264     cache.clear();
265     for (int i = 0; i < sourceModel->rowCount(parent); ++i)
266         collectItems(sourceModel->index(i, 0, parent));
267 }
268 
collectItems(const QModelIndex & parent)269 void BookmarkFilterModel::collectItems(const QModelIndex &parent)
270 {
271     if (parent.isValid()) {
272         bool isFolder = sourceModel->data(parent, UserRoleFolder).toBool();
273         if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks))
274             cache.append(parent);
275 
276         if (sourceModel->hasChildren(parent)) {
277             for (int i = 0; i < sourceModel->rowCount(parent); ++i)
278                 collectItems(sourceModel->index(i, 0, parent));
279         }
280     }
281 }
282 
283 // -- BookmarkTreeModel
284 
BookmarkTreeModel(QObject * parent)285 BookmarkTreeModel::BookmarkTreeModel(QObject *parent)
286     : QSortFilterProxyModel(parent)
287 {
288 }
289 
columnCount(const QModelIndex & parent) const290 int BookmarkTreeModel::columnCount(const QModelIndex &parent) const
291 {
292     return qMin(1, QSortFilterProxyModel::columnCount(parent));
293 }
294 
filterAcceptsRow(int row,const QModelIndex & parent) const295 bool BookmarkTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const
296 {
297     Q_UNUSED(row);
298     BookmarkModel *model = qobject_cast<BookmarkModel*> (sourceModel());
299     if (model->rowCount(parent) > 0
300         && model->data(model->index(row, 0, parent), UserRoleFolder).toBool())
301         return true;
302     return false;
303 }
304