Browse Source

Use pixmap cache for file icons on Mac OS and Windows. Closes #7264.

adaptive-webui-19844
Eugene Shalygin 7 years ago
parent
commit
3331526865
  1. 89
      src/gui/torrentcontentmodel.cpp

89
src/gui/torrentcontentmodel.cpp

@ -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())
return *cacheIter;
QIcon icon = QIcon(pixmapForExtension(ext, QSize(32, 32))); const QPixmap pixmap = pixmapForExtension(ext);
if (!icon.isNull()) { if (!pixmap.isNull()) {
m_iconCache.insert(ext, icon); QPixmapCache::insert(ext, pixmap);
return icon; return QIcon(pixmap);
} }
} }
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
/** /**

Loading…
Cancel
Save