diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 606a8de68..b8e9cd6d7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,9 @@ find_package(LibtorrentRasterbar REQUIRED) list(APPEND QBT_QT_COMPONENTS Core Network Xml) if (GUI) list (APPEND QBT_QT_COMPONENTS Concurrent Gui Widgets) + if (WIN32) + list (APPEND QBT_QT_COMPONENTS WinExtras) + endif(WIN32) endif (GUI) if (DBUS) list (APPEND QBT_QT_COMPONENTS DBus) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 66b84381f..4d3bb152d 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -150,3 +150,6 @@ target_link_libraries(qbt_gui qbt_lineedit qbt_powermanagement qbt_rss qbt_prope ${QBT_GUI_OPTIONAL_LINK_LIBRARIES} qbt_base QtSingleApplication::QtSingleApplication ) +if(WIN32) + target_link_libraries(qbt_gui Qt5::WinExtras) +endif(WIN32) diff --git a/src/gui/torrentcontentmodel.cpp b/src/gui/torrentcontentmodel.cpp index bae6d58be..c69d7dbda 100644 --- a/src/gui/torrentcontentmodel.cpp +++ b/src/gui/torrentcontentmodel.cpp @@ -29,8 +29,16 @@ */ #include +#include +#include #include +#ifdef Q_OS_WIN +#include +#include +#include +#endif + #include "guiiconprovider.h" #include "base/utils/misc.h" #include "base/utils/fs.h" @@ -47,21 +55,53 @@ namespace return cached; } - QIcon getFileIcon() + class UnifiedFileIconProvider: public QFileIconProvider { - static QIcon cached = GuiIconProvider::instance()->getIcon("text-plain"); - return cached; - } + public: + using QFileIconProvider::icon; + QIcon icon(const QFileInfo &info) const override + { + Q_UNUSED(info); + static QIcon cached = GuiIconProvider::instance()->getIcon("text-plain"); + return cached; + } + }; +#ifdef Q_OS_WIN + // See QTBUG-25319 for explanation why this is required + class WinShellFileIconProvider: public UnifiedFileIconProvider + { + public: + using QFileIconProvider::icon; + QIcon icon(const QFileInfo &info) const override + { + SHFILEINFO sfi = { 0 }; + 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); + ::DestroyIcon(sfi.hIcon); + return QIcon(iconPixmap); + } + }; +#endif } TorrentContentModel::TorrentContentModel(QObject *parent) : QAbstractItemModel(parent) , m_rootItem(new TorrentContentModelFolder(QList({ tr("Name"), tr("Size"), tr("Progress"), tr("Download Priority"), tr("Remaining"), tr("Availability") }))) { +#ifdef Q_OS_WIN + m_fileIconProvider = new WinShellFileIconProvider(); +#else + m_fileIconProvider = new QFileIconProvider(); +#endif } TorrentContentModel::~TorrentContentModel() { + delete m_fileIconProvider; delete m_rootItem; } @@ -202,7 +242,7 @@ QVariant TorrentContentModel::data(const QModelIndex& index, int role) const if (item->itemType() == TorrentContentModelItem::FolderType) return getDirectoryIcon(); else - return getFileIcon(); + return m_fileIconProvider->icon(QFileInfo(item->name())); } if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole)) { diff --git a/src/gui/torrentcontentmodel.h b/src/gui/torrentcontentmodel.h index 31baa9f50..cd6ef3966 100644 --- a/src/gui/torrentcontentmodel.h +++ b/src/gui/torrentcontentmodel.h @@ -39,6 +39,7 @@ #include "base/bittorrent/torrentinfo.h" #include "torrentcontentmodelitem.h" +class QFileIconProvider; class TorrentContentModelFile; class TorrentContentModel: public QAbstractItemModel @@ -77,6 +78,7 @@ public slots: private: TorrentContentModelFolder *m_rootItem; QVector m_filesIndex; + QFileIconProvider *m_fileIconProvider; }; #endif // TORRENTCONTENTMODEL_H diff --git a/src/src.pro b/src/src.pro index 9a296d258..71914081a 100644 --- a/src/src.pro +++ b/src/src.pro @@ -28,6 +28,9 @@ nogui { DEFINES += QBT_STATIC_QT QTPLUGIN += qico } + win32 { + QT += winextras + } TARGET = qbittorrent } nowebui: DEFINES += DISABLE_WEBUI