Reputation: 31
So I'm using a slightly custom QSortFilterProxyModel
(just implemented the filterAcceptsRows
) in order to filter elements from a QStandardItemModel
. Currently it filters perfectly using setFilterRegExp
but the problem I am having is that since the ProxyModel
only searches the elements, I lose the structure. For example lets say I have this structure:
Root Folder 1
|----Sub Folder 1
|-----Item 1
|-----Item 2
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
Root Folder 2
|----Sub Folder 1
|-----Item 1
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
After I'm done filtering say by filtering if the items
name contains '2' I get
Item 2
Item 2
Item 2
Preferably I would like it to output:
Root Folder 1
|----Sub Folder 1
|-----Item 2
|----Sub Folder 2
|-----Item 2
Root Folder 2
|----Sub Folder 2
|-----Item 2
I was thinking of using the original model and just removing the elements if they don't match but that definitely seems the wrong way to go about it. I've tried getting the parent in filterAcceptsRows
but it always seems to be null.
It seems like this would be an easy thing to do or just a setting I missed, but any help would be greatly appreciated!
Thanks!
Upvotes: 0
Views: 223
Reputation: 12879
What you appear to want is that filterAcceptsRow
should return true if either the row itself passes a test or any of its descendants pass the test.
Based on that you might want to try something fairly basic such as...
class sort_filter_proxy: public QSortFilterProxyModel {
public:
virtual bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const
{
if (!source_parent.isValid())
return true;
return test(source_parent.model()->index(source_row, 0, source_parent));
}
private:
bool test (const QModelIndex &source_index) const
{
if (!filterRegExp().isValid())
return true;
/*
* Test source_index itself.
*/
if (source_index.data(filterRole()).toString().contains(filterRegExp()))
return true;
/*
* Test the children of source_index.
*/
for (int row = 0; row < source_index.model()->rowCount(source_index); ++row)
if (test(source_index.model()->index(row, 0, source_index)))
return true;
/*
* Neither source_index nor any of its descendants passed the test.
*/
return false;
}
};
It's a bit 'brute force' in that the same row may end up being tested multiple times, but if your model isn't too big that shouldn't be a problem. A better algorithm would use extra data in a user defined model role to cache the results generated by the calls to sort_filter_proxy::test
.
Upvotes: 1