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
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22QAbstractFileIconProviderPrivate::QAbstractFileIconProviderPrivate(QAbstractFileIconProvider *q)
23 : q_ptr(q)
24{}
25
26QAbstractFileIconProviderPrivate::~QAbstractFileIconProviderPrivate() = default;
27
28using IconTypeCache = QHash<QAbstractFileIconProvider::IconType, QIcon>;
29Q_GLOBAL_STATIC(IconTypeCache, iconTypeCache)
30
31void QAbstractFileIconProviderPrivate::clearIconTypeCache()
32{
33 iconTypeCache()->clear();
34}
35
36QIcon 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
79QIcon 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
101static 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
109QIcon 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
116QIcon 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*/
162QAbstractFileIconProvider::QAbstractFileIconProvider()
163 : d_ptr(new QAbstractFileIconProviderPrivate(this))
164{
165}
166
167/*!
168 \internal
169*/
170QAbstractFileIconProvider::QAbstractFileIconProvider(QAbstractFileIconProviderPrivate &dd)
171 : d_ptr(&dd)
172{}
173
174/*!
175 Destroys the file icon provider.
176*/
177
178QAbstractFileIconProvider::~QAbstractFileIconProvider() = default;
179
180
181/*!
182 Sets \a options that affect the icon provider.
183 \sa options()
184*/
185
186void 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
198QAbstractFileIconProvider::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
211QIcon 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
225QIcon 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
236QString 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
276QT_END_NAMESPACE
277

source code of qtbase/src/gui/image/qabstractfileiconprovider.cpp