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. QSortFilterProxyModel has an internal index failure that does not map to the source correctly

QSortFilterProxyModel has an internal index failure that does not map to the source correctly

Scheduled Pinned Locked Moved Solved General and Desktop
17 Posts 3 Posters 8.7k Views 2 Watching
  • 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.
  • fcarneyF Offline
    fcarneyF Offline
    fcarney
    wrote on last edited by
    #1

    QSortFilterProxyModel seems to be failing to retrieve its own internal data when mapping to a source model QFileSystemModel in my case. I have been able to condense it down to as small as I can get. I have not had issues with QSortFilterProxyModel up to this point, so I have to assume I am doing something wrong.

    This is the function where I notice the internal structure in QSortFilterProxyModel seems to be pointing to garbage:

    QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
    {
        if (!proxy_index.isValid())
            return QModelIndex(); // for now; we may want to be able to set a root index later
        if (proxy_index.model() != q_func()) {
            qWarning("QSortFilterProxyModel: index from wrong model passed to mapToSource");
            Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
            return QModelIndex();
        }
        IndexMap::const_iterator it = index_to_iterator(proxy_index);
        Mapping *m = it.value();
        if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
            return QModelIndex();
        int source_row = m->source_rows.at(proxy_index.row());
        int source_col = m->source_columns.at(proxy_index.column());
        return model->index(source_row, source_col, it.key());
    }
    

    The "m" variable seems to be looking wrong at this point when it crashes on me.

    Here is code which reproduces:
    tableproxymodel.h:

    #include <QAbstractProxyModel>
    #include <QSortFilterProxyModel>
    #include <QAbstractItemModel>
    #include <QModelIndex>
    #include <QFileSystemModel>
    
    #include <QDebug>
    
    #ifndef TABLEPROXYMODEL_H
    #define TABLEPROXYMODEL_H
    
    class SortFilterProxyModel : public QSortFilterProxyModel
    {
        Q_OBJECT
    
    public:
        SortFilterProxyModel(QObject* parent)
            : QSortFilterProxyModel(parent)
        {
    
        }
    };
    
    class FileSystemModel : public QFileSystemModel
    {
        Q_OBJECT
    
        Q_PROPERTY(QString rootPath READ getPathRoot WRITE setPathRoot NOTIFY rootPathChanged)
        Q_PROPERTY(QModelIndex rootIndex READ rootIndex NOTIFY rootIndexChanged)
        Q_PROPERTY(QAbstractItemModel* proxy READ proxy)
    public:
        FileSystemModel(QObject* parent=nullptr)
            : QFileSystemModel(parent)
            , m_proxy(nullptr)
        {
            setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
    
            m_proxy = new SortFilterProxyModel(this);
            m_proxy->setSourceModel(this);
        }
        QString getPathRoot() const
        {
            return rootPath();
        }
        QModelIndex rootIndex() const
        {
            //return index(rootPath());
            return m_proxy->mapFromSource(index(rootPath()));
        }
    
        QAbstractItemModel* proxy(){
            return m_proxy;
        }
    
    public slots:
        void setPathRoot(QString rootPath)
        {
            if (m_rootPath == rootPath)
                return;
    
            beginResetModel();
            m_rootPath = rootPath;
            setRootPath(rootPath);
            endResetModel();
    
            emit rootPathChanged(m_rootPath);
            emit rootIndexChanged(rootIndex());
        }
    
    signals:
        void rootPathChanged(QString rootPath);
        void rootIndexChanged(QModelIndex rootIndex);
    
    protected:
        QString m_rootPath;
        QModelIndex m_rootIndex;
    
        SortFilterProxyModel* m_proxy;
    };
    
    class FileSystemTableProxyModel : public QAbstractProxyModel
    {
        Q_OBJECT
    
        Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
        Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
    public:
        FileSystemTableProxyModel(QObject* parent=nullptr)
            : QAbstractProxyModel(parent)
        {
        }
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
        {
            if(index.model() != this || !index.isValid())
                return QVariant();
    
            //auto sourcemodel = qobject_cast<QFileSystemModel*>(sourceModel());
            auto sourcemodel = sourceModel();
            if(!sourcemodel)
                return QVariant();
    
            auto sourceindex = mapToSource(index);
            if(!sourceindex.isValid())
                return QVariant();
    
            if(role == Qt::DisplayRole){
                switch(index.column()){
                    case 0:
                        return sourcemodel->data(sourceindex, QFileSystemModel::FileNameRole);
                    case 1:
                        return sourcemodel->data(sourceindex, QFileSystemModel::FilePathRole);
                    case 2:
                        return QString().setNum(sourcemodel->data(sourceindex, QFileSystemModel::FilePermissions).toInt(), 16);
                    case 3:
                        return "dummy";
                    default:
                        return QVariant();
                }
            }
    
            return sourcemodel->data(sourceindex, role);
        }
        QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
        {
            Q_UNUSED(parent)
    
            if(row < 0 || row >= rowCount())
                return QModelIndex();
            if(column < 0 || column >= columnCount())
                return QModelIndex();
    
            return createIndex(row, column);
        }
        QModelIndex parent(const QModelIndex &index) const override
        {
            Q_UNUSED(index)
    
            return QModelIndex();
        }
        int rowCount(const QModelIndex &parent = QModelIndex()) const override
        {
            Q_UNUSED(parent)
    
            return sourceModel()->rowCount(m_rootIndex);
        }
        int columnCount(const QModelIndex &parent = QModelIndex()) const override
        {
            Q_UNUSED(parent)
    
            return 4;
        }
    
        QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
        {
            if(sourceIndex.model() != sourceModel() || !sourceIndex.isValid())
                return QModelIndex();
    
            auto proxyindex = index(sourceIndex.row(), sourceIndex.column());
            if(!proxyindex.isValid())
                return QModelIndex();
    
            return proxyindex;
        }
        QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
        {
            if(proxyIndex.model() != this || !proxyIndex.isValid())
                return QModelIndex();
    
            //if(proxyIndex == QModelIndex())
            //    return m_rootIndex;
    
            //if(!proxyIndex.isValid())
            //    return QModelIndex();
    
            auto sourceindex = sourceModel()->index(proxyIndex.row(), proxyIndex.column(), m_rootIndex);
            if(!sourceindex.isValid())
                return QModelIndex();
    
            return sourceindex;
        }
    
        QModelIndex rootIndex() const
        {
            return m_rootIndex;
        }
    
        QAbstractItemModel* sourceModel() const
        {
            return QAbstractProxyModel::sourceModel();
        }
    
    public slots:
        void setRootIndex(const QModelIndex& rootindex)
        {
            if (m_rootIndex == rootindex)
                return;
    
            if(sourceModel() != rootindex.model())
                return;
    
            beginResetModel();
            m_rootIndex = rootindex;
            endResetModel();
    
            emit rootIndexChanged();
        }
    
        void setSourceModel(QAbstractItemModel* model) override
        {
            if (QAbstractProxyModel::sourceModel() == model)
                return;
    
            beginResetModel();
    
            auto oldmodel = sourceModel();
            if(oldmodel){
                disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &FileSystemTableProxyModel::on_columnsAboutToBeInserted);
                disconnect(oldmodel, &QAbstractItemModel::columnsInserted, this, &FileSystemTableProxyModel::on_columnsInserted);
                disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeMoved);
                disconnect(oldmodel, &QAbstractItemModel::columnsMoved, this, &FileSystemTableProxyModel::on_columnsMoved);
                disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeRemoved);
                disconnect(oldmodel, &QAbstractItemModel::columnsRemoved, this, &FileSystemTableProxyModel::on_columnsRemoved);
    
                disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &FileSystemTableProxyModel::on_rowsAboutToBeInserted);
                disconnect(oldmodel, &QAbstractItemModel::rowsInserted, this, &FileSystemTableProxyModel::on_rowsInserted);
                disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeMoved);
                disconnect(oldmodel, &QAbstractItemModel::rowsMoved, this, &FileSystemTableProxyModel::on_rowsMoved);
                disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeRemoved);
                disconnect(oldmodel, &QAbstractItemModel::rowsRemoved, this, &FileSystemTableProxyModel::on_rowsRemoved);
    
                disconnect(oldmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &FileSystemTableProxyModel::on_layoutAboutToBeChanged);
                disconnect(oldmodel, &QAbstractItemModel::layoutChanged, this, &FileSystemTableProxyModel::on_layoutChanged);
    
                disconnect(oldmodel, &QAbstractItemModel::modelAboutToBeReset, this, &FileSystemTableProxyModel::on_modelAboutToBeReset);
                disconnect(oldmodel, &QAbstractItemModel::modelReset, this, &FileSystemTableProxyModel::on_modelReset);
    
                disconnect(oldmodel, &QAbstractItemModel::dataChanged, this, &FileSystemTableProxyModel::on_dataChanged);
                disconnect(oldmodel, &QAbstractItemModel::headerDataChanged, this, &FileSystemTableProxyModel::on_headerDataChanged);
            }
    
            QAbstractProxyModel::setSourceModel(model);
            auto newmodel = sourceModel();
            if(newmodel){
                connect(newmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &FileSystemTableProxyModel::on_columnsAboutToBeInserted);
                connect(newmodel, &QAbstractItemModel::columnsInserted, this, &FileSystemTableProxyModel::on_columnsInserted);
                connect(newmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeMoved);
                connect(newmodel, &QAbstractItemModel::columnsMoved, this, &FileSystemTableProxyModel::on_columnsMoved);
                connect(newmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeRemoved);
                connect(newmodel, &QAbstractItemModel::columnsRemoved, this, &FileSystemTableProxyModel::on_columnsRemoved);
    
                connect(newmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &FileSystemTableProxyModel::on_rowsAboutToBeInserted);
                connect(newmodel, &QAbstractItemModel::rowsInserted, this, &FileSystemTableProxyModel::on_rowsInserted);
                connect(newmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeMoved);
                connect(newmodel, &QAbstractItemModel::rowsMoved, this, &FileSystemTableProxyModel::on_rowsMoved);
                connect(newmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeRemoved);
                connect(newmodel, &QAbstractItemModel::rowsRemoved, this, &FileSystemTableProxyModel::on_rowsRemoved);
    
                connect(newmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &FileSystemTableProxyModel::on_layoutAboutToBeChanged);
                connect(newmodel, &QAbstractItemModel::layoutChanged, this, &FileSystemTableProxyModel::on_layoutChanged);
    
                connect(newmodel, &QAbstractItemModel::modelAboutToBeReset, this, &FileSystemTableProxyModel::on_modelAboutToBeReset);
                connect(newmodel, &QAbstractItemModel::modelReset, this, &FileSystemTableProxyModel::on_modelReset);
    
                connect(newmodel, &QAbstractItemModel::dataChanged, this, &FileSystemTableProxyModel::on_dataChanged);
                connect(newmodel, &QAbstractItemModel::headerDataChanged, this, &FileSystemTableProxyModel::on_headerDataChanged);
            }
    
            endResetModel();
    
            auto tindex = QModelIndex();
            setRootIndex(tindex);
    
            emit sourceModelChanged();
        }
    
    private slots:
        // slots from hell
        void on_columnsAboutToBeInserted(const QModelIndex &parent, int first, int last){
            beginInsertColumns(mapToSource(parent), first, last);
        }
        void on_columnsInserted(const QModelIndex &parent, int first, int last){
            endInsertColumns();
        }
        void on_columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn){
            beginMoveColumns(mapToSource(sourceParent), sourceStart, sourceEnd, mapToSource(destinationParent), destinationColumn);
        }
        void on_columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column){
            endMoveColumns();
        }
        void on_columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last){
            beginRemoveColumns(mapToSource(parent), first, last);
        }
        void on_columnsRemoved(const QModelIndex &parent, int first, int last){
            endRemoveColumns();
        }
    
        void on_rowsAboutToBeInserted(const QModelIndex &parent, int first, int last){
            beginInsertRows(mapFromSource(parent), first, last);
        }
        void on_rowsInserted(const QModelIndex &parent, int first, int last){
            endInsertRows();
        }
        void on_rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow){
            beginMoveRows(mapFromSource(sourceParent), sourceStart, sourceEnd, mapFromSource(destinationParent), destinationRow);
        }
        void on_rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row){
            endMoveRows();
        }
        void on_rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last){
            beginRemoveRows(mapFromSource(parent), first, last);
        }
        void on_rowsRemoved(const QModelIndex &parent, int first, int last){
            endRemoveRows();
        }
    
        void on_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint){
            QList<QPersistentModelIndex> proxyparents;
            for(auto parent: parents){
                proxyparents.append(mapFromSource(parent));
            }
            emit layoutAboutToBeChanged(proxyparents, hint);
        }
        void on_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint){
            QList<QPersistentModelIndex> proxyparents;
            for(auto parent: parents){
                proxyparents.append(mapFromSource(parent));
            }
            emit layoutChanged(proxyparents, hint);
        }
        void on_modelAboutToBeReset(){
            beginResetModel();
        }
        void on_modelReset(){
            endResetModel();
        }
    
        void on_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles){
            emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
        }
        void on_headerDataChanged(Qt::Orientation orientation, int first, int last){
            emit headerDataChanged(orientation, first, last);
        }
    
    
    signals:
        void rootIndexChanged();
        void sourceModelChanged();
    
    private:
        QModelIndex m_rootIndex;
    };
    
    #endif // TABLEPROXYMODEL_H
    

    main.cpp:

    #include <QGuiApplication>
    #include <QApplication>
    #include <QQmlApplicationEngine>
    
    #include <tableproxymodel.h>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        //QGuiApplication app(argc, argv);
        QApplication app(argc, argv);
    
        qmlRegisterType<FileSystemModel>("Models",1,0,"FileSystemModel");
        qmlRegisterType<FileSystemTableProxyModel>("Models",1,0,"FileSystemTableProxyModel");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    

    qml:

    import QtQuick 2.12
    import QtQuick.Window 2.12
    
    import Models 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Proxy Model Testing")
    
        FileSystemModel {
            id: filesystemmodel
            rootPath: "/"
        }
    
        FileSystemTableProxyModel {
            id: tableproxymodel
    
            model: filesystemmodel.proxy
            rootIndex: filesystemmodel.rootIndex
        }
    
        TableView {
            anchors.fill: parent
    
            model: tableproxymodel
    
            delegate: Item {
                implicitWidth: 100
                implicitHeight: 25
                Rectangle {
                    anchors.fill: parent
    
                    color: "blue"
                }
    
                Text {
                    text: display
                }
    
                Component.onCompleted: {
                    console.log("tableproxymodel:delegate")
                }
            }
    
            Component.onCompleted: {
                console.log(model.rowCount())
            }
        }
    }
    

    I will point out, that I originally developed this code having FileSystemTableProxyModel talk directly to FileSystemModel and it never had issues. Once I noticed I was having proxy issues in other code I injected the proxy into FileSystemModel to see if it crashes at the same place. It does. So I have to assume there is either a usage problem on my end with QSortFilterProxyModel, or there is an issue with that way it handles its own internal objects. I could sort of find issues the Qt Debug reports, and I did find one that sounded similar, but it was having different errors for different usage reasons.

    OS: Fails under both Windows and Linux (mingw, g++)
    Qt: 5.12.5 and 5.12.8
    64 bit

    C++ is a perfectly valid school of magic.

    1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by
      #2

      Here is the pro file too:

      QT += quick widgets
      
      CONFIG += c++11
      
      # The following define makes your compiler emit warnings if you use
      # any Qt feature that has been marked deprecated (the exact warnings
      # depend on your compiler). Refer to the documentation for the
      # deprecated API to know how to port your code away from it.
      DEFINES += QT_DEPRECATED_WARNINGS
      
      # You can also make your code fail to compile if it uses deprecated APIs.
      # In order to do so, uncomment the following line.
      # You can also select to disable deprecated APIs only up to a certain version of Qt.
      #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
      
      SOURCES += \
              main.cpp \
              tableproxymodel.cpp
      
      RESOURCES += qml.qrc
      
      # Additional import path used to resolve QML modules in Qt Creator's code model
      QML_IMPORT_PATH =
      
      # Additional import path used to resolve QML modules just for Qt Quick Designer
      QML_DESIGNER_IMPORT_PATH =
      
      # Default rules for deployment.
      qnx: target.path = /tmp/$${TARGET}/bin
      else: unix:!android: target.path = /opt/$${TARGET}/bin
      !isEmpty(target.path): INSTALLS += target
      
      HEADERS += \
          tableproxymodel.h
      

      C++ is a perfectly valid school of magic.

      1 Reply Last reply
      0
      • fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on last edited by
        #3

        Also, it only ever seems to crash when calling rowCount on the root index.

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        0
        • fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by
          #4

          I modified the code to take the proxy out if noproxy is set to true on the FileSystemModel:

          import QtQuick 2.12
          import QtQuick.Window 2.12
          
          import Models 1.0
          
          Window {
              visible: true
              width: 640
              height: 480
              title: qsTr("Proxy Model Testing")
          
              FileSystemModel {
                  id: filesystemmodel
                  rootPath: "/"
                  noproxy: true
              }
          
              FileSystemTableProxyModel {
                  id: tableproxymodel
          
                  model: filesystemmodel.proxy
                  rootIndex: filesystemmodel.rootIndex
              }
          
              TableView {
                  anchors.fill: parent
          
                  model: tableproxymodel
          
                  delegate: Item {
                      implicitWidth: 100
                      implicitHeight: 25
                      Rectangle {
                          anchors.fill: parent
          
                          color: "blue"
                      }
          
                      Text {
                          text: display
                      }
                  }
              }
          }
          

          Also, it seems like it has issues starting or showing anything when the proxy is enabled. Very odd.

          C++ is a perfectly valid school of magic.

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by fcarney
            #5

            I think (hope) I found some relevant bug reports.
            https://bugreports.qt.io/browse/QTBUG-44611
            https://bugreports.qt.io/browse/QTBUG-47711

            It looks like I "might" be able to sidestep this by using the QIdentityProxyModel. No idea if this is a good idea. I will be testing this.

            Edit:
            Well it doesn't crash. But it won't filter either: "Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model."

            C++ is a perfectly valid school of magic.

            fcarneyF 1 Reply Last reply
            0
            • fcarneyF fcarney

              I think (hope) I found some relevant bug reports.
              https://bugreports.qt.io/browse/QTBUG-44611
              https://bugreports.qt.io/browse/QTBUG-47711

              It looks like I "might" be able to sidestep this by using the QIdentityProxyModel. No idea if this is a good idea. I will be testing this.

              Edit:
              Well it doesn't crash. But it won't filter either: "Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model."

              fcarneyF Offline
              fcarneyF Offline
              fcarney
              wrote on last edited by
              #6

              And this might be relevant too:
              https://bugreports.qt.io/browse/QTBUG-14336
              This indicates it happens when data changes. Which is what happens on a QFileSystemModel. It returns 0 rows at first and then gets updated after data is loaded in another thread.

              C++ is a perfectly valid school of magic.

              1 Reply Last reply
              0
              • kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by
                #7

                Why derive the file system model? Also please provide a trace of the crash, for one my just-in-head debugging isn't that advanced.

                Read and abide by the Qt Code of Conduct

                fcarneyF 2 Replies Last reply
                1
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by VRonin
                  #8
                  1. FileSystemTableProxyModel looks like a QIdentityProxyModel with custom columnCount() and data() methods. There is no need to inherit from QAbstractProxyModel and implement the other dangerous stuff
                  2. FileSystemModel is nesting beginResetModel(); (setRootPath(rootPath); will call beginResetModel(); internally)
                  3. When you have problems with models (i.e. always if you are like me) the absolute first thing to do is run the custom models through the model test. I can't even count the times it detected a mistake I did in my implementations

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  fcarneyF 1 Reply Last reply
                  2
                  • kshegunovK kshegunov

                    Why derive the file system model? Also please provide a trace of the crash, for one my just-in-head debugging isn't that advanced.

                    fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #9

                    @kshegunov said in QSortFilterProxyModel has an internal index failure that does not map to the source correctly:

                    Why derive the file system model?

                    I have a much more complex version of qfilesystemmodel that provides images for qml. This one is a placeholder for testing and I add properties to use in QML.

                    C++ is a perfectly valid school of magic.

                    1 Reply Last reply
                    0
                    • VRoninV VRonin
                      1. FileSystemTableProxyModel looks like a QIdentityProxyModel with custom columnCount() and data() methods. There is no need to inherit from QAbstractProxyModel and implement the other dangerous stuff
                      2. FileSystemModel is nesting beginResetModel(); (setRootPath(rootPath); will call beginResetModel(); internally)
                      3. When you have problems with models (i.e. always if you are like me) the absolute first thing to do is run the custom models through the model test. I can't even count the times it detected a mistake I did in my implementations
                      fcarneyF Offline
                      fcarneyF Offline
                      fcarney
                      wrote on last edited by
                      #10

                      @VRonin said in QSortFilterProxyModel has an internal index failure that does not map to the source correctly:

                      FileSystemTableProxyModel looks like a QIdentityProxyModel with custom columnCount() and data() methods. There is no need to inherit from QAbstractProxyModel and implement the other dangerous stuff
                      FileSystemModel is nesting beginResetModel(); (setRootPath(rootPath); will call beginResetModel(); internally)
                      When you have problems with models (i.e. always if you are like me) the absolute first thing to do is run the custom models through the model test. I can't even count the times it detected a mistace I did in my implementations

                      When I read the docs on the indentity model I was under the impression you should not reinterpret the data as columns. That seemed like it was a transformation of the data. Maybe I don't know what they are referring to when talking about transforming data.

                      Yeah, I forgot about the model test. Thanks.

                      C++ is a perfectly valid school of magic.

                      1 Reply Last reply
                      0
                      • kshegunovK kshegunov

                        Why derive the file system model? Also please provide a trace of the crash, for one my just-in-head debugging isn't that advanced.

                        fcarneyF Offline
                        fcarneyF Offline
                        fcarney
                        wrote on last edited by
                        #11

                        @kshegunov said in QSortFilterProxyModel has an internal index failure that does not map to the source correctly:

                        provide a trace of the crash

                        1   QSortFilterProxyModelPrivate::proxy_to_source                                                                                                                                          qsortfilterproxymodel.cpp     553  0x7ffff6742f54 
                        2   QSortFilterProxyModel::mapToSource                                                                                                                                                     qsortfilterproxymodel.cpp     3061 0x7ffff6746316 
                        3   QSortFilterProxyModel::rowCount                                                                                                                                                        qsortfilterproxymodel.cpp     2184 0x7ffff6746316 
                        4   FileSystemTableProxyModel::rowCount                                                                                                                                                    tableproxymodel.h             191  0x55555555da16 
                        5   FileSystemTableProxyModel::index                                                                                                                                                       tableproxymodel.h             159  0x55555555d7f6 
                        6   FileSystemTableProxyModel::mapFromSource                                                                                                                                               tableproxymodel.h             205  0x55555555db0a 
                        7   FileSystemTableProxyModel::on_rowsAboutToBeInserted                                                                                                                                    tableproxymodel.h             345  0x55555555f097 
                        8   QtPrivate::FunctorCall<QtPrivate::IndexesList<0, 1, 2>, QtPrivate::List<QModelIndex const&, int, int>, void, void (FileSystemTableProxyModel:: *)(QModelIndex const&, int, int)>::call qobjectdefs_impl.h            152  0x555555564189 
                        9   QtPrivate::FunctionPointer<void (FileSystemTableProxyModel:: *)(QModelIndex const&, int, int)>::call<QtPrivate::List<QModelIndex const&, int, int>, void>                              qobjectdefs_impl.h            185  0x5555555638fe 
                        10  QtPrivate::QSlotObject<void (FileSystemTableProxyModel:: *)(QModelIndex const&, int, int), QtPrivate::List<QModelIndex const&, int, int>, void>::impl                                  qobjectdefs_impl.h            414  0x5555555627f5 
                        11  QtPrivate::QSlotObjectBase::call                                                                                                                                                       qobjectdefs_impl.h            394  0x7ffff679cdf6 
                        12  QMetaObject::activate                                                                                                                                                                  qobject.cpp                   3783 0x7ffff679cdf6 
                        13  QMetaObject::activate                                                                                                                                                                  qobject.cpp                   3656 0x7ffff679d3d7 
                        14  QAbstractItemModel::rowsAboutToBeInserted                                                                                                                                              moc_qabstractitemmodel.cpp    584  0x7ffff672015e 
                        15  QAbstractItemModel::beginInsertRows                                                                                                                                                    qabstractitemmodel.cpp        2735 0x7ffff67278f3 
                        16  QSortFilterProxyModelPrivate::insert_source_items                                                                                                                                      qsortfilterproxymodel.cpp     890  0x7ffff674788a 
                        17  QSortFilterProxyModelPrivate::source_items_inserted                                                                                                                                    qsortfilterproxymodel.cpp     1013 0x7ffff674ce3b 
                        18  QSortFilterProxyModelPrivate::_q_sourceRowsInserted                                                                                                                                    qsortfilterproxymodel.cpp     1644 0x7ffff674ce3b 
                        19  QSortFilterProxyModel::qt_static_metacall                                                                                                                                              moc_qsortfilterproxymodel.cpp 231  0x7ffff674dd49 
                        20  QMetaObject::activate                                                                                                                                                                  qobject.cpp                   3803 0x7ffff679cac9 
                        ... <More>                                                                                                                                                                                                                                   
                        

                        The m object in seems to have bad data in it:

                        QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
                        {
                            if (!proxy_index.isValid())
                                return QModelIndex(); // for now; we may want to be able to set a root index later
                            if (proxy_index.model() != q_func()) {
                                qWarning("QSortFilterProxyModel: index from wrong model passed to mapToSource");
                                Q_ASSERT(!"QSortFilterProxyModel: index from wrong model passed to mapToSource");
                                return QModelIndex();
                            }
                            IndexMap::const_iterator it = index_to_iterator(proxy_index);
                            Mapping *m = it.value();
                            if ((proxy_index.row() >= m->source_rows.size()) || (proxy_index.column() >= m->source_columns.size()))
                                return QModelIndex();
                            int source_row = m->source_rows.at(proxy_index.row());
                            int source_col = m->source_columns.at(proxy_index.column());
                            return model->index(source_row, source_col, it.key());
                        }
                        

                        The object itself:

                        	Locals		
                        		it		QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping*>::const_iterator
                        		m	@0x555555ca57d0	QSortFilterProxyModelPrivate::Mapping
                        			map_iter	@0x555555ca57f8	QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping*>::const_iterator
                        			mapped_children	<21845 items>	QVector<QModelIndex>
                        			proxy_columns	<32767 items>	QVector<int>
                        			proxy_rows	<not accessible>	QVector<int>
                        			source_columns	<not accessible>	QVector<int>
                        			source_rows	<21845 items>	QVector<int>
                        		proxy_index	@0x555555cac620	QModelIndex &
                        		source_col	<optimized out>	
                        		source_row	<optimized out>	
                        		this	@0x555555b1dfc0	QSortFilterProxyModelPrivate
                        	Inspector		
                        	Expressions		
                        		item	<no such value>	 
                        	Return Value		
                        	Tooltip		
                        		QModelIndex	<no such value>	 
                        
                        

                        Note the mapped children and proxy columns. This tells me the object pointed to by m is no longer a valid object.

                        C++ is a perfectly valid school of magic.

                        1 Reply Last reply
                        0
                        • fcarneyF Offline
                          fcarneyF Offline
                          fcarney
                          wrote on last edited by
                          #12

                          This is getting even more interesting. I created a version of the proxy model using the QIdentityProxyModel. It doesn't really work right, because I didnt redefine mapToSource and mapFromSource, but it does still crash when, and only when, I put a proxy model between QFileSystemModel and itself.

                          tablemodelproxy.h:

                          #include <QAbstractProxyModel>
                          #include <QSortFilterProxyModel>
                          #include <QIdentityProxyModel>
                          #include <QAbstractItemModel>
                          #include <QModelIndex>
                          #include <QFileSystemModel>
                          
                          #include <QDebug>
                          #include <QAbstractItemModelTester>
                          
                          #ifndef TABLEPROXYMODEL_H
                          #define TABLEPROXYMODEL_H
                          
                          class SortFilterProxyModel :
                                  public QSortFilterProxyModel
                                  //public QIdentityProxyModel
                          {
                              Q_OBJECT
                          
                          public:
                              SortFilterProxyModel(QObject* parent)
                                  : QSortFilterProxyModel(parent)
                                  //: QIdentityProxyModel(parent)
                              {
                          
                              }
                          };
                          
                          class FileSystemModel : public QFileSystemModel
                          {
                              Q_OBJECT
                          
                              Q_PROPERTY(QString rootPath READ getPathRoot WRITE setPathRoot NOTIFY rootPathChanged)
                              Q_PROPERTY(QModelIndex rootIndex READ rootIndex NOTIFY rootIndexChanged)
                              Q_PROPERTY(bool noproxy READ noproxy WRITE setnoproxy NOTIFY noproxyChanged)
                              Q_PROPERTY(QAbstractItemModel* proxy READ proxy)
                          public:
                              FileSystemModel(QObject* parent=nullptr)
                                  : QFileSystemModel(parent)
                                  , m_proxy(nullptr)
                                  , m_noproxy(false)
                              {
                                  setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
                          
                                  m_proxy = new SortFilterProxyModel(this);
                                  m_proxy->setSourceModel(this);
                          
                                  //new QAbstractItemModelTester(m_proxy, QAbstractItemModelTester::FailureReportingMode::Warning, this);
                              }
                              QString getPathRoot() const
                              {
                                  return rootPath();
                              }
                              QModelIndex rootIndex() const
                              {
                                  if(m_noproxy)
                                      return index(rootPath());
                                  else
                                      return m_proxy->mapFromSource(index(rootPath()));
                              }
                          
                              QAbstractItemModel* proxy(){
                                  if(m_noproxy)
                                      return this;
                                  else
                                      return m_proxy;
                              }
                          
                              bool noproxy() const
                              {
                                  return m_noproxy;
                              }
                          
                          public slots:
                              void setPathRoot(QString rootPath)
                              {
                                  if (m_rootPath == rootPath)
                                      return;
                          
                                  beginResetModel();
                                  m_rootPath = rootPath;
                                  setRootPath(rootPath);
                                  endResetModel();
                          
                                  emit rootPathChanged(m_rootPath);
                                  emit rootIndexChanged(rootIndex());
                              }
                          
                              void setnoproxy(bool noproxy)
                              {
                                  if (m_noproxy == noproxy)
                                      return;
                          
                                  m_noproxy = noproxy;
                                  emit noproxyChanged(m_noproxy);
                              }
                          
                          signals:
                              void rootPathChanged(QString rootPath);
                              void rootIndexChanged(QModelIndex rootIndex);
                          
                              void noproxyChanged(bool noproxy);
                          
                          protected:
                              QString m_rootPath;
                              QModelIndex m_rootIndex;
                          
                              SortFilterProxyModel* m_proxy;
                              bool m_noproxy;
                          };
                          
                          class FileSystemTableProxyModel : public QAbstractProxyModel
                          {
                              Q_OBJECT
                          
                              Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
                              Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
                          public:
                              FileSystemTableProxyModel(QObject* parent=nullptr)
                                  : QAbstractProxyModel(parent)
                              {
                              }
                          
                              QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
                              {
                                  if(index.model() != this || !index.isValid())
                                      return QVariant();
                          
                                  //auto sourcemodel = qobject_cast<QFileSystemModel*>(sourceModel());
                                  auto sourcemodel = sourceModel();
                                  if(!sourcemodel)
                                      return QVariant();
                          
                                  auto sourceindex = mapToSource(index);
                                  if(!sourceindex.isValid())
                                      return QVariant();
                          
                                  if(role == Qt::DisplayRole){
                                      switch(index.column()){
                                          case 0:
                                              return sourcemodel->data(sourceindex, QFileSystemModel::FileNameRole);
                                          case 1:
                                              return sourcemodel->data(sourceindex, QFileSystemModel::FilePathRole);
                                          case 2:
                                              return QString().setNum(sourcemodel->data(sourceindex, QFileSystemModel::FilePermissions).toInt(), 16);
                                          case 3:
                                              return "dummy";
                                          default:
                                              return QVariant();
                                      }
                                  }
                          
                                  return sourcemodel->data(sourceindex, role);
                              }
                              QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
                              {
                                  Q_UNUSED(parent)
                          
                                  if(row < 0 || row >= rowCount())
                                      return QModelIndex();
                                  if(column < 0 || column >= columnCount())
                                      return QModelIndex();
                          
                                  return createIndex(row, column);
                              }
                              QModelIndex parent(const QModelIndex &index) const override
                              {
                                  Q_UNUSED(index)
                          
                                  return QModelIndex();
                              }
                              bool hasChildren(const QModelIndex &parent = QModelIndex()) const override
                              {
                                  if(parent == QModelIndex()){
                                      return rowCount();
                                  }
                          
                                  return false;
                              }
                              int rowCount(const QModelIndex &parent = QModelIndex()) const override
                              {
                                  Q_UNUSED(parent)
                          
                                  if(parent != QModelIndex())
                                      return 0;
                          
                                  auto sourcemodel = sourceModel();
                                  if(!sourcemodel || !m_rootIndex.isValid())
                                      return 0;
                          
                                  return sourceModel()->rowCount(m_rootIndex);
                              }
                              int columnCount(const QModelIndex &parent = QModelIndex()) const override
                              {
                                  Q_UNUSED(parent)
                          
                                  return 4;
                              }
                          
                              QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
                              {
                                  if(sourceIndex.model() != sourceModel() || !sourceIndex.isValid())
                                      return QModelIndex();
                          
                                  auto proxyindex = index(sourceIndex.row(), sourceIndex.column());
                                  if(!proxyindex.isValid())
                                      return QModelIndex();
                          
                                  return proxyindex;
                              }
                              QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
                              {
                                  if(proxyIndex.model() != this || !proxyIndex.isValid())
                                      return QModelIndex();
                          
                                  //if(proxyIndex == QModelIndex())
                                  //    return m_rootIndex;
                          
                                  //if(!proxyIndex.isValid())
                                  //    return QModelIndex();
                          
                                  auto sourceindex = sourceModel()->index(proxyIndex.row(), proxyIndex.column(), m_rootIndex);
                                  if(!sourceindex.isValid())
                                      return QModelIndex();
                          
                                  return sourceindex;
                              }
                          
                              QModelIndex rootIndex() const
                              {
                                  return m_rootIndex;
                              }
                          
                              QAbstractItemModel* sourceModel() const
                              {
                                  return QAbstractProxyModel::sourceModel();
                              }
                          
                          public slots:
                              void setRootIndex(const QModelIndex& rootindex)
                              {
                                  if (m_rootIndex == rootindex)
                                      return;
                          
                                  if(sourceModel() != rootindex.model())
                                      return;
                          
                                  beginResetModel();
                                  m_rootIndex = rootindex;
                                  endResetModel();
                          
                                  emit rootIndexChanged();
                              }
                          
                              void setSourceModel(QAbstractItemModel* model) override
                              {
                                  if (QAbstractProxyModel::sourceModel() == model)
                                      return;
                          
                                  beginResetModel();
                          
                                  auto oldmodel = sourceModel();
                                  if(oldmodel){
                                      disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &FileSystemTableProxyModel::on_columnsAboutToBeInserted);
                                      disconnect(oldmodel, &QAbstractItemModel::columnsInserted, this, &FileSystemTableProxyModel::on_columnsInserted);
                                      disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeMoved);
                                      disconnect(oldmodel, &QAbstractItemModel::columnsMoved, this, &FileSystemTableProxyModel::on_columnsMoved);
                                      disconnect(oldmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeRemoved);
                                      disconnect(oldmodel, &QAbstractItemModel::columnsRemoved, this, &FileSystemTableProxyModel::on_columnsRemoved);
                          
                                      disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &FileSystemTableProxyModel::on_rowsAboutToBeInserted);
                                      disconnect(oldmodel, &QAbstractItemModel::rowsInserted, this, &FileSystemTableProxyModel::on_rowsInserted);
                                      disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeMoved);
                                      disconnect(oldmodel, &QAbstractItemModel::rowsMoved, this, &FileSystemTableProxyModel::on_rowsMoved);
                                      disconnect(oldmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeRemoved);
                                      disconnect(oldmodel, &QAbstractItemModel::rowsRemoved, this, &FileSystemTableProxyModel::on_rowsRemoved);
                          
                                      disconnect(oldmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &FileSystemTableProxyModel::on_layoutAboutToBeChanged);
                                      disconnect(oldmodel, &QAbstractItemModel::layoutChanged, this, &FileSystemTableProxyModel::on_layoutChanged);
                          
                                      disconnect(oldmodel, &QAbstractItemModel::modelAboutToBeReset, this, &FileSystemTableProxyModel::on_modelAboutToBeReset);
                                      disconnect(oldmodel, &QAbstractItemModel::modelReset, this, &FileSystemTableProxyModel::on_modelReset);
                          
                                      disconnect(oldmodel, &QAbstractItemModel::dataChanged, this, &FileSystemTableProxyModel::on_dataChanged);
                                      disconnect(oldmodel, &QAbstractItemModel::headerDataChanged, this, &FileSystemTableProxyModel::on_headerDataChanged);
                                  }
                          
                                  QAbstractProxyModel::setSourceModel(model);
                                  auto newmodel = sourceModel();
                                  if(newmodel){
                                      connect(newmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &FileSystemTableProxyModel::on_columnsAboutToBeInserted);
                                      connect(newmodel, &QAbstractItemModel::columnsInserted, this, &FileSystemTableProxyModel::on_columnsInserted);
                                      connect(newmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeMoved);
                                      connect(newmodel, &QAbstractItemModel::columnsMoved, this, &FileSystemTableProxyModel::on_columnsMoved);
                                      connect(newmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_columnsAboutToBeRemoved);
                                      connect(newmodel, &QAbstractItemModel::columnsRemoved, this, &FileSystemTableProxyModel::on_columnsRemoved);
                          
                                      connect(newmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &FileSystemTableProxyModel::on_rowsAboutToBeInserted);
                                      connect(newmodel, &QAbstractItemModel::rowsInserted, this, &FileSystemTableProxyModel::on_rowsInserted);
                                      connect(newmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeMoved);
                                      connect(newmodel, &QAbstractItemModel::rowsMoved, this, &FileSystemTableProxyModel::on_rowsMoved);
                                      connect(newmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &FileSystemTableProxyModel::on_rowsAboutToBeRemoved);
                                      connect(newmodel, &QAbstractItemModel::rowsRemoved, this, &FileSystemTableProxyModel::on_rowsRemoved);
                          
                                      connect(newmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &FileSystemTableProxyModel::on_layoutAboutToBeChanged);
                                      connect(newmodel, &QAbstractItemModel::layoutChanged, this, &FileSystemTableProxyModel::on_layoutChanged);
                          
                                      connect(newmodel, &QAbstractItemModel::modelAboutToBeReset, this, &FileSystemTableProxyModel::on_modelAboutToBeReset);
                                      connect(newmodel, &QAbstractItemModel::modelReset, this, &FileSystemTableProxyModel::on_modelReset);
                          
                                      connect(newmodel, &QAbstractItemModel::dataChanged, this, &FileSystemTableProxyModel::on_dataChanged);
                                      connect(newmodel, &QAbstractItemModel::headerDataChanged, this, &FileSystemTableProxyModel::on_headerDataChanged);
                                  }
                          
                                  endResetModel();
                          
                                  auto tindex = QModelIndex();
                                  setRootIndex(tindex);
                          
                                  emit sourceModelChanged();
                              }
                          
                          private slots:
                              // slots from hell
                              void on_columnsAboutToBeInserted(const QModelIndex &parent, int first, int last){
                                  beginInsertColumns(mapToSource(parent), first, last);
                              }
                              void on_columnsInserted(const QModelIndex &parent, int first, int last){
                                  endInsertColumns();
                              }
                              void on_columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn){
                                  beginMoveColumns(mapToSource(sourceParent), sourceStart, sourceEnd, mapToSource(destinationParent), destinationColumn);
                              }
                              void on_columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column){
                                  endMoveColumns();
                              }
                              void on_columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last){
                                  beginRemoveColumns(mapToSource(parent), first, last);
                              }
                              void on_columnsRemoved(const QModelIndex &parent, int first, int last){
                                  endRemoveColumns();
                              }
                          
                              void on_rowsAboutToBeInserted(const QModelIndex &parent, int first, int last){
                                  beginInsertRows(mapFromSource(parent), first, last);
                              }
                              void on_rowsInserted(const QModelIndex &parent, int first, int last){
                                  endInsertRows();
                              }
                              void on_rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow){
                                  beginMoveRows(mapFromSource(sourceParent), sourceStart, sourceEnd, mapFromSource(destinationParent), destinationRow);
                              }
                              void on_rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row){
                                  endMoveRows();
                              }
                              void on_rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last){
                                  beginRemoveRows(mapFromSource(parent), first, last);
                              }
                              void on_rowsRemoved(const QModelIndex &parent, int first, int last){
                                  endRemoveRows();
                              }
                          
                              void on_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint){
                                  QList<QPersistentModelIndex> proxyparents;
                                  for(auto parent: parents){
                                      proxyparents.append(mapFromSource(parent));
                                  }
                                  emit layoutAboutToBeChanged(proxyparents, hint);
                              }
                              void on_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint){
                                  QList<QPersistentModelIndex> proxyparents;
                                  for(auto parent: parents){
                                      proxyparents.append(mapFromSource(parent));
                                  }
                                  emit layoutChanged(proxyparents, hint);
                              }
                              void on_modelAboutToBeReset(){
                                  beginResetModel();
                              }
                              void on_modelReset(){
                                  endResetModel();
                              }
                          
                              void on_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles){
                                  emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
                              }
                              void on_headerDataChanged(Qt::Orientation orientation, int first, int last){
                                  emit headerDataChanged(orientation, first, last);
                              }
                          
                          
                          signals:
                              void rootIndexChanged();
                              void sourceModelChanged();
                          
                          private:
                              QModelIndex m_rootIndex;
                          };
                          
                          class FileSystemTableIdentityModel : public QIdentityProxyModel
                          {
                              Q_OBJECT
                          
                              Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
                              Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
                          public:
                              FileSystemTableIdentityModel(QObject* parent=nullptr)
                                  : QIdentityProxyModel(parent)
                              {
                              }
                          
                              QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
                              {
                                  if(index.model() != this || !index.isValid())
                                      return QVariant();
                          
                                  //auto sourcemodel = qobject_cast<QFileSystemModel*>(sourceModel());
                                  auto sourcemodel = sourceModel();
                                  if(!sourcemodel)
                                      return QVariant();
                          
                                  auto sourceindex = mapToSource(index);
                                  if(!sourceindex.isValid())
                                      return QVariant();
                          
                                  if(role == Qt::DisplayRole){
                                      switch(index.column()){
                                          case 0:
                                              return sourcemodel->data(sourceindex, QFileSystemModel::FileNameRole);
                                          case 1:
                                              return sourcemodel->data(sourceindex, QFileSystemModel::FilePathRole);
                                          case 2:
                                              return QString().setNum(sourcemodel->data(sourceindex, QFileSystemModel::FilePermissions).toInt(), 16);
                                          case 3:
                                              return "dummy";
                                          default:
                                              return QVariant();
                                      }
                                  }
                          
                                  return sourcemodel->data(sourceindex, role);
                              }
                          
                              int rowCount(const QModelIndex &parent = QModelIndex()) const override
                              {
                                  Q_UNUSED(parent)
                          
                                  if(parent != QModelIndex())
                                      return 0;
                          
                                  auto sourcemodel = sourceModel();
                                  //if(!sourcemodel || !m_rootIndex.isValid())
                                  //    return 0;
                          
                                  return sourceModel()->rowCount(m_rootIndex);
                                  //return sourceModel()->rowCount(mapToSource(parent));
                              }
                              int columnCount(const QModelIndex &parent = QModelIndex()) const override
                              {
                                  Q_UNUSED(parent)
                          
                                  return 4;
                              }
                          
                              void setSourceModel(QAbstractItemModel* model) override
                              {
                                  if (QAbstractProxyModel::sourceModel() == model)
                                      return;
                          
                                  beginResetModel();
                                  QIdentityProxyModel::setSourceModel(model);
                                  m_rootIndex = QModelIndex();
                                  endResetModel();
                              }
                          
                              QAbstractItemModel* sourceModel() const
                              {
                                  return QIdentityProxyModel::sourceModel();
                              }
                              QModelIndex rootIndex() const
                              {
                                  return m_rootIndex;
                              }
                          
                          public slots:
                              void setRootIndex(QModelIndex rootIndex)
                              {
                                  if (m_rootIndex == rootIndex)
                                      return;
                          
                                  beginResetModel();
                                  m_rootIndex = rootIndex;
                                  endResetModel();
                          
                                  emit rootIndexChanged(m_rootIndex);
                              }
                          
                          signals:
                              void sourceModelChanged(QAbstractItemModel* model);
                              void rootIndexChanged(QModelIndex rootIndex);
                          
                          private:
                              QModelIndex m_rootIndex;
                          };
                          
                          class ModelTester : public QObject
                          {
                              Q_OBJECT
                          
                              Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged)
                          public:
                              ModelTester(QObject* parent=nullptr)
                                  : QObject(parent)
                                  , m_model(nullptr)
                                  , m_tester(nullptr)
                              {
                                  //new QAbstractItemModelTester(m_proxy, QAbstractItemModelTester::FailureReportingMode::Warning, this);
                              }
                              QAbstractItemModel* model() const
                              {
                                  return m_model;
                              }
                          public slots:
                              void setModel(QAbstractItemModel* model)
                              {
                                  if (m_model == model)
                                      return;
                          
                                  if(m_tester){
                                      qInfo() << "Done testing:" << m_model;
                                      m_tester->deleteLater();
                                  }
                          
                                  m_model = model;
                                  if(m_model){
                                      qInfo() << "Beging testing:" << m_model;
                                      m_tester = new QAbstractItemModelTester(m_model, QAbstractItemModelTester::FailureReportingMode::Warning, this);
                                  }
                                  else{
                                      m_tester = nullptr;
                                  }
                          
                                  emit modelChanged(m_model);
                              }
                          signals:
                              void modelChanged(QAbstractItemModel* model);
                          
                          protected:
                              QAbstractItemModel* m_model;
                              QAbstractItemModelTester* m_tester;
                          };
                          
                          #endif // TABLEPROXYMODEL_H
                          

                          qml:

                          import QtQuick 2.12
                          import QtQuick.Window 2.12
                          
                          import Models 1.0
                          
                          Window {
                              visible: true
                              width: 640
                              height: 480
                              title: qsTr("Proxy Model Testing")
                          
                              FileSystemModel {
                                  id: filesystemmodel
                                  rootPath: "/"
                                  noproxy: false
                              }
                          
                              /*
                              FileSystemTableProxyModel {
                                  id: tableproxymodel
                          
                                  model: filesystemmodel.proxy
                                  rootIndex: filesystemmodel.rootIndex
                              }
                              */
                          
                              FileSystemTableIdentityModel {
                                  id: tableproxymodel
                          
                                  model: filesystemmodel.proxy
                                  rootIndex: filesystemmodel.rootIndex
                              }
                          
                          
                              TableView {
                                  anchors.fill: parent
                          
                                  model: tableproxymodel
                                  //model: filesystemmodel.proxy
                          
                                  delegate: Item {
                                      implicitWidth: 100
                                      implicitHeight: 25
                                      Rectangle {
                                          anchors.fill: parent
                          
                                          color: "blue"
                                      }
                          
                                      Text {
                                          text: display
                                      }
                                  }
                              }
                          
                              ModelTester {
                                  //model: tableproxymodel
                                  //model: filesystemmodel.proxy
                              }
                          }
                          

                          C++ is a perfectly valid school of magic.

                          1 Reply Last reply
                          0
                          • fcarneyF Offline
                            fcarneyF Offline
                            fcarney
                            wrote on last edited by
                            #13

                            I really don't know how to do what I want to do I guess. I think I need to backup and think if I really need to create a translation table at all. I have spent so much time trying to understand how to make this work that it is not productive at all.

                            C++ is a perfectly valid school of magic.

                            1 Reply Last reply
                            0
                            • fcarneyF Offline
                              fcarneyF Offline
                              fcarney
                              wrote on last edited by
                              #14

                              Minimalist version to reproduce:
                              main.cpp:

                              #include <QApplication>
                              #include <QQmlApplicationEngine>
                              
                              #include <QSortFilterProxyModel>
                              #include <QFileSystemModel>
                              #include <QAbstractTableModel>
                              #include <QAbstractItemModel>
                              
                              #include <QQmlContext>
                              
                              #include <QDebug>
                              
                              // https://doc.qt.io/qt-5/qml-qtquick-tableview.html#example-usage
                              class TableModel : public QAbstractTableModel
                              {
                                  Q_OBJECT
                              
                                  Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged)
                                  Q_PROPERTY(QModelIndex rootindex READ rootindex WRITE setRootindex NOTIFY rootindexChanged)
                              public:
                              
                                  int rowCount(const QModelIndex & = QModelIndex()) const override
                                  {
                                      if(!m_model)
                                          return 0;
                              
                                      return m_model->rowCount(m_rootindex);
                                  }
                              
                                  int columnCount(const QModelIndex & = QModelIndex()) const override
                                  {
                                      return 1;
                                  }
                              
                                  QVariant data(const QModelIndex &index, int role) const override
                                  {
                                      if(!m_model)
                                          return QVariant();
                              
                                      switch (role) {
                                          case Qt::DisplayRole:
                                              return m_model->data(m_model->index(index.row(), index.column(), m_rootindex), QFileSystemModel::FileNameRole);
                                          default:
                                              break;
                                      }
                              
                                      return QVariant();
                                  }
                              
                                  QHash<int, QByteArray> roleNames() const override
                                  {
                                      return { {Qt::DisplayRole, "display"} };
                                  }
                                  QAbstractItemModel* model() const
                                  {
                                      return m_model;
                                  }
                                  QModelIndex rootindex() const
                                  {
                                      return m_rootindex;
                                  }
                              
                              public slots:
                                  void setModel(QAbstractItemModel* model)
                                  {
                                      if (m_model == model)
                                          return;
                              
                                      m_model = model;
                              
                                      if(m_model) {
                                          auto newmodel = m_model;
                                          connect(newmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::columnsInserted, this, &TableModel::endreset);
                                          connect(newmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::columnsMoved, this, &TableModel::endreset);
                                          connect(newmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::columnsRemoved, this, &TableModel::endreset);
                              
                                          connect(newmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::rowsInserted, this, &TableModel::endreset);
                                          connect(newmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::rowsMoved, this, &TableModel::endreset);
                                          connect(newmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::rowsRemoved, this, &TableModel::endreset);
                              
                                          connect(newmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::layoutChanged, this, &TableModel::endreset);
                              
                                          connect(newmodel, &QAbstractItemModel::modelAboutToBeReset, this, &TableModel::beginreset);
                                          connect(newmodel, &QAbstractItemModel::modelReset, this, &TableModel::endreset);
                              
                                          connect(newmodel, &QAbstractItemModel::dataChanged, this, [this](){
                                              beginResetModel();
                                              endResetModel();
                                          });
                                          connect(newmodel, &QAbstractItemModel::headerDataChanged, this, [this](){
                                              beginResetModel();
                                              endResetModel();
                                          });
                                      }
                              
                                      emit modelChanged(m_model);
                                  }
                                  void setRootindex(QModelIndex rootindex)
                                  {
                                      if (m_rootindex == rootindex)
                                          return;
                              
                                      m_rootindex = rootindex;
                                      emit rootindexChanged(m_rootindex);
                                  }
                              
                                  void beginreset(){
                                      beginResetModel();
                                  }
                                  void endreset(){
                                      endResetModel();
                                  }
                              
                              signals:
                                  void modelChanged(QAbstractItemModel* model);
                                  void rootindexChanged(QModelIndex rootindex);
                              
                              protected:
                                  QAbstractItemModel* m_model;
                                  QModelIndex m_rootindex;
                              };
                              
                              
                              int main(int argc, char *argv[])
                              {
                                  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                              
                                  QApplication app(argc, argv);
                              
                                  QFileSystemModel fsmodel;
                                  QSortFilterProxyModel sfpmodel;
                              
                                  TableModel tbmodel;
                              
                                  sfpmodel.setSourceModel(&fsmodel);
                              
                                  fsmodel.setRootPath("/");
                              
                                  bool nocrash = false;
                                  if(nocrash){
                                      tbmodel.setModel(&fsmodel);
                                      tbmodel.setRootindex(fsmodel.index(fsmodel.rootPath()));
                                      qInfo() << fsmodel.index(fsmodel.rootPath()) << QModelIndex();
                                  }else{
                                      tbmodel.setModel(&sfpmodel);
                                      tbmodel.setRootindex(sfpmodel.index(0,0));
                                  }
                              
                                  QQmlApplicationEngine engine;
                              
                                  engine.rootContext()->setContextProperty("tbmodel", &tbmodel);
                              
                                  const QUrl url(QStringLiteral("qrc:/main.qml"));
                                  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                                   &app, [url](QObject *obj, const QUrl &objUrl) {
                                      if (!obj && url == objUrl)
                                          QCoreApplication::exit(-1);
                                  }, Qt::QueuedConnection);
                                  engine.load(url);
                              
                                  return app.exec();
                              }
                              
                              #include "main.moc"
                              

                              main.qml:

                              import QtQuick 2.12
                              import QtQuick.Window 2.12
                              
                              Window {
                                  visible: true
                                  width: 640
                                  height: 480
                                  title: qsTr("Sort Proxy Model Crash")
                              
                                  TableView {
                                      anchors.fill: parent
                              
                                      model: tbmodel
                              
                                      delegate: Item {
                                          implicitWidth: 100
                                          implicitHeight: 25
                                          Rectangle {
                                              anchors.fill: parent
                              
                                              color: "blue"
                                          }
                              
                                          Text {
                                              text: display
                                          }
                                      }
                                  }
                              }
                              

                              Crashes in the exact place if nocrash is set to false in main.cpp. May take a few tries to trigger crash as sometimes it shows as blank. Another issues is the asynchronous behavior of QFileSystemModel. However, the code works perfectly if nocrash is set to true, but once a QSortProxyFilter is in the middle it has problems. Really really really frustrated because either I need to work around this, not use QSortProxyFilter and roll my own, or go cry in the corner hoping it goes away.

                              C++ is a perfectly valid school of magic.

                              kshegunovK 1 Reply Last reply
                              0
                              • fcarneyF fcarney

                                Minimalist version to reproduce:
                                main.cpp:

                                #include <QApplication>
                                #include <QQmlApplicationEngine>
                                
                                #include <QSortFilterProxyModel>
                                #include <QFileSystemModel>
                                #include <QAbstractTableModel>
                                #include <QAbstractItemModel>
                                
                                #include <QQmlContext>
                                
                                #include <QDebug>
                                
                                // https://doc.qt.io/qt-5/qml-qtquick-tableview.html#example-usage
                                class TableModel : public QAbstractTableModel
                                {
                                    Q_OBJECT
                                
                                    Q_PROPERTY(QAbstractItemModel* model READ model WRITE setModel NOTIFY modelChanged)
                                    Q_PROPERTY(QModelIndex rootindex READ rootindex WRITE setRootindex NOTIFY rootindexChanged)
                                public:
                                
                                    int rowCount(const QModelIndex & = QModelIndex()) const override
                                    {
                                        if(!m_model)
                                            return 0;
                                
                                        return m_model->rowCount(m_rootindex);
                                    }
                                
                                    int columnCount(const QModelIndex & = QModelIndex()) const override
                                    {
                                        return 1;
                                    }
                                
                                    QVariant data(const QModelIndex &index, int role) const override
                                    {
                                        if(!m_model)
                                            return QVariant();
                                
                                        switch (role) {
                                            case Qt::DisplayRole:
                                                return m_model->data(m_model->index(index.row(), index.column(), m_rootindex), QFileSystemModel::FileNameRole);
                                            default:
                                                break;
                                        }
                                
                                        return QVariant();
                                    }
                                
                                    QHash<int, QByteArray> roleNames() const override
                                    {
                                        return { {Qt::DisplayRole, "display"} };
                                    }
                                    QAbstractItemModel* model() const
                                    {
                                        return m_model;
                                    }
                                    QModelIndex rootindex() const
                                    {
                                        return m_rootindex;
                                    }
                                
                                public slots:
                                    void setModel(QAbstractItemModel* model)
                                    {
                                        if (m_model == model)
                                            return;
                                
                                        m_model = model;
                                
                                        if(m_model) {
                                            auto newmodel = m_model;
                                            connect(newmodel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::columnsInserted, this, &TableModel::endreset);
                                            connect(newmodel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::columnsMoved, this, &TableModel::endreset);
                                            connect(newmodel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::columnsRemoved, this, &TableModel::endreset);
                                
                                            connect(newmodel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::rowsInserted, this, &TableModel::endreset);
                                            connect(newmodel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::rowsMoved, this, &TableModel::endreset);
                                            connect(newmodel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::rowsRemoved, this, &TableModel::endreset);
                                
                                            connect(newmodel, &QAbstractItemModel::layoutAboutToBeChanged, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::layoutChanged, this, &TableModel::endreset);
                                
                                            connect(newmodel, &QAbstractItemModel::modelAboutToBeReset, this, &TableModel::beginreset);
                                            connect(newmodel, &QAbstractItemModel::modelReset, this, &TableModel::endreset);
                                
                                            connect(newmodel, &QAbstractItemModel::dataChanged, this, [this](){
                                                beginResetModel();
                                                endResetModel();
                                            });
                                            connect(newmodel, &QAbstractItemModel::headerDataChanged, this, [this](){
                                                beginResetModel();
                                                endResetModel();
                                            });
                                        }
                                
                                        emit modelChanged(m_model);
                                    }
                                    void setRootindex(QModelIndex rootindex)
                                    {
                                        if (m_rootindex == rootindex)
                                            return;
                                
                                        m_rootindex = rootindex;
                                        emit rootindexChanged(m_rootindex);
                                    }
                                
                                    void beginreset(){
                                        beginResetModel();
                                    }
                                    void endreset(){
                                        endResetModel();
                                    }
                                
                                signals:
                                    void modelChanged(QAbstractItemModel* model);
                                    void rootindexChanged(QModelIndex rootindex);
                                
                                protected:
                                    QAbstractItemModel* m_model;
                                    QModelIndex m_rootindex;
                                };
                                
                                
                                int main(int argc, char *argv[])
                                {
                                    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                                
                                    QApplication app(argc, argv);
                                
                                    QFileSystemModel fsmodel;
                                    QSortFilterProxyModel sfpmodel;
                                
                                    TableModel tbmodel;
                                
                                    sfpmodel.setSourceModel(&fsmodel);
                                
                                    fsmodel.setRootPath("/");
                                
                                    bool nocrash = false;
                                    if(nocrash){
                                        tbmodel.setModel(&fsmodel);
                                        tbmodel.setRootindex(fsmodel.index(fsmodel.rootPath()));
                                        qInfo() << fsmodel.index(fsmodel.rootPath()) << QModelIndex();
                                    }else{
                                        tbmodel.setModel(&sfpmodel);
                                        tbmodel.setRootindex(sfpmodel.index(0,0));
                                    }
                                
                                    QQmlApplicationEngine engine;
                                
                                    engine.rootContext()->setContextProperty("tbmodel", &tbmodel);
                                
                                    const QUrl url(QStringLiteral("qrc:/main.qml"));
                                    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                                     &app, [url](QObject *obj, const QUrl &objUrl) {
                                        if (!obj && url == objUrl)
                                            QCoreApplication::exit(-1);
                                    }, Qt::QueuedConnection);
                                    engine.load(url);
                                
                                    return app.exec();
                                }
                                
                                #include "main.moc"
                                

                                main.qml:

                                import QtQuick 2.12
                                import QtQuick.Window 2.12
                                
                                Window {
                                    visible: true
                                    width: 640
                                    height: 480
                                    title: qsTr("Sort Proxy Model Crash")
                                
                                    TableView {
                                        anchors.fill: parent
                                
                                        model: tbmodel
                                
                                        delegate: Item {
                                            implicitWidth: 100
                                            implicitHeight: 25
                                            Rectangle {
                                                anchors.fill: parent
                                
                                                color: "blue"
                                            }
                                
                                            Text {
                                                text: display
                                            }
                                        }
                                    }
                                }
                                

                                Crashes in the exact place if nocrash is set to false in main.cpp. May take a few tries to trigger crash as sometimes it shows as blank. Another issues is the asynchronous behavior of QFileSystemModel. However, the code works perfectly if nocrash is set to true, but once a QSortProxyFilter is in the middle it has problems. Really really really frustrated because either I need to work around this, not use QSortProxyFilter and roll my own, or go cry in the corner hoping it goes away.

                                kshegunovK Offline
                                kshegunovK Offline
                                kshegunov
                                Moderators
                                wrote on last edited by kshegunov
                                #15

                                As a first attempt, could you try with the system available QFileSystemModel and QIdentityProxyModel?

                                One thing that caught my eye while going through the stack trace is the m_rootIndex you have. You appear to store a QModelIndex (you shouldn't) which may get invalidated due to the way QFileSystemModel does its (re)loading. An easy thing to try is to substitute that with QPersistentModelIndex and see where that leads you.

                                Read and abide by the Qt Code of Conduct

                                fcarneyF 1 Reply Last reply
                                3
                                • kshegunovK kshegunov

                                  As a first attempt, could you try with the system available QFileSystemModel and QIdentityProxyModel?

                                  One thing that caught my eye while going through the stack trace is the m_rootIndex you have. You appear to store a QModelIndex (you shouldn't) which may get invalidated due to the way QFileSystemModel does its (re)loading. An easy thing to try is to substitute that with QPersistentModelIndex and see where that leads you.

                                  fcarneyF Offline
                                  fcarneyF Offline
                                  fcarney
                                  wrote on last edited by fcarney
                                  #16

                                  @kshegunov said in QSortFilterProxyModel has an internal index failure that does not map to the source correctly:

                                  and see where that leads you

                                  And this seems to have resolved the problem. Thank you.

                                  Edit:
                                  QPersistentModelIndex for variable storage is the fix. Just to be clear. It starts to make sense now. It tells me why the index could invalidate its memory due to updates.

                                  C++ is a perfectly valid school of magic.

                                  kshegunovK 1 Reply Last reply
                                  1
                                  • fcarneyF fcarney

                                    @kshegunov said in QSortFilterProxyModel has an internal index failure that does not map to the source correctly:

                                    and see where that leads you

                                    And this seems to have resolved the problem. Thank you.

                                    Edit:
                                    QPersistentModelIndex for variable storage is the fix. Just to be clear. It starts to make sense now. It tells me why the index could invalidate its memory due to updates.

                                    kshegunovK Offline
                                    kshegunovK Offline
                                    kshegunov
                                    Moderators
                                    wrote on last edited by
                                    #17

                                    You're very welcome.

                                    Read and abide by the Qt Code of Conduct

                                    1 Reply Last reply
                                    2

                                    • Login

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