1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets 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 "qfileiconprovider.h"
41 #include "qfileiconprovider_p.h"
42
43 #include <qapplication.h>
44 #include <qdir.h>
45 #include <qpixmapcache.h>
46 #include <private/qfunctions_p.h>
47 #include <private/qguiapplication_p.h>
48 #include <private/qicon_p.h>
49 #include <private/qfilesystementry_p.h>
50 #include <qpa/qplatformintegration.h>
51 #include <qpa/qplatformservices.h>
52 #include <qpa/qplatformtheme.h>
53
54 #if defined(Q_OS_WIN)
55 # include <qt_windows.h>
56 # ifndef Q_OS_WINRT
57 # include <commctrl.h>
58 # include <objbase.h>
59 # endif
60 #endif
61
62 QT_BEGIN_NAMESPACE
63
64 /*!
65 \class QFileIconProvider
66
67 \inmodule QtWidgets
68
69 \brief The QFileIconProvider class provides file icons for the QDirModel and the QFileSystemModel classes.
70 */
71
72 /*!
73 \enum QFileIconProvider::IconType
74 \value Computer
75 \value Desktop
76 \value Trashcan
77 \value Network
78 \value Drive
79 \value Folder
80 \value File
81 */
82
83
84 /*!
85 \enum QFileIconProvider::Option
86 \since 5.2
87
88 \value DontUseCustomDirectoryIcons Always use the default directory icon.
89 Some platforms allow the user to set a different icon. Custom icon lookup
90 cause a big performance impact over network or removable drives.
91 */
92
QFileIconProviderPrivate(QFileIconProvider * q)93 QFileIconProviderPrivate::QFileIconProviderPrivate(QFileIconProvider *q) :
94 q_ptr(q), homePath(QDir::home().absolutePath())
95 {
96 }
97
getIcon(QStyle::StandardPixmap name) const98 QIcon QFileIconProviderPrivate::getIcon(QStyle::StandardPixmap name) const
99 {
100 switch (name) {
101 case QStyle::SP_FileIcon:
102 if (file.isNull())
103 file = QApplication::style()->standardIcon(name);
104 return file;
105 case QStyle::SP_FileLinkIcon:
106 if (fileLink.isNull())
107 fileLink = QApplication::style()->standardIcon(name);
108 return fileLink;
109 case QStyle::SP_DirIcon:
110 if (directory.isNull())
111 directory = QApplication::style()->standardIcon(name);
112 return directory;
113 case QStyle::SP_DirLinkIcon:
114 if (directoryLink.isNull())
115 directoryLink = QApplication::style()->standardIcon(name);
116 return directoryLink;
117 case QStyle::SP_DriveHDIcon:
118 if (harddisk.isNull())
119 harddisk = QApplication::style()->standardIcon(name);
120 return harddisk;
121 case QStyle::SP_DriveFDIcon:
122 if (floppy.isNull())
123 floppy = QApplication::style()->standardIcon(name);
124 return floppy;
125 case QStyle::SP_DriveCDIcon:
126 if (cdrom.isNull())
127 cdrom = QApplication::style()->standardIcon(name);
128 return cdrom;
129 case QStyle::SP_DriveNetIcon:
130 if (network.isNull())
131 network = QApplication::style()->standardIcon(name);
132 return network;
133 case QStyle::SP_ComputerIcon:
134 if (computer.isNull())
135 computer = QApplication::style()->standardIcon(name);
136 return computer;
137 case QStyle::SP_DesktopIcon:
138 if (desktop.isNull())
139 desktop = QApplication::style()->standardIcon(name);
140 return desktop;
141 case QStyle::SP_TrashIcon:
142 if (trashcan.isNull())
143 trashcan = QApplication::style()->standardIcon(name);
144 return trashcan;
145 case QStyle::SP_DirHomeIcon:
146 if (home.isNull())
147 home = QApplication::style()->standardIcon(name);
148 return home;
149 default:
150 return QIcon();
151 }
152 return QIcon();
153 }
154
155 /*!
156 Constructs a file icon provider.
157 */
158
QFileIconProvider()159 QFileIconProvider::QFileIconProvider()
160 : d_ptr(new QFileIconProviderPrivate(this))
161 {
162 }
163
164 /*!
165 Destroys the file icon provider.
166
167 */
168
~QFileIconProvider()169 QFileIconProvider::~QFileIconProvider()
170 {
171 }
172
173 /*!
174 \since 5.2
175 Sets \a options that affect the icon provider.
176 \sa options()
177 */
178
setOptions(QFileIconProvider::Options options)179 void QFileIconProvider::setOptions(QFileIconProvider::Options options)
180 {
181 Q_D(QFileIconProvider);
182 d->options = options;
183 }
184
185 /*!
186 \since 5.2
187 Returns all the options that affect the icon provider.
188 By default, all options are disabled.
189 \sa setOptions()
190 */
191
options() const192 QFileIconProvider::Options QFileIconProvider::options() const
193 {
194 Q_D(const QFileIconProvider);
195 return d->options;
196 }
197
198 /*!
199 Returns an icon set for the given \a type.
200 */
201
icon(IconType type) const202 QIcon QFileIconProvider::icon(IconType type) const
203 {
204 Q_D(const QFileIconProvider);
205 switch (type) {
206 case Computer:
207 return d->getIcon(QStyle::SP_ComputerIcon);
208 case Desktop:
209 return d->getIcon(QStyle::SP_DesktopIcon);
210 case Trashcan:
211 return d->getIcon(QStyle::SP_TrashIcon);
212 case Network:
213 return d->getIcon(QStyle::SP_DriveNetIcon);
214 case Drive:
215 return d->getIcon(QStyle::SP_DriveHDIcon);
216 case Folder:
217 return d->getIcon(QStyle::SP_DirIcon);
218 case File:
219 return d->getIcon(QStyle::SP_FileIcon);
220 default:
221 break;
222 };
223 return QIcon();
224 }
225
toThemeIconOptions(QFileIconProvider::Options options)226 static inline QPlatformTheme::IconOptions toThemeIconOptions(QFileIconProvider::Options options)
227 {
228 QPlatformTheme::IconOptions result;
229 if (options & QFileIconProvider::DontUseCustomDirectoryIcons)
230 result |= QPlatformTheme::DontUseCustomDirectoryIcons;
231 return result;
232 }
233
getIcon(const QFileInfo & fi) const234 QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const
235 {
236 return QGuiApplicationPrivate::platformTheme()->fileIcon(fi, toThemeIconOptions(options));
237 }
238
239 /*!
240 Returns an icon for the file described by \a info.
241 */
242
icon(const QFileInfo & info) const243 QIcon QFileIconProvider::icon(const QFileInfo &info) const
244 {
245 Q_D(const QFileIconProvider);
246
247 QIcon retIcon = d->getIcon(info);
248 if (!retIcon.isNull())
249 return retIcon;
250
251 const QString &path = info.absoluteFilePath();
252 if (path.isEmpty() || QFileSystemEntry::isRootPath(path))
253 #if defined (Q_OS_WIN) && !defined(Q_OS_WINRT)
254 {
255 UINT type = GetDriveType(reinterpret_cast<const wchar_t *>(path.utf16()));
256
257 switch (type) {
258 case DRIVE_REMOVABLE:
259 return d->getIcon(QStyle::SP_DriveFDIcon);
260 case DRIVE_FIXED:
261 return d->getIcon(QStyle::SP_DriveHDIcon);
262 case DRIVE_REMOTE:
263 return d->getIcon(QStyle::SP_DriveNetIcon);
264 case DRIVE_CDROM:
265 return d->getIcon(QStyle::SP_DriveCDIcon);
266 case DRIVE_RAMDISK:
267 case DRIVE_UNKNOWN:
268 case DRIVE_NO_ROOT_DIR:
269 default:
270 return d->getIcon(QStyle::SP_DriveHDIcon);
271 }
272 }
273 #else
274 return d->getIcon(QStyle::SP_DriveHDIcon);
275 #endif
276
277 if (info.isFile()) {
278 if (info.isSymLink())
279 return d->getIcon(QStyle::SP_FileLinkIcon);
280 else
281 return d->getIcon(QStyle::SP_FileIcon);
282 }
283 if (info.isDir()) {
284 if (info.isSymLink()) {
285 return d->getIcon(QStyle::SP_DirLinkIcon);
286 } else {
287 if (info.absoluteFilePath() == d->homePath) {
288 return d->getIcon(QStyle::SP_DirHomeIcon);
289 } else {
290 return d->getIcon(QStyle::SP_DirIcon);
291 }
292 }
293 }
294 return QIcon();
295 }
296
297 /*!
298 Returns the type of the file described by \a info.
299 */
300
type(const QFileInfo & info) const301 QString QFileIconProvider::type(const QFileInfo &info) const
302 {
303 if (QFileSystemEntry::isRootPath(info.absoluteFilePath()))
304 return QApplication::translate("QFileDialog", "Drive");
305 if (info.isFile()) {
306 if (!info.suffix().isEmpty()) {
307 //: %1 is a file name suffix, for example txt
308 return QApplication::translate("QFileDialog", "%1 File").arg(info.suffix());
309 }
310 return QApplication::translate("QFileDialog", "File");
311 }
312
313 if (info.isDir())
314 #ifdef Q_OS_WIN
315 return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer");
316 #else
317 return QApplication::translate("QFileDialog", "Folder", "All other platforms");
318 #endif
319 // Windows - "File Folder"
320 // OS X - "Folder"
321 // Konqueror - "Folder"
322 // Nautilus - "folder"
323
324 if (info.isSymLink())
325 #ifdef Q_OS_MAC
326 return QApplication::translate("QFileDialog", "Alias", "OS X Finder");
327 #else
328 return QApplication::translate("QFileDialog", "Shortcut", "All other platforms");
329 #endif
330 // OS X - "Alias"
331 // Windows - "Shortcut"
332 // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to
333 // Nautilus - "link to folder" or "link to object file", same as Konqueror
334
335 return QApplication::translate("QFileDialog", "Unknown");
336 }
337
338 QT_END_NAMESPACE
339