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.8k 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
    #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