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