File indexing completed on 2024-02-25 04:00:58

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef KDIRMODEL_H
0009 #define KDIRMODEL_H
0010 
0011 #include "kiowidgets_export.h"
0012 #include <QAbstractItemModel>
0013 #include <kfileitem.h>
0014 
0015 #include <memory>
0016 
0017 class KDirLister;
0018 class KDirModelPrivate;
0019 class JobUrlCache;
0020 
0021 /**
0022  * @class KDirModel kdirmodel.h <KDirModel>
0023  *
0024  * @short A model for a KIO-based directory tree.
0025  *
0026  * KDirModel implements the QAbstractItemModel interface (for use with Qt's model/view widgets)
0027  * around the directory listing for one directory or a tree of directories.
0028  *
0029  * Note that there are some cases when using QPersistentModelIndexes from this model will not give
0030  * expected results. QPersistentIndexes will remain valid and updated if its siblings are added or
0031  * removed. However, if the QPersistentIndex or one of its ancestors is moved, the QPersistentIndex will become
0032  * invalid. For example, if a file or directory is renamed after storing a QPersistentModelIndex for it,
0033  * the index (along with any stored children) will become invalid even though it is still in the model. The reason
0034  * for this is that moves of files and directories are treated as separate insert and remove actions.
0035  *
0036  * @see KDirSortFilterProxyModel
0037  *
0038  * @author David Faure
0039  * Based on work by Hamish Rodda and Pascal Letourneau
0040  */
0041 class KIOWIDGETS_EXPORT KDirModel : public QAbstractItemModel
0042 {
0043     Q_OBJECT
0044 
0045 public:
0046     /**
0047      * @param parent parent qobject
0048      */
0049     explicit KDirModel(QObject *parent = nullptr);
0050     ~KDirModel() override;
0051 
0052     /**
0053      * Flags for the openUrl() method
0054      * @see OpenUrlFlags
0055      * @since 5.69
0056      */
0057     enum OpenUrlFlag {
0058         NoFlags = 0x0, ///< No additional flags specified.
0059         Reload = 0x1, ///< Indicates whether to use the cache or to reread
0060                       ///< the directory from the disk.
0061                       ///< Use only when opening a dir not yet listed by our dirLister()
0062                       ///< without using the cache. Otherwise use dirLister()->updateDirectory().
0063         ShowRoot = 0x2, ///< Display a root node for the URL being opened.
0064     };
0065     /**
0066      * Stores a combination of #OpenUrlFlag values.
0067      */
0068     Q_DECLARE_FLAGS(OpenUrlFlags, OpenUrlFlag)
0069     Q_FLAG(OpenUrlFlags)
0070 
0071     /**
0072      * Display the contents of @p url in the model.
0073      * Apart from the support for the ShowRoot flag, this is equivalent to dirLister()->openUrl(url, flags)
0074      * @param url   the URL of the directory whose contents should be listed.
0075      *              Unless ShowRoot is set, the item for this directory will NOT be shown, the model starts at its children.
0076      * @param flags see OpenUrlFlag
0077      * @since 5.69
0078      */
0079     Q_INVOKABLE void openUrl(const QUrl &url, OpenUrlFlags flags = NoFlags);
0080 
0081     /**
0082      * Set the directory lister to use by this model, instead of the default KDirLister created internally.
0083      * The model takes ownership.
0084      */
0085     void setDirLister(KDirLister *dirLister);
0086 
0087     /**
0088      * Return the directory lister used by this model.
0089      */
0090     KDirLister *dirLister() const;
0091 
0092     /**
0093      * Return the fileitem for a given index. This is O(1), i.e. fast.
0094      */
0095     KFileItem itemForIndex(const QModelIndex &index) const;
0096 
0097     /**
0098      * Return the index for a given kfileitem. This can be slow.
0099      */
0100     Q_INVOKABLE QModelIndex indexForItem(const KFileItem &) const;
0101 
0102     /**
0103      * Return the index for a given url. This can be slow.
0104      */
0105     Q_INVOKABLE QModelIndex indexForUrl(const QUrl &url) const;
0106 
0107     /**
0108      * @short Lists subdirectories using fetchMore() as needed until the given @p url exists in the model.
0109      *
0110      * When the model is used by a treeview, call KDirLister::openUrl with the base url of the tree,
0111      * then the treeview will take care of calling fetchMore() when the user opens directories.
0112      * However if you want the tree to show a given URL (i.e. open the tree recursively until that URL),
0113      * call expandToUrl().
0114      * Note that this is asynchronous; the necessary listing of subdirectories will take time so
0115      * the model will not immediately have this url available.
0116      * The model emits the signal expand() when an index has become available; this can be connected
0117      * to the treeview in order to let it open that index.
0118      * @param url the url of a subdirectory of the directory model (or a file in a subdirectory)
0119      */
0120     Q_INVOKABLE void expandToUrl(const QUrl &url);
0121 
0122     /**
0123      * Notify the model that the item at this index has changed.
0124      * For instance because KMimeTypeResolver called determineMimeType on it.
0125      * This makes the model emit its dataChanged signal at this index, so that views repaint.
0126      * Note that for most things (renaming, changing size etc.), KDirLister's signals tell the model already.
0127      */
0128     Q_INVOKABLE void itemChanged(const QModelIndex &index);
0129 
0130     /**
0131      * Forget all previews (optimization for turning previews off).
0132      * The items will again have their default appearance (not controlled by the model).
0133      * @since 5.28
0134      */
0135     Q_INVOKABLE void clearAllPreviews();
0136 
0137     /**
0138      * Useful "default" columns. Views can use a proxy to have more control over this.
0139      */
0140     enum ModelColumns {
0141         Name = 0,
0142         Size,
0143         ModifiedTime,
0144         Permissions,
0145         Owner,
0146         Group,
0147         Type,
0148         ColumnCount,
0149     };
0150 
0151     /// Possible return value for data(ChildCountRole), meaning the item isn't a directory,
0152     /// or we haven't calculated its child count yet
0153     enum { ChildCountUnknown = -1 };
0154 
0155     enum AdditionalRoles {
0156         // Note: use   printf "0x%08X\n" $(($RANDOM*$RANDOM))
0157         // to define additional roles.
0158         FileItemRole = 0x07A263FF, ///< returns the KFileItem for a given index. roleName is "fileItem".
0159         ChildCountRole = 0x2C4D0A40, ///< returns the number of items in a directory, or ChildCountUnknown. roleName is "childCount".
0160         HasJobRole = 0x01E555A5, ///< returns whether or not there is a job on an item (file/directory). roleName is "hasJob".
0161     };
0162 
0163     /**
0164      * @see DropsAllowed
0165      */
0166     enum DropsAllowedFlag {
0167         NoDrops = 0,
0168         DropOnDirectory = 1, ///< allow drops on any directory
0169         DropOnAnyFile = 2, ///< allow drops on any file
0170         DropOnLocalExecutable = 4, ///< allow drops on local executables, shell scripts and desktop files. Can be used with DropOnDirectory.
0171     };
0172     /**
0173      * Stores a combination of #DropsAllowedFlag values.
0174      */
0175     Q_DECLARE_FLAGS(DropsAllowed, DropsAllowedFlag)
0176     Q_FLAG(DropsAllowed)
0177 
0178     /// Set whether dropping onto items should be allowed, and for which kind of item
0179     /// Drops are disabled by default.
0180     Q_INVOKABLE void setDropsAllowed(DropsAllowed dropsAllowed);
0181 
0182     /// Reimplemented from QAbstractItemModel. Returns true for empty directories.
0183     bool canFetchMore(const QModelIndex &parent) const override;
0184     /// Reimplemented from QAbstractItemModel. Returns ColumnCount.
0185     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0186     /// Reimplemented from QAbstractItemModel.
0187     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0188     /// Reimplemented from QAbstractItemModel. Not implemented yet.
0189     bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
0190     /// Reimplemented from QAbstractItemModel. Lists the subdirectory.
0191     void fetchMore(const QModelIndex &parent) override;
0192     /// Reimplemented from QAbstractItemModel.
0193     Qt::ItemFlags flags(const QModelIndex &index) const override;
0194     /// Reimplemented from QAbstractItemModel. Returns true for directories.
0195     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
0196     /// Reimplemented from QAbstractItemModel. Returns the column titles.
0197     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
0198     /// Reimplemented from QAbstractItemModel. O(1)
0199     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0200     /// Reimplemented from QAbstractItemModel.
0201     QMimeData *mimeData(const QModelIndexList &indexes) const override;
0202     /// Reimplemented from QAbstractItemModel.
0203     QStringList mimeTypes() const override;
0204     /// Reimplemented from QAbstractItemModel.
0205     QModelIndex parent(const QModelIndex &index) const override;
0206     /// Reimplemented from QAbstractItemModel.
0207     QModelIndex sibling(int row, int column, const QModelIndex &index) const override;
0208     /// Reimplemented from QAbstractItemModel.
0209     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0210     /// Reimplemented from QAbstractItemModel.
0211     /// Call this to set a new icon, e.g. a preview
0212     bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
0213     /// Reimplemented from QAbstractItemModel. Not implemented. @see KDirSortFilterProxyModel
0214     void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
0215     /// Reimplemented from QAbstractItemModel.
0216     /// @see AdditionalRoles
0217     QHash<int, QByteArray> roleNames() const override;
0218 
0219     /**
0220      * Remove urls from the list if an ancestor is present on the list. This can
0221      * be used to delete only the ancestor url and skip a potential error of a non-existent url.
0222      *
0223      * 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",
0224      * "home/foo/b/b.txt", this method will return the list "/home/foo/a", "/home/foo/b/b.txt".
0225      *
0226      * @return the list @p urls without parented urls inside.
0227      */
0228     static QList<QUrl> simplifiedUrlList(const QList<QUrl> &urls);
0229 
0230     /**
0231      * This emits the needSequenceIcon signal, requesting another sequence icon
0232      *
0233      * If there is a KFilePreviewGenerator attached to this model, that generator will care
0234      * about creating another preview.
0235      *
0236      * @param index Index of the item that should get another icon
0237      * @param sequenceIndex Index in the sequence. If it is zero, the standard icon will be assigned.
0238      *                                        For higher indices, arbitrary different meaningful icons will be generated.
0239      */
0240     void requestSequenceIcon(const QModelIndex &index, int sequenceIndex);
0241 
0242     /**
0243      * Enable/Disable the displaying of an animated overlay that is shown for any destination
0244      * urls (in the view). When enabled, the animations (if any) will be drawn automatically.
0245      *
0246      * Only the files/folders that are visible and have jobs associated with them
0247      * will display the animation.
0248      * You would likely not want this enabled if you perform some kind of custom painting
0249      * that takes up a whole item, and will just make this(and what you paint) look funky.
0250      *
0251      * Default is disabled.
0252      *
0253      * Note: KFileItemDelegate needs to have it's method called with the same
0254      * value, when you make the call to this method.
0255      */
0256     void setJobTransfersVisible(bool show);
0257 
0258     /**
0259      * Returns whether or not displaying job transfers has been enabled.
0260      */
0261     bool jobTransfersVisible() const;
0262 
0263     Qt::DropActions supportedDropActions() const override;
0264 
0265 Q_SIGNALS:
0266     /**
0267      * Emitted for each subdirectory that is a parent of a url passed to expandToUrl
0268      * This allows to asynchronously open a tree view down to a given directory.
0269      * Also emitted for the final file, if expandToUrl is called with a file
0270      * (for instance so that it can be selected).
0271      */
0272     void expand(const QModelIndex &index);
0273     /**
0274      * Emitted when another icon sequence index is requested
0275      * @param index Index of the item that should get another icon
0276      * @param sequenceIndex Index in the sequence. If it is zero, the standard icon should be assigned.
0277      *                                        For higher indices, arbitrary different meaningful icons should be generated.
0278      *                                        This is usually slowly counted up while the user hovers the icon.
0279      *                                        If no meaningful alternative icons can be generated, this should be ignored.
0280      */
0281     void needSequenceIcon(const QModelIndex &index, int sequenceIndex);
0282 
0283 private:
0284     // Make those private, they shouldn't be called by applications
0285     bool insertRows(int, int, const QModelIndex & = QModelIndex()) override;
0286     bool insertColumns(int, int, const QModelIndex & = QModelIndex()) override;
0287     bool removeRows(int, int, const QModelIndex & = QModelIndex()) override;
0288     bool removeColumns(int, int, const QModelIndex & = QModelIndex()) override;
0289 
0290 private:
0291     friend class KDirModelPrivate;
0292     std::unique_ptr<KDirModelPrivate> const d;
0293 };
0294 
0295 Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::DropsAllowed)
0296 Q_DECLARE_OPERATORS_FOR_FLAGS(KDirModel::OpenUrlFlags)
0297 
0298 #endif /* KDIRMODEL_H */