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

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