From 6771aafb9c20f9f173ee83ad74bb1860495bdfa7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Thu, 28 Jan 2010 15:47:45 +0100 Subject: [PATCH] FileIconProvider: Refactor class. Streamline code, avoid functions and container.end() invocations, introduce private, reduce #ifdefs, clarify code and add comments about usage on various platforms. Implement QFileIconProvider interface, making it usable for file system models. Use in FolderNavigationWidget. On this occasion, add checkable "Synchronize" action to FolderNavigationWidget. Task-number: QTCREATORBUG-62 --- src/plugins/coreplugin/fileiconprovider.cpp | 185 ++++++++++++------ src/plugins/coreplugin/fileiconprovider.h | 40 ++-- src/plugins/cppeditor/cppplugin.cpp | 4 +- .../foldernavigationwidget.cpp | 17 +- .../projectexplorer/foldernavigationwidget.h | 6 +- 5 files changed, 164 insertions(+), 88 deletions(-) diff --git a/src/plugins/coreplugin/fileiconprovider.cpp b/src/plugins/coreplugin/fileiconprovider.cpp index 5615fb81d9a..03bfb56cf4d 100644 --- a/src/plugins/coreplugin/fileiconprovider.cpp +++ b/src/plugins/coreplugin/fileiconprovider.cpp @@ -30,68 +30,138 @@ #include "fileiconprovider.h" #include "mimedatabase.h" +#include <utils/qtcassert.h> + #include <QtGui/QApplication> #include <QtGui/QStyle> #include <QtGui/QPainter> +#include <QtCore/QFileInfo> +#include <QtCore/QPair> +#include <QtCore/QDebug> -using namespace Core; +#include <QtGui/QFileIconProvider> +#include <QtGui/QIcon> +#include <QtGui/QStyle> /*! \class FileIconProvider - Provides icons based on file suffixes. + Provides icons based on file suffixes with the ability to overwrite system + icons for specific subtypes. Implements the QFileIconProvider interface + and can therefore be used for QFileSystemModel. + + Note: Registering overlay icons currently completely replaces the system + icon and is therefore not recommended on platforms that have their + own overlay icon handling (Mac/Windows). The class is a singleton: It's instance can be accessed via the static instance() method. Plugins can register custom icons via registerIconSuffix(), and retrieve icons via the icon() method. + The instance is explicitly deleted by the core plugin for destruction order reasons. */ -FileIconProvider *FileIconProvider::m_instance = 0; +// Cache icons in a list of pairs suffix/icon which should be faster than +// hashes for small lists. + +enum { debug = 0 }; + +typedef QPair<QString, QIcon> StringIconPair; +typedef QList<StringIconPair> StringIconPairList; + +// Helper to find an icon by suffix in a list of pairs for const/non-const-iterators. + +template <class StringIconPairListIterator> +inline StringIconPairListIterator +findBySuffix(const QString &suffix, + StringIconPairListIterator iter, + const StringIconPairListIterator &end) +{ + for (; iter != end; ++iter) + if ((*iter).first == suffix) + return iter; + return end; +} + +namespace Core { + +struct FileIconProviderPrivate { + FileIconProviderPrivate(); + + // Mapping of file suffix to icon. + StringIconPairList m_cache; -FileIconProvider::FileIconProvider() - : m_unknownFileIcon(qApp->style()->standardIcon(QStyle::SP_FileIcon)) + QFileIconProvider m_systemIconProvider; + QIcon m_unknownFileIcon; + + // singleton pattern + static FileIconProvider *m_instance; +}; + +FileIconProviderPrivate::FileIconProviderPrivate() : + m_unknownFileIcon(qApp->style()->standardIcon(QStyle::SP_FileIcon)) +{ +} + +FileIconProvider *FileIconProviderPrivate::m_instance = 0; + +// FileIconProvider + +FileIconProvider::FileIconProvider() : + d(new FileIconProviderPrivate) { + FileIconProviderPrivate::m_instance = this; } FileIconProvider::~FileIconProvider() { - m_instance = 0; + FileIconProviderPrivate::m_instance = 0; + delete d; } /*! Returns the icon associated with the file suffix in fileInfo. If there is none, the default icon of the operating system is returned. */ -QIcon FileIconProvider::icon(const QFileInfo &fileInfo) -{ - const QString suffix = fileInfo.suffix(); - QIcon icon = iconForSuffix(suffix); - - if (icon.isNull()) { - // Get icon from OS and store it in the cache - // Disabled since for now we'll make sure that all icons fit with our - // own custom icons by returning an empty one if we don't know it. +QIcon FileIconProvider::icon(const QFileInfo &fileInfo) const +{ + typedef StringIconPairList::const_iterator CacheConstIterator; + + if (debug) + qDebug() << "FileIconProvider::icon" << fileInfo.absoluteFilePath(); + // Check for cached overlay icons by file suffix. + if (!d->m_cache.isEmpty() && !fileInfo.isDir()) { + const QString suffix = fileInfo.suffix(); + if (!suffix.isEmpty()) { + const CacheConstIterator it = findBySuffix(suffix, d->m_cache.constBegin(), d->m_cache.constEnd()); + if (it != d->m_cache.constEnd()) + return (*it).second; + } + } + // Get icon from OS. #if defined(Q_WS_WIN) || defined(Q_WS_MAC) - // This is incorrect if the OS does not always return the same icon for the - // same suffix (Mac OS X), but should speed up the retrieval a lot ... - icon = m_systemIconProvider.icon(fileInfo); - if (!suffix.isEmpty()) - registerIconOverlayForSuffix(icon, suffix); + return d->m_systemIconProvider.icon(fileInfo); #else - if (fileInfo.isDir()) { - icon = m_systemIconProvider.icon(fileInfo); - } else { - icon = m_unknownFileIcon; - } + // File icons are unknown on linux systems. + return (fileInfo.isDir()) ? + d->m_systemIconProvider.icon(fileInfo) : + d->m_unknownFileIcon; #endif - } +} + +QIcon FileIconProvider::icon(IconType type) const +{ + return d->m_systemIconProvider.icon(type); +} - return icon; +QString FileIconProvider::type(const QFileInfo &info) const +{ + return d->m_systemIconProvider.type(info); } /*! Creates a pixmap with baseicon at size and overlays overlayIcon over it. + See platform note in class documentation about recommended usage. */ QPixmap FileIconProvider::overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlayIcon, const QSize &size) const { @@ -104,21 +174,26 @@ QPixmap FileIconProvider::overlayIcon(QStyle::StandardPixmap baseIcon, const QIc /*! Registers an icon for a given suffix, overlaying the system file icon. + See platform note in class documentation about recommended usage. */ -void FileIconProvider::registerIconOverlayForSuffix(const QIcon &icon, const QString &suffix) +void FileIconProvider::registerIconOverlayForSuffix(const QIcon &icon, + const QString &suffix) { - QPixmap fileIconPixmap = overlayIcon(QStyle::SP_FileIcon, icon, QSize(16, 16)); - // delete old icon, if it exists - QList<QPair<QString,QIcon> >::iterator iter = m_cache.begin(); - for (; iter != m_cache.end(); ++iter) { - if ((*iter).first == suffix) { - iter = m_cache.erase(iter); - break; - } - } + typedef StringIconPairList::iterator CacheIterator; - QPair<QString,QIcon> newEntry(suffix, fileIconPixmap); - m_cache.append(newEntry); + if (debug) + qDebug() << "FileIconProvider::registerIconOverlayForSuffix" << suffix; + + QTC_ASSERT(!icon.isNull() && !suffix.isEmpty(), return) + + const QPixmap fileIconPixmap = overlayIcon(QStyle::SP_FileIcon, icon, QSize(16, 16)); + // replace old icon, if it exists + const CacheIterator it = findBySuffix(suffix, d->m_cache.begin(), d->m_cache.end()); + if (it == d->m_cache.end()) { + d->m_cache.append(StringIconPair(suffix, fileIconPixmap)); + } else { + (*it).second = fileIconPixmap; + } } /*! @@ -130,35 +205,15 @@ void FileIconProvider::registerIconOverlayForMimeType(const QIcon &icon, const M registerIconOverlayForSuffix(icon, suffix); } -/*! - Returns an icon for the given suffix, or an empty one if none registered. - */ -QIcon FileIconProvider::iconForSuffix(const QString &suffix) const -{ - QIcon icon; -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) // On Windows and Mac we use the file system icons - Q_UNUSED(suffix) -#else - if (suffix.isEmpty()) - return icon; - - QList<QPair<QString,QIcon> >::const_iterator iter = m_cache.constBegin(); - for (; iter != m_cache.constEnd(); ++iter) { - if ((*iter).first == suffix) { - icon = (*iter).second; - break; - } - } -#endif - return icon; -} - /*! Returns the sole instance of FileIconProvider. */ + FileIconProvider *FileIconProvider::instance() { - if (!m_instance) - m_instance = new FileIconProvider; - return m_instance; + if (!FileIconProviderPrivate::m_instance) + FileIconProviderPrivate::m_instance = new FileIconProvider; + return FileIconProviderPrivate::m_instance; } + +} // namespace core diff --git a/src/plugins/coreplugin/fileiconprovider.h b/src/plugins/coreplugin/fileiconprovider.h index a4973399c1c..a86f895a8fc 100644 --- a/src/plugins/coreplugin/fileiconprovider.h +++ b/src/plugins/coreplugin/fileiconprovider.h @@ -32,22 +32,35 @@ #include <coreplugin/core_global.h> -#include <QtCore/QFileInfo> -#include <QtCore/QPair> -#include <QtGui/QFileIconProvider> -#include <QtGui/QIcon> #include <QtGui/QStyle> +#include <QtGui/QFileIconProvider> + +QT_BEGIN_NAMESPACE +class QFileInfo; +class QIcon; +class QPixmap; +class QString; +QT_END_NAMESPACE namespace Core { class MimeType; +struct FileIconProviderPrivate; -class CORE_EXPORT FileIconProvider +class CORE_EXPORT FileIconProvider : public QFileIconProvider { + Q_DISABLE_COPY(FileIconProvider) + FileIconProvider(); + public: - ~FileIconProvider(); // used to clear the cache - QIcon icon(const QFileInfo &fileInfo); + virtual ~FileIconProvider(); + // Implement QFileIconProvider + virtual QIcon icon(IconType type) const; + virtual QIcon icon(const QFileInfo &info) const; + virtual QString type(const QFileInfo &info) const; + + // Register additional overlay icons QPixmap overlayIcon(QStyle::StandardPixmap baseIcon, const QIcon &overlayIcon, const QSize &size) const; void registerIconOverlayForSuffix(const QIcon &icon, const QString &suffix); void registerIconOverlayForMimeType(const QIcon &icon, const MimeType &mimeType); @@ -55,18 +68,7 @@ public: static FileIconProvider *instance(); private: - QIcon iconForSuffix(const QString &suffix) const; - - // mapping of file ending to icon - // TODO: Check if this is really faster than a QHash - mutable QList<QPair<QString, QIcon> > m_cache; - - QFileIconProvider m_systemIconProvider; - QIcon m_unknownFileIcon; - - // singleton pattern - FileIconProvider(); - static FileIconProvider *m_instance; + FileIconProviderPrivate *d; }; } // namespace Core diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp index d3f5b2a3e49..ace3b776d86 100644 --- a/src/plugins/cppeditor/cppplugin.cpp +++ b/src/plugins/cppeditor/cppplugin.cpp @@ -75,7 +75,7 @@ CppEditorFactory::CppEditorFactory(CppPlugin *owner) : << QLatin1String(CppEditor::Constants::CPP_SOURCE_MIMETYPE) << QLatin1String(CppEditor::Constants::CPP_HEADER_MIMETYPE); -#ifndef Q_WS_MAC +#if !defined(Q_WS_MAC) && !defined(Q_WS_WIN) Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance(); Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase(); iconProvider->registerIconOverlayForMimeType(QIcon(":/cppeditor/images/qt_cpp.png"), @@ -89,7 +89,7 @@ CppEditorFactory::CppEditorFactory(CppPlugin *owner) : QString CppEditorFactory::id() const { - return QLatin1String(QLatin1String(CppEditor::Constants::CPPEDITOR_ID)); + return QLatin1String(CppEditor::Constants::CPPEDITOR_ID); } QString CppEditorFactory::displayName() const diff --git a/src/plugins/projectexplorer/foldernavigationwidget.cpp b/src/plugins/projectexplorer/foldernavigationwidget.cpp index eb30b850bba..0e6bed1c4f9 100644 --- a/src/plugins/projectexplorer/foldernavigationwidget.cpp +++ b/src/plugins/projectexplorer/foldernavigationwidget.cpp @@ -33,6 +33,7 @@ #include "environment.h" #include <coreplugin/icore.h> +#include <coreplugin/fileiconprovider.h> #include <coreplugin/filemanager.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/coreconstants.h> @@ -100,9 +101,11 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) m_fileSystemModel(new QFileSystemModel(this)), m_filterModel(new DotRemovalFilter(this)), m_title(new QLabel(this)), - m_autoSync(false) + m_autoSync(false), + m_autoSyncAction(0) { m_fileSystemModel->setResolveSymlinks(false); + m_fileSystemModel->setIconProvider(Core::FileIconProvider::instance()); QDir::Filters filters = QDir::AllDirs | QDir::Files | QDir::Drives | QDir::Readable| QDir::Writable | QDir::Executable | QDir::Hidden; @@ -158,6 +161,9 @@ void FolderNavigationWidget::setAutoSynchronization(bool sync) disconnect(fileManager, SIGNAL(currentFileChanged(QString)), this, SLOT(setCurrentFile(QString))); } + + if (m_autoSyncAction && m_autoSyncAction->isChecked() != m_autoSync) + m_autoSyncAction->setChecked(m_autoSync); } void FolderNavigationWidget::setCurrentFile(const QString &filePath) @@ -280,6 +286,15 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev) actionTerminal->setEnabled(hasCurrentItem); // Open file dialog to choose a path starting from current QAction *actionChooseFolder = menu.addAction(tr("Choose folder...")); + // Sync checkable action + if (!m_autoSyncAction) { + m_autoSyncAction = new QAction(tr("Synchronize"), this); + m_autoSyncAction->setCheckable(true); + m_autoSyncAction->setChecked(autoSynchronization()); + connect(m_autoSyncAction, SIGNAL(toggled(bool)), this, SLOT(setAutoSynchronization(bool))); + } + menu.addSeparator(); + menu.addAction(m_autoSyncAction); QAction *action = menu.exec(ev->globalPos()); if (!action) diff --git a/src/plugins/projectexplorer/foldernavigationwidget.h b/src/plugins/projectexplorer/foldernavigationwidget.h index cfb4f8870f2..f63524105df 100644 --- a/src/plugins/projectexplorer/foldernavigationwidget.h +++ b/src/plugins/projectexplorer/foldernavigationwidget.h @@ -41,6 +41,7 @@ class QSortFilterProxyModel; class QModelIndex; class QFileSystemModel; class QDir; +class QAction; QT_END_NAMESPACE namespace ProjectExplorer { @@ -54,11 +55,12 @@ namespace Internal { class FolderNavigationWidget : public QWidget { Q_OBJECT + Q_PROPERTY(bool autoSynchronization READ autoSynchronization WRITE setAutoSynchronization) public: FolderNavigationWidget(QWidget *parent = 0); bool autoSynchronization() const; - void setAutoSynchronization(bool sync); + // Helpers for common directory browser options. static void showInGraphicalShell(QWidget *parent, const QString &path); @@ -68,6 +70,7 @@ public: static QString msgTerminalAction(); public slots: + void setAutoSynchronization(bool sync); void toggleAutoSynchronization(); private slots: @@ -90,6 +93,7 @@ private: QSortFilterProxyModel *m_filterModel; QLabel *m_title; bool m_autoSync; + QAction *m_autoSyncAction; }; class FolderNavigationWidgetFactory : public Core::INavigationWidgetFactory -- GitLab