1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qabstractfileiconprovider.h" |
5 | |
6 | #include <qguiapplication.h> |
7 | #include <private/qguiapplication_p.h> |
8 | #include <qpa/qplatformtheme.h> |
9 | #include <qicon.h> |
10 | #if QT_CONFIG(mimetype) |
11 | #include <qmimedatabase.h> |
12 | #endif |
13 | |
14 | |
15 | #include <private/qabstractfileiconprovider_p.h> |
16 | #include <private/qfilesystementry_p.h> |
17 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | using namespace Qt::StringLiterals; |
21 | |
22 | QAbstractFileIconProviderPrivate::QAbstractFileIconProviderPrivate(QAbstractFileIconProvider *q) |
23 | : q_ptr(q) |
24 | {} |
25 | |
26 | QAbstractFileIconProviderPrivate::~QAbstractFileIconProviderPrivate() = default; |
27 | |
28 | using IconTypeCache = QHash<QAbstractFileIconProvider::IconType, QIcon>; |
29 | Q_GLOBAL_STATIC(IconTypeCache, iconTypeCache) |
30 | |
31 | void QAbstractFileIconProviderPrivate::clearIconTypeCache() |
32 | { |
33 | iconTypeCache()->clear(); |
34 | } |
35 | |
36 | QIcon QAbstractFileIconProviderPrivate::getPlatformThemeIcon(QAbstractFileIconProvider::IconType type) const |
37 | { |
38 | auto theme = QGuiApplicationPrivate::platformTheme(); |
39 | if (theme == nullptr) |
40 | return {}; |
41 | |
42 | auto &cache = *iconTypeCache(); |
43 | auto it = cache.find(key: type); |
44 | if (it == cache.end()) { |
45 | const auto sp = [&]() -> QPlatformTheme::StandardPixmap { |
46 | switch (type) { |
47 | case QAbstractFileIconProvider::Computer: |
48 | return QPlatformTheme::ComputerIcon; |
49 | case QAbstractFileIconProvider::Desktop: |
50 | return QPlatformTheme::DesktopIcon; |
51 | case QAbstractFileIconProvider::Trashcan: |
52 | return QPlatformTheme::TrashIcon; |
53 | case QAbstractFileIconProvider::Network: |
54 | return QPlatformTheme::DriveNetIcon; |
55 | case QAbstractFileIconProvider::Drive: |
56 | return QPlatformTheme::DriveHDIcon; |
57 | case QAbstractFileIconProvider::Folder: |
58 | return QPlatformTheme::DirIcon; |
59 | case QAbstractFileIconProvider::File: |
60 | break; |
61 | // no default on purpose; we want warnings when the type enum is extended |
62 | } |
63 | return QPlatformTheme::FileIcon; |
64 | }(); |
65 | |
66 | const auto sizesHint = theme->themeHint(hint: QPlatformTheme::IconPixmapSizes); |
67 | auto sizes = sizesHint.value<QList<QSize>>(); |
68 | if (sizes.isEmpty()) |
69 | sizes.append(t: {64, 64}); |
70 | |
71 | QIcon icon; |
72 | for (const auto &size : sizes) |
73 | icon.addPixmap(pixmap: theme->standardPixmap(sp, size)); |
74 | it = cache.insert(key: type, value: icon); |
75 | } |
76 | return it.value(); |
77 | } |
78 | |
79 | QIcon QAbstractFileIconProviderPrivate::getIconThemeIcon(QAbstractFileIconProvider::IconType type) const |
80 | { |
81 | switch (type) { |
82 | case QAbstractFileIconProvider::Computer: |
83 | return QIcon::fromTheme(name: "computer"_L1 ); |
84 | case QAbstractFileIconProvider::Desktop: |
85 | return QIcon::fromTheme(name: "user-desktop"_L1 ); |
86 | case QAbstractFileIconProvider::Trashcan: |
87 | return QIcon::fromTheme(name: "user-trash"_L1 ); |
88 | case QAbstractFileIconProvider::Network: |
89 | return QIcon::fromTheme(name: "network-workgroup"_L1 ); |
90 | case QAbstractFileIconProvider::Drive: |
91 | return QIcon::fromTheme(name: "drive-harddisk"_L1 ); |
92 | case QAbstractFileIconProvider::Folder: |
93 | return QIcon::fromTheme(name: "folder"_L1 ); |
94 | case QAbstractFileIconProvider::File: |
95 | return QIcon::fromTheme(name: "text-x-generic"_L1 ); |
96 | // no default on purpose; we want warnings when the type enum is extended |
97 | } |
98 | return QIcon::fromTheme(name: "text-x-generic"_L1 ); |
99 | } |
100 | |
101 | static inline QPlatformTheme::IconOptions toThemeIconOptions(QAbstractFileIconProvider::Options options) |
102 | { |
103 | QPlatformTheme::IconOptions result; |
104 | if (options.testFlag(flag: QAbstractFileIconProvider::DontUseCustomDirectoryIcons)) |
105 | result |= QPlatformTheme::DontUseCustomDirectoryIcons; |
106 | return result; |
107 | } |
108 | |
109 | QIcon QAbstractFileIconProviderPrivate::getPlatformThemeIcon(const QFileInfo &info) const |
110 | { |
111 | if (auto theme = QGuiApplicationPrivate::platformTheme()) |
112 | return theme->fileIcon(fileInfo: info, iconOptions: toThemeIconOptions(options)); |
113 | return {}; |
114 | } |
115 | |
116 | QIcon QAbstractFileIconProviderPrivate::getIconThemeIcon(const QFileInfo &info) const |
117 | { |
118 | if (info.isRoot()) |
119 | return getIconThemeIcon(type: QAbstractFileIconProvider::Drive); |
120 | if (info.isDir()) |
121 | return getIconThemeIcon(type: QAbstractFileIconProvider::Folder); |
122 | #if QT_CONFIG(mimetype) |
123 | return QIcon::fromTheme(name: mimeDatabase.mimeTypeForFile(fileInfo: info).iconName()); |
124 | #else |
125 | return QIcon::fromTheme("text-x-generic"_L1 ); |
126 | #endif |
127 | } |
128 | |
129 | /*! |
130 | \class QAbstractFileIconProvider |
131 | |
132 | \inmodule QtGui |
133 | \since 6.0 |
134 | |
135 | \brief The QAbstractFileIconProvider class provides file icons for the QFileSystemModel class. |
136 | */ |
137 | |
138 | /*! |
139 | \enum QAbstractFileIconProvider::IconType |
140 | |
141 | \value Computer The icon used for the computing device as a whole |
142 | \value Desktop The icon for the special "Desktop" directory of the user |
143 | \value Trashcan The icon for the user's "Trash" place in the desktop's file manager |
144 | \value Network The icon for the “Network Servers” place in the desktop's file manager, |
145 | and workgroups within the network |
146 | \value Drive The icon used for disk drives |
147 | \value Folder The standard folder icon used to represent directories on local filesystems |
148 | \value File The icon used for generic text file types |
149 | */ |
150 | |
151 | /*! |
152 | \enum QAbstractFileIconProvider::Option |
153 | |
154 | \value DontUseCustomDirectoryIcons Always use the default directory icon. |
155 | Some platforms allow the user to set a different icon. Custom icon lookup |
156 | cause a big performance impact over network or removable drives. |
157 | */ |
158 | |
159 | /*! |
160 | Constructs a file icon provider. |
161 | */ |
162 | QAbstractFileIconProvider::QAbstractFileIconProvider() |
163 | : d_ptr(new QAbstractFileIconProviderPrivate(this)) |
164 | { |
165 | } |
166 | |
167 | /*! |
168 | \internal |
169 | */ |
170 | QAbstractFileIconProvider::QAbstractFileIconProvider(QAbstractFileIconProviderPrivate &dd) |
171 | : d_ptr(&dd) |
172 | {} |
173 | |
174 | /*! |
175 | Destroys the file icon provider. |
176 | */ |
177 | |
178 | QAbstractFileIconProvider::~QAbstractFileIconProvider() = default; |
179 | |
180 | |
181 | /*! |
182 | Sets \a options that affect the icon provider. |
183 | \sa options() |
184 | */ |
185 | |
186 | void QAbstractFileIconProvider::setOptions(QAbstractFileIconProvider::Options options) |
187 | { |
188 | Q_D(QAbstractFileIconProvider); |
189 | d->options = options; |
190 | } |
191 | |
192 | /*! |
193 | Returns all the options that affect the icon provider. |
194 | By default, all options are disabled. |
195 | \sa setOptions() |
196 | */ |
197 | |
198 | QAbstractFileIconProvider::Options QAbstractFileIconProvider::options() const |
199 | { |
200 | Q_D(const QAbstractFileIconProvider); |
201 | return d->options; |
202 | } |
203 | |
204 | /*! |
205 | Returns an icon set for the given \a type, using the current |
206 | icon theme. |
207 | |
208 | \sa QIcon::fromTheme |
209 | */ |
210 | |
211 | QIcon QAbstractFileIconProvider::icon(IconType type) const |
212 | { |
213 | Q_D(const QAbstractFileIconProvider); |
214 | const QIcon result = d->getIconThemeIcon(type); |
215 | return result.isNull() ? d->getPlatformThemeIcon(type) : result; |
216 | } |
217 | |
218 | /*! |
219 | Returns an icon for the file described by \a info, using the |
220 | current icon theme. |
221 | |
222 | \sa QIcon::fromTheme |
223 | */ |
224 | |
225 | QIcon QAbstractFileIconProvider::icon(const QFileInfo &info) const |
226 | { |
227 | Q_D(const QAbstractFileIconProvider); |
228 | const QIcon result = d->getIconThemeIcon(info); |
229 | return result.isNull() ? d->getPlatformThemeIcon(info) : result; |
230 | } |
231 | |
232 | /*! |
233 | Returns the type of the file described by \a info. |
234 | */ |
235 | |
236 | QString QAbstractFileIconProvider::type(const QFileInfo &info) const |
237 | { |
238 | Q_D(const QAbstractFileIconProvider); |
239 | if (QFileSystemEntry::isRootPath(path: info.absoluteFilePath())) |
240 | return QGuiApplication::translate(context: "QAbstractFileIconProvider" , key: "Drive" ); |
241 | if (info.isFile()) { |
242 | #if QT_CONFIG(mimetype) |
243 | const QMimeType mimeType = d->mimeDatabase.mimeTypeForFile(fileInfo: info); |
244 | return mimeType.comment().isEmpty() ? mimeType.name() : mimeType.comment(); |
245 | #else |
246 | Q_UNUSED(d); |
247 | return QGuiApplication::translate("QAbstractFileIconProvider" , "File" ); |
248 | #endif |
249 | } |
250 | |
251 | if (info.isDir()) |
252 | #ifdef Q_OS_WIN |
253 | return QGuiApplication::translate("QAbstractFileIconProvider" , "File Folder" , "Match Windows Explorer" ); |
254 | #else |
255 | return QGuiApplication::translate(context: "QAbstractFileIconProvider" , key: "Folder" , disambiguation: "All other platforms" ); |
256 | #endif |
257 | // Windows - "File Folder" |
258 | // macOS - "Folder" |
259 | // Konqueror - "Folder" |
260 | // Nautilus - "folder" |
261 | |
262 | if (info.isSymLink()) |
263 | #ifdef Q_OS_MACOS |
264 | return QGuiApplication::translate("QAbstractFileIconProvider" , "Alias" , "macOS Finder" ); |
265 | #else |
266 | return QGuiApplication::translate(context: "QAbstractFileIconProvider" , key: "Shortcut" , disambiguation: "All other platforms" ); |
267 | #endif |
268 | // macOS - "Alias" |
269 | // Windows - "Shortcut" |
270 | // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to |
271 | // Nautilus - "link to folder" or "link to object file", same as Konqueror |
272 | |
273 | return QGuiApplication::translate(context: "QAbstractFileIconProvider" , key: "Unknown" ); |
274 | } |
275 | |
276 | QT_END_NAMESPACE |
277 | |