1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
4 SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
5 SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-only
8*/
9
10#ifndef KFILEPLACESMODEL_H
11#define KFILEPLACESMODEL_H
12
13#include "kiofilewidgets_export.h"
14
15#include <KBookmark>
16#include <QAbstractItemModel>
17#include <QUrl>
18
19#include <solid/device.h>
20#include <solid/solidnamespace.h>
21
22#include <memory>
23
24class KFilePlacesModelPrivate;
25class KBookmarkManager;
26
27class QMimeData;
28class QAction;
29
30/*!
31 * \class KFilePlacesModel
32 * \inmodule KIOFileWidgets
33 *
34 * This class is a list view model. Each entry represents a "place"
35 * where user can access files. Only relevant when
36 * used with QListView or QTableView.
37 *
38 * \reentrant
39 */
40class KIOFILEWIDGETS_EXPORT KFilePlacesModel : public QAbstractItemModel
41{
42 Q_OBJECT
43
44 /*!
45 * \property KFilePlacesModel::supportedSchemes
46 */
47 Q_PROPERTY(QStringList supportedSchemes READ supportedSchemes WRITE setSupportedSchemes NOTIFY supportedSchemesChanged)
48
49public:
50 // Note: run printf "0x%08X\n" $(($RANDOM*$RANDOM))
51 // to define additional roles.
52 /*!
53 * \value UrlRole roleName is "url". See url()
54 * \value HiddenRole roleName is "isHidden". See isHidden()
55 * \value SetupNeededRole roleName is "isSetupNeeded". See setupNeeded()
56 * \value FixedDeviceRole Whether the place is a fixed device (neither hotpluggable nor removable). roleName is "isFixedDevice".
57 * \value CapacityBarRecommendedRole Whether the place should have its free space displayed in a capacity bar. roleName is "isCapacityBarRecommended".
58 * \value[since 5.40] GroupRole The name of the group, for example "Remote" or "Devices". roleName is "group".
59 * \value[since 5.41] IconNameRole roleName is "iconName". See icon().
60 * \value[since 5.42] GroupHiddenRole roleName is "isGroupHidden".
61 * \value[since 5.91] TeardownAllowedRole roleName is "isTeardownAllowed".
62 * \value[since 5.94] EjectAllowedRole roleName is "isEjectAllowed".
63 * \value[since 5.95] TeardownOverlayRecommendedRole roleName is "isTeardownOverlayRecommended".
64 * \value[since 5.99] DeviceAccessibilityRole roleName is "deviceAccessibility".
65 */
66 enum AdditionalRoles {
67 UrlRole = 0x069CD12B,
68 HiddenRole = 0x0741CAAC,
69 SetupNeededRole = 0x059A935D,
70 FixedDeviceRole = 0x332896C1,
71 CapacityBarRecommendedRole = 0x1548C5C4,
72 GroupRole = 0x0a5b64ee,
73 IconNameRole = 0x00a45c00,
74 GroupHiddenRole = 0x21a4b936,
75 TeardownAllowedRole = 0x02533364,
76 EjectAllowedRole = 0x0A16AC5B,
77 TeardownOverlayRecommendedRole = 0x032EDCCE,
78 DeviceAccessibilityRole = 0x023FFD93,
79 };
80
81 /*!
82 * Describes the available group types used in this model.
83 * \since 5.42
84 *
85 * \value PlacesType "Places" section
86 * \value RemoteType "Remote" section
87 * \value RecentlySavedType "Recent" section
88 * \value SearchForType "Search for" section
89 * \value DevicesType "Devices" section
90 * \value RemovableDevicesType "Removable Devices" section
91 * \value UnknownType Unknown GroupType
92 * \value[since 5.54] TagsType "Tags" section
93 */
94 enum GroupType {
95 PlacesType,
96 RemoteType,
97 RecentlySavedType,
98 SearchForType,
99 DevicesType,
100 RemovableDevicesType,
101 UnknownType,
102 TagsType,
103 };
104 Q_ENUM(GroupType)
105
106 /*!
107 * \value SetupNeeded
108 * \value SetupInProgress
109 * \value Accessible
110 * \value TeardownInProgress
111 */
112 enum DeviceAccessibility {
113 SetupNeeded,
114 SetupInProgress,
115 Accessible,
116 TeardownInProgress
117 };
118 Q_ENUM(DeviceAccessibility)
119
120 /*!
121 *
122 */
123 explicit KFilePlacesModel(QObject *parent = nullptr);
124 ~KFilePlacesModel() override;
125
126 /*!
127 * Returns The URL of the place at index \a index.
128 */
129 Q_INVOKABLE QUrl url(const QModelIndex &index) const;
130
131 /*!
132 * Returns Whether the place at index \a index needs to be mounted before it can be used.
133 */
134 Q_INVOKABLE bool setupNeeded(const QModelIndex &index) const;
135
136 /*!
137 * Returns Whether the place is a device that can be unmounted, e.g. it is
138 * mounted but does not point at system Root or the user's Home directory.
139 *
140 * It does not indicate whether the teardown can succeed.
141 * \since 5.91
142 */
143 Q_INVOKABLE bool isTeardownAllowed(const QModelIndex &index) const;
144
145 /*!
146 * Returns Whether the place is a device that can be ejected, e.g. it is
147 * a CD, DVD, etc.
148 *
149 * It does not indicate whether the eject can succeed.
150 * \since 5.94
151 */
152 Q_INVOKABLE bool isEjectAllowed(const QModelIndex &index) const;
153
154 /*!
155 * Returns Whether showing an inline teardown button is recommended,
156 * e.g. when it is a removable drive.
157 *
158 * \since 5.95
159 **/
160 Q_INVOKABLE bool isTeardownOverlayRecommended(const QModelIndex &index) const;
161
162 /*!
163 * Returns Whether this device is currently accessible or being (un)mounted.
164 *
165 * \since 5.99
166 */
167 Q_INVOKABLE KFilePlacesModel::DeviceAccessibility deviceAccessibility(const QModelIndex &index) const;
168
169 /*!
170 * Returns The icon of the place at index \a index.
171 */
172 Q_INVOKABLE QIcon icon(const QModelIndex &index) const;
173
174 /*!
175 * Returns The user-visible text of the place at index \a index.
176 */
177 Q_INVOKABLE QString text(const QModelIndex &index) const;
178
179 /*!
180 * Returns Whether the place at index \a index is hidden or is inside an hidden group.
181 */
182 Q_INVOKABLE bool isHidden(const QModelIndex &index) const;
183
184 /*!
185 * Returns Whether the group type \a type is hidden.
186 * \since 5.42
187 */
188 Q_INVOKABLE bool isGroupHidden(const GroupType type) const;
189
190 /*!
191 * Returns Whether the group of the place at index \a index is hidden.
192 * \since 5.42
193 */
194 Q_INVOKABLE bool isGroupHidden(const QModelIndex &index) const;
195
196 /*!
197 * Returns Whether the place at index \a index is a device handled by Solid.
198 * \sa deviceForIndex()
199 */
200 Q_INVOKABLE bool isDevice(const QModelIndex &index) const;
201
202 /*!
203 * Returns The solid device of the place at index \a index, if it is a device. Otherwise a default Solid::Device() instance is returned.
204 * \sa isDevice()
205 */
206 Solid::Device deviceForIndex(const QModelIndex &index) const;
207
208 /*!
209 * Returns The KBookmark instance of the place at index \a index.
210 * If the index is not valid, a default KBookmark instance is returned.
211 */
212 KBookmark bookmarkForIndex(const QModelIndex &index) const;
213
214 /*!
215 * Returns The KBookmark instance of the place with url \a searchUrl.
216 * If the bookmark corresponding to searchUrl is not found, a default KBookmark instance is returned.
217 * \since 5.63
218 */
219 KBookmark bookmarkForUrl(const QUrl &searchUrl) const;
220
221 /*!
222 * Returns The group type of the place at index \a index.
223 * \since 5.42
224 */
225 Q_INVOKABLE GroupType groupType(const QModelIndex &index) const;
226
227 /*!
228 * Returns The list of model indexes that have @ type as their group type.
229 * \sa groupType()
230 * \since 5.42
231 */
232 Q_INVOKABLE QModelIndexList groupIndexes(const GroupType type) const;
233
234 /*!
235 * Returns A QAction with a proper translated label that can be used to trigger the requestTeardown()
236 * method for the place at index \a index.
237 * \sa requestTeardown()
238 */
239 Q_INVOKABLE QAction *teardownActionForIndex(const QModelIndex &index) const;
240
241 /*!
242 * Returns A QAction with a proper translated label that can be used to trigger the requestEject()
243 * method for the place at index \a index.
244 * \sa requestEject()
245 */
246 Q_INVOKABLE QAction *ejectActionForIndex(const QModelIndex &index) const;
247
248 /*!
249 * Returns A QAction with a proper translated label that can be used to open a partitioning menu for the device. nullptr if not a device.
250 */
251 Q_INVOKABLE QAction *partitionActionForIndex(const QModelIndex &index) const;
252
253 /*!
254 * Unmounts the place at index \a index by triggering the teardown functionality of its Solid device.
255 * \sa deviceForIndex()
256 */
257 Q_INVOKABLE void requestTeardown(const QModelIndex &index);
258
259 /*!
260 * Ejects the place at index \a index by triggering the eject functionality of its Solid device.
261 * \sa deviceForIndex()
262 */
263 Q_INVOKABLE void requestEject(const QModelIndex &index);
264
265 /*!
266 * Mounts the place at index \a index by triggering the setup functionality of its Solid device.
267 * \sa deviceForIndex()
268 */
269 Q_INVOKABLE void requestSetup(const QModelIndex &index);
270
271 /*!
272 * Adds a new place to the model.
273 *
274 * \a text The user-visible text for the place
275 *
276 * \a url The URL of the place. It will be stored in its QUrl::FullyEncoded string format.
277 *
278 * \a iconName The icon of the place
279 *
280 * \a appName If set as the value of QCoreApplication::applicationName(), will make the place visible only in this application.
281 */
282 Q_INVOKABLE void addPlace(const QString &text, const QUrl &url, const QString &iconName = QString(), const QString &appName = QString());
283
284 /*!
285 * Adds a new place to the model.
286 * \a text The user-visible text for the place
287 *
288 * \a url The URL of the place. It will be stored in its QUrl::FullyEncoded string format.
289 *
290 * \a iconName The icon of the place
291 *
292 * \a appName If set as the value of QCoreApplication::applicationName(), will make the place visible only in this application.
293 *
294 * \a after The index after which the new place will be added.
295 */
296 Q_INVOKABLE void addPlace(const QString &text, const QUrl &url, const QString &iconName, const QString &appName, const QModelIndex &after);
297
298 /*!
299 * Edits the place with index \a index.
300 *
301 * \a text The new user-visible text for the place
302 *
303 * \a url The new URL of the place
304 *
305 * \a iconName The new icon of the place
306 *
307 * \a appName The new application-local filter for the place (see addPlace()).
308 */
309 Q_INVOKABLE void
310 editPlace(const QModelIndex &index, const QString &text, const QUrl &url, const QString &iconName = QString(), const QString &appName = QString());
311
312 /*!
313 * Deletes the place with index \a index from the model.
314 */
315 Q_INVOKABLE void removePlace(const QModelIndex &index) const;
316
317 /*!
318 * Changes the visibility of the place with index \a index, but only if the place is not inside an hidden group.
319 *
320 * \a hidden Whether the place should be hidden or visible.
321 * \sa isGroupHidden()
322 */
323 Q_INVOKABLE void setPlaceHidden(const QModelIndex &index, bool hidden);
324
325 /*!
326 * Changes the visibility of the group with type \a type.
327 *
328 * \a hidden Whether the group should be hidden or visible.
329 * \sa isGroupHidden()
330 * \since 5.42
331 */
332 Q_INVOKABLE void setGroupHidden(const GroupType type, bool hidden);
333
334 /*!
335 * Move place at \a itemRow to a position before \a row
336 *
337 * Returns whether the place has been moved.
338 * \since 5.41
339 */
340 Q_INVOKABLE bool movePlace(int itemRow, int row);
341
342 /*!
343 * Returns the number of hidden places in the model.
344 * \sa isHidden()
345 */
346 Q_INVOKABLE int hiddenCount() const;
347
348 QVariant data(const QModelIndex &index, int role) const override;
349
350 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
351
352 QModelIndex parent(const QModelIndex &child) const override;
353
354 QHash<int, QByteArray> roleNames() const override;
355
356 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
357
358 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
359
360 /*!
361 * Returns the closest item for the URL \a url.
362 * The closest item is defined as item which is equal to
363 * the URL or at least is a parent URL. If there are more than
364 * one possible parent URL candidates, the item which covers
365 * the bigger range of the URL is returned.
366 *
367 * Example: the url is '/home/peter/Documents/Music'.
368 * Available items are:
369 * - /home/peter
370 * - /home/peter/Documents
371 *
372 * The returned item will the one for '/home/peter/Documents'.
373 */
374 QModelIndex closestItem(const QUrl &url) const;
375
376 Qt::DropActions supportedDropActions() const override;
377 Qt::ItemFlags flags(const QModelIndex &index) const override;
378 QStringList mimeTypes() const override;
379 QMimeData *mimeData(const QModelIndexList &indexes) const override;
380 bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
381
382 /*!
383 * Reload bookmark information
384 * \since 5.41
385 */
386 Q_INVOKABLE void refresh() const;
387
388 /*!
389 * Converts the URL, which contains "virtual" URLs for system-items like
390 * "timeline:/lastmonth" into a Query-URL "timeline:/2017-10"
391 * that will be handled by the corresponding KIO worker.
392 * Virtual URLs for bookmarks are used to be independent from
393 * internal format changes.
394 *
395 * \a an url
396 *
397 * Returns the converted URL, which can be handled by a KIO worker
398 * \since 5.41
399 */
400 static QUrl convertedUrl(const QUrl &url);
401
402 /*!
403 * Set the URL schemes that the file widget should allow navigating to.
404 *
405 * If the returned list is empty, all schemes are supported. Examples for
406 * schemes are "file" or "ftp".
407 *
408 * \sa QFileDialog::setSupportedSchemes
409 * \since 5.43
410 */
411 void setSupportedSchemes(const QStringList &schemes);
412
413 /*!
414 * Returns the URL schemes that the file widget should allow navigating to.
415 *
416 * If the returned list is empty, all schemes are supported.
417 *
418 * \sa QFileDialog::supportedSchemes
419 * \since 5.43
420 */
421 QStringList supportedSchemes() const;
422
423Q_SIGNALS:
424 /*!
425 * \a message An error message explaining what went wrong.
426 */
427 void errorMessage(const QString &message);
428
429 /*!
430 * Emitted after the Solid setup ends.
431 *
432 * \a success Whether the Solid setup has been successful.
433 * \sa requestSetup()
434 */
435 void setupDone(const QModelIndex &index, bool success);
436
437 /*!
438 * Emitted after the teardown of a device ends.
439 *
440 * \note In case of an error, the errorMessage() signal
441 * will also be emitted with a message describing the error.
442 *
443 * \a error Type of error that occurred, if any.
444 *
445 * \a errorData More information about the error, if any.
446 *
447 * \since 5.100
448 */
449 void teardownDone(const QModelIndex &index, Solid::ErrorType error, const QVariant &errorData);
450
451 /*!
452 * Emitted whenever the visibility of the group \a group changes.
453 *
454 * \a hidden The new visibility of the group.
455 *
456 * \sa setGroupHidden()
457 * \since 5.42
458 */
459 void groupHiddenChanged(KFilePlacesModel::GroupType group, bool hidden);
460
461 /*!
462 * Called once the model has been reloaded
463 *
464 * \since 5.71
465 */
466 void reloaded();
467
468 /*!
469 * Emitted whenever the list of supported schemes has been changed
470 *
471 * \since 5.94
472 */
473 void supportedSchemesChanged();
474
475private:
476 friend class KFilePlacesModelPrivate;
477 std::unique_ptr<KFilePlacesModelPrivate> d;
478};
479
480#endif
481

source code of kio/src/filewidgets/kfileplacesmodel.h