]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kfileitemmodel.h
Selection and current item fixes
[dolphin.git] / src / kitemviews / kfileitemmodel.h
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #ifndef KFILEITEMMODEL_H
21 #define KFILEITEMMODEL_H
22
23 #include <libdolphin_export.h>
24 #include <KFileItemList>
25 #include <KUrl>
26 #include <kitemviews/kitemmodelbase.h>
27
28 #include <QHash>
29
30 class KDirLister;
31 class QTimer;
32
33 /**
34 * @brief KItemModelBase implementation for KFileItems.
35 *
36 * KFileItemModel is connected with one KDirLister. Each time the KDirLister
37 * emits new items, removes items or changes items the model gets synchronized.
38 *
39 * KFileItemModel supports sorting and grouping of items. Additional roles that
40 * are not part of KFileItem can be added with KFileItemModel::setData().
41 *
42 * Also the recursive expansion of sub-directories is supported by
43 * KFileItemModel::setExpanded().
44 */
45 class LIBDOLPHINPRIVATE_EXPORT KFileItemModel : public KItemModelBase
46 {
47 Q_OBJECT
48
49 public:
50 explicit KFileItemModel(KDirLister* dirLister, QObject* parent = 0);
51 virtual ~KFileItemModel();
52
53 virtual int count() const;
54 virtual QHash<QByteArray, QVariant> data(int index) const;
55 virtual bool setData(int index, const QHash<QByteArray, QVariant>& values);
56
57 /**
58 * Sets a separate sorting with folders first (true) or a mixed sorting of files and folders (false).
59 */
60 void setSortFoldersFirst(bool foldersFirst);
61 bool sortFoldersFirst() const;
62
63 /** @reimp */
64 virtual QMimeData* createMimeData(const QSet<int>& indexes) const;
65
66 /** @reimp */
67 virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const;
68
69 /** @reimp */
70 virtual bool supportsDropping(int index) const;
71
72 /** @reimp */
73 virtual QString roleDescription(const QByteArray& role) const;
74
75 /** @reimp */
76 virtual QList<QPair<int, QVariant> > groups() const;
77
78 /**
79 * @return The file-item for the index \a index. If the index is in a valid
80 * range it is assured that the file-item is not null. The runtime
81 * complexity of this call is O(1).
82 */
83 KFileItem fileItem(int index) const;
84
85 /**
86 * @return The file-item for the url \a url. If no file-item with the given
87 * URL is found KFileItem::isNull() will be true for the returned
88 * file-item. The runtime complexity of this call is O(1).
89 */
90 KFileItem fileItem(const KUrl& url) const;
91
92 /**
93 * @return The index for the file-item \a item. -1 is returned if no file-item
94 * is found or if the file-item is null. The runtime
95 * complexity of this call is O(1).
96 */
97 int index(const KFileItem& item) const;
98
99 /**
100 * @return The index for the URL \a url. -1 is returned if no file-item
101 * is found. The runtime complexity of this call is O(1).
102 */
103 int index(const KUrl& url) const;
104
105 /**
106 * @return Root item of all items.
107 */
108 KFileItem rootItem() const;
109
110 /**
111 * Clears all items of the model.
112 */
113 void clear();
114
115 // TODO: "name" + "isDir" is default in ctor
116 void setRoles(const QSet<QByteArray>& roles);
117 QSet<QByteArray> roles() const;
118
119 virtual bool setExpanded(int index, bool expanded);
120 virtual bool isExpanded(int index) const;
121 virtual bool isExpandable(int index) const;
122
123 QSet<KUrl> expandedUrls() const;
124
125 /**
126 * Marks the URLs in \a urls as subfolders which were expanded previously.
127 * They are re-expanded one by one each time the KDirLister's completed() signal is received.
128 * Note that a manual triggering of the KDirLister is required.
129 */
130 void restoreExpandedUrls(const QSet<KUrl>& urls);
131
132 /**
133 * Expands all parent-items of each URL given by \a urls.
134 */
135 void setExpanded(const QSet<KUrl>& urls);
136
137 void setNameFilter(const QString& nameFilter);
138 QString nameFilter() const;
139
140 signals:
141 void loadingCompleted();
142
143 protected:
144 virtual void onGroupedSortingChanged(bool current);
145 virtual void onSortRoleChanged(const QByteArray& current, const QByteArray& previous);
146 virtual void onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
147
148 private slots:
149 /**
150 * Resorts all items dependent on the set sortRole(), sortOrder()
151 * and foldersFirst() settings.
152 */
153 void resortAllItems();
154
155 void slotCompleted();
156 void slotCanceled();
157 void slotNewItems(const KFileItemList& items);
158 void slotItemsDeleted(const KFileItemList& items);
159 void slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& items);
160 void slotClear();
161 void slotClear(const KUrl& url);
162
163 void dispatchPendingItemsToInsert();
164
165 private:
166 enum Role {
167 NoRole,
168 NameRole,
169 SizeRole,
170 DateRole,
171 PermissionsRole,
172 OwnerRole,
173 GroupRole,
174 TypeRole,
175 DestinationRole,
176 PathRole,
177 CommentRole,
178 TagsRole,
179 RatingRole,
180 IsDirRole,
181 IsExpandedRole,
182 ExpansionLevelRole,
183 RolesCount // Mandatory last entry
184 };
185
186 struct ItemData
187 {
188 KFileItem item;
189 QHash<QByteArray, QVariant> values;
190 };
191
192 void insertItems(const KFileItemList& items);
193 void removeItems(const KFileItemList& items);
194
195 /**
196 * Helper method for insertItems() and removeItems(): Creates
197 * a list of ItemData elements based on the given items.
198 * Note that the ItemData instances are created dynamically and
199 * must be deleted by the caller.
200 */
201 QList<ItemData*> createItemDataList(const KFileItemList& items) const;
202
203 void removeExpandedItems();
204
205 /**
206 * Resets all values from m_requestRole to false.
207 */
208 void resetRoles();
209
210 Role roleIndex(const QByteArray& role) const;
211
212 QHash<QByteArray, QVariant> retrieveData(const KFileItem& item) const;
213
214 bool lessThan(const ItemData* a, const ItemData* b) const;
215
216 /**
217 * Sorts the items by using lessThan() as comparison criteria.
218 * The merge sort algorithm is used to assure a worst-case
219 * of O(n * log(n)) and to keep the number of comparisons low.
220 */
221 void sort(QList<ItemData*>::iterator begin, QList<ItemData*>::iterator end);
222
223 /** Helper method for sort(). */
224 void merge(QList<ItemData*>::iterator begin,
225 QList<ItemData*>::iterator pivot,
226 QList<ItemData*>::iterator end);
227
228 /** Helper method for sort(). */
229 QList<ItemData*>::iterator lowerBound(QList<ItemData*>::iterator begin,
230 QList<ItemData*>::iterator end,
231 const ItemData* value);
232
233 /** Helper method for sort(). */
234 QList<ItemData*>::iterator upperBound(QList<ItemData*>::iterator begin,
235 QList<ItemData*>::iterator end,
236 const ItemData* value);
237 /** Helper method for sort(). */
238 void reverse(QList<ItemData*>::iterator begin, QList<ItemData*>::iterator end);
239
240 int stringCompare(const QString& a, const QString& b) const;
241
242 /**
243 * Compares the expansion level of both items. The "expansion level" is defined
244 * by the number of parent directories. However simply comparing just the numbers
245 * is not sufficient, it is also important to check the hierarchy for having
246 * a correct order like shown in a tree.
247 */
248 int expansionLevelsCompare(const KFileItem& a, const KFileItem& b) const;
249
250 /**
251 * Helper method for expansionLevelCompare().
252 */
253 QString subPath(const KFileItem& item,
254 const QString& itemPath,
255 int start,
256 bool* isDir) const;
257
258 bool useMaximumUpdateInterval() const;
259
260 QList<QPair<int, QVariant> > nameRoleGroups() const;
261 QList<QPair<int, QVariant> > sizeRoleGroups() const;
262 QList<QPair<int, QVariant> > dateRoleGroups() const;
263 QList<QPair<int, QVariant> > permissionRoleGroups() const;
264 QList<QPair<int, QVariant> > ratingRoleGroups() const;
265 QList<QPair<int, QVariant> > genericStringRoleGroups(const QByteArray& role) const;
266
267 /**
268 * Helper method for all xxxRoleGroups() methods to check whether the
269 * item with the given index is a child-item. A child-item is defined
270 * as item having an expansion-level > 0. All xxxRoleGroups() methods
271 * should skip the grouping if the item is a child-item (although
272 * KItemListView would be capable to show sub-groups in groups this
273 * results in visual clutter for most usecases).
274 */
275 bool isChildItem(int index) const;
276
277 /**
278 * @return True if the given item matches with the current set name filter.
279 */
280 bool matchesNameFilter(const KFileItem& item) const;
281
282 private:
283 QWeakPointer<KDirLister> m_dirLister;
284
285 bool m_naturalSorting;
286 bool m_sortFoldersFirst;
287
288 Role m_sortRole;
289 QSet<QByteArray> m_roles;
290 Qt::CaseSensitivity m_caseSensitivity;
291
292 QList<ItemData*> m_itemData;
293 QHash<KUrl, int> m_items; // Allows O(1) access for KFileItemModel::index(const KFileItem& item)
294
295 QString m_nameFilter;
296 QSet<KFileItem> m_filteredItems; // Items that got hidden by KFileItemModel::setNameFilter()
297
298 bool m_requestRole[RolesCount];
299
300 QTimer* m_minimumUpdateIntervalTimer;
301 QTimer* m_maximumUpdateIntervalTimer;
302 QTimer* m_resortAllItemsTimer;
303 KFileItemList m_pendingItemsToInsert;
304 bool m_pendingEmitLoadingCompleted;
305
306 // Cache for KFileItemModel::groups()
307 mutable QList<QPair<int, QVariant> > m_groups;
308
309 // Stores the smallest expansion level of the root-URL. Is required to calculate
310 // the "expansionLevel" role in an efficient way. A value < 0 indicates that
311 // it has not been initialized yet.
312 mutable int m_rootExpansionLevel;
313
314 // Stores the URLs of the expanded folders.
315 QSet<KUrl> m_expandedUrls;
316
317 // URLs that must be expanded. The expanding is initially triggered in setExpanded()
318 // and done step after step in slotCompleted().
319 QSet<KUrl> m_urlsToExpand;
320
321 friend class KFileItemModelTest; // For unit testing
322 };
323
324 inline bool KFileItemModel::isChildItem(int index) const
325 {
326 return m_requestRole[ExpansionLevelRole] && m_itemData.at(index)->values.value("expansionLevel").toInt() > 0;
327 }
328
329 #endif
330
331