PDA

View Full Version : How to indicate that hasChildren() has changed when using lazy population?



Coises
6th May 2010, 19:27
I have a subclass of QAbstractItemModel which uses lazy population. Generally I know whether any given item has children before it is actually populated, but sometimes this changes even though the item is not yet populated.

As long as a parent item is populated, I can just use QAbstractItemModel::beginInsertRows()/QAbstractItemModel::endInsertRows() or QAbstractItemModel::beginRemoveRows()/QAbstractItemModel::endRemoveRows() and, with proper adjustments in the various virtual functions, everything works fine. But when the parent item is not yet populated — QAbstractItemModel::canFetchMore() and QAbstractItemModel::hasChildren return the same value, either true or false, and QAbstractItemModel::rowCount() returns 0 — reversing the return values of QAbstractItemModel::canFetchMore() and QAbstractItemModel::hasChildren() doesn’t add or remove the expansion icon in a connected QTreeView without doing something else (which makes sense, since nothing has happened in the model that would send a signal to tell the view to call QAbstractItemModel::hasChildren() again for the item in question).

What do I do in a QAbstractItemModel subclass to tell the connected views that they need to recheck the value of QAbstractItemModel::hasChildren() for a particular item, even though no children have been added or removed, since it is not yet populated?

tbscope
6th May 2010, 19:58
You can of course emit your own signals when you insert or remove items in your model.

But I'm not really sure I understand your problem. If you do not have any childitems for a particular parent item, then hasChildren() will always return false. Do you want to have it return true if there are no children?

Coises
6th May 2010, 23:27
But I'm not really sure I understand your problem. If you do not have any childitems for a particular parent item, then hasChildren() will always return false. Do you want to have it return true if there are no children?

Yes; in fact overriding QAbstractItemModel::hasChildren() to return true even though QAbstractItemModel::rowCount() returns 0 is exactly what one does to implement lazy population (http://doc.trolltech.com/latest/model-view-model-subclassing.html#lazy-population-of-model-data). (The documentation is less than clear on this, but experiment showed me that QAbstractItemModel::rowCount() must return 0 until the rows are actually inserted, following the call in QAbstractItemModel::fetchMore() to QAbstractItemModel::beginInsertRows() — which does itself call QAbstractItemModel::rowCount() and must see 0.)

This all works as it should. The problem I can’t seem to resolve is what to do when the status of an unpopulated parent changes such that it no longer has children; or when the status of an item that previously did not have children changes such that it does, but information about the children should not be retrieved and added to the model until required. Debug statements suggest that QTreeView calls QAbstractModel::hasChildren() when it first shows an item, but nothing I can do in the model, short of removing the item and adding it back again, seems to make it call that function again and update the presence or absence of the expansion icon accordingly.

In the user interface of the QTreeView, collapsing and expanding the item’s parent seems to do the trick; and once the item is populated (QAbstractItemModel::fetchMore() is called) there is no problem. The problem is in switching between childless and unpopulated states.

wysota
7th May 2010, 00:54
The problem I can’t seem to resolve is what to do when the status of an unpopulated parent changes such that it no longer has children;
I would emit layoutChanged() or dataChanged() for the parent in question.

Coises
7th May 2010, 03:13
I would emit layoutChanged() or dataChanged() for the parent in question.

Thank you, Wysota! A single layoutChanged() after a batch of changes appears to work perfectly.