Hi all, please help

Problem summary:

After adding a row to the source model, when called invalidateFilter()->filterAcceptsRow() of the proxy model it receives the outdated child indices of the source model (those which were created before new row is added), as well as correct indices. Looks like proxy model remembers sources model's structure and updates it only partially

In details:

I have the tree model derived from the QAbstractItemModel.
The 3-level model reflects some hierarchical data stored in memory. I use the 32-bit internalId field to store all the tree structure information as follows:
[— L0 pos (15bit) —][— L1 pos (15bit)—][— level (2bit)—]


So for “y” node L0 = 2, L1 = 1 and level = 2, for “2” node L0 = 2, L1 = 0(any), level = 0

Since the data in memory preserve its order and every item knows about its position in the tree so it lets to implement index() and parent() and data() functions and it works fine until a filtering model comes to the scene.

Let’s start with the following structure (B has children “0” and “1”, “0” has no children) (state BEFORE):


Then the data is added on the 0-th position. The beginInsertRows() is called A the the item is added and endInsertRows() is called inside the model. Then beginInsertRows() is called for A-0 and this item(s) is added and then endInsertRows(). (state AFTER)


Then, the dataChanged() is emitted from the source model since A (probably) changes its state which causes the QSortFilterProxyModel::invalidateFilter() to be called (or it can be called in other way). Inside invalidateFilter() the
filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) is called with different source parent indices.

The disaster comes from the last ones: we receive sourceParent’s as B-1 (with row 0 for B-1-y), B (with row 1 for B-1) etc. AND we receive the sourceParent A-1 (with row ==0, pointing to A-1-y). Obviously, the latter somehow remains (inside the QSortFilterProxyModel ?!) from state BEFORE (interanlId value as for B-1-y) and it causes crash when trying to get the child index as follows:
sourceModel()->index(sourceRow, 0, sourceParent), since there are already no node “1” under A in the memory I’m trying to display.

1) How to correctly update filter model to make it know that the child structure is changed in the source model and avoid receivind an outdated indices into filterAcceptsRow()?
2) Is this idea of building tree is sane (while searching for this problem solurion I’ve found exactly the same proposal http://lynxline.com/designing-tree-like-models/)

Filtering model code:

Qt Code:
  1. TractsListProxyModel::TractsListProxyModel(QObject *parent)
  2. m_state(0)
  3. {
  4. setDynamicSortFilter(true);
  5. }
  7. bool TractsListProxyModel::filterAcceptsRow(int sourceRow,
  8. const QModelIndex &sourceParent) const
  9. {
  11. QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
  13. Tract::Ptr tract = index.data(Qt::EditRole).value<Tract::Ptr>();
  15. return stateFilter(tract) && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
  16. }
  18. bool TractsListProxyModel::stateFilter(Tract::Ptr tract) const
  19. {
  20. return m_state == 0 ?
  21. true
  22. : tract->getState() == m_state;
  23. }
  25. void TractsListProxyModel::setStateFilter(terminal::TractState::Type state)
  26. {
  27. m_state = state;
  29. invalidateFilter();
  30. }
  32. void TractsListProxyModel::setSourceModel(QAbstractItemModel *model)
  33. {
  34. connect_assert(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
  35. this, SLOT(sourceModelDataChanged(QModelIndex, QModelIndex)));
  37. QSortFilterProxyModel::setSourceModel(model);
  38. }
  40. void TractsListProxyModel::sourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
  41. {
  42. Q_UNUSED(topLeft);
  43. Q_UNUSED(bottomRight);
  44. invalidateFilter();
  45. }
To copy to clipboard, switch view to plain text mode 
P.S. I’ve tried to connect
Qt Code:
  1. connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
  2. this, SLOT(invalidate()));
  3. connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
  4. this, SLOT(invalidate()));
  5. connect(sourceModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
  6. this, SLOT(invalidate()));
  7. connect(sourceModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
  8. this, SLOT(invalidate()));
  9. connect(sourceModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
  10. this, SLOT(invalidate()));
  11. connect(sourceModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
  12. this, SLOT(invalidate()));
  13. connect(sourceModel, SIGNAL(modelReset()),
  14. this, SLOT(invalidate()));
To copy to clipboard, switch view to plain text mode 
But with no avail