PDA

View Full Version : Help with QAbstractProxyModel



killerwookie99
11th September 2008, 16:42
Ok, I am still learning Qt4 and trying to understand how to do things correctly, or as correct as they can be.

Here is my situation. I want to make use of QDirModel, but it doesn't have everything that I need, so I made an inherited class, MyDirModel.

MyDirModel adds a few extra columns to QDirModel on population.

Then I have a couple of QAbstractProxyModels because I want to display the data differently. I have a FolderTreeProxyModel and a FolderListTreeProxyModel. One displays only a few columns and folders only the other displays all columns and files and folders.

Finally I have two custom QTreeView classes. FolderTree and FolderListTree. Which I set the model FolderTreeProxyModel and FolderListProxyModel respectively.

Now here's where I am not sure if I am doing this correctly or not. How do I reference indexes from MyDirModel, do I have to reimplement all the sorting searching loading functions?

Example:


...
connect(folderTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(setRootIndex(QModelIndex)));

...

void mainwindow::setRootIndex(QModelIndex index)
{
QModelIndex dir = index.sibling(index.row(), 0);

if (!myDirModel->isDir(dir))
{
dir = dir.parent();
}

if (dir != folderListTree->rootIndex() && myDirModel->isDir(dir))
{
folderListTree->setCurrentIndex(index);
folderListTree->setCurrentIndex(index);
lineEdit->setText(myDirModel->filePath(dir));
}
}


This won't work because the index is from MyDirModel? I am kinda confused on this abstraction process any ides/suggestions would be greatly appreciated!

-KW

wysota
11th September 2008, 17:27
There are two things to do:
1. Always use index objects with models they are owned by.

2. If an index is from a different model than you expect, convert it to a proper one. I use something like this:

QModelIndex index;
QAbstractItemModel *model;
while((QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel*>(model))!=0){
model = proxy->sourceModel();
index = proxy->mapToSource(index);
}
After that you'll get an index and model pair referring to the bottom-most (non-proxy) model.

killerwookie99
11th September 2008, 21:05
I am doing the following and it returns empty path:



connect(folderTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(folderTreeClicked(QModelIndex));

void mainwindow::folderTreeClicked(QModleIndex &index)
{
QModelIndex dir = folderTreeModel->mapFromSource(index).sibling(index.row(), 0);

lineEdit->setText(myDirModel->filePath(dir));

cout << lineEdit->text().toStdString() << endl; // always blank
return;
}


Do I have to re-implement MyDirModel::filePath? Or do change the way I'm getting dir index?

Thanks,
-KW

wysota
11th September 2008, 21:47
You should be mapping to source, not from source, don't you think? The index you get is the one you clicked in the view and the view's model is the proxy therefore to reach the real dir model you have to convert the index from the proxy to the source model. In doubt you can call QModelIndex::model() to see what model you are dealing with. For instance try:

qDebug() << QModelIndex::model()->metaObject()->className();

killerwookie99
12th September 2008, 01:13
I appreciate your help, I am just slow in understanding. So I tried the following in the same function to see what comes out still a blank entry...



...

qDebug() << index.model()->metaObject()->className();

qDebug() << myDirModel()->fileName(index);

...


Output:

FolderTreeModel
""

Thanks for the qDebug() btw, sweet.

-KW

wysota
12th September 2008, 02:17
And what about index.row() and index.column()? FolderTreeModel is the proxy isn't it? myDirModel() is of type FolderTreeModel or other?

killerwookie99
12th September 2008, 02:52
Hmm maybe I am doing this wrong? Here are the class definitions:

MyDirModel : public QDirModel

FolderTreeModel : public QAbstractProxyModel
->setSourceModel(MyDirModel)

FolderTreeView : public QTreeView
->setModel(FolderTreeModel)

... I am trying to display things about files that Qt doesn't understand and I want to be able to control the loading of how QDirModel loads the files, because it doesn't understand the filesystem completely either... Am I doing things in the wrong order?

-KW

wysota
12th September 2008, 03:21
Well.. certainly trying to access an index from FolderTreeModel with a MyDirModel is something I would call wrong. When you take an index from the view it references the model set on the view. And in your case this model is the proxy around the base model. To be able to call methods from the base model, you need to convert the index to the proper model. To do that you have to call mapToSource on the proxy, passing it the index taken from the view. In return you will receive an index that is related to the source model of the proxy - in your case the base model you seek to use.


QModelIndex index = folderTreeView->currentIndex();
QModelIndex baseIndex = folderTreeModel->mapToSource(index);
QString xyz = myDirModel->fileName(baseIndex);

Of course I'd do it differently:

QModelIndex index = folderTreeView->currentIndex();
const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>(index.model());
while(proxy!=0){
index = proxy->mapToSource(index);
proxy = qobject_cast<const QAbstractProxyModel*>(index.model());
}
QString xyz = myDirModel->fileName(index);

killerwookie99
12th September 2008, 15:18
Wow, lol ok, so I see now. :o

On your second example, what exactly is this doing:



const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>(index.model());

while(proxy!=0){
index = proxy->mapToSource(index);
proxy = qobject_cast<const QAbstractProxyModel*>(index.model());
}


Is it to keep the proxy and index in sync? Thanks for being patient with me :(

wysota
12th September 2008, 23:13
I already explained it in post #2. It converts the index to the one belonging to a non-proxy model.