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