diff --git a/src/plugins/coreplugin/fileiconprovider.cpp b/src/plugins/coreplugin/fileiconprovider.cpp index 5615fb81d9a746cb911c470a76db31888cb7e57d..03bfb56cf4da0c834e90cc8292f0add7e2b8ae98 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 a4973399c1c9819b3d3ea94e702c0f9a31c897f7..a86f895a8fcce6a48bd129ca84f28d9899cdd86f 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 d3f5b2a3e494c679c72312087e37dee032d2e4cc..ace3b776d868ca5003aba93af8d64c189d564bd9 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 eb30b850bbaf1d35073ec4fb655bd17154340ee5..0e6bed1c4f9634a6884c6377ae469ad4bbeb46b4 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 cfb4f8870f26ea1ece80f3329331b6deb2e27039..f63524105df82e0155464bc984930847961e07f4 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