src/gui/itemviews/qfileiconprovider.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/itemviews/qfileiconprovider.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,495 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfileiconprovider.h"
+
+#ifndef QT_NO_FILEICONPROVIDER
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qdir.h>
+#include <qpixmapcache.h>
+#if defined(Q_WS_WIN)
+#define _WIN32_IE 0x0500
+#include <qt_windows.h>
+#include <commctrl.h>
+#include <objbase.h>
+#elif defined(Q_WS_MAC)
+#include <private/qt_cocoa_helpers_mac_p.h>
+#endif
+
+#if defined(Q_WS_X11) && !defined(Q_NO_STYLE_GTK)
+#include <private/qt_x11_p.h>
+#include <private/gtksymbols_p.h>
+#endif
+
+#include <private/qfunctions_p.h>
+#include <private/qguiplatformplugin_p.h>
+
+#ifndef SHGFI_ADDOVERLAYS
+#define SHGFI_ADDOVERLAYS 0x000000020
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+  \class QFileIconProvider
+
+  \brief The QFileIconProvider class provides file icons for the QDirModel class.
+*/
+
+/*!
+  \enum QFileIconProvider::IconType
+  \value Computer
+  \value Desktop
+  \value Trashcan
+  \value Network
+  \value Drive
+  \value Folder
+  \value File
+*/
+
+class QFileIconProviderPrivate
+{
+    Q_DECLARE_PUBLIC(QFileIconProvider)
+
+public:
+    QFileIconProviderPrivate();
+    QIcon getIcon(QStyle::StandardPixmap name) const;
+#ifdef Q_WS_WIN
+    QIcon getWinIcon(const QFileInfo &fi) const;
+#elif defined(Q_WS_MAC)
+    QIcon getMacIcon(const QFileInfo &fi) const;
+#endif
+    QFileIconProvider *q_ptr;
+    QString homePath;
+
+private:
+    QIcon file;
+    QIcon fileLink;
+    QIcon directory;
+    QIcon directoryLink;
+    QIcon harddisk;
+    QIcon floppy;
+    QIcon cdrom;
+    QIcon ram;
+    QIcon network;
+    QIcon computer;
+    QIcon desktop;
+    QIcon trashcan;
+    QIcon generic;
+    QIcon home;
+};
+
+QFileIconProviderPrivate::QFileIconProviderPrivate()
+{
+    QStyle *style = QApplication::style();
+    file = style->standardIcon(QStyle::SP_FileIcon);
+    directory = style->standardIcon(QStyle::SP_DirIcon);
+    fileLink = style->standardIcon(QStyle::SP_FileLinkIcon);
+    directoryLink = style->standardIcon(QStyle::SP_DirLinkIcon);
+    harddisk = style->standardIcon(QStyle::SP_DriveHDIcon);
+    floppy = style->standardIcon(QStyle::SP_DriveFDIcon);
+    cdrom = style->standardIcon(QStyle::SP_DriveCDIcon);
+    network = style->standardIcon(QStyle::SP_DriveNetIcon);
+    computer = style->standardIcon(QStyle::SP_ComputerIcon);
+    desktop = style->standardIcon(QStyle::SP_DesktopIcon);
+    trashcan = style->standardIcon(QStyle::SP_TrashIcon);
+    home = style->standardIcon(QStyle::SP_DirHomeIcon);
+    homePath = QDir::home().absolutePath();
+}
+
+QIcon QFileIconProviderPrivate::getIcon(QStyle::StandardPixmap name) const
+{
+    switch (name) {
+    case QStyle::SP_FileIcon:
+        return file;
+    case QStyle::SP_FileLinkIcon:
+        return fileLink;
+    case QStyle::SP_DirIcon:
+        return directory;
+    case QStyle::SP_DirLinkIcon:
+        return directoryLink;
+    case QStyle::SP_DriveHDIcon:
+        return harddisk;
+    case QStyle::SP_DriveFDIcon:
+        return floppy;
+    case QStyle::SP_DriveCDIcon:
+        return cdrom;
+    case QStyle::SP_DriveNetIcon:
+        return network;
+    case QStyle::SP_ComputerIcon:
+        return computer;
+    case QStyle::SP_DesktopIcon:
+        return desktop;
+    case QStyle::SP_TrashIcon:
+        return trashcan;
+    case QStyle::SP_DirHomeIcon:
+        return home;
+    default:
+        return QIcon();
+    }
+    return QIcon();
+}
+
+/*!
+  Constructs a file icon provider.
+*/
+
+QFileIconProvider::QFileIconProvider()
+    : d_ptr(new QFileIconProviderPrivate)
+{
+}
+
+/*!
+  Destroys the file icon provider.
+
+*/
+
+QFileIconProvider::~QFileIconProvider()
+{
+}
+
+/*!
+  Returns an icon set for the given \a type.
+*/
+
+QIcon QFileIconProvider::icon(IconType type) const
+{
+    Q_D(const QFileIconProvider);
+    switch (type) {
+    case Computer:
+        return d->getIcon(QStyle::SP_ComputerIcon);
+    case Desktop:
+        return d->getIcon(QStyle::SP_DesktopIcon);
+    case Trashcan:
+        return d->getIcon(QStyle::SP_TrashIcon);
+    case Network:
+        return d->getIcon(QStyle::SP_DriveNetIcon);
+    case Drive:
+        return d->getIcon(QStyle::SP_DriveHDIcon);
+    case Folder:
+        return d->getIcon(QStyle::SP_DirIcon);
+    case File:
+        return d->getIcon(QStyle::SP_FileIcon);
+    default:
+        break;
+    };
+    return QIcon();
+}
+
+#ifdef Q_WS_WIN
+QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const
+{
+    QIcon retIcon;
+    const QString fileExtension = QLatin1Char('.') + fileInfo.suffix().toUpper();
+
+    QString key;
+    if (fileInfo.isFile() && !fileInfo.isExecutable() && !fileInfo.isSymLink())
+        key = QLatin1String("qt_") + fileExtension;
+
+    QPixmap pixmap;
+    if (!key.isEmpty()) {
+        QPixmapCache::find(key, pixmap);
+    }
+
+    if (!pixmap.isNull()) {
+        retIcon.addPixmap(pixmap);
+        if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
+            retIcon.addPixmap(pixmap);
+        return retIcon;
+    }
+
+    /* We don't use the variable, but by storing it statically, we
+     * ensure CoInitialize is only called once. */
+    static HRESULT comInit = CoInitialize(NULL);
+    Q_UNUSED(comInit);
+
+    SHFILEINFO info;
+    unsigned long val = 0;
+
+    //Get the small icon
+#ifndef Q_OS_WINCE
+    val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
+                        sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS);
+#else
+    val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
+                        sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_SYSICONINDEX);
+#endif
+    if (val) {
+        if (fileInfo.isDir() && !fileInfo.isRoot()) {
+            //using the unique icon index provided by windows save us from duplicate keys
+            key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
+            QPixmapCache::find(key, pixmap);
+            if (!pixmap.isNull()) {
+                retIcon.addPixmap(pixmap);
+                if (QPixmapCache::find(key + QLatin1Char('l'), pixmap))
+                    retIcon.addPixmap(pixmap);
+                DestroyIcon(info.hIcon);
+                return retIcon;
+            }
+        }
+        if (pixmap.isNull()) {
+#ifndef Q_OS_WINCE
+            pixmap = QPixmap::fromWinHICON(info.hIcon);
+#else
+            pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
+#endif
+            if (!pixmap.isNull()) {
+                retIcon.addPixmap(pixmap);
+                if (!key.isEmpty())
+                    QPixmapCache::insert(key, pixmap);
+            }
+            else {
+              qWarning("QFileIconProviderPrivate::getWinIcon() no small icon found");
+            }
+        }
+        DestroyIcon(info.hIcon);
+    }
+
+    //Get the big icon
+#ifndef Q_OS_WINCE
+    val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
+                        sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_LARGEICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS);
+#else
+    val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info,
+                        sizeof(SHFILEINFO), SHGFI_LARGEICON|SHGFI_SYSICONINDEX);
+#endif
+    if (val) {
+        if (fileInfo.isDir() && !fileInfo.isRoot()) {
+            //using the unique icon index provided by windows save us from duplicate keys
+            key = QString::fromLatin1("qt_dir_%1").arg(info.iIcon);
+        }
+#ifndef Q_OS_WINCE
+        pixmap = QPixmap::fromWinHICON(info.hIcon);
+#else
+        pixmap = QPixmap::fromWinHICON(ImageList_GetIcon((HIMAGELIST) val, info.iIcon, ILD_NORMAL));
+#endif
+        if (!pixmap.isNull()) {
+            retIcon.addPixmap(pixmap);
+            if (!key.isEmpty())
+                QPixmapCache::insert(key + QLatin1Char('l'), pixmap);
+        }
+        else {
+            qWarning("QFileIconProviderPrivate::getWinIcon() no large icon found");
+        }
+        DestroyIcon(info.hIcon);
+    }
+    return retIcon;
+}
+
+#elif defined(Q_WS_MAC)
+QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const
+{
+    QIcon retIcon;
+    QString fileExtension = fi.suffix().toUpper();
+    fileExtension.prepend(QLatin1String("."));
+
+    const QString keyBase = QLatin1String("qt_") + fileExtension;
+
+    QPixmap pixmap;
+    if (fi.isFile() && !fi.isExecutable() && !fi.isSymLink()) {
+        QPixmapCache::find(keyBase + QLatin1String("16"), pixmap);
+    }
+
+    if (!pixmap.isNull()) {
+        retIcon.addPixmap(pixmap);
+        if (QPixmapCache::find(keyBase + QLatin1String("32"), pixmap)) {
+            retIcon.addPixmap(pixmap);
+            if (QPixmapCache::find(keyBase + QLatin1String("64"), pixmap)) {
+                retIcon.addPixmap(pixmap);
+                if (QPixmapCache::find(keyBase + QLatin1String("128"), pixmap)) {
+                    retIcon.addPixmap(pixmap);
+                    return retIcon;
+                }
+            }
+        }
+    }
+
+
+    FSRef macRef;
+    OSStatus status = FSPathMakeRef(reinterpret_cast<const UInt8*>(fi.canonicalFilePath().toUtf8().constData()),
+                                    &macRef, 0);
+    if (status != noErr)
+        return retIcon;
+    FSCatalogInfo info;
+    HFSUniStr255 macName;
+    status = FSGetCatalogInfo(&macRef, kIconServicesCatalogInfoMask, &info, &macName, 0, 0);
+    if (status != noErr)
+        return retIcon;
+    IconRef iconRef;
+    SInt16 iconLabel;
+    status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode,
+                                    kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag,
+                                    &iconRef, &iconLabel);
+    if (status != noErr)
+        return retIcon;
+    qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon);
+    ReleaseIconRef(iconRef);
+
+    pixmap = retIcon.pixmap(16);
+    QPixmapCache::insert(keyBase + QLatin1String("16"), pixmap);
+    pixmap = retIcon.pixmap(32);
+    QPixmapCache::insert(keyBase + QLatin1String("32"), pixmap);
+    pixmap = retIcon.pixmap(64);
+    QPixmapCache::insert(keyBase + QLatin1String("64"), pixmap);
+    pixmap = retIcon.pixmap(128);
+    QPixmapCache::insert(keyBase + QLatin1String("128"), pixmap);
+
+    return retIcon;
+}
+#endif
+
+
+/*!
+  Returns an icon for the file described by \a info.
+*/
+
+QIcon QFileIconProvider::icon(const QFileInfo &info) const
+{
+    Q_D(const QFileIconProvider);
+
+    QIcon platformIcon = qt_guiPlatformPlugin()->fileSystemIcon(info);
+    if (!platformIcon.isNull())
+        return platformIcon;
+
+#if defined(Q_WS_X11) && !defined(QT_NO_STYLE_GTK)
+    if (X11->desktopEnvironment == DE_GNOME) {
+        QIcon gtkIcon = QGtk::getFilesystemIcon(info);
+        if (!gtkIcon.isNull())
+            return gtkIcon;
+    }
+#endif
+
+#ifdef Q_WS_MAC
+    QIcon retIcon = d->getMacIcon(info);
+    if (!retIcon.isNull())
+        return retIcon;
+#elif defined Q_WS_WIN
+    QIcon icon = d->getWinIcon(info);
+    if (!icon.isNull())
+        return icon;
+#endif
+    if (info.isRoot())
+#if defined (Q_WS_WIN) && !defined(Q_WS_WINCE)
+    {
+        UINT type = GetDriveType((wchar_t *)info.absoluteFilePath().utf16());
+
+        switch (type) {
+        case DRIVE_REMOVABLE:
+            return d->getIcon(QStyle::SP_DriveFDIcon);
+        case DRIVE_FIXED:
+            return d->getIcon(QStyle::SP_DriveHDIcon);
+        case DRIVE_REMOTE:
+            return d->getIcon(QStyle::SP_DriveNetIcon);
+        case DRIVE_CDROM:
+            return d->getIcon(QStyle::SP_DriveCDIcon);
+        case DRIVE_RAMDISK:
+        case DRIVE_UNKNOWN:
+        case DRIVE_NO_ROOT_DIR:
+        default:
+            return d->getIcon(QStyle::SP_DriveHDIcon);
+        }
+    }
+#else
+    return d->getIcon(QStyle::SP_DriveHDIcon);
+#endif
+    if (info.isFile()) {
+        if (info.isSymLink())
+            return d->getIcon(QStyle::SP_FileLinkIcon);
+        else
+            return d->getIcon(QStyle::SP_FileIcon);
+    }
+  if (info.isDir()) {
+    if (info.isSymLink()) {
+      return d->getIcon(QStyle::SP_DirLinkIcon);
+    } else {
+      if (info.absoluteFilePath() == d->homePath) {
+        return d->getIcon(QStyle::SP_DirHomeIcon);
+      } else {
+        return d->getIcon(QStyle::SP_DirIcon);
+      }
+    }
+  }
+  return QIcon();
+}
+
+/*!
+  Returns the type of the file described by \a info.
+*/
+
+QString QFileIconProvider::type(const QFileInfo &info) const
+{
+    if (info.isRoot())
+        return QApplication::translate("QFileDialog", "Drive");
+    if (info.isFile()) {
+        if (!info.suffix().isEmpty())
+            return info.suffix() + QLatin1Char(' ') + QApplication::translate("QFileDialog", "File");
+        return QApplication::translate("QFileDialog", "File");
+    }
+
+    if (info.isDir())
+#ifdef Q_WS_WIN
+        return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer");
+#else
+        return QApplication::translate("QFileDialog", "Folder", "All other platforms");
+#endif
+    // Windows   - "File Folder"
+    // OS X      - "Folder"
+    // Konqueror - "Folder"
+    // Nautilus  - "folder"
+
+    if (info.isSymLink())
+#ifdef Q_OS_MAC
+        return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder");
+#else
+        return QApplication::translate("QFileDialog", "Shortcut", "All other platforms");
+#endif
+    // OS X      - "Alias"
+    // Windows   - "Shortcut"
+    // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to
+    // Nautilus  - "link to folder" or "link to object file", same as Konqueror
+
+    return QApplication::translate("QFileDialog", "Unknown");
+}
+
+QT_END_NAMESPACE
+
+#endif