[Qt-interest] QSortProxyModel - row being filtered before it is inserted

Laura Arhire larhire at gmail.com
Wed Feb 3 16:02:03 CET 2010


Hello

I've got a custom, lazy-loaded model which can be used in tree views and
list views. The model is very similar to a directory structure (it contains
folders/files sort of objects). The lazy population is performed using the
canFetchMode and fetchMore methods.

In order to show the model properly for each view, I'm using a filter proxy:
this proxy filters the structure in such a way that:
* list views (which just show one "directory" at a time) show all items
* tree views show the whole structure, but only "directories"

The normal model works fine, I've tested it with the model test in qt labs
and separately without a filter model. However, if I attach a "tree" proxy
to it, I have some trouble when fetching items. It seems that the proxy
model's filterAcceptsRow method is called as a result of the call to
beginInsertRows in the target mode. This means that the row itself is not
yet added to the model, which causes a SIGSEG.

I think I'm missing something related to the implementation, but I haven't
been able to find anything relevant on the discussion lists and on the web.
Here is the relevant stacktrace I get:

Program received signal SIGSEGV, Segmentation fault.
0x0048efd4 in ExplorerModel::get_child_explorer_item (this=0xcdbbc48,
    row=0, parent=@0x27cb14) at browser/qt/src/ExplorerModel.cpp:321
321                 item->add_child(); // note - this is here so we can
crash & get a stacktrace when the filter model attempts to filter rows
before they're added
Current language:  auto; currently c++
(gdb) bt
#0  0x0048efd4 in  ExplorerModel::get_child_explorer_item (
    this=0xcdbbc48, row=0, parent=@0x27cb14)
    at browser/qt/src/ExplorerModel.cpp:321
#1  0x00497ef6 in  ModelSortFilterProxy::filterAcceptsRow (
    this=0xdc54258, row=0, parent=@0x27cb14)
    at browser/qt/src/ModelSortFilterProxy.cpp:159
#2  0x02cca1c1 in QSortFilterProxyModelPrivate::create_mapping (
    this=0xdc54998, source_parent=@0x27cb14)
    at itemviews\qsortfilterproxymodel.cpp:291
#3  0x02ccdbf6 in
QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted
    (this=0xdc54998, source_parent=@0x27cb14, start=0, end=0)
    at itemviews\qsortfilterproxymodel.cpp:1236
#4  0x02cd1acb in QSortFilterProxyModel::qt_metacall (this=0xdc54258,
    _c=QMetaObject::InvokeMetaMethod, _id=11, _a=0x27ca48)
    at tmp/moc/debug_shared/moc_qsortfilterproxymodel.cpp:134
#5  0x00496d64 in  ModelSortFilterProxy::qt_metacall (this=0xdc54258,
    _c=QMetaObject::InvokeMetaMethod, _id=36, _a=0x27ca48)
    at browser/qt/include/ModelSortFilterProxy_moc.cpp:74
#6  0x6a20181c in QMetaObject::metacall (object=0xdc54258,
    cl=QMetaObject::InvokeMetaMethod, idx=36, argv=0x27ca48)
    at kernel\qmetaobject.cpp:237
#7  0x6a2115b5 in QMetaObject::activate (sender=0xcdbbc48, m=0x6a33aa40,
    local_signal_index=4, argv=0x27ca48) at kernel\qobject.cpp:3267
#8  0x6a24cef2 in QAbstractItemModel::rowsAboutToBeInserted
(this=0xcdbbc48,
    _t1=@0x27cb14, _t2=0, _t3=0)
    at tmp\moc\debug_shared\moc_qabstractitemmodel.cpp:174
#9  0x6a1f89e6 in QAbstractItemModel::beginInsertRows (this=0xcdbbc48,
    parent=@0x27cb14, first=0, last=0) at kernel\qabstractitemmodel.cpp:2393
#10 0x0048f421 in  ExplorerModel::fetchMore (this=0xcdbbc48,
    parent=@0x27cb14) at browser/qt/src/ExplorerModel.cpp:382
#11 0x02cd02c6 in QSortFilterProxyModel::fetchMore (this=0xdc54258,
    parent=@0x27cb88) at itemviews\qsortfilterproxymodel.cpp:1922
#12 0x02c95481 in QTreeViewPrivate::layout (this=0xdc4d950, i=0)
    at itemviews\qtreeview.cpp:3143
#13 0x02c94283 in QTreeViewPrivate::expand (this=0xdc4d950, item=0,
    emitSignal=true) at itemviews\qtreeview.cpp:2943
#14 0x02c8cf0e in QTreeViewPrivate::expandOrCollapseItemAtPos (
    this=0xdc4d950, pos=@0x27d704) at itemviews\qtreeview.cpp:1320
#15 0x02c8f59e in QTreeView::mousePressEvent (this=0xdb0e088,
event=0x27d6f4)
    at itemviews\qtreeview.cpp:1817

And I have the following relevant methods :

void ExplorerModel::fetchMore(const QModelIndex& parent )
{
    ExplorerItem *item = get_explorer_item(parent);

    if (item != NULL && item->get_children_count() > 0)
    {
        beginInsertRows(parent, 0, item->get_children_count() - 1);
        item->populate();
        endInsertRows();
    }
}

bool ExplorerModel::canFetchMore(const QModelIndex& parent, ViewType view)
const
{
    if (parent.isValid())
    {
        ExplorerItem *item = get_explorer_item(parent);
        return !item->is_populated() && item->has_children(view);
    }

    return false; // root always fetched
}

bool ModelSortFilterProxy::filterAcceptsRow(int row, const QModelIndex
&parent) const
{
    bool result = true;

    if (this->view_type == ExplorerModel::TREE_VIEW)
    {
        ExplorerItem *item = this->model->get_child_explorer_item(row,
parent);
        result = item->is_dir();
    }

    return result;
}

bool ModelSortFilterProxy::canFetchMore(const QModelIndex &parent) const
{
    return model->canFetchMore(mapToSource(parent), this->view_type);
}

>From the stack trace, the filterAcceptsRow seems to be called when I call
beginInsertRows on the target model - and if I look at Qt source code, that
is indeed what should happen. But I don't think this should happen - I also
know how to fix this, since I don't know anything about the rows being
populated until after they are populated.

Can anyone spot what I'm missing?

Thanks,
Laura
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20100203/3c0ac704/attachment.html 


More information about the Qt-interest-old mailing list