ksming
ksming

Reputation: 1462

QSortFilterProxyModel crashes when deleting a row from the source model via the source model function

I have created a custom QAbstractItemModel-derived model that contains a set of XML data in a tree hierarchical fashion that will display in a QTreeView as shown in this image:

http://imageshack.us/photo/my-images/840/xmltreeview.png

This model has successfully pass the ModelTest and some basic editing tests. However, I have run into some problems when trying to do some filtering on this model so that I can split the model into a few different views. I have tried QSortFilterProxyModel and it crashes alot. After some fixing, it still crashes after attempting to remove a row from the model.

Console Application shows these messages when crash occurs:

ratbr QModelIndex(0,0,0xd162000,CGHXmlModel(0xb197e68) ) 0 0

rr QModelIndex(0,0,0xd162000,CGHXmlModel(0xb197e68) ) 0 0

and this is the callstack when crash happened:

0   QSortFilterProxyModelPrivate::index_to_iterator qsortfilterproxymodel.cpp   193 0x0134714b  
1   QSortFilterProxyModel::parent   qsortfilterproxymodel.cpp   1654    0x0111a677  
2   QModelIndex::parent qabstractitemmodel.h    389 0x6a2ad95e  
3   QPersistentModelIndex::parent   qabstractitemmodel.cpp  347 0x6a1f7320  
4   QItemSelectionRange::isValid    qitemselectionmodel.h   108 0x01341ea4  
5   QItemSelectionModel::isSelected qitemselectionmodel.cpp 1187    0x010f0b58  
6   QTreeView::drawRow  qtreeview.cpp   1602    0x010db133  
7   QTreeView::drawTree qtreeview.cpp   1441    0x010da4f4  
8   QTreeView::paintEvent   qtreeview.cpp   1274    0x010d9bed  
9   QWidget::event  qwidget.cpp 8333    0x00c1492d  
10  QFrame::event   qframe.cpp  557 0x00f8e6bc  
11  QAbstractScrollArea::viewportEvent  qabstractscrollarea.cpp 1043    0x0101bf0f  
12  QAbstractItemView::viewportEvent    qabstractitemview.cpp   1619    0x010a5785  
13  QTreeView::viewportEvent    qtreeview.cpp   1256    0x010d9aa3  
14  QAbstractScrollAreaPrivate::viewportEvent   qabstractscrollarea_p.h 100 0x01276a13  
15  QAbstractScrollAreaFilter::eventFilter  qabstractscrollarea_p.h 116 0x0127506c  
16  QCoreApplicationPrivate::sendThroughObjectEventFilters  qcoreapplication.cpp    847 0x6a1ffc73  
17  QApplicationPrivate::notify_helper  qapplication.cpp    4392    0x00bc96e5  
18  QApplication::notify    qapplication.cpp    4361    0x00bc9586  
19  QCoreApplication::notifyInternal    qcoreapplication.cpp    732 0x6a1ff9dc  
20  QCoreApplication::sendSpontaneousEvent  qcoreapplication.h  218 0x0123d53e

I'm still quite new to Qt Model/View programming and this error has really been daunting and left me scratching my head for days. I hope someone here can help me out here before I lose all my hair! Thanks!

EDIT: Update to include some source codes

My test project has two dialog windows, with one QTreeView each. One is the main window containing the QAbstractItemModel-derived class member and the other is a child window contain the QSortFilterProxyModel-derived class member. The child window also has a QAbstractItemModel pointer to the actual model.

Main window:

class CGHXMLModelDialog : public QDialog
{
    Q_OBJECT
...
private:
    Ui::CGHXMLModelDialog *ui;
    CGHXmlModel*            m_mainModel;
    CGHXMLParameterDialog*  m_ParamDialog;


...

}

Child window:

class CGHXMLParameterDialog : public QDialog
{
    Q_OBJECT
...

private:
    void setupProxyModel();

    Ui::CGHXMLParameterDialog*      ui;
    QAbstractItemModel*             m_coreModel;//A CGHXMLModel
    CGHXMLSortFilterProxyModel*     m_ParamModel;

...

}

In CGHXMLModelDialog constructor:

m_mainModel = new CGHXmlModel(theDomDocument, this);
ui->CGHXMLTreeView->setModel(m_mainModel);

//Create sub-dialog window containing proxy filter model
m_ParamDialog = new CGHXMLParameterDialog(m_mainModel, this);

which then calls the setupProxyModel() method:

CGHXMLParameterDialog::CGHXMLParameterDialog(QAbstractItemModel* coreModel, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CGHXMLParameterDialog),
    m_coreModel(coreModel)
{
    ui->setupUi(this);
    setupProxyModel();
}

void CGHXMLParameterDialog::setupProxyModel()
{
    m_ParamModel = new CGHXMLSortFilterProxyModel(this);
    m_ParamModel->setSourceModel(m_coreModel);

    m_ParamModel->setFilterRegExp(QRegExp("Parameter"));
    m_ParamModel->setFilterKeyColumn(0);
    m_ParamModel->setDynamicSortFilter(true);

    ui->CGHXMLParamView->setModel(m_ParamModel);
}

I have tested insert rows, edit row content, insert XML attribute via column editing (custom column manipulating; I won't elaborate) etc on the source model directly and it worked both with and without the presence of the Sort-Filter model. The problem occurs when I try to delete a "row", which is an XML element for my model, when there is a Sort-Filter model attached to it.

Here is my code for removeRows:

bool CGHXmlModel::removeRows(int rowposition, int rows, const QModelIndex &parent)
{
    CGHXMLTreeItem *parentItem = getItem(parent);
    bool success = false;

    beginRemoveRows(parent, rowposition, rowposition + rows - 1);
    success = parentItem->removeChildren(rowposition, rows);
    endRemoveRows();

    if(success)//Works!
    {
        emit layoutChanged();
    }

    return success;
}

which is called by a button event handler in the main window:

void CGHXMLModelDialog::on_deleteRowButton_clicked()
{
    QModelIndex currIndex = ui->CGHXMLTreeView->selectionModel()->currentIndex();

    if(!m_mainModel->removeRow(currIndex.row(), currIndex.parent()))
    {
        qDebug() << "Fail to remove row from Model.";
        return;
    }
}
//Program crashes after this function returns.

Update: Is it wrong to emit layoutChanged() without emitting layoutAboutToBeChanged()?

Upvotes: 5

Views: 3996

Answers (2)

ksming
ksming

Reputation: 1462

I have solved this problem by commenting the line "emit layoutChanged()" for my insertRows, removeRows methods. Originally the code did not have this line but an updating problem with QTreeView forced me to include it, without including "emit layoutAboutToChanged()". It seems the updating problem has disappeared for some reason.

Anyway thanks to those who tried to help. I will surely need more in the near future.

Upvotes: 2

eli
eli

Reputation: 672

Are you aware that indexes from QAbstractItemModel and QSortFilterProxyModel cannot be mixed?

If you have a QModelIndex from your filterProxy model, then you need to convert it to a QModelIndex from the item model using QAbstractProxyModel::mapToSource().

Upvotes: 1

Related Questions