1 | /* |
2 | This file is part of the KDE project |
3 | SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-or-later |
6 | */ |
7 | |
8 | #ifndef KDIRMODEL_H |
9 | #define KDIRMODEL_H |
10 | |
11 | #include "kiowidgets_export.h" |
12 | #include <QAbstractItemModel> |
13 | #include <kfileitem.h> |
14 | |
15 | #include <memory> |
16 | |
17 | class KDirLister; |
18 | class KDirModelPrivate; |
19 | class JobUrlCache; |
20 | |
21 | /*! |
22 | * \class KDirModel |
23 | * \inmodule KIOWidgets |
24 | * |
25 | * \brief A model for a KIO-based directory tree. |
26 | * |
27 | * KDirModel implements the QAbstractItemModel interface (for use with Qt's model/view widgets) |
28 | * around the directory listing for one directory or a tree of directories. |
29 | * |
30 | * Note that there are some cases when using QPersistentModelIndexes from this model will not give |
31 | * expected results. QPersistentIndexes will remain valid and updated if its siblings are added or |
32 | * removed. However, if the QPersistentIndex or one of its ancestors is moved, the QPersistentIndex will become |
33 | * invalid. For example, if a file or directory is renamed after storing a QPersistentModelIndex for it, |
34 | * the index (along with any stored children) will become invalid even though it is still in the model. The reason |
35 | * for this is that moves of files and directories are treated as separate insert and remove actions. |
36 | * |
37 | * \sa KDirSortFilterProxyModel |
38 | * |
39 | */ |
40 | class KIOWIDGETS_EXPORT KDirModel : public QAbstractItemModel |
41 | { |
42 | Q_OBJECT |
43 | |
44 | public: |
45 | /*! |
46 | * \a parent parent qobject |
47 | */ |
48 | explicit KDirModel(QObject *parent = nullptr); |
49 | ~KDirModel() override; |
50 | |
51 | /*! |
52 | * Flags for the openUrl() method |
53 | * |
54 | * \value NoFlags No additional flags specified. |
55 | * \value Reload Indicates whether to use the cache or to reread the directory from the disk. Use only when opening a dir not yet listed by our dirLister() |
56 | * without using the cache. Otherwise use dirLister()->updateDirectory(). |
57 | * \value ShowRoot Display a root node for the URL being opened. |
58 | * \since 5.69 |
59 | */ |
60 | enum OpenUrlFlag { |
61 | NoFlags = 0x0, |
62 | Reload = 0x1, |
63 | ShowRoot = 0x2, |
64 | }; |
65 | Q_DECLARE_FLAGS(OpenUrlFlags, OpenUrlFlag) |
66 | Q_FLAG(OpenUrlFlags) |
67 | |
68 | /*! |
69 | * Display the contents of \a url in the model. |
70 | * |
71 | * Apart from the support for the ShowRoot flag, this is equivalent to dirLister()->openUrl(url, flags) |
72 | * |
73 | * \a url the URL of the directory whose contents should be listed. Unless ShowRoot is set, the item for this directory will NOT be shown, the model starts |
74 | * at its children. |
75 | * |
76 | * \a flags see OpenUrlFlag |
77 | * |
78 | * \since 5.69 |
79 | */ |
80 | Q_INVOKABLE void openUrl(const QUrl &url, OpenUrlFlags flags = NoFlags); |
81 | |
82 | /*! |
83 | * Set the directory lister to use by this model, instead of the default KDirLister created internally. |
84 | * The model takes ownership. |
85 | */ |
86 | void setDirLister(KDirLister *dirLister); |
87 | |
88 | /*! |
89 | * Return the directory lister used by this model. |
90 | */ |
91 | KDirLister *dirLister() const; |
92 | |
93 | /*! |
94 | * Return the fileitem for a given index. This is O(1), i.e. fast. |
95 | */ |
96 | KFileItem itemForIndex(const QModelIndex &index) const; |
97 | |
98 | /*! |
99 | * Return the index for a given kfileitem. This can be slow. |
100 | */ |
101 | Q_INVOKABLE QModelIndex indexForItem(const KFileItem &) const; |
102 | |
103 | /*! |
104 | * Return the index for a given url. This can be slow. |
105 | */ |
106 | Q_INVOKABLE QModelIndex indexForUrl(const QUrl &url) const; |
107 | |
108 | /*! |
109 | * Lists subdirectories using fetchMore() as needed until the given url exists in the model. |
110 | * |
111 | * When the model is used by a treeview, call KDirLister::openUrl with the base url of the tree, |
112 | * then the treeview will take care of calling fetchMore() when the user opens directories. |
113 | * However if you want the tree to show a given URL (i.e. open the tree recursively until that URL), |
114 | * call expandToUrl(). |
115 | * Note that this is asynchronous; the necessary listing of subdirectories will take time so |
116 | * the model will not immediately have this url available. |
117 | * The model emits the signal expand() when an index has become available; this can be connected |
118 | * to the treeview in order to let it open that index. |
119 | * |
120 | * \a url the url of a subdirectory of the directory model (or a file in a subdirectory) |
121 | */ |
122 | Q_INVOKABLE void expandToUrl(const QUrl &url); |
123 | |
124 | /*! |
125 | * Notify the model that the item at this index has changed. |
126 | * For instance because its mimetype was resolved. |
127 | * This makes the model emit its dataChanged signal at this index, so that views repaint. |
128 | * Note that for most things (renaming, changing size etc.), KDirLister's signals tell the model already. |
129 | */ |
130 | Q_INVOKABLE void itemChanged(const QModelIndex &index); |
131 | |
132 | /*! |
133 | * Forget all previews (optimization for turning previews off). |
134 | * The items will again have their default appearance (not controlled by the model). |
135 | * \since 5.28 |
136 | */ |
137 | Q_INVOKABLE void clearAllPreviews(); |
138 | |
139 | /*! |
140 | * Useful "default" columns. Views can use a proxy to have more control over this. |
141 | * |
142 | * \value Name |
143 | * \value Size |
144 | * \value ModifiedTime |
145 | * \value Permissions |
146 | * \value Owner |
147 | * \value Group |
148 | * \value Type |
149 | * \value ColumnCount |
150 | */ |
151 | enum ModelColumns { |
152 | Name = 0, |
153 | Size, |
154 | ModifiedTime, |
155 | Permissions, |
156 | Owner, |
157 | Group, |
158 | Type, |
159 | ColumnCount, |
160 | }; |
161 | |
162 | /*! |
163 | * Possible return value for data(ChildCountRole), meaning the item isn't a directory, |
164 | * or we haven't calculated its child count yet |
165 | * |
166 | * \value ChildCountUnknown |
167 | */ |
168 | enum { |
169 | ChildCountUnknown = -1 |
170 | }; |
171 | |
172 | /*! |
173 | * \value FileItemRole Returns the KFileItem for a given index. roleName is "fileItem". |
174 | * \value ChildCountRole Returns the number of items in a directory, or ChildCountUnknown. roleName is "childCount". |
175 | * \value HasJobRole Returns whether or not there is a job on an item (file/directory). roleName is "hasJob". |
176 | * \value HandleSequencesRole |
177 | */ |
178 | enum AdditionalRoles { |
179 | // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) |
180 | // to define additional roles. |
181 | FileItemRole = 0x07A263FF, |
182 | ChildCountRole = 0x2C4D0A40, |
183 | HasJobRole = 0x01E555A5, |
184 | HandleSequencesRole = 0x1E642272, |
185 | }; |
186 | |
187 | /*! |
188 | * \value NoDrops |
189 | * \value DropOnDirectory Allow drops on any directory |
190 | * \value DropOnAnyFile Allow drops on any file |
191 | * \value DropOnLocalExecutable Allow drops on local executables, shell scripts and desktop files. Can be used with DropOnDirectory. |
192 | */ |
193 | enum DropsAllowedFlag { |
194 | NoDrops = 0, |
195 | DropOnDirectory = 1, |
196 | DropOnAnyFile = 2, |
197 | DropOnLocalExecutable = 4, |
198 | }; |
199 | Q_DECLARE_FLAGS(DropsAllowed, DropsAllowedFlag) |
200 | Q_FLAG(DropsAllowed) |
201 | |
202 | /*! |
203 | * Set whether dropping onto items should be allowed, and for which kind of item |
204 | * Drops are disabled by default. |
205 | */ |
206 | Q_INVOKABLE void setDropsAllowed(DropsAllowed dropsAllowed); |
207 | |
208 | /*! |
209 | * \reimp |
210 | * Returns \c true for empty directories. |
211 | */ |
212 | bool canFetchMore(const QModelIndex &parent) const override; |
213 | |
214 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; |
215 | |
216 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
217 | |
218 | bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; |
219 | |
220 | /*! |
221 | * \reimp Lists the subdirectory. |
222 | */ |
223 | void fetchMore(const QModelIndex &parent) override; |
224 | |
225 | Qt::ItemFlags flags(const QModelIndex &index) const override; |
226 | |
227 | /*! |
228 | * \reimp |
229 | * Returns \c true for directories |
230 | */ |
231 | bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; |
232 | |
233 | /*! |
234 | * \reimp |
235 | * Returns the column titles. |
236 | */ |
237 | QVariant (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; |
238 | |
239 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; |
240 | |
241 | QMimeData *mimeData(const QModelIndexList &indexes) const override; |
242 | |
243 | QStringList mimeTypes() const override; |
244 | |
245 | QModelIndex parent(const QModelIndex &index) const override; |
246 | |
247 | QModelIndex sibling(int row, int column, const QModelIndex &index) const override; |
248 | |
249 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
250 | |
251 | /*! |
252 | * \reimp |
253 | * Call this to set a new icon, e.g. a preview |
254 | */ |
255 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; |
256 | |
257 | /*! |
258 | * \reimp |
259 | * Not implemented. |
260 | * \sa KDirSortFilterProxyModel |
261 | */ |
262 | void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; |
263 | |
264 | QHash<int, QByteArray> roleNames() const override; |
265 | |
266 | /*! |
267 | * Remove urls from the list if an ancestor is present on the list. This can |
268 | * be used to delete only the ancestor url and skip a potential error of a non-existent url. |
269 | * |
270 | * For example, for a list of "/home/foo/a", "/home/foo/a/a.txt", "/home/foo/a/a/a.txt", "/home/foo/a/b/b.txt", |
271 | * "home/foo/b/b.txt", this method will return the list "/home/foo/a", "/home/foo/b/b.txt". |
272 | * |
273 | * Returns the list \a urls without parented urls inside. |
274 | */ |
275 | static QList<QUrl> simplifiedUrlList(const QList<QUrl> &urls); |
276 | |
277 | /*! |
278 | * This emits the needSequenceIcon signal, requesting another sequence icon |
279 | * |
280 | * If there is a KFilePreviewGenerator attached to this model, that generator will care |
281 | * about creating another preview. |
282 | * |
283 | * \a index Index of the item that should get another icon |
284 | * |
285 | * \a sequenceIndex Index in the sequence. If it is zero, the standard icon will be assigned. |
286 | * For higher indices, arbitrary different meaningful icons will be generated. |
287 | */ |
288 | void requestSequenceIcon(const QModelIndex &index, int sequenceIndex); |
289 | |
290 | /*! |
291 | * Enable/Disable the displaying of an animated overlay that is shown for any destination |
292 | * urls (in the view). When enabled, the animations (if any) will be drawn automatically. |
293 | * |
294 | * Only the files/folders that are visible and have jobs associated with them |
295 | * will display the animation. |
296 | * You would likely not want this enabled if you perform some kind of custom painting |
297 | * that takes up a whole item, and will just make this(and what you paint) look funky. |
298 | * |
299 | * Default is disabled. |
300 | * |
301 | * Note: KFileItemDelegate needs to have it's method called with the same |
302 | * value, when you make the call to this method. |
303 | */ |
304 | void setJobTransfersVisible(bool show); |
305 | |
306 | /*! |
307 | * Returns whether or not displaying job transfers has been enabled. |
308 | */ |
309 | bool jobTransfersVisible() const; |
310 | |
311 | Qt::DropActions supportedDropActions() const override; |
312 | |
313 | Q_SIGNALS: |
314 | /*! |
315 | * Emitted for each subdirectory that is a parent of a url passed to expandToUrl |
316 | * This allows to asynchronously open a tree view down to a given directory. |
317 | * Also emitted for the final file, if expandToUrl is called with a file |
318 | * (for instance so that it can be selected). |
319 | */ |
320 | void expand(const QModelIndex &index); |
321 | /*! |
322 | * Emitted when another icon sequence index is requested |
323 | * |
324 | * \a index Index of the item that should get another icon |
325 | * |
326 | * \a sequenceIndex Index in the sequence. If it is zero, the standard icon should be assigned. |
327 | * For higher indices, arbitrary different meaningful icons should be generated. |
328 | * This is usually slowly counted up while the user hovers the icon. |
329 | * If no meaningful alternative icons can be generated, this should be ignored. |
330 | */ |
331 | void needSequenceIcon(const QModelIndex &index, int sequenceIndex); |
332 | |
333 | private: |
334 | // Make those private, they shouldn't be called by applications |
335 | bool insertRows(int, int, const QModelIndex & = QModelIndex()) override; |
336 | bool insertColumns(int, int, const QModelIndex & = QModelIndex()) override; |
337 | bool removeRows(int, int, const QModelIndex & = QModelIndex()) override; |
338 | bool removeColumns(int, int, const QModelIndex & = QModelIndex()) override; |
339 | |
340 | private: |
341 | friend class KDirModelPrivate; |
342 | std::unique_ptr<KDirModelPrivate> const d; |
343 | }; |
344 | |
345 | Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::DropsAllowed) |
346 | Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::OpenUrlFlags) |
347 | |
348 | #endif /* KDIRMODEL_H */ |
349 | |