Commit 6771aafb authored by Friedemann Kleint's avatar Friedemann Kleint

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
parent 0fdf02ab
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment