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