Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-53221

QHeaderView: Assertion when shifting a hidden row on layoutChanged

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • None
    • 5.5.1
    • Widgets: Itemviews
    • None
    • Windows 10

    Description

      When inserting rows at the beginning of an item model of a QTableView that has hidden rows, the following assertion is being violated:

      Qt5Cored.dll
      Module: 5.5.1
      File: global\qglobal.cpp
      Line: 2966
      
      ASSERT: "uint(i) < uint(size())" in file d:\depot\thirdparty\redistsdks\qt\5.5.1\src\qtbase\src\corelib\tools\qbitarray.h, line 122
      

      This can be reproduced using the following code:

      #include <QtGui>
      #include <QApplication>
      #include <QTableView>
      #include <QAbstractItemModel>
      
      class MyItemModel : public QAbstractItemModel
      {
      public:
      	void insertRowAtBeginning()
      	{
      		Q_EMIT layoutAboutToBeChanged();
      		//beginInsertRows(QModelIndex(), 0, 0);
      
      		m_displayNames.insert(0, QString("Item %1").arg(m_displayNames.count()));
      
      		// Rows are always inserted at the beginning, so move all others.
      		Q_FOREACH(QModelIndex persIndex, persistentIndexList())
      		{
      			// The vertical header view will have a persistent index stored here on the second call to insertRowAtBeginning.
      			changePersistentIndex(persIndex, index(persIndex.row() + 1, persIndex.column(), persIndex.parent()));
      		}
      
      		Q_EMIT layoutChanged();
      		//endInsertRows();
      	}
      
      	virtual QVariant data(const QModelIndex &index, int role) const
      	{
      		if (role == Qt::DisplayRole)
      			return m_displayNames[index.row()];
      
      		return QVariant();
      	}
      
      	virtual QModelIndex index(int row, int column, const QModelIndex &parent) const { return createIndex(row, column); }
      	virtual QModelIndex parent(const QModelIndex &child) const { return QModelIndex(); }
      	virtual int rowCount(const QModelIndex &parent) const { return m_displayNames.count(); }
      	virtual int columnCount(const QModelIndex &parent) const { return 1; }
      
      private:
      	QStringList m_displayNames;
      };
      
      int main(int argc, char **argv)
      {
      	QApplication app(argc, argv);
      
      	QTableView* tableView = new QTableView();
      	MyItemModel* itemModel = new MyItemModel();
      	tableView->setModel(itemModel);
      	tableView->show();
      
      	itemModel->insertRowAtBeginning();
      	tableView->setRowHidden(0, true);
      	itemModel->insertRowAtBeginning(); // the hidden row is now moved to row 1.
      
      	return app.exec();
      }
      

      This only happens if the item model notifies the view using the layoutChanged signals (instead of rowsInserted signals), which should be working as well if I'm correct to assume that QHeaderViewPrivate::_q_layoutChanged() is supposed to handle section count changes.

      Modifying QHeaderViewPrivate::_q_layoutChanged() like this should fix the problem:

      void QHeaderViewPrivate::_q_layoutChanged()
      {
          Q_Q(QHeaderView);
          viewport->update();
      
          if (modelSectionCount() != sectionCount()) {
              q->initializeSections();
          }
          if (persistentHiddenSections.isEmpty() || modelIsEmpty()) { 
              persistentHiddenSections.clear();
              return;
          }
          ...
      

      Attachments

        Issue Links

          For Gerrit Dashboard: QTBUG-53221
          # Subject Branch Project Status CR V

          Activity

            People

              tmartsum Thorbjørn Lund Martsum
              daniel.hofmann Daniel Hofmann
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes