Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Icons in QFileSystemModel

Icons in QFileSystemModel

Scheduled Pinned Locked Moved Unsolved General and Desktop
9 Posts 4 Posters 1.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • krzysieklfcK Offline
    krzysieklfcK Offline
    krzysieklfc
    wrote on last edited by
    #1

    I want to create an application which will behave like the one in this gif in terms of handling the icons. It comes from SideFX's Houdini software. The main thing is to make it work with .exr and .hdr formats which are natively not supported on Windows without extensions like SageThumbs.

    I have little idea of how exactly QFileSystemModel works with the OS to pull these icons. I installed SageThumbs to have the icons appear in both Windows explorer and my application, but ideally I don't want the user to install any additional 3rd party extensions. Houdini loaded the icons despite them not appearing in Windows explorer.

    Does anyone have any idea of how this can be done?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      You have to derive from QFileSystemModel and overwrite data() for Qt::DecorationRole. There you can return the icon you want.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      krzysieklfcK 1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi,

        I think what you are looking for is to subclass QFileIconProvider.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        2
        • Christian EhrlicherC Christian Ehrlicher

          You have to derive from QFileSystemModel and overwrite data() for Qt::DecorationRole. There you can return the icon you want.

          krzysieklfcK Offline
          krzysieklfcK Offline
          krzysieklfc
          wrote on last edited by krzysieklfc
          #4

          @Christian-Ehrlicher I tried overriding the data function, but I would like to keep most of the default implementation since my changes for now are going to be subtle (e.g concatenating displayName(index) with some metadata).

          //HM_Model.h
          #pragma once
          
          #include <QtWidgets/qfilesystemmodel.h>
          #include <QtCore/qabstractitemmodel.h>
          #include <QtCore/qdatetime.h>
          #include <QtGui/qicon.h>
          #include <qstring.h>
          
          class Model : public QFileSystemModel
          {
          	Q_OBJECT
          
          public:
          
          	Model(QObject *parent = nullptr);
          	~Model();
          	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
          
          
          private:
          	Q_DECLARE_PRIVATE(QFileSystemModel)
          
          	QFileSystemModel* myModel;
          
          };
          
          
          //HM_Model.cpp
          
          #include "HM_Model.h"
          #include <qfilesystemmodel_p.h>
          
          Model::Model(QObject *parent)
          	: QFileSystemModel(parent)
          {
          }
          Model::~Model() {
          	delete myModel;
          }
          
          QVariant Model::data(const QModelIndex &index, int role) const
          {
          	Q_D(const QFileSystemModel);
          
          		if (!index.isValid() || index.model() != this)
          			return QVariant();
          
          		switch (role) {
          		case Qt::EditRole:
          		case Qt::DisplayRole:
          			switch (index.column()) {
          			case 0: return d->displayName(index);
          			case 1: return d->size(index);
          			case 2: return d->time(index);
          			default:
          				qWarning("data: invalid display value column %d", index.column());
          				break;
          			}
          			break;
          		case FilePathRole:
          			return filePath(index);
          		case FileNameRole:
          			return d->name(index);
          		case Qt::DecorationRole:
          			if (index.column() == 0) {
          				QIcon icon = d->icon(index);
          #if QT_CONFIG(filesystemwatcher)
          				if (icon.isNull()) {
          					if (d->node(index)->isDir())
          						icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
          					else
          						icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
          				}
          #endif // filesystemwatcher
          				return icon;
          			}
          			break;
          		case Qt::TextAlignmentRole:
          			if (index.column() == 1)
          				return QVariant(Qt::AlignRight | Qt::AlignVCenter);
          			else
          				return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
          			break;
          		case FilePermissions:
          			int p = permissions(index);
          			return p;
          		}
          
          		return QVariant();
          }
          

          I'm getting following errors:

          error LNK2019: unresolved external symbol "public: class QFileIconProvider * __cdecl QFileInfoGatherer::iconProvider(void)const "
          error LNK2019: unresolved external symbol "public: class QFileSystemModelPrivate::QFileSystemNode * __cdecl QFileSystemModelPrivate::node(class QModelIndex const &)const "
          error LNK2019: unresolved external symbol "public: class QIcon __cdecl QFileSystemModelPrivate::icon(class QModelIndex const &)const "
          error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::name(class QModelIndex const &)const "
          error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::displayName(class QModelIndex const &)const "
          error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::size(class QModelIndex const &)const "
          error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::time(class QModelIndex const &)const "
          
          JonBJ 1 Reply Last reply
          0
          • krzysieklfcK krzysieklfc

            @Christian-Ehrlicher I tried overriding the data function, but I would like to keep most of the default implementation since my changes for now are going to be subtle (e.g concatenating displayName(index) with some metadata).

            //HM_Model.h
            #pragma once
            
            #include <QtWidgets/qfilesystemmodel.h>
            #include <QtCore/qabstractitemmodel.h>
            #include <QtCore/qdatetime.h>
            #include <QtGui/qicon.h>
            #include <qstring.h>
            
            class Model : public QFileSystemModel
            {
            	Q_OBJECT
            
            public:
            
            	Model(QObject *parent = nullptr);
            	~Model();
            	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
            
            
            private:
            	Q_DECLARE_PRIVATE(QFileSystemModel)
            
            	QFileSystemModel* myModel;
            
            };
            
            
            //HM_Model.cpp
            
            #include "HM_Model.h"
            #include <qfilesystemmodel_p.h>
            
            Model::Model(QObject *parent)
            	: QFileSystemModel(parent)
            {
            }
            Model::~Model() {
            	delete myModel;
            }
            
            QVariant Model::data(const QModelIndex &index, int role) const
            {
            	Q_D(const QFileSystemModel);
            
            		if (!index.isValid() || index.model() != this)
            			return QVariant();
            
            		switch (role) {
            		case Qt::EditRole:
            		case Qt::DisplayRole:
            			switch (index.column()) {
            			case 0: return d->displayName(index);
            			case 1: return d->size(index);
            			case 2: return d->time(index);
            			default:
            				qWarning("data: invalid display value column %d", index.column());
            				break;
            			}
            			break;
            		case FilePathRole:
            			return filePath(index);
            		case FileNameRole:
            			return d->name(index);
            		case Qt::DecorationRole:
            			if (index.column() == 0) {
            				QIcon icon = d->icon(index);
            #if QT_CONFIG(filesystemwatcher)
            				if (icon.isNull()) {
            					if (d->node(index)->isDir())
            						icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
            					else
            						icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
            				}
            #endif // filesystemwatcher
            				return icon;
            			}
            			break;
            		case Qt::TextAlignmentRole:
            			if (index.column() == 1)
            				return QVariant(Qt::AlignRight | Qt::AlignVCenter);
            			else
            				return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
            			break;
            		case FilePermissions:
            			int p = permissions(index);
            			return p;
            		}
            
            		return QVariant();
            }
            

            I'm getting following errors:

            error LNK2019: unresolved external symbol "public: class QFileIconProvider * __cdecl QFileInfoGatherer::iconProvider(void)const "
            error LNK2019: unresolved external symbol "public: class QFileSystemModelPrivate::QFileSystemNode * __cdecl QFileSystemModelPrivate::node(class QModelIndex const &)const "
            error LNK2019: unresolved external symbol "public: class QIcon __cdecl QFileSystemModelPrivate::icon(class QModelIndex const &)const "
            error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::name(class QModelIndex const &)const "
            error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::displayName(class QModelIndex const &)const "
            error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::size(class QModelIndex const &)const "
            error LNK2019: unresolved external symbol "public: class QString __cdecl QFileSystemModelPrivate::time(class QModelIndex const &)const "
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #5

            @krzysieklfc
            I don't claim to understand the ins & outs of Q_DECLARE_PRIVATE, but are all of these unresolveds virtual functions? Because that's what https://stackoverflow.com/questions/27189472/virtual-functions-causing-link-errors reported. It didn't seem to get answered though --- other than make sure you do a fully clean rebuild? You might want to read https://stackoverflow.com/questions/25250171/how-to-use-the-qts-pimpl-idiom to see if it helps you --- makes by brain ache!

            Just a couple of thoughts while you await an expert!

            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @krzysieklfc said in Icons in QFileSystemModel:

              Q_DECLARE_PRIVATE(QFileSystemModel)

              I don't see any reason for this at all...

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              JonBJ 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                @krzysieklfc said in Icons in QFileSystemModel:

                Q_DECLARE_PRIVATE(QFileSystemModel)

                I don't see any reason for this at all...

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @Christian-Ehrlicher
                Nor did I, but isn't OP using that as his way of accessing private stuff out of QFileSystemModel... I thought that was what he was saying... ?

                1 Reply Last reply
                0
                • Christian EhrlicherC Offline
                  Christian EhrlicherC Offline
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @JonB: But it's not needed - he wants to change the icon which can be done in data()...

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  1 Reply Last reply
                  1
                  • krzysieklfcK Offline
                    krzysieklfcK Offline
                    krzysieklfc
                    wrote on last edited by krzysieklfc
                    #9

                    I followed the solution described here, but I'm having a weird problem. QTableView doesn't consistentely update the selection when an item is selected, but it does when the mouse cursor leaves the widget area. I haven't had this problem when I used just QFileSystemInfo with no proxy.
                    Initially I thought it's a threading issue, but I get it on a single threaded version too.

                    0_1557782374412_problem.gif

                    //HM.Model.h
                    class ModelProxy : public QIdentityProxyModel {
                    
                    public:
                    	QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
                    	ModelProxy(QObject *parent = nullptr);
                    	virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
                    	virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
                    	virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
                    	 QModelIndex setRootPath(const QString& path);
                    
                    
                    private:
                    	Q_OBJECT
                    	QMap<QString, QIcon> m_icons;
                    	Q_SIGNAL void hasIcon(const QString&, const QIcon&, const QPersistentModelIndex& index) const;
                    	void onIcon(const QString& path, const QIcon& icon, const QPersistentModelIndex& index);
                    	QFileSystemModel* fs() const { return qobject_cast<QFileSystemModel*>(sourceModel()); }
                    
                    signals:
                    	void rootPathChanged(const QString &path);
                    
                    };
                    
                    //HM.Model.cpp
                    void ModelProxy::onIcon(const QString& path, const QIcon& icon, const QPersistentModelIndex& index)
                    {
                    	m_icons.insert(path, icon);
                    	emit dataChanged(index, index, QVector<int>{QFileSystemModel::FileIconRole});
                    }
                    
                    ModelProxy::ModelProxy(QObject* parent) : QIdentityProxyModel{ parent } {
                    
                    	setSourceModel(new QFileSystemModel(this));
                    	fs()->setRootPath(QDir::rootPath());
                    	fs()->setReadOnly(true);
                    	fs()->setFilter(QDir::NoDotAndDotDot | QDir::Files);
                    	QStringList filters;
                    	filters << "*.exr" << "*.hdr";
                    	fs()->setNameFilters(filters);
                    	fs()->setNameFilterDisables(false);
                    
                    	connect(this, &ModelProxy::hasIcon, this, &ModelProxy::onIcon);
                    	connect(fs(), &QFileSystemModel::rootPathChanged,
                    		this, &ModelProxy::rootPathChanged);
                    
                    }
                    
                    QVariant ModelProxy::data(const QModelIndex & index, int role) const {
                    	switch (role) {
                    		case QFileSystemModel::FileIconRole:
                    		{
                    			if (index.column() == 0) {
                    				auto path = index.data(QFileSystemModel::FilePathRole).toString();
                    				auto it = m_icons.find(path);
                    				if (it != m_icons.end())
                    				{
                    					if (!it->isNull()) return *it;
                    					return QIdentityProxyModel::data(index, role);
                    				}
                    				QPersistentModelIndex pIndex{ index };
                    				emit hasIcon(path, getIcon(path), pIndex);
                    
                    				return QIdentityProxyModel::data(index, role);
                    			}
                    		}
                    		case Qt::DisplayRole:
                    		{
                    			if (index.column() == 0) {
                    				auto path = index.data(QFileSystemModel::FilePathRole).toString();
                    				//QFile file(path);
                    				//return index.data(QFileSystemModel::FileNameRole).toString() +
                    				//	"\n4608x2304\t16 bit float RGB";
                    				return QIdentityProxyModel::data(index, role);
                    			}
                    			return QIdentityProxyModel::data(index, role);
                    		}
                    		case Qt::FontRole:
                    		{
                    			return QFont("Roboto", 8);
                    		}
                    
                    		case Qt::TextAlignmentRole:
                    		{
                    			return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
                    		}
                    	}
                    	return QIdentityProxyModel::data(index, role);
                    }
                    
                    QModelIndex ModelProxy::index(int row, int column, const QModelIndex&) const {
                    	QModelIndex proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
                    	return QIdentityProxyModel::index(row, column, proxyRootIndex);
                    }
                    
                    int ModelProxy::columnCount(const QModelIndex&) const {
                    	QModelIndex proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
                    	return QIdentityProxyModel::columnCount(proxyRootIndex);
                    }
                    
                    int ModelProxy::rowCount(const QModelIndex&) const {
                    	QModelIndex proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
                    	return QIdentityProxyModel::rowCount(proxyRootIndex);
                    }
                    
                    QModelIndex ModelProxy::setRootPath(const QString& path)
                    {
                    	return fs()->setRootPath(path);
                    }
                    
                    

                    EDIT:
                    The problem was that I set QTableView to a wrong index. The following works:

                    QModelIndex getRootIndex() { return mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath())); };
                    
                    ui.TableView->setRootIndex(model->getRootIndex());
                    
                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved