File indexing completed on 2025-01-26 05:06:21

0001 /*
0002     SPDX-FileCopyrightText: 2008 Fredrik Höglund <fredrik@kde.org>
0003     SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
0004     SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #pragma once
0010 
0011 #include <QImage>
0012 #include <QItemSelection>
0013 #include <QPointer>
0014 #include <QQmlParserStatus>
0015 #include <QRegularExpression>
0016 #include <QSet>
0017 #include <QSortFilterProxyModel>
0018 #include <QStringList>
0019 
0020 #include <KAbstractViewAdapter>
0021 #include <KActionCollection>
0022 #include <KDirLister>
0023 #include <KFilePreviewGenerator>
0024 
0025 #include <KNewFileMenu>
0026 
0027 #include <Plasma/Applet>
0028 
0029 #include "folderplugin_private_export.h"
0030 
0031 class QDrag;
0032 class QItemSelectionModel;
0033 class QQuickItem;
0034 
0035 class KFileCopyToMenu;
0036 class KDirModel;
0037 class KDirWatch;
0038 class KFileItem;
0039 class KFileItemActions;
0040 class KJob;
0041 
0042 namespace KIO
0043 {
0044 class DropJob;
0045 class StatJob;
0046 }
0047 
0048 class ScreenMapper;
0049 
0050 class DirLister : public KDirLister
0051 {
0052     Q_OBJECT
0053 
0054 public:
0055     explicit DirLister(QObject *parent = nullptr);
0056     ~DirLister() override;
0057 
0058 Q_SIGNALS:
0059     void error(const QString &string);
0060 
0061 private:
0062     void handleJobError(KIO::Job *job);
0063 };
0064 
0065 class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
0066 {
0067     Q_OBJECT
0068     Q_INTERFACES(QQmlParserStatus)
0069 
0070     Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
0071     Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged)
0072     Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged)
0073     Q_PROPERTY(Status status READ status NOTIFY statusChanged)
0074     Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged)
0075     Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
0076     Q_PROPERTY(bool dragInProgressAnywhere READ isDragInProgressAnywhere NOTIFY dragInProgressAnywhereChanged)
0077     Q_PROPERTY(bool usedByContainment READ usedByContainment WRITE setUsedByContainment NOTIFY usedByContainmentChanged)
0078     Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged)
0079     Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
0080     Q_PROPERTY(bool sortDesc READ sortDesc WRITE setSortDesc NOTIFY sortDescChanged)
0081     Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
0082     Q_PROPERTY(bool parseDesktopFiles READ parseDesktopFiles WRITE setParseDesktopFiles NOTIFY parseDesktopFilesChanged)
0083     Q_PROPERTY(QObject *viewAdapter READ viewAdapter WRITE setViewAdapter NOTIFY viewAdapterChanged)
0084     Q_PROPERTY(bool previews READ previews WRITE setPreviews NOTIFY previewsChanged)
0085     Q_PROPERTY(QStringList previewPlugins READ previewPlugins WRITE setPreviewPlugins NOTIFY previewPluginsChanged)
0086     Q_PROPERTY(int filterMode READ filterMode WRITE setFilterMode NOTIFY filterModeChanged)
0087     Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged)
0088     Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged)
0089     Q_PROPERTY(QObject *newMenu READ newMenu CONSTANT)
0090     Q_PROPERTY(Plasma::Applet *applet READ applet WRITE setApplet NOTIFY appletChanged)
0091     Q_PROPERTY(bool showHiddenFiles READ showHiddenFiles WRITE setShowHiddenFiles NOTIFY showHiddenFilesChanged)
0092 
0093 public:
0094     enum DataRole {
0095         BlankRole = Qt::UserRole + 1,
0096         SelectedRole,
0097         IsDirRole,
0098         IsLinkRole,
0099         IsHiddenRole,
0100         UrlRole,
0101         LinkDestinationUrl,
0102         SizeRole,
0103         TypeRole,
0104         FileNameRole,
0105         FileNameWrappedRole,
0106     };
0107 
0108     enum FilterMode {
0109         NoFilter = 0,
0110         FilterShowMatches,
0111         FilterHideMatches,
0112     };
0113 
0114     enum Status {
0115         None,
0116         Ready,
0117         Listing,
0118         Canceled,
0119     };
0120     Q_ENUM(Status)
0121 
0122     explicit FolderModel(QObject *parent = nullptr);
0123     ~FolderModel() override;
0124 
0125     QHash<int, QByteArray> roleNames() const override;
0126     static QHash<int, QByteArray> staticRoleNames();
0127 
0128     void classBegin() override;
0129     void componentComplete() override;
0130 
0131     QString url() const;
0132     void setUrl(const QString &url);
0133 
0134     QString iconName() const;
0135 
0136     QUrl resolvedUrl() const;
0137     Q_INVOKABLE QUrl resolve(const QString &url);
0138 
0139     Status status() const;
0140 
0141     QString errorString() const;
0142 
0143     bool dragging() const;
0144     bool isDragInProgressAnywhere() const;
0145 
0146     bool usedByContainment() const;
0147     void setUsedByContainment(bool used);
0148 
0149     bool locked() const;
0150     void setLocked(bool locked);
0151 
0152     int sortMode() const;
0153     void setSortMode(int mode);
0154 
0155     bool sortDesc() const;
0156     void setSortDesc(bool desc);
0157 
0158     bool sortDirsFirst() const;
0159     void setSortDirsFirst(bool enable);
0160 
0161     bool parseDesktopFiles() const;
0162     void setParseDesktopFiles(bool enable);
0163 
0164     QObject *viewAdapter() const;
0165     void setViewAdapter(QObject *adapter);
0166 
0167     bool previews() const;
0168     void setPreviews(bool previews);
0169 
0170     QStringList previewPlugins() const;
0171     void setPreviewPlugins(const QStringList &previewPlugins);
0172 
0173     int filterMode() const;
0174     void setFilterMode(int filterMode);
0175 
0176     QString filterPattern() const;
0177     void setFilterPattern(const QString &pattern);
0178 
0179     QStringList filterMimeTypes() const;
0180     void setFilterMimeTypes(const QStringList &mimeList);
0181 
0182     Plasma::Applet *applet() const;
0183     void setApplet(Plasma::Applet *applet);
0184 
0185     bool showHiddenFiles() const;
0186     void setShowHiddenFiles(bool enable);
0187 
0188     KFileItem rootItem() const;
0189 
0190     Q_INVOKABLE void up();
0191     Q_INVOKABLE void cd(int row);
0192 
0193     Q_INVOKABLE void run(int row);
0194     Q_INVOKABLE void runSelected();
0195 
0196     Q_INVOKABLE void rename(int row, const QString &name);
0197     Q_INVOKABLE int fileExtensionBoundary(int row);
0198 
0199     Q_INVOKABLE bool hasSelection() const;
0200     Q_INVOKABLE bool isSelected(int row);
0201     Q_INVOKABLE void setSelected(int row);
0202     Q_INVOKABLE void toggleSelected(int row);
0203     Q_INVOKABLE void setRangeSelected(int anchor, int to);
0204     Q_INVOKABLE void updateSelection(const QVariantList &rows, bool toggle);
0205     Q_INVOKABLE void clearSelection();
0206     Q_INVOKABLE void pinSelection();
0207     Q_INVOKABLE void unpinSelection();
0208 
0209     Q_INVOKABLE void addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image);
0210     Q_INVOKABLE void clearDragImages();
0211     Q_INVOKABLE void setDragHotSpotScrollOffset(int x, int y); // FIXME TODO: Propify.
0212     Q_INVOKABLE QPoint dragCursorOffset(int row);
0213     Q_INVOKABLE void dragSelected(int x, int y);
0214     Q_INVOKABLE void drop(QQuickItem *target, QObject *dropEvent, int row, bool showMenuManually = false);
0215     Q_INVOKABLE void dropCwd(QObject *dropEvent);
0216 
0217     Q_INVOKABLE bool isBlank(int row) const;
0218 
0219     Q_INVOKABLE QAction *action(const QString &name) const;
0220     QObject *newMenu() const;
0221     Q_INVOKABLE void updateActions();
0222     Q_INVOKABLE void openContextMenu(QQuickItem *visualParent = nullptr, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
0223 
0224     Q_INVOKABLE void linkHere(const QUrl &sourceUrl);
0225 
0226     Q_INVOKABLE void openPropertiesDialog();
0227 
0228     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0229     int indexForUrl(const QUrl &url) const;
0230     KFileItem itemForIndex(const QModelIndex &index) const;
0231     bool isDir(const QModelIndex &index, const KDirModel *dirModel) const;
0232     bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
0233     Qt::DropActions supportedDragActions() const override;
0234     Qt::DropActions supportedDropActions() const override;
0235 
0236     Q_INVOKABLE void paste();
0237     Q_INVOKABLE void copy();
0238     Q_INVOKABLE void cut();
0239     Q_INVOKABLE void deleteSelected();
0240     Q_INVOKABLE void undo();
0241     Q_INVOKABLE void refresh();
0242     Q_INVOKABLE void createFolder();
0243 
0244     void setScreen(int screen);
0245 
0246 Q_SIGNALS:
0247     void urlChanged() const;
0248     void listingCompleted() const;
0249     void listingCanceled() const;
0250     void iconNameChanged() const;
0251     void resolvedUrlChanged() const;
0252     void statusChanged() const;
0253     void errorStringChanged() const;
0254     void draggingChanged() const;
0255     void dragInProgressAnywhereChanged() const;
0256     void usedByContainmentChanged() const;
0257     void lockedChanged() const;
0258     void sortModeChanged() const;
0259     void sortDescChanged() const;
0260     void sortDirsFirstChanged() const;
0261     void parseDesktopFilesChanged() const;
0262     void viewAdapterChanged();
0263     void previewsChanged() const;
0264     void previewPluginsChanged() const;
0265     void filterModeChanged() const;
0266     void filterPatternChanged() const;
0267     void filterMimeTypesChanged() const;
0268     void screenChanged() const;
0269     void appletChanged() const;
0270     void requestRename() const;
0271     void move(int x, int y, QList<QUrl> urls);
0272     void popupMenuAboutToShow(KIO::DropJob *dropJob, QMimeData *mimeData, int x, int y);
0273     void selectionChanged() const;
0274     void showHiddenFilesChanged() const;
0275 
0276 protected:
0277     bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
0278     bool matchMimeType(const KFileItem &item) const;
0279     bool matchPattern(const KFileItem &item) const;
0280 
0281 private Q_SLOTS:
0282     void dragSelectedInternal(int x, int y);
0283     void dirListFailed(const QString &error);
0284     void statResult(KJob *job);
0285     void evictFromIsDirCache(const KFileItemList &items);
0286     void changeSelection(const QItemSelection &selected, const QItemSelection &deselected);
0287     void pasteTo();
0288     void moveSelectedToTrash();
0289     void emptyTrashBin();
0290     void restoreSelectedFromTrash();
0291     void undoTextChanged(const QString &text);
0292     void invalidateIfComplete();
0293     void invalidateFilterIfComplete();
0294     void newFileMenuItemCreated(const QUrl &url);
0295 
0296 private:
0297     struct DragImage {
0298         int row;
0299         QRect rect;
0300         QPoint cursorOffset;
0301         QImage image;
0302         bool blank;
0303     };
0304 
0305     QPoint localMenuPosition() const;
0306     void createActions();
0307     void addDragImage(QDrag *drag, int x, int y);
0308     void setStatus(Status status);
0309     static bool isTrashEmpty();
0310     static bool isDeleteCommandShown();
0311     QList<QUrl> selectedUrls() const;
0312     KDirModel *m_dirModel;
0313     KDirWatch *m_dirWatch;
0314     QString m_url;
0315     mutable QHash<QUrl, bool> m_isDirCache;
0316     mutable QHash<QUrl, KIO::StatJob *> m_isDirJobs;
0317     QItemSelectionModel *m_selectionModel;
0318     QItemSelection m_pinnedSelection;
0319     QModelIndexList m_dragIndexes;
0320     QHash<int, DragImage *> m_dragImages;
0321     QPoint m_dragHotSpotScrollOffset;
0322     bool m_urlChangedWhileDragging;
0323     // target filename to target position of a drop event, note that this deliberately
0324     // is not using the URL to easily support desktop:/ URL schemes
0325     QHash<QString, QPoint> m_dropTargetPositions;
0326     QTimer *m_dropTargetPositionsCleanup;
0327     QPointer<KFilePreviewGenerator> m_previewGenerator;
0328     QPointer<KAbstractViewAdapter> m_viewAdapter;
0329     KActionCollection m_actionCollection;
0330     KNewFileMenu *m_newMenu;
0331     KFileItemActions *m_fileItemActions;
0332     KFileCopyToMenu *m_copyToMenu;
0333     Status m_status = Status::None;
0334     QString m_errorString;
0335     bool m_usedByContainment;
0336     bool m_locked;
0337     int m_sortMode; // FIXME TODO: Enumify.
0338     bool m_sortDesc;
0339     bool m_sortDirsFirst;
0340     bool m_parseDesktopFiles;
0341     bool m_previews;
0342     // An empty previewPlugin list means use default.
0343     // We don't want to leak that fact to the QML side, however, so the property stays empty
0344     // and internally we operate on effectivePreviewPlugins instead.
0345     QStringList m_previewPlugins;
0346     QStringList m_effectivePreviewPlugins;
0347     FilterMode m_filterMode;
0348     QString m_filterPattern;
0349     bool m_filterPatternMatchAll;
0350     QSet<QString> m_mimeSet;
0351     QList<QRegularExpression> m_regExps;
0352     int m_screen = -1;
0353     bool m_screenUsed;
0354     ScreenMapper *m_screenMapper = nullptr;
0355     Plasma::Applet *m_applet = nullptr;
0356     bool m_complete;
0357     QPoint m_menuPosition;
0358 
0359     /**
0360      * This property is used to save the current activity when FolderModel is initialized.
0361      */
0362     QString m_currentActivity;
0363     bool m_showHiddenFiles;
0364 };
0365 
0366 class DragTracker : public QObject
0367 {
0368     Q_OBJECT
0369 public:
0370     DragTracker(QObject *parent = nullptr);
0371     ~DragTracker();
0372 
0373     bool isDragInProgress() const;
0374     void setDragInProgress(FolderModel *dragOwner, bool drag);
0375 
0376     FolderModel *dragOwner();
0377 
0378     static DragTracker *self();
0379 
0380 Q_SIGNALS:
0381     void dragInProgressChanged(bool dragInProgress);
0382 
0383 private:
0384     bool m_dragInProgress = false;
0385     QPointer<FolderModel> m_dragOwner;
0386 };