PDA

View Full Version : QSortProxyFilterModel invalidation crashes



stillwaiting
13th September 2010, 10:28
Dear friends,

I've faced the next problem. There is a chain of QSortFilterProxyModels in my application:



MainWindow::MainWindow(QWidget *parent) :
....
m1 = new MyFilterModel(this);
m1->setSourceModel(new MyTreeModel(this));
m1->setType(E_SHOW_ALL);

m2 = new MyFilterModel(this);
m2->setSourceModel(m1);
m2->setType(E_SHOW_ALL);

m3 = new MyFilterModel(this);
m3->setSourceModel(m2);
m3->setType(E_SHOW_ALL);

ui->treeView->setModel(m3);
....
}

, MyFilterModel implements custom filtering (overrides QSortFilterProxyModel::filterAcceptRows()).

Now I want to change filtering parameter m1 uses:



void MainWindow::on_pushButton_clicked()
{
m1->setType(E_SHOW_FEW); // it only
// changes m1->m_parameter value which
// one uses inside m1->filterAcceptRows()

m1->invalidate(); // crash :(
}

, m1->invalidate() call crashes the application.

Could you, guys, please, help me to figure out what am I doing wrong?

Platform: Windows Vista;
Qt version: 4.6.0 (from SDK);
Compiler: MinGW

P.S. I also tried to call "invalidateFilter()" instead of "invalidate()", it works fine, but I can't use it: the production version of our application uses old version of Qt (4.5) and it seems that there was a bug in invalidateFilter(): sometimes it doesn't show some rows (by the way if I call invalidateFilter() twice everything works as a charm)

wysota
13th September 2010, 10:33
What if you substitute MyTreeModel with QStandardItemModel? Does it still crash?

ChrisW67
13th September 2010, 10:41
If setType() changes internal values that are only used in filterAcceptsRows() the invalidateFilter() would be the correct thing to call. I didn't see a related bug in the tracker. Do you have a bug number?

Storing pointers to things that invalidate() might throw away is just one of a multitude of things that could be going wrong. Running in a debugger should fairly quickly tell you where your program dies. If you still cannot fathom it then it would help if you could show us what you are doing in the setType() and filterAcceptsRows() methods.

stillwaiting
13th September 2010, 12:45
ChrisW67, wysota, thank you very much for your help.


What if you substitute MyTreeModel with QStandardItemModel? Does it still crash?

No, it's not. Everything works fine. But it is a sandbox, I can't replace QAbstractItemModel with QStandardItemModel in the real application, it's too expensive.


If setType() changes internal values that are only used in filterAcceptsRows() the invalidateFilter() would be the correct thing to call. I didn't see a related bug in the tracker. Do you have a bug number?


No, I haven't.

Let me describe the situation in more details:
I have an application with QTreeView, which uses chain of QSortFilterProxyModel (3 filters) to display data from the model. But in my code QSortFilterProxyModel::invalidateFilter() behave itself in very strange way: sometimes it misses rows, no matter which filter model calls it... I don't know if it is a bug in my code (3 days of debug already... oh my head) or in the Qt (4.5), but this:


this->invalidateFilter();
this->invalidateFilter();

works just great. If the chain contains only 2 filters, then:


this->invalidate();
works fine too. But it crashes when there are 3 filters.

So I was trying to reproduce the problem in sandbox and I succeed with crash.



Storing pointers to things that invalidate() might throw away is just one of a multitude of things that could be going wrong. Running in a debugger should fairly quickly tell you where your program dies. If you still cannot fathom it then it would help if you could show us what you are doing in the setType() and filterAcceptsRows() methods.

That's funny, this code crashes too:


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

m1 = new QSortFilterProxyModel(this);
m1->setSourceModel(new MyTreeModel(NULL));

m2 = new QSortFilterProxyModel(this);
m2->setSourceModel(m1);

m3 = new QSortFilterProxyModel(this);
m3->setSourceModel(m2);

ui->treeView->setModel(m3);
ui->treeView->expandAll();
}

void MainWindow::on_pushButton_clicked()
{
m1->invalidate(); // crash
ui->treeView->expandAll();
}

, but this works fine:


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

m1 = new QSortFilterProxyModel(this);
m1->setSourceModel(new MyTreeModel(NULL));

m2 = new QSortFilterProxyModel(this);
m2->setSourceModel(m1);

//m3 = new QSortFilterProxyModel(this);
//m3->setSourceModel(m2);

ui->treeView->setModel(/*m3*/m2);
ui->treeView->expandAll();


}

void MainWindow::on_pushButton_clicked()
{
m1->invalidate(); // works!
ui->treeView->expandAll();
}


:p

The stacktrace, MyTreeModel's implementation and the whole sandbox project are attached. Please let me know if there's anything else I can provide.

wysota
13th September 2010, 14:11
No, it's not. Everything works fine. But it is a sandbox, I can't replace QAbstractItemModel with QStandardItemModel in the real application, it's too expensive.
Nobody said you should. If it works with the standard item model then it is most probable that the error is in your model class and not the proxy.

Take the model checker from Qt labs and test your model implementation.

stillwaiting
13th September 2010, 14:35
Nobody said you should. If it works with the standard item model then it is most probable that the error is in your model class and not the proxy.

Take the model checker from Qt labs and test your model implementation.

I checked it: a few asserts were raised in my code (not in the model checker). I replaced them with "if"s and all tests were successully passed. But it still crashes :(

wysota
13th September 2010, 15:39
For me your parent() implementation is incorrect or at least weird :) I would get rid of all the asserts too (you probably already did that).

stillwaiting
13th September 2010, 15:53
For me your parent() implementation is incorrect or at least weird :) I would get rid of all the asserts too (you probably already did that).

This is just a sample model from my sandbox . I can't find any errors, QTreeView shows it properly, modelchecker shows no errors too. It even works with two proxy models in the chain. I can't understand what is wrong with the 3rd one and why it crashes. I just can't. :(

wysota
13th September 2010, 16:16
I'm not getting a crash for your sandbox app. Or maybe I just don't know how to replicate it.

stillwaiting
13th September 2010, 16:35
I'm not getting a crash for your sandbox app. Or maybe I just don't know how to replicate it.

Wysota, thank you for your interest :) , I really appreciate it.

Here's the project which I've just checked. It crashes when I click the only enabled button: sometimes it crashes after the 1st click, sometimes I have to click up to 10 times. The debug version raises the assert somewhere deep inside the QSortFilterProxyModel's implementation.

I am able to reproduce this on my environment:
OS: Windows Vista;
Qt: 4.6.0, Compiler: MinGW; or
Qt: 4.5.1, Compiler: cl from M$VC 2005

wysota
13th September 2010, 16:39
Doesn't crash, sorry. Linux/x86, Qt4.7.0 snapshot. I do experience some temporary slowdowns after clicking the button many times however.

stillwaiting
13th September 2010, 16:44
Doesn't crash, sorry. Linux/x86, Qt4.7.0 snapshot. I do experience some temporary slowdowns after clicking the button many times however.

That's sad :(

stillwaiting
19th September 2010, 14:56
Anybody?...