|
|
@ -43,6 +43,11 @@ |
|
|
|
#include <QMimeType> |
|
|
|
#include <QMimeType> |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined Q_OS_WIN || defined Q_OS_MAC |
|
|
|
|
|
|
|
#define QBT_PIXMAP_CACHE_FOR_FILE_ICONS |
|
|
|
|
|
|
|
#include <QPixmapCache> |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#include "guiiconprovider.h" |
|
|
|
#include "guiiconprovider.h" |
|
|
|
#include "base/utils/misc.h" |
|
|
|
#include "base/utils/misc.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
@ -74,55 +79,79 @@ namespace |
|
|
|
return cached; |
|
|
|
return cached; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
#if defined(Q_OS_WIN) |
|
|
|
|
|
|
|
// See QTBUG-25319 for explanation why this is required
|
|
|
|
#ifdef QBT_PIXMAP_CACHE_FOR_FILE_ICONS |
|
|
|
class WinShellFileIconProvider: public UnifiedFileIconProvider |
|
|
|
struct Q_DECL_UNUSED PixmapCacheSetup |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
static const int PixmapCacheForIconsSize = 2 * 1024 * 1024; // 2 MiB for file icons
|
|
|
|
using QFileIconProvider::icon; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QIcon icon(const QFileInfo &info) const override |
|
|
|
PixmapCacheSetup() |
|
|
|
{ |
|
|
|
{ |
|
|
|
SHFILEINFO sfi = { 0 }; |
|
|
|
QPixmapCache::setCacheLimit(QPixmapCache::cacheLimit() + PixmapCacheForIconsSize); |
|
|
|
HRESULT hr = ::SHGetFileInfoW(info.absoluteFilePath().toStdWString().c_str(), |
|
|
|
} |
|
|
|
FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES); |
|
|
|
|
|
|
|
if (FAILED(hr)) |
|
|
|
|
|
|
|
return UnifiedFileIconProvider::icon(info); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QPixmap iconPixmap = QtWin::fromHICON(sfi.hIcon); |
|
|
|
~PixmapCacheSetup() |
|
|
|
::DestroyIcon(sfi.hIcon); |
|
|
|
{ |
|
|
|
return QIcon(iconPixmap); |
|
|
|
Q_ASSERT(QPixmapCache::cacheLimit() > PixmapCacheForIconsSize); |
|
|
|
|
|
|
|
QPixmapCache::setCacheLimit(QPixmapCache::cacheLimit() - PixmapCacheForIconsSize); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
#elif defined(Q_OS_MAC) |
|
|
|
|
|
|
|
// There is a similar bug on macOS, to be reported to Qt
|
|
|
|
PixmapCacheSetup pixmapCacheSetup; |
|
|
|
// https://github.com/qbittorrent/qBittorrent/pull/6156#issuecomment-316302615
|
|
|
|
|
|
|
|
class MacFileIconProvider: public UnifiedFileIconProvider |
|
|
|
class CachingFileIconProvider: public UnifiedFileIconProvider |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
public: |
|
|
|
using QFileIconProvider::icon; |
|
|
|
using QFileIconProvider::icon; |
|
|
|
|
|
|
|
|
|
|
|
QIcon icon(const QFileInfo &info) const override |
|
|
|
QIcon icon(const QFileInfo &info) const final override |
|
|
|
{ |
|
|
|
{ |
|
|
|
const QString ext = info.suffix(); |
|
|
|
const QString ext = info.suffix(); |
|
|
|
if (!ext.isEmpty()) { |
|
|
|
if (!ext.isEmpty()) { |
|
|
|
auto cacheIter = m_iconCache.find(ext); |
|
|
|
QPixmap cached; |
|
|
|
|
|
|
|
if (QPixmapCache::find(ext, &cached)) return QIcon(cached); |
|
|
|
|
|
|
|
|
|
|
|
if (cacheIter != m_iconCache.end()) |
|
|
|
const QPixmap pixmap = pixmapForExtension(ext); |
|
|
|
return *cacheIter; |
|
|
|
if (!pixmap.isNull()) { |
|
|
|
|
|
|
|
QPixmapCache::insert(ext, pixmap); |
|
|
|
QIcon icon = QIcon(pixmapForExtension(ext, QSize(32, 32))); |
|
|
|
return QIcon(pixmap); |
|
|
|
if (!icon.isNull()) { |
|
|
|
|
|
|
|
m_iconCache.insert(ext, icon); |
|
|
|
|
|
|
|
return icon; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return UnifiedFileIconProvider::icon(info); |
|
|
|
return UnifiedFileIconProvider::icon(info); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
protected: |
|
|
|
mutable QMap<QString, QIcon> m_iconCache; |
|
|
|
virtual QPixmap pixmapForExtension(const QString &ext) const = 0; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN) |
|
|
|
|
|
|
|
// See QTBUG-25319 for explanation why this is required
|
|
|
|
|
|
|
|
class WinShellFileIconProvider final: public CachingFileIconProvider |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
QPixmap pixmapForExtension(const QString &ext) const override |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
const QString extWithDot = QLatin1Char('.') + ext; |
|
|
|
|
|
|
|
SHFILEINFO sfi = { 0 }; |
|
|
|
|
|
|
|
HRESULT hr = ::SHGetFileInfoW(extWithDot.toStdWString().c_str(), |
|
|
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES); |
|
|
|
|
|
|
|
if (FAILED(hr)) |
|
|
|
|
|
|
|
return QPixmap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QPixmap iconPixmap = QtWin::fromHICON(sfi.hIcon); |
|
|
|
|
|
|
|
::DestroyIcon(sfi.hIcon); |
|
|
|
|
|
|
|
return iconPixmap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
#elif defined(Q_OS_MAC) |
|
|
|
|
|
|
|
// There is a similar bug on macOS, to be reported to Qt
|
|
|
|
|
|
|
|
// https://github.com/qbittorrent/qBittorrent/pull/6156#issuecomment-316302615
|
|
|
|
|
|
|
|
class MacFileIconProvider final: public CachingFileIconProvider |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
QPixmap pixmapForExtension(const QString &ext) const override |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return ::pixmapForExtension(ext, QSize(32, 32)); |
|
|
|
|
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
#else |
|
|
|
#else |
|
|
|
/**
|
|
|
|
/**
|
|
|
|