PDA

View Full Version : Using QFileSystemModel, QItemSelectionModel, QSortFilterProxyModel



Festus Hagen
8th July 2013, 00:17
Hi All,

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.

WinXPsp3
Qt5.0.2 and Qt Creator 2.7.0
TagLib2 (should work with all versions)

I started with the Qt GUI Application, and started adding bit by bit in the following steps.
1. directoryTreeView (QTreeView) and QFSMdirectoryView (QFileSystemModel), got it working.
2. filenameListView (QListView) and QFSMfilenameView (QFileSystemModel), got it working.
3. frameListView (QListView) and QSIMframeView (QStandardItemModel), got it working.

All works as expected ... Mouse only though, So I added:
4. directorySelectionModel (QItemSelectionModel), hooked it all up and got it working with the keyboard then added:
5. filenameSelectionModel (QItemSelectionModel), hooked it all up and got it working with the keyboard.

Now all is good everything works as expected, Except sorting and filtering, So I added:
6. directoryProxyModel (QSortFilterProxyModel) for SORT purposes.

Sorting the directoryTreeView works ... However:

Question:
How do I get the directoryTreeView selected path (used to setRootIndex for filenameListView) in
void MainWindow::directorySelectionChanged(...)
Looking at (at very end of MainWindow.cpp)
void MainWindow::directorySelectionChanged(...) one can see how I did it prior to adding QSortFilterProxyModel.

MainWindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileSystemModel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QSortFilterProxyModel>
#include <QMessageBox>

#include <mpegfile.h>
#include <id3v2tag.h>

#define MyQStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

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

private slots:
void on_actionExit_triggered();

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

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

private:
Ui::MainWindow *ui;
QFileSystemModel *QFSMdirectoryView;
QFileSystemModel *QFSMfilenameView;
QStandardItemModel *QSIMframeView;
QItemSelectionModel *directorySelectionModel;
QItemSelectionModel *filenameSelectionModel;
QSortFilterProxyModel *directoryProxyModel;
};

#endif // MAINWINDOW_H

MainWindow.cpp


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

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

QString qsPath = QDir::currentPath();

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

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

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

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

QFSMdirectoryView->setRootPath(qsPath);

QFSMfilenameView = new QFileSystemModel(this);
QFSMfilenameView->setFilter(QDir::Files | QDir::NoDotAndDotDot);
ui->filenameListView->setModel(QFSMfilenameView);

QSIMframeView = new QStandardItemModel(this);
ui->frameListView->setModel(QSIMframeView);

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

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

void MainWindow::on_actionExit_triggered()
{
close();
}

void MainWindow::filenameSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
QSIMframeView->clear();

TagLib::String sfn = MyQStringToTString(QFSMfilenameView->filePath(filenameSelectionModel->currentIndex()));

TagLib::MPEG::File f(sfn.toCString());

TagLib::ID3v2::Tag *id3v2tag = f.ID3v2Tag();
if(id3v2tag)
{
for(TagLib::ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin(); it != id3v2tag->frameList().end(); ++it)
{
TagLib::String fid = (*it)->frameID();
QStandardItem *child = new QStandardItem(QString("%1 : %2").arg(TStringToQString(fid)).arg(TStringToQString( (*it)->toString())));
QSIMframeView->appendRow(child);
}
} else {
QStandardItem *child = new QStandardItem(QString("ERROR: No valid tag!"));
QSIMframeView->appendRow(child);
}
}

void MainWindow::directorySelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{

qDebug("directoySelectionChanged fired.");

// QString qsPath = QFSMdirectoryView->fileInfo(directorySelectionModel->currentIndex()).absoluteFilePath();
// ui->filenameListView->setRootIndex(QFSMfilenameView->setRootPath(qsPath));
}


Thanks all

-Enjoy
fh : )_~

anda_skoa
8th July 2013, 08:47
The indexes in the selection are now from the proxy model, the directory model doesn't understand them.

You have two options:
1) use the mapToSource() function of the proxy model to get an index that the source model understands
2) retrieve the data directly through the index using the data() method of QModelIndex and the item role for the data aspect you want (in your case most likely QFileSystemModel::FilePathRole)

Cheers,
_

Festus Hagen
9th July 2013, 10:13
Yea, I understood the proxy took over, I had tried both ways, got nowhere with MapToSource, Docs confused me. With the data() method all I could get back was the un-qualified directory name (ie: no path), And that is because I didn't have the missing key: QFileSystemModel::FilePathRole!

Thank you!

The fixed directorySelectionChanged:


void MainWindow::directorySelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
ui->filenameListView->setRootIndex(QFSMfilenameView->setRootPath(directorySortFilterModel->data(selected.indexes()[0], QFileSystemModel::FilePathRole).toString()));
}


Think I'm going to change selectionChanged(...) to currentChanged(...) and use QModelIndex versus QItemSelection ...

Thanks

-Enjoy
fh : )_~