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
17class KDirLister;
18class KDirModelPrivate;
19class 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 */
41class KIOWIDGETS_EXPORT KDirModel : public QAbstractItemModel
42{
43 Q_OBJECT
44
45public:
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 headerData(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
265Q_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
283private:
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
290private:
291 friend class KDirModelPrivate;
292 std::unique_ptr<KDirModelPrivate> const d;
293};
294
295Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::DropsAllowed)
296Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::OpenUrlFlags)
297
298#endif /* KDIRMODEL_H */
299

source code of kio/src/widgets/kdirmodel.h