PDA

View Full Version : how to setRootPath(...) on a QSortFilterProxyModel of a QFileSystemModel



Festus Hagen
10th July 2013, 20:49
Hi all,

WinXPsp3
Qt5.0.2 and Qt Creator 2.7.0

My first Qt GUI App ... been coding C for many many years, have simple basic C++ skills, no GUI experience, Very little OO experience.
So ALL explained comments and suggestions welcome.
I'm it it to learn, so if there is a better way ...

The goal:
To have a sorted directory only TreeView on the left, the files of the currently selected directory are listed (filtered and sorted) in the ListView (or TableView) in the middle, the elements of the currently selected file are listed in the (yet to be added) TableView to the right.

Info:
A TreeView populated with QFileSystemModel wrapped with a QSortFilterProxyModel purely for sort, no filters ... There is also a QItemSelectionModel attached!
A ListView populated with QFileSystemModel wrapped with a QSortFilterProxyModel for sort and filter purposes ... There is also a QItemSelectionModel attached.

Question 1:
Once the proxyModel is attached, how does one setRootPath(...) of the under laying QFileSystemModel.
I also need the QModelIndex returned from that setRootPath(...) call as well.

See commented code at end of .cpp to see how I had previously done it prior to the proxyModel.

Have tried many things, to many to list all (besides I'm sure I've forgotten more then I remember)
Like casting the proxies sourceModel(...) as I've seen others do in my searches.

Question 2:
Maybe my whole design is flawed?

For the ui:
TreeView named directoryTreeView
ListView named filenameListView

The code:


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileSystemModel>
#include <QItemSelectionModel>
#include <QSortFilterProxyModel>
#include <QtDebug>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void filenameSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);

void directorySelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);

private:
Ui::MainWindow *ui;
// directory Tree View
QFileSystemModel *QFSMdirectoryView;
QItemSelectionModel *directorySelectionModel;
QSortFilterProxyModel *directorySortFilterModel;
// filename List View
QFileSystemModel *QFSMfilenameView;
QItemSelectionModel *filenameSelectionModel;
QSortFilterProxyModel *filenameSortFilterModel;
};

#endif // MAINWINDOW_H



#include "MainWindow.h"
#include "ui_MainWindow.h"

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

QString qsPath = QDir::currentPath();

// directory Tree View
QFSMdirectoryView = new QFileSystemModel(this);
QFSMdirectoryView->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);

directorySortFilterModel = new QSortFilterProxyModel(this);
directorySortFilterModel->setSourceModel(QFSMdirectoryView);
directorySortFilterModel->sort(0, Qt::AscendingOrder);

ui->directoryTreeView->setModel(directorySortFilterModel);
ui->directoryTreeView->setSortingEnabled(true);
ui->directoryTreeView->setColumnHidden(1, true);
ui->directoryTreeView->setColumnHidden(2, true);
ui->directoryTreeView->setColumnHidden(3, true);

directorySelectionModel = new QItemSelectionModel(directorySortFilterModel);
ui->directoryTreeView->setSelectionModel(directorySelectionModel);
connect(directorySelectionModel, SIGNAL(selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT(directorySelectionChanged(QItemSelection,QIte mSelection)));

QFSMdirectoryView->setRootPath(qsPath);

// filename List View
QFSMfilenameView = new QFileSystemModel(this);
QFSMfilenameView->setFilter(QDir::Files | QDir::NoDotAndDotDot);

filenameSortFilterModel = new QSortFilterProxyModel(this);
filenameSortFilterModel->setSourceModel(QFSMfilenameView);
filenameSortFilterModel->sort(0, Qt::AscendingOrder);

ui->filenameListView->setModel(filenameSortFilterModel);

filenameSelectionModel = new QItemSelectionModel(filenameSortFilterModel);
ui->filenameListView->setSelectionModel(filenameSelectionModel);
connect(filenameSelectionModel, SIGNAL(selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT(filenameSelectionChanged(QItemSelection,QItem Selection)));
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::filenameSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
QString qsPath = QFSMfilenameView->filePath(selected.indexes()[0]);
qDebug() << "Selected filename: " << qsPath;
}

void MainWindow::directorySelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
QString qsPath = directorySortFilterModel->data(selected.indexes()[0], QFileSystemModel::FilePathRole).toString();

// Obviously this no longer works with the proxy ...
// QModelIndex index = QFSMfilenameView->setRootPath(qsPath);
// ui->filenameListView->setRootIndex(index);
}

-Enjoy
fh : )_~

ChrisW67
10th July 2013, 22:13
Keep a pointer to the source model and call setRootPath() on that. Take the returned QModelIndex and call mapFromSource() on the proxy model to get a filtered-side index that corresponds

Festus Hagen
10th July 2013, 23:36
You mean like this ...


QFSMfilenameView = new QFileSystemModel(this);

and


QModelIndex index = QFSMfilenameView->setRootPath(qsPath);


-Enjoy
fh : )_~

ChrisW67
11th July 2013, 00:29
QModelIndex sourceIndex = QFSMfilenameView->setRootPath(qsPath); // gives a model index on the original model
QModelIndex proxyIndex = filenameSortFilterModel->mapFromSource(sourceIndex); // converts that to an index on the proxy
// do something with the view(s) using the proxy index
ui->filenameListView->setRootIndex(proxyIindex);

You need the index on the proxy because those are the indexes the view(s) you have attached to the proxy will see and use.

Festus Hagen
11th July 2013, 00:49
I have done exactly that excluding the proxyIndex (had it at one time), no point in having it because the code


QFSMfilenameView->setRootPath(qsPath);

Returns an invalid index after the QSortFilterProxyModel has been attached.

And yes, qsPath is valid.

EDIT:
Off topic, but ... What tags are used to get the Qt objects to link to the docs like you do in your posts?

-Enjoy
fh : )_~

ChrisW67
11th July 2013, 05:04
The base model is unaware of the proxy which interacts with it no differently than a view would. I guess the question is, what are you trying to achieve?

Many Qclasses are linked automatically when they are inside
tags. Outside of code use can use or

Festus Hagen
11th July 2013, 14:03
Hate to be a dink ... But!

Did you even read the OP?

Everything that has been discussed so far (other then the Markup tags) is in the unedited OP.
Including the goal!

Thanks for the [qtclass] markup tags.

-Enjoy
fh : )_~

ChrisW67
12th July 2013, 00:26
Yes I read the OP. At your kind invitation I have re-read it. Your variable naming had me mildly confused (e.g. models and views with names ending View) and I was assuming that both views sat on the same model. There's no mention of mapFromSource() in your OP, so you've learned something new there.

You are retrieving a path from the directory view. You have a correct path to a directory.

You want that path to be the root of the file view. You need the index of that path in the model underlying the file view and QFileSystemModel::index() does that.


QModelIndex index = QFSMfilenameView->index(qsPath);
// your view is sitting on the top of a proxy you need to map the index to a proxy index:
QModelIndex proxyIndex = filenameSortFilterModel->mapFromSource(index);
// before you can use that to set the root of the file view:
ui->filenameListView->setRootIndex(proxyIndex);

Unfortunately this doesn't work because QFSMfilenameView is filtered to exclude directories, and the path you are supplying is a directory, so there is no index in the source model for that path. As a result, both indexes are invalid and the file view does not behave as expected. If you remove the filter on the QFSMfilenameView the indexes are good but the file view displays directories you don't want.

I cannot see a straightforward way to make this work with the models as is. You may be able to use the file proxy to filter on QFileSystemModel::type() to exclude "Directory" or "Folder".

Festus Hagen
12th July 2013, 01:00
Beautiful ... I understand!

As already stated I removed the proxyIndex (mapToSource) for the post, it wasn't working, not needed for the question.

Yup, I agree about the "View" variable names on the data models... I already changed them to be more inline with the others. Hey, It's where I started!

Working on trying to come up with a different design, ain't visioned one yet ...

Thank you

-Enjoy
fh : )_~