Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QTreeView, QFileSystemModel, setRootPath and QSortFilterProxyModel with RegExp for filtering

Tags:

c++

qt

I need to show a QTreeView of a specific directory and I want to give the user the possibility to filter the files with a RegExp.

As I understand the Qt Documentation I can achieve this with the classes mentioned in the title like this:

// Create the Models
QFileSystemModel *fileSystemModel = new QFileSystemModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);

// Set the Root Path
QModelIndex rootModelIndex = fileSystemModel->setRootPath("E:\\example");

// Assign the Model to the Proxy and the Proxy to the View
proxyModel->setSourceModel(fileSystemModel);
ui->fileSystemView->setModel(proxyModel);

// Fix the TreeView on the Root Path of the Model
ui->fileSystemView->setRootIndex(proxyModel->mapFromSource(rootModelIndex));

// Set the RegExp when the user enters it
connect(ui->nameFilterLineEdit, SIGNAL(textChanged(QString)),
        proxyModel, SLOT(setFilterRegExp(QString)));

When starting the program the TreeView is correctly fixed to the specified directory. But as soon as the user changes the RegExp it seems like the TreeView forgets its RootIndex. After removing all text in the RegExp LineEdit (or entering a RegExp like ".") it shows all directories again (on Windows this means all drives and so on)

What am I doing wrong? :/

like image 810
Strayer Avatar asked Jul 09 '10 12:07

Strayer


2 Answers

I got a response from the Qt mailing list which explained this issue:

What I think is happening, is that as soon as you start filtering, the index you use as your root does no longer exist. The view then resets to an invalid index as the root index. The filtering works on the whole model tree, not just on the part you see if you start to enter your filter!

I think you are going to need a modified proxy model to do what you want. It should only apply the filtering on items under your root path, but let the root path itself (and everything else) alone.

So after subclassing QSortFilterProxyModel and some parent() checking in the function filterAcceptsRow() this does work as expected now!

like image 138
Strayer Avatar answered Nov 15 '22 10:11

Strayer


I found this through Google and worked out a solution based on this thread (and other Google results). You can find my solution at:

https://github.com/ghutchis/avogadro/blob/testing/libavogadro/src/extensions/sortfiltertreeproxymodel.h

https://github.com/ghutchis/avogadro/blob/testing/libavogadro/src/extensions/sortfiltertreeproxymodel.cpp

One thing you have to remember (that's not mentioned here) is that child rows are not automatically fetched by the QFileSystemModel, so you have to call fetchMore() on them. In my case, we only have one level of subdirectories, so it's fairly easy.

If your code wanted to handle more varied directory hierarchies, you'd need to change the for() loop near the bottom of filterAcceptsRow() to be recursive.

like image 28
Geoff Hutchison Avatar answered Nov 15 '22 09:11

Geoff Hutchison