Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Add column to proxied Model



  • I have subclassed a QIdentityProxyModel which proxies QFileSystemModel and which I use in a QTableView. Now, I want to append the 4th column at the end.

    I followed the sugestions described here:

    1. I incremented the return value of columnCount() - this results in a blank, glitched column.
    2. I implemented index() with the following:
    QModelIndex ModelProxy::index(int row, int column, const QModelIndex& parent) const {
    	if (column == 4) 
    		return createIndex(row, column);
    
            auto proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
    	return QIdentityProxyModel::index(row, column, proxyRootIndex);
    }
    

    But this gives me access violation error when I'm creating these indexes.

    I realize there are already some threads addressing the same issue, but they did not help me so I would appreciate if anyone could point out what I'm missing.

    Here's my code:

    class ModelProxy : public QIdentityProxyModel
    {
    public:
    
    	ModelProxy(QObject* parent = nullptr);
    	QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
    
    	virtual QVariant headerData(int section, Qt::Orientation orientation = Qt::Horizontal, int role = Qt::DisplayRole) 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) { return fs()->setRootPath(path); };
    	QString getRootPath() { return fs()->rootPath(); };
    	QModelIndex getRootIndex() { return mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath())); };
    
    	virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
    
    private:
    	Q_OBJECT
    
    	QFileSystemModel* fs() const { return qobject_cast<QFileSystemModel*>(sourceModel()); }
    
    	QMultiMap<QString, QVariant> m_icon, m_width, m_height, m_type, m_channels, m_size;
    
    signals:
    	void rootPathChanged(const QString&);
    };
    
    
    ModelProxy::ModelProxy(QObject* parent)
    	: QIdentityProxyModel(parent)
    {
    	setSourceModel(new QFileSystemModel(this));
    	fs()->setReadOnly(true);
    	fs()->setFilter(QDir::NoDotAndDotDot | QDir::Files);
    	auto filters = QStringList{ "*.exr", "*.EXR", "*.hdr", "*.HDR" };
    	fs()->setNameFilters(filters);
    	fs()->setNameFilterDisables(false);
    
    
    	connect(fs(), &QFileSystemModel::rootPathChanged,
    		this, &ModelProxy::rootPathChanged);
    }
    
    QModelIndex ModelProxy::index(int row, int column, const QModelIndex& parent) const {
    	auto proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
    
    	if (column == 4) {
    		return createIndex(row, column);
    	}
    	return QIdentityProxyModel::index(row, column, proxyRootIndex);
    }
    
    int ModelProxy::columnCount(const QModelIndex&) const {
    	QModelIndex proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
    	return QIdentityProxyModel::columnCount(proxyRootIndex) + 1;
    }
    
    int ModelProxy::rowCount(const QModelIndex&) const {
    	QModelIndex proxyRootIndex = mapFromSource(fs()->QFileSystemModel::index(fs()->rootPath()));
    	return QIdentityProxyModel::rowCount(proxyRootIndex);
    }
    
    QVariant ModelProxy::headerData(int index, Qt::Orientation orient, int role) const {
    	return QIdentityProxyModel::headerData(index, orient, role);
    }
    
    QVariant ModelProxy::data(const QModelIndex& index, int role) const
    {
    	qDebug() << "data " << index.row() << index.column();
    
    	switch (role) {
    	case QFileSystemModel::FileIconRole:
    	{
    		if (index.column() == 0) {
    			auto const path = QString{ index.data(QFileSystemModel::FilePathRole).toString() };
    
    			if (QFile::exists(path) && path.toLower().endsWith(".exr") || path.toLower().endsWith(".hdr")) {
    				if (m_icon.contains(path))
    					return m_icon.value(path);
    				else {
    					QPersistentModelIndex pIndex = index;
    					emit hasIcon(path, QIdentityProxyModel::data(index, role).value<QIcon>(), pIndex);
    
    					QThreadPool::globalInstance()->setMaxThreadCount(1);
    					QtConcurrent::run([this, path, pIndex, role] {
    						emit hasIcon(path, QIcon{ ":/resources/img/arrow_icon.png" }, pIndex);
    						emit hasIcon(path, loadHDRtoIcon(path, pIndex), pIndex);
    					});
    				}
    			}
    			else
    				return QIdentityProxyModel::data(index, role);
    		}
    	}
    
    	case Qt::DisplayRole:
    	{
    		auto const path = QString{ index.data(QFileSystemModel::FilePathRole).toString() };
    
    		switch (index.column()) {
    		case 1:
    		{
    			if (m_type.contains(path))
    				return m_type.value(path);
    			else return QVariant{};
    		}
    		case 2:
    		{
    			if (m_channels.contains(path))
    				return m_channels.value(path);
    			else return QVariant{};
    		}
    		case 3:
    		{
    			if (m_width.contains(path) && m_height.contains(path))
    				return m_width.value(path).toString() + "x" + m_height.value(path).toString();
    			else return QVariant{};
    		}
    		case 4:
    		{
    			if (m_size.contains(path))
    				return m_size.value(path);
    			return QString{ "test" };
    		}
    		default: return QIdentityProxyModel::data(index, role);
    		}
    	}
    	}
    	return QIdentityProxyModel::data(index, role);
    }

  • Lifetime Qt Champion

    @krzysieklfc said in Add column to proxied Model:

    But this gives me access violation error when I'm creating these indexes.

    Please provide a backtrace for this. I would guess it's an assertion rather than a crash.
    And your rowCount() doesn't look correct - since it's a tree it's important to pass the correct parent instead simply using the rootPath. The same goes for columnCount



  • @christian-ehrlicher Hello,

    The exception occurs at the last line of ModelProxy::data(), in return QIdentityProxyModel::data(index, role);
    when data() is called for the 0th row and 4th column.

    Exception thrown at 0x00007FFE0B373D4A (Qt5Widgets.dll) in 3dsmax.exe: 0xC0000005: Access violation reading location 0x0000000000000030.

    I reimplemented columnCount() and rowCount() to use parent, but the result is the same. I'm not sure if this is correct though.

    int ModelProxy::columnCount(const QModelIndex& parent) const {
    	auto sp = mapToSource(parent);
    	if (sp.isValid() && sp.model())
    		return (sp.model()->columnCount(sp) + 1);
    	return 0;
    }
    
    int ModelProxy::rowCount(const QModelIndex& parent) const {
    	auto sp = mapToSource(parent);
    	if (sp.isValid() && sp.model())
    		return sp.model()->rowCount(sp);
    	return 0;
    }
    

  • Lifetime Qt Champion

    Please provide a backtrace for the exception. For me it looks like your're working on an invalid instance of the class.


Log in to reply