Qt 4.8
qfileiconprovider.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qfileiconprovider.h"
43 #include "qfileiconprovider_p.h"
44 
45 #ifndef QT_NO_FILEICONPROVIDER
46 #include <qfileinfo.h>
47 #include <qapplication.h>
48 #include <qdir.h>
49 #include <qpixmapcache.h>
50 #if defined(Q_WS_WIN)
51 # define _WIN32_IE 0x0500
52 # include <qt_windows.h>
53 # include <commctrl.h>
54 # include <objbase.h>
55 #elif defined(Q_WS_MAC)
56 # include <private/qt_cocoa_helpers_mac_p.h>
57 #endif
58 
59 #include <private/qfunctions_p.h>
60 #include <private/qguiplatformplugin_p.h>
61 
62 #if defined(Q_WS_X11) && !defined(QT_NO_STYLE_GTK)
63 # include <private/qgtkstyle_p.h>
64 # include <private/qt_x11_p.h>
65 #endif
66 
67 #ifndef SHGFI_ADDOVERLAYS
68 # define SHGFI_ADDOVERLAYS 0x000000020
69 # define SHGFI_OVERLAYINDEX 0x000000040
70 #endif
71 
73 
95  homePath(QDir::home().absolutePath()), useCustomDirectoryIcons(true)
96 {
97 }
98 
100 {
101  useCustomDirectoryIcons = enable;
102 }
103 
105 {
106  switch (name) {
107  case QStyle::SP_FileIcon:
108  if (file.isNull())
110  return file;
112  if (fileLink.isNull())
114  return fileLink;
115  case QStyle::SP_DirIcon:
116  if (directory.isNull())
118  return directory;
120  if (directoryLink.isNull())
122  return directoryLink;
124  if (harddisk.isNull())
126  return harddisk;
128  if (floppy.isNull())
130  return floppy;
132  if (cdrom.isNull())
134  return cdrom;
136  if (network.isNull())
138  return network;
140  if (computer.isNull())
142  return computer;
144  if (desktop.isNull())
146  return desktop;
148  if (trashcan.isNull())
150  return trashcan;
152  if (home.isNull())
154  return home;
155  default:
156  return QIcon();
157  }
158  return QIcon();
159 }
160 
166  : d_ptr(new QFileIconProviderPrivate)
167 {
168 }
169 
176 {
177 }
178 
184 {
185  Q_D(const QFileIconProvider);
186  switch (type) {
187  case Computer:
188  return d->getIcon(QStyle::SP_ComputerIcon);
189  case Desktop:
190  return d->getIcon(QStyle::SP_DesktopIcon);
191  case Trashcan:
192  return d->getIcon(QStyle::SP_TrashIcon);
193  case Network:
194  return d->getIcon(QStyle::SP_DriveNetIcon);
195  case Drive:
196  return d->getIcon(QStyle::SP_DriveHDIcon);
197  case Folder:
198  return d->getIcon(QStyle::SP_DirIcon);
199  case File:
200  return d->getIcon(QStyle::SP_FileIcon);
201  default:
202  break;
203  };
204  return QIcon();
205 }
206 
207 #ifdef Q_WS_WIN
208 
209 static bool isCacheable(const QFileInfo &fi)
210 {
211  if (!fi.isFile())
212  return false;
213 
214  // On windows it's faster to just look at the file extensions. QTBUG-13182
215  const QString fileExtension = fi.suffix();
216  return fileExtension.compare(QLatin1String("exe"), Qt::CaseInsensitive) &&
217  fileExtension.compare(QLatin1String("lnk"), Qt::CaseInsensitive) &&
218  fileExtension.compare(QLatin1String("ico"), Qt::CaseInsensitive);
219 }
220 
222 {
223  QIcon retIcon;
224  static int defaultFolderIIcon = -1;
225 
226  QString key;
227  QPixmap pixmap;
228  // If it's a file, non-{exe,lnk,ico} then we might have it cached already
229  if (isCacheable(fileInfo)) {
230  const QString fileExtension = QLatin1Char('.') + fileInfo.suffix().toUpper();
231  key = QLatin1String("qt_") + fileExtension;
232  QPixmapCache::find(key, pixmap);
233  if (!pixmap.isNull()) {
234  retIcon.addPixmap(pixmap);
235  if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
236  retIcon.addPixmap(pixmap);
237  return retIcon;
238  }
239  }
240 
241  const bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot();
242  if (!useCustomDirectoryIcons && defaultFolderIIcon >= 0 && cacheableDirIcon) {
243  // We already have the default folder icon, just return it
244  key = QString::fromLatin1("qt_dir_%1").arg(defaultFolderIIcon);
245  QPixmapCache::find(key, pixmap);
246  if (!pixmap.isNull()) {
247  retIcon.addPixmap(pixmap);
248  if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
249  retIcon.addPixmap(pixmap);
250  return retIcon;
251  }
252  }
253 
254  /* We don't use the variable, but by storing it statically, we
255  * ensure CoInitialize is only called once. */
256  static HRESULT comInit = CoInitialize(NULL);
257  Q_UNUSED(comInit);
258 
259  SHFILEINFO info;
260  unsigned long val = 0;
261 
262  //Get the small icon
263  unsigned int flags =
264 #ifndef Q_OS_WINCE
265  SHGFI_ICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX;
266 #else
267  SHGFI_SYSICONINDEX;
268 #endif
269 
270  if (cacheableDirIcon && !useCustomDirectoryIcons) {
271  flags |= SHGFI_USEFILEATTRIBUTES;
272  val = SHGetFileInfo(L"dummy",
273  FILE_ATTRIBUTE_DIRECTORY, &info,
274  sizeof(SHFILEINFO), flags | SHGFI_SMALLICON);
275  } else {
276  val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(),
277  0, &info, sizeof(SHFILEINFO), flags | SHGFI_SMALLICON);
278  }
279 
280  // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
281  if (val && info.hIcon) {
282  if (fileInfo.isDir() && !fileInfo.isRoot()) {
283  if (!useCustomDirectoryIcons && defaultFolderIIcon < 0)
284  defaultFolderIIcon = info.iIcon;
285  //using the unique icon index provided by windows save us from duplicate keys
286  key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
287  QPixmapCache::find(key, pixmap);
288  if (!pixmap.isNull()) {
289  retIcon.addPixmap(pixmap);
290  if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
291  retIcon.addPixmap(pixmap);
292  DestroyIcon(info.hIcon);
293  return retIcon;
294  }
295  }
296  if (pixmap.isNull()) {
297 #ifndef Q_OS_WINCE
298  pixmap = QPixmap::fromWinHICON(info.hIcon);
299 #else
300  pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
301 #endif
302  if (!pixmap.isNull()) {
303  retIcon.addPixmap(pixmap);
304  if (!key.isEmpty())
305  QPixmapCache::insert(key, pixmap);
306  }
307  else {
308  qWarning("QFileIconProviderPrivate::getWinIcon() no small icon found");
309  }
310  }
311  DestroyIcon(info.hIcon);
312  }
313 
314  //Get the big icon
315  val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(),
316  0, &info, sizeof(SHFILEINFO), flags | SHGFI_LARGEICON);
317 
318  if (val && info.hIcon) {
319  if (fileInfo.isDir() && !fileInfo.isRoot()) {
320  //using the unique icon index provided by windows save us from duplicate keys
321  key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
322  }
323 #ifndef Q_OS_WINCE
324  pixmap = QPixmap::fromWinHICON(info.hIcon);
325 #else
326  pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
327 #endif
328  if (!pixmap.isNull()) {
329  retIcon.addPixmap(pixmap);
330  if (!key.isEmpty())
331  QPixmapCache::insert(key + QLatin1Char('l'), pixmap);
332  }
333  else {
334  qWarning("QFileIconProviderPrivate::getWinIcon() no large icon found");
335  }
336  DestroyIcon(info.hIcon);
337  }
338  return retIcon;
339 }
340 
341 #elif defined(Q_WS_MAC)
342 QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const
343 {
344  QIcon retIcon;
345  QString fileExtension = fi.suffix().toUpper();
346  fileExtension.prepend(QLatin1String("."));
347 
348  const QString keyBase = QLatin1String("qt_") + fileExtension;
349 
350  QPixmap pixmap;
351  if (fi.isFile() && !fi.isExecutable() && !fi.isSymLink()) {
352  QPixmapCache::find(keyBase + QLatin1String("16"), pixmap);
353  }
354 
355  if (!pixmap.isNull()) {
356  retIcon.addPixmap(pixmap);
357  if (QPixmapCache::find(keyBase + QLatin1String("32"), pixmap)) {
358  retIcon.addPixmap(pixmap);
359  if (QPixmapCache::find(keyBase + QLatin1String("64"), pixmap)) {
360  retIcon.addPixmap(pixmap);
361  if (QPixmapCache::find(keyBase + QLatin1String("128"), pixmap)) {
362  retIcon.addPixmap(pixmap);
363  return retIcon;
364  }
365  }
366  }
367  }
368 
369 
370  FSRef macRef;
371  OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fi.canonicalFilePath().toUtf8().constData()),
372  &macRef, 0);
373  if (status != noErr)
374  return retIcon;
375  FSCatalogInfo info;
376  HFSUniStr255 macName;
377  status = FSGetCatalogInfo(&macRef, kIconServicesCatalogInfoMask, &info, &macName, 0, 0);
378  if (status != noErr)
379  return retIcon;
380  IconRef iconRef;
381  SInt16 iconLabel;
382  status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode,
383  kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag,
384  &iconRef, &iconLabel);
385  if (status != noErr)
386  return retIcon;
387  qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon);
388  ReleaseIconRef(iconRef);
389 
390  if (fi.isFile() && !fi.isExecutable() && !fi.isSymLink()) {
391  pixmap = retIcon.pixmap(16);
392  QPixmapCache::insert(keyBase + QLatin1String("16"), pixmap);
393  pixmap = retIcon.pixmap(32);
394  QPixmapCache::insert(keyBase + QLatin1String("32"), pixmap);
395  pixmap = retIcon.pixmap(64);
396  QPixmapCache::insert(keyBase + QLatin1String("64"), pixmap);
397  pixmap = retIcon.pixmap(128);
398  QPixmapCache::insert(keyBase + QLatin1String("128"), pixmap);
399  }
400 
401  return retIcon;
402 }
403 #endif
404 
405 
411 {
412  Q_D(const QFileIconProvider);
413 
414  QIcon platformIcon = qt_guiPlatformPlugin()->fileSystemIcon(info);
415  if (!platformIcon.isNull())
416  return platformIcon;
417 
418 #if defined(Q_WS_X11) && !defined(QT_NO_STYLE_GTK)
419  if (X11->desktopEnvironment == DE_GNOME) {
421  if (!gtkIcon.isNull())
422  return gtkIcon;
423  }
424 #endif
425 
426 #ifdef Q_WS_MAC
427  QIcon retIcon = d->getMacIcon(info);
428  if (!retIcon.isNull())
429  return retIcon;
430 #elif defined Q_WS_WIN
431  QIcon icon = d->getWinIcon(info);
432  if (!icon.isNull())
433  return icon;
434 #endif
435  if (info.isRoot())
436 #if defined (Q_WS_WIN) && !defined(Q_WS_WINCE)
437  {
438  UINT type = GetDriveType((wchar_t *)info.absoluteFilePath().utf16());
439 
440  switch (type) {
441  case DRIVE_REMOVABLE:
442  return d->getIcon(QStyle::SP_DriveFDIcon);
443  case DRIVE_FIXED:
444  return d->getIcon(QStyle::SP_DriveHDIcon);
445  case DRIVE_REMOTE:
446  return d->getIcon(QStyle::SP_DriveNetIcon);
447  case DRIVE_CDROM:
448  return d->getIcon(QStyle::SP_DriveCDIcon);
449  case DRIVE_RAMDISK:
450  case DRIVE_UNKNOWN:
451  case DRIVE_NO_ROOT_DIR:
452  default:
453  return d->getIcon(QStyle::SP_DriveHDIcon);
454  }
455  }
456 #else
457  return d->getIcon(QStyle::SP_DriveHDIcon);
458 #endif
459  if (info.isFile()) {
460  if (info.isSymLink())
461  return d->getIcon(QStyle::SP_FileLinkIcon);
462  else
463  return d->getIcon(QStyle::SP_FileIcon);
464  }
465  if (info.isDir()) {
466  if (info.isSymLink()) {
467  return d->getIcon(QStyle::SP_DirLinkIcon);
468  } else {
469  if (info.absoluteFilePath() == d->homePath) {
470  return d->getIcon(QStyle::SP_DirHomeIcon);
471  } else {
472  return d->getIcon(QStyle::SP_DirIcon);
473  }
474  }
475  }
476  return QIcon();
477 }
478 
484 {
485  if (info.isRoot())
486  return QApplication::translate("QFileDialog", "Drive");
487  if (info.isFile()) {
488  if (!info.suffix().isEmpty())
489  return info.suffix() + QLatin1Char(' ') + QApplication::translate("QFileDialog", "File");
490  return QApplication::translate("QFileDialog", "File");
491  }
492 
493  if (info.isDir())
494 #ifdef Q_WS_WIN
495  return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer");
496 #else
497  return QApplication::translate("QFileDialog", "Folder", "All other platforms");
498 #endif
499  // Windows - "File Folder"
500  // OS X - "Folder"
501  // Konqueror - "Folder"
502  // Nautilus - "folder"
503 
504  if (info.isSymLink())
505 #ifdef Q_OS_MAC
506  return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder");
507 #else
508  return QApplication::translate("QFileDialog", "Shortcut", "All other platforms");
509 #endif
510  // OS X - "Alias"
511  // Windows - "Shortcut"
512  // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to
513  // Nautilus - "link to folder" or "link to object file", same as Konqueror
514 
515  return QApplication::translate("QFileDialog", "Unknown");
516 }
517 
519 
520 #endif
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:58
double d
Definition: qnumeric_p.h:62
static bool isCacheable(const QFileInfo &fi)
static mach_timebase_info_data_t info
void addPixmap(const QPixmap &pixmap, Mode mode=Normal, State state=Off)
Adds pixmap to the icon, as a specialization for mode and state.
Definition: qicon.cpp:814
#define SHGFI_OVERLAYINDEX
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QPixmap fromWinHICON(HICON hicon)
virtual ~QFileIconProvider()
Destroys the file icon provider.
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
#define Q_WS_WIN
Defined on Windows.
Definition: qglobal.h:921
QString & prepend(QChar c)
Definition: qstring.h:261
QString toUpper() const Q_REQUIRED_RESULT
Returns an uppercase copy of the string.
Definition: qstring.cpp:5483
virtual QIcon icon(IconType type) const
Returns an icon set for the given type.
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
QString absoluteFilePath() const
Returns an absolute path including the file name.
Definition: qfileinfo.cpp:534
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
QGuiPlatformPlugin * qt_guiPlatformPlugin()
Return (an construct if necesseray) the Gui Platform plugin.
static QStyle * style()
Returns the application&#39;s style object.
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define X11
Definition: qt_x11_p.h:724
#define CoInitialize(x)
#define Q_D(Class)
Definition: qglobal.h:2482
virtual QString type(const QFileInfo &info) const
Returns the type of the file described by info.
StandardPixmap
This enum describes the available standard pixmaps.
Definition: qstyle.h:755
static QPixmap * find(const QString &key)
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
#define Q_OS_MAC
Defined on MAC OS (synonym for Darwin).
Definition: qglobal.h:274
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option=0, const QWidget *widget=0) const
Returns an icon for the given standardIcon.
Definition: qstyle.cpp:2327
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory; otherwise ret...
Definition: qfileinfo.cpp:990
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
const char * name
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition: qicon.cpp:769
QString canonicalFilePath() const
Returns the canonical path including the file name, i.e.
Definition: qfileinfo.cpp:551
Q_CORE_EXPORT void qWarning(const char *,...)
The QFileIconProvider class provides file icons for the QDirModel and the QFileSystemModel classes...
QFileIconProvider()
Constructs a file icon provider.
bool isExecutable() const
Returns true if the file is executable; otherwise returns false.
Definition: qfileinfo.cpp:932
signed long OSStatus
static QIcon getFilesystemIcon(const QFileInfo &)
#define SHGFI_ADDOVERLAYS
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
long HRESULT
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
int compare(const QString &s) const
Definition: qstring.cpp:5037
bool isRoot() const
Returns true if the object points to a directory or to a symbolic link to a directory, and that directory is the root directory; otherwise returns false.
Definition: qfileinfo.cpp:1062
QIcon getWinIcon(const QFileInfo &fi) const
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
QString suffix() const
Returns the suffix of the file.
Definition: qfileinfo.cpp:834
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
int key
void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon)
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
Definition: qfileinfo.cpp:971
QIcon getIcon(QStyle::StandardPixmap name) const
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition: qicon.cpp:693
#define Q_WS_WINCE
Definition: qglobal.h:895
virtual QIcon fileSystemIcon(const QFileInfo &)
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition: qpixmap.cpp:615
bool isSymLink() const
Returns true if this object points to a symbolic link (or to a shortcut on Windows); otherwise return...
Definition: qfileinfo.cpp:1044
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
QString filePath() const
Returns the file name, including the path (which may be absolute or relative).
Definition: qfileinfo.cpp:707
static QString toNativeSeparators(const QString &pathName)
Returns pathName with the &#39;/&#39; separators converted to separators that are appropriate for the underly...
Definition: qdir.cpp:812
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
struct OpaqueIconRef * IconRef
void setUseCustomDirectoryIcons(bool enable)
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290
The QIcon class provides scalable icons in different modes and states.
Definition: qicon.h:60