Hello!

I've met a problem with subclassing QSortFilterProxyModel.
What I want is a proxy model which hides some of the source table model columns (and also supports sorting, and do some other things).

I subclass a QSortFilterProxyModel and override filterAcceptsColumn() function.

The decision on which column to hide is based on rather huge computation. So I wish to do such computations only when source model changes significantly, e,g, when new column is added. Thus I connect source model's corresponding signal to my proxy's updateCache() slot. That slot does the computation and saves it's results in to a vector of bools.

filterAcceptsColumn() function simply uses this vector to find out which column to hide.

Below is a complete test code which I expect to work. But it crashes.

The reason of the failure is that QSortFilterProxyModel() constructor also connects that signal to it's private slot. That slot is invoked before my updateCache() slot in a subclass. That parent slot emits similsr signal which is connected to a view object. The view tries to react on model change and calls columnCount() functoin of the proxy which in turn calls filterAcceptsColumn() for every column of a changed source model. But my updateCache() slot in a subclass was not called yet. Thus the required computation was not done for a new number of a source columns and the vector was not resized properly. The program crashes trying to access non existent element of the vector.

Any suggestions on how to solve this problem?

MyProxy.h
Qt Code:
  1. #ifndef MYPROXY_H
  2. #define MYPROXY_H
  3.  
  4. #include <QSortFilterProxyModel>
  5. #include <QDebug>
  6. #include <QVector>
  7.  
  8. class MyProxy : public QSortFilterProxyModel
  9. {
  10. Q_OBJECT
  11. private:
  12. QVector<bool> hiddenColumns;
  13.  
  14. public:
  15. void setSourceModel(QAbstractItemModel* sourceModel)
  16. {
  17. QSortFilterProxyModel::setSourceModel(sourceModel);
  18.  
  19. updateCache();
  20.  
  21. connect(sourceModel, SIGNAL(columnsInserted(const QModelIndex&, int, int)),
  22. SLOT(updateCache()));
  23. }
  24.  
  25. virtual bool filterAcceptsColumn(int source_column, const QModelIndex&) const
  26. {
  27. qDebug() << "filterAcceptsColumn(): column = " << source_column <<
  28. "\tcached = " << hiddenColumns.size();
  29. return ! hiddenColumns.at(source_column);
  30. }
  31.  
  32. private slots:
  33. void updateCache()
  34. {
  35. qDebug() << "updateCache()";
  36.  
  37. hiddenColumns.resize(sourceModel()->columnCount());
  38.  
  39. for (int c = 0; c < hiddenColumns.size(); c++)
  40. hiddenColumns[c] = c % 2; // consider huge computation here
  41. }
  42.  
  43. };
  44.  
  45. #endif // MYPROXY_H
To copy to clipboard, switch view to plain text mode 
MyProxy.cpp
Qt Code:
  1. #include "MyProxy.h"
  2.  
  3. #include <QApplication>
  4. #include <QTableView>
  5. #include <QStandardItemModel>
  6.  
  7. int main(int argc, char *argv[])
  8. {
  9. QApplication a(argc, argv);
  10.  
  11. QStandardItemModel source(1, 1);
  12. MyProxy proxy;
  13. proxy.setSourceModel(& source);
  14.  
  15. v.setModel(& source);
  16. v.show();
  17.  
  18. qDebug() << "adding column...";
  19. source.setColumnCount(2);
  20.  
  21. return a.exec();
  22. }
To copy to clipboard, switch view to plain text mode 
Program output:
updateCache()
adding column...
filterAcceptsColumn(): column = 0 cached = 1
filterAcceptsColumn(): column = 1 cached = 1
ASSERT failure in QVector<T>::at: "index out of range", file ..\..\..\..\Qt\2010.05\qt\include/QtCore/../../src/corelib/tools/qvector.h, line 339
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
P.S. I use Qt 4.7 on Windows with gcc