diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-07-27 14:00:14 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-08-05 08:06:21 +0000 |
commit | 2cd2cba0868efb7e8dd2d00805f1a5ceed0a1349 (patch) | |
tree | 7fff626ad15f65aeb09508559d82b94f97337714 | |
parent | 955b2bdfc0cb1d707f8914be230e5e00c548b6ab (diff) |
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>
-rw-r--r-- | src/gui/kernel/qplatformtheme.cpp | 10 | ||||
-rw-r--r-- | src/gui/kernel/qplatformtheme.h | 3 | ||||
-rw-r--r-- | src/platformsupport/themes/qabstractfileiconengine.cpp | 130 | ||||
-rw-r--r-- | src/platformsupport/themes/qabstractfileiconengine_p.h | 96 | ||||
-rw-r--r-- | src/platformsupport/themes/themes.pri | 6 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoatheme.mm | 53 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowstheme.cpp | 78 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowstheme.h | 11 | ||||
-rw-r--r-- | src/widgets/itemviews/qfileiconprovider.cpp | 134 | ||||
-rw-r--r-- | src/widgets/styles/qcommonstyle.cpp | 10 |
11 files changed, 347 insertions, 188 deletions
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index a00c572e07..d80ab8b597 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -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 diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index c04ebd2190..a8baca1967 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -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; diff --git a/src/platformsupport/themes/qabstractfileiconengine.cpp b/src/platformsupport/themes/qabstractfileiconengine.cpp new file mode 100644 index 0000000000..19a8eee47b --- /dev/null +++ b/src/platformsupport/themes/qabstractfileiconengine.cpp @@ -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 diff --git a/src/platformsupport/themes/qabstractfileiconengine_p.h b/src/platformsupport/themes/qabstractfileiconengine_p.h new file mode 100644 index 0000000000..ce38cf262e --- /dev/null +++ b/src/platformsupport/themes/qabstractfileiconengine_p.h @@ -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 diff --git a/src/platformsupport/themes/themes.pri b/src/platformsupport/themes/themes.pri index adee852626..552973431f 100644 --- a/src/platformsupport/themes/themes.pri +++ b/src/platformsupport/themes/themes.pri @@ -1,3 +1,9 @@ unix:!mac { include($$PWD/genericunix/genericunix.pri) } + +HEADERS += \ + $$PWD/qabstractfileiconengine_p.h + +SOURCES += \ + $$PWD/qabstractfileiconengine.cpp diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index 282e527b0b..d47e620fbb 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -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; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 01b654af68..3a3d634f5a 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -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) {} + + 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(); } - NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())]; - if (!iconImage) - return QPixmap(); - return qt_mac_toQPixmap(iconImage, size); +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: diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 2c3ffd45d9..79befc56c2 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -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 diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index fa1fb4d998..0384899efa 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -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 diff --git a/src/widgets/itemviews/qfileiconprovider.cpp b/src/widgets/itemviews/qfileiconprovider.cpp index 5638e438d5..8c3cf3859e 100644 --- a/src/widgets/itemviews/qfileiconprovider.cpp +++ b/src/widgets/itemviews/qfileiconprovider.cpp @@ -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)); } /*! diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 36975c5877..6cdfc061e1 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -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); } |