Files
transmission/qt/IconCache.cc
Charles Kerr f59118d1fe feat: add torrent-get 'primary-mime-type' to RPC. (#1464)
* feat: add torrent-get 'primary-mime-type' to RPC.

This is a cheap way for RPC clients to know what type of content is in a
torrent. This info can be used to display the torrent, e.g. by using an
icon that corresponds to the mime type.

* use size_t for content byte count

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>

* explicit boolean expressions

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>

* use uint64_t for content byte counts

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>

* avoid unnecessary logic branches

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>

* explicit cast

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>

* refactor: add an autogenerated mime-type.h header

* chore: maybe fix the win32 FTBFS

* chore: add mime-types.[ch] to xcode

* Squashed commit of the following:

commit 4c7153fa48
Author: Mike Gelfand <mikedld@users.noreply.github.com>
Date:   Tue Oct 13 03:15:19 2020 +0300

    Remove autotools-based build system (#1465)

    * Support .git files (e.g. for worktrees, submodules)
    * Fix symlinks in source tarball, switch to TXZ, adjust non-release name
    * Remove autotools stuff

Co-authored-by: Mike Gelfand <mikedld@users.noreply.github.com>
2020-10-13 10:33:56 -05:00

212 lines
4.7 KiB
C++

/*
* This file Copyright (C) 2009-2015 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "IconCache.h"
#ifdef _WIN32
#include <windows.h>
#include <shellapi.h>
#endif
#include <QFile>
#include <QFileIconProvider>
#include <QFileInfo>
#include <QIcon>
#include <QMimeDatabase>
#include <QObject>
#include <QPainter>
#include <QStyle>
#ifdef _WIN32
#include <QPixmapCache>
#include <QtWin>
#endif
#include <libtransmission/transmission.h>
/***
****
***/
IconCache& IconCache::get()
{
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static auto& singleton = *new IconCache();
return singleton;
}
IconCache::IconCache() :
folder_icon_(QFileIconProvider().icon(QFileIconProvider::Folder)),
file_icon_(QFileIconProvider().icon(QFileIconProvider::File))
{
}
QIcon IconCache::guessMimeIcon(QString const& filename, QIcon fallback) const
{
QIcon icon;
#ifdef _WIN32
if (!filename.isEmpty())
{
QFileInfo const file_info(filename);
addAssociatedFileIcon(file_info, SHGFI_SMALLICON, icon);
addAssociatedFileIcon(file_info, 0, icon);
addAssociatedFileIcon(file_info, SHGFI_LARGEICON, icon);
}
#else
icon = getMimeIcon(filename);
#endif
if (icon.isNull())
{
icon = fallback;
}
return icon;
}
QIcon IconCache::getMimeTypeIcon(QString const& mime_type_name, bool multifile) const
{
auto& icon = (multifile ? name_to_emblem_icon_ : name_to_icon_)[mime_type_name];
if (!icon.isNull())
{
return icon;
}
if (!multifile)
{
QMimeDatabase mime_db;
auto const type = mime_db.mimeTypeForName(mime_type_name);
icon = QIcon::fromTheme(type.iconName());
if (icon.isNull())
{
icon = QIcon::fromTheme(type.genericIconName());
}
if (icon.isNull())
{
icon = file_icon_;
}
return icon;
}
auto const mime_icon = getMimeTypeIcon(mime_type_name, false);
for (auto const& size : { QSize(24, 24), QSize(32, 32), QSize(48, 48) })
{
// upper left corner
auto const folder_size = size / 2;
auto const folder_rect = QRect(QPoint(), folder_size);
// fullsize
auto const mime_size = size;
auto const mime_rect = QRect(QPoint(), mime_size);
// build the icon
auto pixmap = QPixmap(size);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHints(QPainter::SmoothPixmapTransform);
painter.drawPixmap(folder_rect, folder_icon_.pixmap(folder_size));
painter.drawPixmap(mime_rect, mime_icon.pixmap(mime_size));
icon.addPixmap(pixmap);
}
return icon;
}
/***
****
***/
#ifdef _WIN32
void IconCache::addAssociatedFileIcon(QFileInfo const& file_info, UINT icon_size, QIcon& icon) const
{
QString const pixmap_cache_key = QStringLiteral("tr_file_ext_") + QString::number(icon_size) + QLatin1Char('_') +
file_info.suffix();
QPixmap pixmap;
if (!QPixmapCache::find(pixmap_cache_key, &pixmap))
{
auto const filename = file_info.fileName().toStdWString();
SHFILEINFO shell_file_info;
if (::SHGetFileInfoW(filename.data(), FILE_ATTRIBUTE_NORMAL, &shell_file_info,
sizeof(shell_file_info), SHGFI_ICON | icon_size | SHGFI_USEFILEATTRIBUTES) != 0)
{
if (shell_file_info.hIcon != nullptr)
{
pixmap = QtWin::fromHICON(shell_file_info.hIcon);
::DestroyIcon(shell_file_info.hIcon);
}
}
QPixmapCache::insert(pixmap_cache_key, pixmap);
}
if (!pixmap.isNull())
{
icon.addPixmap(pixmap);
}
}
#else
QIcon IconCache::getMimeIcon(QString const& filename) const
{
if (suffixes_.empty())
{
for (auto const& type : QMimeDatabase().allMimeTypes())
{
auto const tmp = type.suffixes();
suffixes_.insert(tmp.begin(), tmp.end());
}
}
auto const ext = QFileInfo(filename).suffix();
if (suffixes_.count(ext) == 0)
{
return {};
}
QIcon& icon = ext_to_icon_[ext];
if (icon.isNull()) // cache miss
{
QMimeDatabase mime_db;
auto const type = mime_db.mimeTypeForFile(filename, QMimeDatabase::MatchExtension);
if (icon.isNull())
{
icon = QIcon::fromTheme(type.iconName());
}
if (icon.isNull())
{
icon = QIcon::fromTheme(type.genericIconName());
}
if (icon.isNull())
{
icon = {};
}
}
return icon;
}
#endif