QtPlatformSupport: Add QAbstractFileIconEngine

Move the code from QtWidgets/QFileIconEngine into a new class with
virtuals in QtPlatformSupport so that platforms can reuse it.

Prototypically use the class in the Windows and macOS QPA plugins.

Remove QPlatformTheme::fileIconPixmap() and change the type
of the hint QPlatformTheme::IconPixmapSizes from QList<int>
to QList<QSize> so that it fits better with the icon code.

Change-Id: I580e936f3507218757565ca099272cd575b3a779
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
Friedemann Kleint 2016-07-27 14:00:14 +02:00
parent 955b2bdfc0
commit 2cd2cba086
11 changed files with 347 additions and 188 deletions

View File

@ -424,16 +424,6 @@ QIcon QPlatformTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOp
return QIcon();
}
QPixmap QPlatformTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
QPlatformTheme::IconOptions iconOptions) const
{
Q_UNUSED(fileInfo);
Q_UNUSED(size);
Q_UNUSED(iconOptions);
// TODO Should return QCommonStyle pixmaps?
return QPixmap();
}
QVariant QPlatformTheme::themeHint(ThemeHint hint) const
{
// For theme hints which mirror platform integration style hints, query

View File

@ -304,9 +304,6 @@ public:
virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const;
virtual QIcon fileIcon(const QFileInfo &fileInfo,
QPlatformTheme::IconOptions iconOptions = 0) const;
virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
QPlatformTheme::IconOptions iconOptions = 0) const;
virtual QIconEngine *createIconEngine(const QString &iconName) const;
virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const;

View File

@ -0,0 +1,130 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qabstractfileiconengine_p.h"
#include <qpixmapcache.h>
QT_BEGIN_NAMESPACE
/*!
\class QAbstractFileIconEngine
\brief Helper base class for retrieving icons for files for usage by QFileIconProvider and related.
Reimplement availableSizes() and new virtual filePixmap() and return icons created
with this engine from QPlatformTheme::fileIcon().
Note: The class internally caches pixmaps for files by suffix (with the exception
of some files on Windows), but not for directories (since directory icons may have
overlay icons on Windows). You might want to cache pixmaps for directories
in your implementation.
\since 5.8
\internal
\sa QFileIconProvider::DontUseCustomDirectoryIcons, QPlatformTheme
\ingroup qpa
*/
QPixmap QAbstractFileIconEngine::pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state)
{
Q_UNUSED(mode);
Q_UNUSED(state);
if (!size.isValid())
return QPixmap();
QString key = cacheKey();
if (key.isEmpty())
return filePixmap(size, mode, state);
key += QLatin1Char('_');
key += QString::number(size.width());
QPixmap result;
if (!QPixmapCache::find(key, result)) {
result = filePixmap(size, mode, state);
if (!result.isNull())
QPixmapCache::insert(key, result);
}
return result;
}
QSize QAbstractFileIconEngine::actualSize(const QSize &size, QIcon::Mode mode,
QIcon::State state)
{
const QList<QSize> &sizes = availableSizes(mode, state);
const int numberSizes = sizes.length();
if (numberSizes == 0)
return QSize();
// Find the smallest available size whose area is still larger than the input
// size. Otherwise, use the largest area available size. (We don't assume the
// platform theme sizes are sorted, hence the extra logic.)
const int sizeArea = size.width() * size.height();
QSize actualSize = sizes.first();
int actualArea = actualSize.width() * actualSize.height();
for (int i = 1; i < numberSizes; ++i) {
const QSize &s = sizes.at(i);
const int a = s.width() * s.height();
if ((sizeArea <= a && a < actualArea) || (actualArea < sizeArea && actualArea < a)) {
actualSize = s;
actualArea = a;
}
}
if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
return actualSize;
}
/* Reimplement to return a cache key for the entry. An empty result indicates
* the icon should not be cached (for example, directory icons having custom icons). */
QString QAbstractFileIconEngine::cacheKey() const
{
if (!m_fileInfo.isFile() || m_fileInfo.isSymLink() || m_fileInfo.isExecutable())
return QString();
const QString &suffix = m_fileInfo.suffix();
return QLatin1String("qt_.")
+ (suffix.isEmpty() ? m_fileInfo.fileName() : suffix); // handle "Makefile" ;)
}
QT_END_NAMESPACE

View File

@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QABSTRACTFILEICONENGINE_P_H
#define QABSTRACTFILEICONENGINE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qfileinfo.h>
#include <private/qicon_p.h>
#include <qpa/qplatformtheme.h>
QT_BEGIN_NAMESPACE
class QAbstractFileIconEngine : public QPixmapIconEngine
{
public:
explicit QAbstractFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts)
: QPixmapIconEngine(), m_fileInfo(info), m_options(opts) {}
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override;
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
QFileInfo fileInfo() const { return m_fileInfo; }
QPlatformTheme::IconOptions options() const { return m_options; }
// Helper to convert a sequence of ints to a list of QSize
template <class It> static QList<QSize> toSizeList(It i1, It i2);
protected:
virtual QPixmap filePixmap(const QSize &size, QIcon::Mode mode, QIcon::State) = 0;
virtual QString cacheKey() const;
private:
const QFileInfo m_fileInfo;
const QPlatformTheme::IconOptions m_options;
};
template <class It>
inline QList<QSize> QAbstractFileIconEngine::toSizeList(It i1, It i2)
{
QList<QSize> result;
result.reserve(int(i2 - i1));
for ( ; i1 != i2; ++i1)
result.append(QSize(*i1, *i1));
return result;
}
QT_END_NAMESPACE
#endif // QABSTRACTFILEICONENGINE_P_H

View File

@ -1,3 +1,9 @@
unix:!mac {
include($$PWD/genericunix/genericunix.pri)
}
HEADERS += \
$$PWD/qabstractfileiconengine_p.h
SOURCES += \
$$PWD/qabstractfileiconengine.cpp

View File

@ -70,9 +70,7 @@ public:
const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE;
const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE;
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE;
QPixmap fileIconPixmap(const QFileInfo &fileInfo,
const QSizeF &size,
QPlatformTheme::IconOptions options = 0) const Q_DECL_OVERRIDE;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = 0) const override;
QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE;
QString standardButtonText(int button) const Q_DECL_OVERRIDE;

View File

@ -58,6 +58,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpainter.h>
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
#include <QtPlatformSupport/private/qabstractfileiconengine_p.h>
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformnativeinterface.h>
@ -274,16 +275,41 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
return QPlatformTheme::standardPixmap(sp, size);
}
QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
QPlatformTheme::IconOptions iconOptions) const
class QCocoaFileIconEngine : public QAbstractFileIconEngine
{
Q_UNUSED(iconOptions);
QMacAutoReleasePool pool;
public:
explicit QCocoaFileIconEngine(const QFileInfo &info,
QPlatformTheme::IconOptions opts) :
QAbstractFileIconEngine(info, opts) {}
NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())];
if (!iconImage)
return QPixmap();
return qt_mac_toQPixmap(iconImage, size);
static QList<QSize> availableIconSizes()
{
const qreal devicePixelRatio = qGuiApp->devicePixelRatio();
const int sizes[] = {
qRound(16 * devicePixelRatio), qRound(32 * devicePixelRatio),
qRound(64 * devicePixelRatio), qRound(128 * devicePixelRatio)
};
return QAbstractFileIconEngine::toSizeList(sizes, sizes + sizeof(sizes) / sizeof(sizes[0]));
}
QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override
{ return QCocoaFileIconEngine::availableIconSizes(); }
protected:
QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override
{
QMacAutoReleasePool pool;
NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo().canonicalFilePath())];
if (!iconImage)
return QPixmap();
return qt_mac_toQPixmap(iconImage, size);
}
};
QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const
{
return QIcon(new QCocoaFileIconEngine(fileInfo, iconOptions));
}
QVariant QCocoaTheme::themeHint(ThemeHint hint) const
@ -298,15 +324,8 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
case TabFocusBehavior:
return QVariant([[NSApplication sharedApplication] isFullKeyboardAccessEnabled] ?
int(Qt::TabFocusAllControls) : int(Qt::TabFocusTextControls | Qt::TabFocusListControls));
case IconPixmapSizes: {
qreal devicePixelRatio = qGuiApp->devicePixelRatio();
QList<int> sizes;
sizes << 16 * devicePixelRatio
<< 32 * devicePixelRatio
<< 64 * devicePixelRatio
<< 128 * devicePixelRatio;
return QVariant::fromValue(sizes);
}
case IconPixmapSizes:
return QVariant::fromValue(QCocoaFileIconEngine::availableIconSizes());
case QPlatformTheme::PasswordMaskCharacter:
return QVariant(QChar(kBulletUnicode));
case QPlatformTheme::UiEffects:

View File

@ -68,6 +68,7 @@
#include <QtGui/QPainter>
#include <QtGui/QPixmapCache>
#include <qpa/qwindowsysteminterface.h>
#include <QtPlatformSupport/private/qabstractfileiconengine_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qsystemlibrary_p.h>
@ -314,6 +315,7 @@ const char *QWindowsTheme::name = "windows";
QWindowsTheme *QWindowsTheme::m_instance = 0;
QWindowsTheme::QWindowsTheme()
: m_threadPoolRunner(new QWindowsThreadPoolRunner)
{
m_instance = this;
std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
@ -384,7 +386,7 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
case UiEffects:
return QVariant(uiEffects());
case IconPixmapSizes:
return m_fileIconSizes;
return QVariant::fromValue(m_fileIconSizes);
case DialogSnapToDefaultButton:
return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false));
case ContextMenuOnMouseRelease:
@ -492,15 +494,14 @@ void QWindowsTheme::refreshIconPixmapSizes()
fileIconSizes[ExtraLargeFileIcon] =
fileIconSizes[LargeFileIcon] + fileIconSizes[LargeFileIcon] / 2;
fileIconSizes[JumboFileIcon] = 8 * fileIconSizes[LargeFileIcon]; // empirical, has not been observed to work
QList<int> sizes;
sizes << fileIconSizes[SmallFileIcon] << fileIconSizes[LargeFileIcon];
#ifdef USE_IIMAGELIST
sizes << fileIconSizes[ExtraLargeFileIcon]; // sHIL_EXTRALARGE
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
sizes << fileIconSizes[JumboFileIcon]; // SHIL_JUMBO
int *availEnd = fileIconSizes + JumboFileIcon + 1;
#else
int *availEnd = fileIconSizes + LargeFileIcon + 1;
#endif // USE_IIMAGELIST
qCDebug(lcQpaWindows) << __FUNCTION__ << sizes;
m_fileIconSizes = QVariant::fromValue(sizes);
m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
qCDebug(lcQpaWindows) << __FUNCTION__ << m_fileIconSizes;
}
// Defined in qpixmap_win.cpp
@ -714,8 +715,46 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
return result;
}
QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
QPlatformTheme::IconOptions iconOptions) const
class QWindowsFileIconEngine : public QAbstractFileIconEngine
{
public:
explicit QWindowsFileIconEngine(const QFileInfo &info,
QPlatformTheme::IconOptions opts,
const QSharedPointer<QWindowsThreadPoolRunner> &runner) :
QAbstractFileIconEngine(info, opts), m_threadPoolRunner(runner) {}
QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override
{ return QWindowsTheme::instance()->availableFileIconSizes(); }
protected:
QString cacheKey() const override;
QPixmap filePixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override;
private:
const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner;
};
QString QWindowsFileIconEngine::cacheKey() const
{
// Cache directories unless custom or drives, which have custom icons depending on type
if ((options() & QPlatformTheme::DontUseCustomDirectoryIcons) && fileInfo().isDir() && !fileInfo().isRoot())
return QStringLiteral("qt_/directory/");
if (!fileInfo().isFile())
return QString();
// Return "" for .exe, .lnk and .ico extensions.
// It is faster to just look at the file extensions;
// avoiding slow QFileInfo::isExecutable() (QTBUG-13182)
const QString &suffix = fileInfo().suffix();
if (!suffix.compare(QLatin1String("exe"), Qt::CaseInsensitive)
|| !suffix.compare(QLatin1String("lnk"), Qt::CaseInsensitive)
|| !suffix.compare(QLatin1String("ico"), Qt::CaseInsensitive)) {
return QString();
}
return QLatin1String("qt_.")
+ (suffix.isEmpty() ? fileInfo().fileName() : suffix.toUpper()); // handle "Makefile" ;)
}
QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon::State)
{
/* We don't use the variable, but by storing it statically, we
* ensure CoInitialize is only called once. */
@ -725,10 +764,10 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
static QCache<QString, FakePointer<int> > dirIconEntryCache(1000);
static QMutex mx;
static int defaultFolderIIcon = -1;
const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons;
const bool useDefaultFolderIcon = options() & QPlatformTheme::DontUseCustomDirectoryIcons;
QPixmap pixmap;
const QString filePath = QDir::toNativeSeparators(fileInfo.filePath());
const QString filePath = QDir::toNativeSeparators(fileInfo().filePath());
const int width = int(size.width());
const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
const int requestedImageListSize =
@ -739,7 +778,7 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
#else
0;
#endif // !USE_IIMAGELIST
bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot();
bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
if (cacheableDirIcon) {
QMutexLocker locker(&mx);
int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon
@ -758,9 +797,9 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX;
const bool val = cacheableDirIcon && useDefaultFolderIcon
? shGetFileInfoBackground(m_threadPoolRunner, L"dummy", FILE_ATTRIBUTE_DIRECTORY,
? shGetFileInfoBackground(*m_threadPoolRunner.data(), L"dummy", FILE_ATTRIBUTE_DIRECTORY,
&info, flags | SHGFI_USEFILEATTRIBUTES)
: shGetFileInfoBackground(m_threadPoolRunner, reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
: shGetFileInfoBackground(*m_threadPoolRunner.data(), reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
&info, flags);
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
@ -800,9 +839,12 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
DestroyIcon(info.hIcon);
}
if (!pixmap.isNull())
return pixmap;
return QPlatformTheme::fileIconPixmap(fileInfo, size);
return pixmap;
}
QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const
{
return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions, m_threadPoolRunner));
}
QT_END_NAMESPACE

View File

@ -43,6 +43,7 @@
#include "qwindowsthreadpoolrunner.h"
#include <qpa/qplatformtheme.h>
#include <QtCore/QSharedPointer>
#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
@ -66,12 +67,14 @@ public:
{ return m_fonts[type]; }
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE;
QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
QPlatformTheme::IconOptions iconOptions = 0) const Q_DECL_OVERRIDE;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = 0) const override;
void windowsThemeChanged(QWindow *window);
void displayChanged() { refreshIconPixmapSizes(); }
QList<QSize> availableFileIconSizes() const { return m_fileIconSizes; }
static const char *name;
private:
@ -85,8 +88,8 @@ private:
static QWindowsTheme *m_instance;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
mutable QWindowsThreadPoolRunner m_threadPoolRunner;
QVariant m_fileIconSizes;
const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner;
QList<QSize> m_fileIconSizes;
};
QT_END_NAMESPACE

View File

@ -60,110 +60,6 @@
QT_BEGIN_NAMESPACE
static bool isCacheable(const QFileInfo &fi);
static QPlatformTheme::IconOptions toThemeIconOptions(QFileIconProvider::Options options)
{
QPlatformTheme::IconOptions result;
if (options & QFileIconProvider::DontUseCustomDirectoryIcons)
result |= QPlatformTheme::DontUseCustomDirectoryIcons;
return result;
}
class QFileIconEngine : public QPixmapIconEngine
{
public:
QFileIconEngine(const QFileInfo &info, QFileIconProvider::Options opts)
: QPixmapIconEngine(), m_fileInfo(info), m_fipOpts(opts)
{ }
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE
{
Q_UNUSED(mode);
Q_UNUSED(state);
QPixmap pixmap;
if (!size.isValid())
return pixmap;
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
if (!theme)
return pixmap;
const QString &keyBase = QLatin1String("qt_.") + m_fileInfo.suffix().toUpper();
bool cacheable = isCacheable(m_fileInfo);
if (cacheable) {
QPixmapCache::find(keyBase + QString::number(size.width()), pixmap);
if (!pixmap.isNull())
return pixmap;
}
pixmap = theme->fileIconPixmap(m_fileInfo, size, toThemeIconOptions(m_fipOpts));
if (!pixmap.isNull()) {
if (cacheable)
QPixmapCache::insert(keyBase + QString::number(size.width()), pixmap);
}
return pixmap;
}
QList<QSize> availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) const Q_DECL_OVERRIDE
{
Q_UNUSED(mode);
Q_UNUSED(state);
static QList<QSize> sizes;
static QPlatformTheme *theme = 0;
if (!theme) {
theme = QGuiApplicationPrivate::platformTheme();
if (!theme)
return sizes;
QList<int> themeSizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int> >();
if (themeSizes.isEmpty())
return sizes;
sizes.reserve(themeSizes.count());
foreach (int size, themeSizes)
sizes << QSize(size, size);
}
return sizes;
}
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE
{
const QList<QSize> &sizes = availableSizes(mode, state);
const int numberSizes = sizes.length();
if (numberSizes == 0)
return QSize();
// Find the smallest available size whose area is still larger than the input
// size. Otherwise, use the largest area available size. (We don't assume the
// platform theme sizes are sorted, hence the extra logic.)
const int sizeArea = size.width() * size.height();
QSize actualSize = sizes.first();
int actualArea = actualSize.width() * actualSize.height();
for (int i = 1; i < numberSizes; ++i) {
const QSize &s = sizes.at(i);
const int a = s.width() * s.height();
if ((sizeArea <= a && a < actualArea) || (actualArea < sizeArea && actualArea < a)) {
actualSize = s;
actualArea = a;
}
}
if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
return actualSize;
}
private:
QFileInfo m_fileInfo;
QFileIconProvider::Options m_fipOpts;
};
/*!
\class QFileIconProvider
@ -326,35 +222,17 @@ QIcon QFileIconProvider::icon(IconType type) const
return QIcon();
}
static bool isCacheable(const QFileInfo &fi)
static inline QPlatformTheme::IconOptions toThemeIconOptions(QFileIconProvider::Options options)
{
if (!fi.isFile())
return false;
#ifdef Q_OS_WIN
// On windows it's faster to just look at the file extensions. QTBUG-13182
const QString fileExtension = fi.suffix();
// Will return false for .exe, .lnk and .ico extensions
return fileExtension.compare(QLatin1String("exe"), Qt::CaseInsensitive) &&
fileExtension.compare(QLatin1String("lnk"), Qt::CaseInsensitive) &&
fileExtension.compare(QLatin1String("ico"), Qt::CaseInsensitive);
#else
return !fi.isExecutable() && !fi.isSymLink();
#endif
QPlatformTheme::IconOptions result;
if (options & QFileIconProvider::DontUseCustomDirectoryIcons)
result |= QPlatformTheme::DontUseCustomDirectoryIcons;
return result;
}
QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const
{
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
if (!theme)
return QIcon();
QIcon themeFileIcon = theme->fileIcon(fi, toThemeIconOptions(options));
if (!themeFileIcon.isNull())
return themeFileIcon;
QList<int> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int> >();
return sizes.isEmpty() ? QIcon() : QIcon(new QFileIconEngine(fi, options));
return QGuiApplicationPrivate::platformTheme()->fileIcon(fi, toThemeIconOptions(options));
}
/*!

View File

@ -5913,14 +5913,14 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
QIcon retIcon;
QList<int> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int> >();
Q_FOREACH (int size, sizes) {
const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize> >();
for (const QSize &size : sizes) {
QPixmap mainIcon;
const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size);
const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size.width());
if (standardIcon >= QStyle::SP_CustomBase) {
mainIcon = theme->standardPixmap(sp, QSizeF(size, size));
mainIcon = theme->standardPixmap(sp, QSizeF(size));
} else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
mainIcon = theme->standardPixmap(sp, QSizeF(size, size));
mainIcon = theme->standardPixmap(sp, QSizeF(size));
QPixmapCache::insert(cacheKey, mainIcon);
}