1 /*
2     SPDX-FileCopyrightText: 2008 Fredrik Höglund <fredrik@kde.org>
3     SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
4     SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #ifndef FOLDERMODEL_H
10 #define FOLDERMODEL_H
11 
12 #include <QImage>
13 #include <QItemSelection>
14 #include <QPointer>
15 #include <QQmlParserStatus>
16 #include <QRegExp>
17 #include <QSet>
18 #include <QSortFilterProxyModel>
19 #include <QStringList>
20 
21 #include <KAbstractViewAdapter>
22 #include <KActionCollection>
23 #include <KDirLister>
24 #include <KFilePreviewGenerator>
25 
26 #include <KNewFileMenu>
27 
28 #include "folderplugin_private_export.h"
29 
30 class QDrag;
31 class QItemSelectionModel;
32 class QQuickItem;
33 
34 class KFileCopyToMenu;
35 class KActionCollection;
36 class KDirModel;
37 class KDirWatch;
38 class KFileItem;
39 class KFileItemActions;
40 class KJob;
41 class KNewFileMenu;
42 
43 namespace KIO
44 {
45 class DropJob;
46 class StatJob;
47 }
48 
49 class ScreenMapper;
50 
51 class DirLister : public KDirLister
52 {
53     Q_OBJECT
54 
55 public:
56     explicit DirLister(QObject *parent = nullptr);
57     ~DirLister() override;
58 
59 Q_SIGNALS:
60     void error(const QString &string);
61 
62 protected:
63     void handleError(KIO::Job *job) override;
64 };
65 
66 class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
67 {
68     Q_OBJECT
69     Q_INTERFACES(QQmlParserStatus)
70 
71     Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
72     Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged)
73     Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged)
74     Q_PROPERTY(Status status READ status NOTIFY statusChanged)
75     Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged)
76     Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
77     Q_PROPERTY(bool usedByContainment READ usedByContainment WRITE setUsedByContainment NOTIFY usedByContainmentChanged)
78     Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged)
79     Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
80     Q_PROPERTY(bool sortDesc READ sortDesc WRITE setSortDesc NOTIFY sortDescChanged)
81     Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged)
82     Q_PROPERTY(bool parseDesktopFiles READ parseDesktopFiles WRITE setParseDesktopFiles NOTIFY parseDesktopFilesChanged)
83     Q_PROPERTY(QObject *viewAdapter READ viewAdapter WRITE setViewAdapter NOTIFY viewAdapterChanged)
84     Q_PROPERTY(bool previews READ previews WRITE setPreviews NOTIFY previewsChanged)
85     Q_PROPERTY(QStringList previewPlugins READ previewPlugins WRITE setPreviewPlugins NOTIFY previewPluginsChanged)
86     Q_PROPERTY(int filterMode READ filterMode WRITE setFilterMode NOTIFY filterModeChanged)
87     Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged)
88     Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged)
89     Q_PROPERTY(QObject *newMenu READ newMenu CONSTANT)
90     Q_PROPERTY(QObject *appletInterface READ appletInterface WRITE setAppletInterface NOTIFY appletInterfaceChanged)
91 
92 public:
93     enum DataRole {
94         BlankRole = Qt::UserRole + 1,
95         SelectedRole,
96         IsDirRole,
97         IsLinkRole,
98         IsHiddenRole,
99         UrlRole,
100         LinkDestinationUrl,
101         SizeRole,
102         TypeRole,
103         FileNameRole,
104         FileNameWrappedRole,
105     };
106 
107     enum FilterMode {
108         NoFilter = 0,
109         FilterShowMatches,
110         FilterHideMatches,
111     };
112 
113     enum Status {
114         None,
115         Ready,
116         Listing,
117         Canceled,
118     };
119     Q_ENUM(Status)
120 
121     explicit FolderModel(QObject *parent = nullptr);
122     ~FolderModel() override;
123 
124     QHash<int, QByteArray> roleNames() const override;
125     static QHash<int, QByteArray> staticRoleNames();
126 
127     void classBegin() override;
128     void componentComplete() override;
129 
130     QString url() const;
131     void setUrl(const QString &url);
132 
133     QString iconName() const;
134 
135     QUrl resolvedUrl() const;
136     Q_INVOKABLE QUrl resolve(const QString &url);
137 
138     Status status() const;
139 
140     QString errorString() const;
141 
142     bool dragging() const;
143 
144     bool usedByContainment() const;
145     void setUsedByContainment(bool used);
146 
147     bool locked() const;
148     void setLocked(bool locked);
149 
150     int sortMode() const;
151     void setSortMode(int mode);
152 
153     bool sortDesc() const;
154     void setSortDesc(bool desc);
155 
156     bool sortDirsFirst() const;
157     void setSortDirsFirst(bool enable);
158 
159     bool parseDesktopFiles() const;
160     void setParseDesktopFiles(bool enable);
161 
162     QObject *viewAdapter() const;
163     void setViewAdapter(QObject *adapter);
164 
165     bool previews() const;
166     void setPreviews(bool previews);
167 
168     QStringList previewPlugins() const;
169     void setPreviewPlugins(const QStringList &previewPlugins);
170 
171     int filterMode() const;
172     void setFilterMode(int filterMode);
173 
174     QString filterPattern() const;
175     void setFilterPattern(const QString &pattern);
176 
177     QStringList filterMimeTypes() const;
178     void setFilterMimeTypes(const QStringList &mimeList);
179 
180     QObject *appletInterface() const;
181     void setAppletInterface(QObject *appletInterface);
182 
183     KFileItem rootItem() const;
184 
185     Q_INVOKABLE void up();
186     Q_INVOKABLE void cd(int row);
187 
188     Q_INVOKABLE void run(int row);
189     Q_INVOKABLE void runSelected();
190 
191     Q_INVOKABLE void rename(int row, const QString &name);
192     Q_INVOKABLE int fileExtensionBoundary(int row);
193 
194     Q_INVOKABLE bool hasSelection() const;
195     Q_INVOKABLE bool isSelected(int row);
196     Q_INVOKABLE void setSelected(int row);
197     Q_INVOKABLE void toggleSelected(int row);
198     Q_INVOKABLE void setRangeSelected(int anchor, int to);
199     Q_INVOKABLE void updateSelection(const QVariantList &rows, bool toggle);
200     Q_INVOKABLE void clearSelection();
201     Q_INVOKABLE void pinSelection();
202     Q_INVOKABLE void unpinSelection();
203 
204     Q_INVOKABLE void addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image);
205     Q_INVOKABLE void clearDragImages();
206     Q_INVOKABLE void setDragHotSpotScrollOffset(int x, int y); // FIXME TODO: Propify.
207     Q_INVOKABLE QPoint dragCursorOffset(int row);
208     Q_INVOKABLE void dragSelected(int x, int y);
209     Q_INVOKABLE void drop(QQuickItem *target, QObject *dropEvent, int row, bool showMenuManually = false);
210     Q_INVOKABLE void dropCwd(QObject *dropEvent);
211 
212     Q_INVOKABLE bool isBlank(int row) const;
213 
214     Q_INVOKABLE QAction *action(const QString &name) const;
215     QObject *newMenu() const;
216     Q_INVOKABLE void updateActions();
217     Q_INVOKABLE void openContextMenu(QQuickItem *visualParent = nullptr, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
218 
219     Q_INVOKABLE void linkHere(const QUrl &sourceUrl);
220 
221     Q_INVOKABLE void openPropertiesDialog();
222 
223     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
224     int indexForUrl(const QUrl &url) const;
225     KFileItem itemForIndex(const QModelIndex &index) const;
226     bool isDir(const QModelIndex &index, const KDirModel *dirModel) const;
227     bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
228     Qt::DropActions supportedDragActions() const override;
229     Qt::DropActions supportedDropActions() const override;
230 
231     Q_INVOKABLE void paste();
232     Q_INVOKABLE void copy();
233     Q_INVOKABLE void cut();
234     Q_INVOKABLE void deleteSelected();
235     Q_INVOKABLE void openSelected();
236     Q_INVOKABLE void undo();
237     Q_INVOKABLE void refresh();
238     Q_INVOKABLE void createFolder();
239 
240     void setScreen(int screen);
241 
242 Q_SIGNALS:
243     void urlChanged() const;
244     void listingCompleted() const;
245     void listingCanceled() const;
246     void iconNameChanged() const;
247     void resolvedUrlChanged() const;
248     void statusChanged() const;
249     void errorStringChanged() const;
250     void draggingChanged() const;
251     void usedByContainmentChanged() const;
252     void lockedChanged() const;
253     void sortModeChanged() const;
254     void sortDescChanged() const;
255     void sortDirsFirstChanged() const;
256     void parseDesktopFilesChanged() const;
257     void viewAdapterChanged();
258     void previewsChanged() const;
259     void previewPluginsChanged() const;
260     void filterModeChanged() const;
261     void filterPatternChanged() const;
262     void filterMimeTypesChanged() const;
263     void screenChanged() const;
264     void appletInterfaceChanged() const;
265     void requestRename() const;
266     void move(int x, int y, QList<QUrl> urls);
267     void popupMenuAboutToShow(KIO::DropJob *dropJob, QMimeData *mimeData, int x, int y);
268 
269 protected:
270     bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
271     bool matchMimeType(const KFileItem &item) const;
272     bool matchPattern(const KFileItem &item) const;
273 
274 private Q_SLOTS:
275     void dragSelectedInternal(int x, int y);
276     void dirListFailed(const QString &error);
277     void statResult(KJob *job);
278     void evictFromIsDirCache(const KFileItemList &items);
279     void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
280     void pasteTo();
281     void moveSelectedToTrash();
282     void emptyTrashBin();
283     void restoreSelectedFromTrash();
284     void undoTextChanged(const QString &text);
285     void invalidateIfComplete();
286     void invalidateFilterIfComplete();
287     void newFileMenuItemCreated(const QUrl &url);
288 
289 private:
290     struct DragImage {
291         int row;
292         QRect rect;
293         QPoint cursorOffset;
294         QImage image;
295         bool blank;
296     };
297 
298     QPoint localMenuPosition() const;
299     void createActions();
300     void addDragImage(QDrag *drag, int x, int y);
301     void setStatus(Status status);
302     static bool isTrashEmpty();
303     static bool isDeleteCommandShown();
304     QList<QUrl> selectedUrls() const;
305     KDirModel *m_dirModel;
306     KDirWatch *m_dirWatch;
307     QString m_url;
308     mutable QHash<QUrl, bool> m_isDirCache;
309     mutable QHash<QUrl, KIO::StatJob *> m_isDirJobs;
310     QItemSelectionModel *m_selectionModel;
311     QItemSelection m_pinnedSelection;
312     QModelIndexList m_dragIndexes;
313     QHash<int, DragImage *> m_dragImages;
314     QPoint m_dragHotSpotScrollOffset;
315     bool m_dragInProgress;
316     bool m_urlChangedWhileDragging;
317     // target filename to target position of a drop event, note that this deliberately
318     // is not using the URL to easily support desktop:/ URL schemes
319     QHash<QString, QPoint> m_dropTargetPositions;
320     QTimer *m_dropTargetPositionsCleanup;
321     QPointer<KFilePreviewGenerator> m_previewGenerator;
322     QPointer<KAbstractViewAdapter> m_viewAdapter;
323     KActionCollection m_actionCollection;
324     KNewFileMenu *m_newMenu;
325     KFileItemActions *m_fileItemActions;
326     KFileCopyToMenu *m_copyToMenu;
327     Status m_status = Status::None;
328     QString m_errorString;
329     bool m_usedByContainment;
330     bool m_locked;
331     int m_sortMode; // FIXME TODO: Enumify.
332     bool m_sortDesc;
333     bool m_sortDirsFirst;
334     bool m_parseDesktopFiles;
335     bool m_previews;
336     // An empty previewPlugin list means use default.
337     // We don't want to leak that fact to the QML side, however, so the property stays empty
338     // and internally we operate on effectivePreviewPlugins instead.
339     QStringList m_previewPlugins;
340     QStringList m_effectivePreviewPlugins;
341     FilterMode m_filterMode;
342     QString m_filterPattern;
343     bool m_filterPatternMatchAll;
344     QSet<QString> m_mimeSet;
345     QList<QRegExp> m_regExps;
346     int m_screen = -1;
347     bool m_screenUsed;
348     ScreenMapper *m_screenMapper = nullptr;
349     QObject *m_appletInterface = nullptr;
350     bool m_complete;
351     QPoint m_menuPosition;
352 };
353 
354 #endif
355