From 46685f755b01288fd53c4483cb97a22c426a57f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Mon, 29 Apr 2013 12:58:23 +0100 Subject: Windows: Introduce QFileDialog::DontUseCustomDirectoryIcons Folders can have a custom icon, set by the user. Some system folders also have one, for example c:\windows\fonts. This option allows you to disable this behavior, you'll get the folder directory icon. As a side-effect, you'll get a very big performance improvement on removable/network media: 2 seconds vs 60 seconds on a SDCard with 10000 folders. Change-Id: Id55ea628186e0a6523585ec7a4ff622d6f5da505 Reviewed-by: Giuseppe D'Angelo --- src/gui/kernel/qplatformdialoghelper.h | 15 +++++---- src/gui/kernel/qplatformtheme.cpp | 4 ++- src/gui/kernel/qplatformtheme.h | 8 ++++- src/plugins/platforms/cocoa/qcocoatheme.h | 4 ++- src/plugins/platforms/cocoa/qcocoatheme.mm | 4 ++- src/plugins/platforms/windows/qwindowstheme.cpp | 23 ++++++++++--- src/plugins/platforms/windows/qwindowstheme.h | 3 +- src/widgets/dialogs/qfiledialog.cpp | 14 ++++++++ src/widgets/dialogs/qfiledialog.h | 15 +++++---- src/widgets/itemviews/qfileiconprovider.cpp | 44 +++++++++++++++++++++++-- src/widgets/itemviews/qfileiconprovider.h | 11 +++++++ tests/manual/dialogs/filedialogpanel.cpp | 5 +++ tests/manual/dialogs/filedialogpanel.h | 1 + 13 files changed, 126 insertions(+), 25 deletions(-) diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index ecc00ed8c6..f9a8a33354 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -217,13 +217,14 @@ public: enum FileDialogOption { - ShowDirsOnly = 0x00000001, - DontResolveSymlinks = 0x00000002, - DontConfirmOverwrite = 0x00000004, - DontUseSheet = 0x00000008, - DontUseNativeDialog = 0x00000010, - ReadOnly = 0x00000020, - HideNameFilterDetails = 0x00000040 + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(FileDialogOptions, FileDialogOption) diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 02b69bcb4d..098b8dad66 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -208,10 +208,12 @@ QPixmap QPlatformTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) co return QPixmap(); } -QPixmap QPlatformTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +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(); } diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 80ba29a028..f974f18908 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -253,6 +253,11 @@ public: AnimateToolBoxUiEffect = 0x40 }; + enum IconOption { + DontUseCustomDirectoryIcons = 0x01 + }; + Q_DECLARE_FLAGS(IconOptions, IconOption) + explicit QPlatformTheme(); virtual ~QPlatformTheme(); @@ -274,7 +279,8 @@ public: virtual QVariant themeHint(ThemeHint hint) const; virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; virtual QIconEngine *createIconEngine(const QString &iconName) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index cac059763d..e4237c9b3e 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -68,7 +68,9 @@ public: const QPalette *palette(Palette type = SystemPalette) const; const QFont *font(Font type = SystemFont) const; QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, + const QSizeF &size, + QPlatformTheme::IconOptions options = 0) const; QVariant themeHint(ThemeHint hint) const; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 36d7a49746..31bbd63e36 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -249,8 +249,10 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const return QPlatformTheme::standardPixmap(sp, size); } -QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { + Q_UNUSED(iconOptions); QCocoaAutoReleasePool pool; NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())]; diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 844e46eec5..2531dc681a 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -595,7 +595,8 @@ public: void operator delete (void *) {} }; -QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const +QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions) const { /* We don't use the variable, but by storing it statically, we * ensure CoInitialize is only called once. */ @@ -604,6 +605,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s static QCache > dirIconEntryCache(1000); static QMutex mx; + static int defaultFolderIIcon = 0; + const bool useDefaultFolderIcon = iconOptions & QPlatformTheme::DontUseCustomDirectoryIcons; QPixmap pixmap; const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); @@ -612,7 +615,8 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s bool cacheableDirIcon = fileInfo.isDir() && !fileInfo.isRoot(); if (cacheableDirIcon) { QMutexLocker locker(&mx); - int iIcon = **dirIconEntryCache.object(filePath); + int iIcon = (useDefaultFolderIcon && defaultFolderIIcon) ? defaultFolderIIcon + : **dirIconEntryCache.object(filePath); if (iIcon) { QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize), pixmap); if (pixmap.isNull()) // Let's keep both caches in sync @@ -629,13 +633,24 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s #else iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE - unsigned long val = SHGetFileInfo((const wchar_t *)filePath.utf16(), 0, - &info, sizeof(SHFILEINFO), flags); + unsigned long val = 0; + if (cacheableDirIcon && useDefaultFolderIcon) { + flags |= SHGFI_USEFILEATTRIBUTES; + val = SHGetFileInfo(L"dummy", + FILE_ATTRIBUTE_DIRECTORY, + &info, sizeof(SHFILEINFO), flags); + } else { + val = SHGetFileInfo(reinterpret_cast(filePath.utf16()), 0, + &info, sizeof(SHFILEINFO), flags); + } // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { QString key; if (cacheableDirIcon) { + if (useDefaultFolderIcon && !defaultFolderIIcon) + defaultFolderIIcon = info.iIcon; + //using the unique icon index provided by windows save us from duplicate keys key = dirIconPixmapCacheKey(info.iIcon, iconSize); QPixmapCache::find(key, pixmap); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index bbd7f4623f..9346621d59 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -68,7 +68,8 @@ public: { return m_fonts[type]; } virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size) const; + virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const; void windowsThemeChanged(QWindow *window); diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index e6b6c2b73f..657c8cc7c2 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -255,6 +255,11 @@ Q_WIDGETS_EXPORT _qt_filedialog_save_file_url_hook qt_filedialog_save_file_url_h static functions will always be an application modal dialog. If you want to use sheets, use QFileDialog::open() instead. + \value DontUseCustomDirectoryIcons Always use the default directory icon. + Some platforms allow the user to set a different icon. Custom icon lookup + cause a big performance impact over network or removable drives. + Setting this will enable the QFileIconProvider::DontUseCustomDirectoryIcons + option in the icon provider. This enum value was added in Qt 5.2. */ /*! @@ -754,6 +759,15 @@ void QFileDialog::setOptions(Options options) if (changed & ShowDirsOnly) setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files); + + if (changed & DontUseCustomDirectoryIcons) { + QFileIconProvider::Options providerOptions = iconProvider()->options(); + if (options & DontUseCustomDirectoryIcons) + providerOptions |= QFileIconProvider::DontUseCustomDirectoryIcons; + else + providerOptions &= ~QFileIconProvider::DontUseCustomDirectoryIcons; + iconProvider()->setOptions(providerOptions); + } } QFileDialog::Options QFileDialog::options() const diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h index 2b276be8f1..6b12a00ae6 100644 --- a/src/widgets/dialogs/qfiledialog.h +++ b/src/widgets/dialogs/qfiledialog.h @@ -84,13 +84,14 @@ public: enum Option { - ShowDirsOnly = 0x00000001, - DontResolveSymlinks = 0x00000002, - DontConfirmOverwrite = 0x00000004, - DontUseSheet = 0x00000008, - DontUseNativeDialog = 0x00000010, - ReadOnly = 0x00000020, - HideNameFilterDetails = 0x00000040 + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseSheet = 0x00000008, + DontUseNativeDialog = 0x00000010, + ReadOnly = 0x00000020, + HideNameFilterDetails = 0x00000040, + DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(Options, Option) diff --git a/src/widgets/itemviews/qfileiconprovider.cpp b/src/widgets/itemviews/qfileiconprovider.cpp index b435639390..f03d9fb81b 100644 --- a/src/widgets/itemviews/qfileiconprovider.cpp +++ b/src/widgets/itemviews/qfileiconprovider.cpp @@ -83,6 +83,16 @@ QT_BEGIN_NAMESPACE \value File */ + +/*! + \enum QFileIconProvider::Option + \since 5.2 + + \value DontUseCustomDirectoryIcons Always use the default directory icon. + Some platforms allow the user to set a different icon. Custom icon lookup + cause a big performance impact over network or removable drives. +*/ + class QFileIconProviderPrivate { Q_DECLARE_PUBLIC(QFileIconProvider) @@ -94,6 +104,7 @@ public: QFileIconProvider *q_ptr; const QString homePath; + QFileIconProvider::Options options; private: mutable QIcon file; @@ -192,6 +203,31 @@ QFileIconProvider::~QFileIconProvider() { } +/*! + \since 5.2 + Sets \a options that affect the icon provider. + \sa options() +*/ + +void QFileIconProvider::setOptions(QFileIconProvider::Options options) +{ + Q_D(QFileIconProvider); + d->options = options; +} + +/*! + \since 5.2 + Returns all the options that affect the icon provider. + By default, all options are disabled. + \sa setOptions() +*/ + +QFileIconProvider::Options QFileIconProvider::options() const +{ + Q_D(const QFileIconProvider); + return d->options; +} + /*! Returns an icon set for the given \a type. */ @@ -228,6 +264,7 @@ static bool isCacheable(const QFileInfo &fi) #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); @@ -247,7 +284,6 @@ QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const if (sizes.isEmpty()) return retIcon; - const QString fileExtension = fi.suffix().toUpper(); const QString keyBase = QLatin1String("qt_.") + fi.suffix().toUpper(); bool cacheable = isCacheable(fi); @@ -269,8 +305,12 @@ QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const } } + QPlatformTheme::IconOptions iconOptions; + if (options & QFileIconProvider::DontUseCustomDirectoryIcons) + iconOptions |= QPlatformTheme::DontUseCustomDirectoryIcons; + Q_FOREACH (int size, sizes) { - QPixmap pixmap = theme->fileIconPixmap(fi, QSizeF(size, size)); + QPixmap pixmap = theme->fileIconPixmap(fi, QSizeF(size, size), iconOptions); if (!pixmap.isNull()) { retIcon.addPixmap(pixmap); if (cacheable) diff --git a/src/widgets/itemviews/qfileiconprovider.h b/src/widgets/itemviews/qfileiconprovider.h index cac135fe71..ed270619ed 100644 --- a/src/widgets/itemviews/qfileiconprovider.h +++ b/src/widgets/itemviews/qfileiconprovider.h @@ -59,10 +59,19 @@ public: QFileIconProvider(); virtual ~QFileIconProvider(); enum IconType { Computer, Desktop, Trashcan, Network, Drive, Folder, File }; + + enum Option { + DontUseCustomDirectoryIcons = 0x00000001 + }; + Q_DECLARE_FLAGS(Options, Option) + virtual QIcon icon(IconType type) const; virtual QIcon icon(const QFileInfo &info) const; virtual QString type(const QFileInfo &info) const; + void setOptions(Options options); + Options options() const; + private: Q_DECLARE_PRIVATE(QFileIconProvider) QScopedPointer d_ptr; @@ -71,6 +80,8 @@ private: #endif // QT_NO_FILEICONPROVIDER +Q_DECLARE_OPERATORS_FOR_FLAGS(QFileIconProvider::Options) + QT_END_NAMESPACE #endif // QFILEICONPROVIDER_H diff --git a/tests/manual/dialogs/filedialogpanel.cpp b/tests/manual/dialogs/filedialogpanel.cpp index 69e25e753a..dbb2e379b2 100644 --- a/tests/manual/dialogs/filedialogpanel.cpp +++ b/tests/manual/dialogs/filedialogpanel.cpp @@ -154,6 +154,7 @@ FileDialogPanel::FileDialogPanel(QWidget *parent) , m_nameFilterDetailsVisible(new QCheckBox(tr("Name filter details visible"))) , m_resolveSymLinks(new QCheckBox(tr("Resolve symlinks"))) , m_native(new QCheckBox(tr("Use native dialog"))) + , m_customDirIcons(new QCheckBox(tr("Don't use custom directory icons"))) , m_acceptMode(createCombo(this, acceptModeComboData, sizeof(acceptModeComboData)/sizeof(ComboData))) , m_fileMode(createCombo(this, fileModeComboData, sizeof(fileModeComboData)/sizeof(ComboData))) , m_viewMode(createCombo(this, viewModeComboData, sizeof(viewModeComboData)/sizeof(ComboData))) @@ -178,6 +179,7 @@ FileDialogPanel::FileDialogPanel(QWidget *parent) optionsLayout->addRow(m_nameFilterDetailsVisible); optionsLayout->addRow(m_resolveSymLinks); optionsLayout->addRow(m_readOnly); + optionsLayout->addRow(m_customDirIcons); // Files QGroupBox *filesGroupBox = new QGroupBox(tr("Files / Filters")); @@ -322,6 +324,8 @@ QFileDialog::Options FileDialogPanel::options() const result |= QFileDialog::DontConfirmOverwrite; if (!m_native->isChecked()) result |= QFileDialog::DontUseNativeDialog; + if (!m_customDirIcons->isChecked()) + result |= QFileDialog::DontUseCustomDirectoryIcons; return result; } @@ -454,6 +458,7 @@ void FileDialogPanel::restoreDefaults() m_resolveSymLinks->setChecked(d.resolveSymlinks()); m_readOnly->setChecked(d.isReadOnly()); m_native->setChecked(true); + m_customDirIcons->setChecked(d.testOption(QFileDialog::DontUseCustomDirectoryIcons)); m_directory->setText(QDir::homePath()); m_defaultSuffix->setText(QLatin1String("txt")); m_nameFilters->setPlainText(QLatin1String("Any files (*)\nImage files (*.png *.xpm *.jpg)\nText files (*.txt)")); diff --git a/tests/manual/dialogs/filedialogpanel.h b/tests/manual/dialogs/filedialogpanel.h index 601fb7fc51..ce99836467 100644 --- a/tests/manual/dialogs/filedialogpanel.h +++ b/tests/manual/dialogs/filedialogpanel.h @@ -92,6 +92,7 @@ private: QCheckBox *m_nameFilterDetailsVisible; QCheckBox *m_resolveSymLinks; QCheckBox *m_native; + QCheckBox *m_customDirIcons; QComboBox *m_acceptMode; QComboBox *m_fileMode; QComboBox *m_viewMode; -- cgit v1.2.3