| 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 | |