PDA

View Full Version : fetchMore() not working on the top-level index in a QFileSystemModel



Guett_31
3rd April 2013, 05:35
The directoryLoaded() signal is never emitted after calling fetchMore() on the top-level index (QModelIndex()) in a QFileSystemModel. CanFetchMore() returns true though...

I use fetchMore() to be able to determine how many item are under a given index by using rowCount() after receiving directoryLoaded() signal. It works well for any item in my QFileSystemModel except for the top level one.

Does anybody know why? How can I get this to work?

Thanks

In other words, how can I determine how many drives my file system has? (C:, D:, etc... I'm working on windows)

wysota
3rd April 2013, 07:57
QDir::drives()

Guett_31
3rd April 2013, 18:27
QDir::drives() gives me access to the number of drives, however it does it doesn't help for what I'm trying to do. I actually need to work indexes.
I should not have put the last stentence in previous post... sorry.

Here is the context.
I'm not happy with the way QTreeView shows a tree sctructue. It shows it starting form the RootIndex's index chidren, not from RootIndex itself.

Expected: (each "-" represents a level)
-Root_item(1)
-- item(1,1)
--- item(1,1,1)
--- item(1,1,2)
--- item(1,1,3)
-- item(1,2)
--- item(1,2,1)
--- item(1,2,2)
-- item(1,3)

Actual:
-- item(1,1)
--- item(1,1,1)
--- item(1,1,2)
--- item(1,1,3)
-- item(1,2)
--- item(1,2,1)
--- item(1,2,2)
-- item(1,3)

I modified the behavior of setRootIndex() in my QTreeView, so it acctually sets the RootIndex one level higher, on the specified index's parent, and it hides all its chidren execpt the specified index using setRowHidden(). It works pretty well for any indexes in the QFileSystemModel except for the QFileSystemModel's topindex. (...if I want to display C:/ and its tree scructure for example).

I tried QDir::drives() like you suggested. It is a work arround that helps me to get the number of items under the QFileSystemModel topindex instead of using QFileSystemModel:rowCount. I can then use a For Loop to apply QTreeView::setRowHidden() on each item but one like I do in the other cases. But it seems that QTreeView::setRowHidden() does not even work in that case. And I think this is because the data under the topindex is not loaded yet in the model at that point, which bring me to the original problem:
The directoryLoaded() signal is never emitted after calling fetchMore() on the top-level index in a QFileSystemModel.

wysota
3rd April 2013, 18:47
To be honest I think you are going the wrong way. It seems easiest to obtain what you want by implementing a simple proxy model that would add the additional parent item to the model.

Guett_31
5th April 2013, 00:03
Thank you for your suggestion. I liked my way, but I gave a try to yours. I never worked with proxy models before, so it is a good trainning anyway.

The result is that I'm falling in the exact same situation than before. I managed to setup a "transparent" proxi that does not do anything between my QFileSystemModel and my QtreeView in the first place. That worked well.
Now, when I try to insert a new index in the proxi to do the trick, I still have to deal with the fact that my QFileSystemModel source model populates incrementally. I cannot insert new index if the data of the trageted parent for the insertion is not loaded first in the QFileSystemModel. I have to use fetchMore() to do that, and since the loading process is asynchroneous, I have to "wait" until the corresponding directoryLoaded() signal is emitted to procced with the insertion. I end up with the same problem I had earlier. It works fine for any indexes execpt for the top-level index for which directoryLoaded() is never emitted after fetchMore() is querried...
I'm back to the same issue...

wysota
5th April 2013, 01:01
In that case maybe I simply fail to see what your problem is. I thought the problem was that you wanted to add an artificial index on top of the file system model. Now it seems you have problems with the file system model itself, at least if I understand you correctly.

Guett_31
5th April 2013, 03:07
Both actually. My intend is to display the root index at the top of the tree view. To do that I tried two different approches:
#1: Modify the setRootIndex() in my QTreeView to look one level higher and hide all the siblings of my original target index (my approch)
#2: Use a proxy model to insert an artificial index right above the targeted index and then point at that artificial index as the root index.

The two approches are valid but they fail to works with the top-level item. In both cases the nature of the QFileSysemModel requires the use of fetchMore() and directoryLoaded() signal, and
fetchMore() does not work with the top-level item...

Here is a little experiment to demonstrate the problem: (See attached the entire project)


#include "SATT_MainWindow.h"

SATT_MainWindow::SATT_MainWindow(): QWidget()
{
setFixedSize(900,600);

//creates Run button

m_model = new QFileSystemModel(this);
m_view = new QTreeView(this);
m_view->setFixedSize(900,600);
m_model->setRootPath(QDir::currentPath());
m_view->setModel(m_model);
QObject::connect(m_model, SIGNAL(directoryLoaded(QString)), this, SLOT(someSlot(QString)));

QModelIndex root = m_model->index("C:/");
if (m_model->canFetchMore(root))
{
m_model->canFetchMore(root);
}
m_view->setRootIndex(root);
}

void SATT_MainWindow::someSlot(const QString &path)
{
int rowCountTest = (m_model->rowCount(m_model->index(path)));
}

Put a break point at line 19 and at line 26.
If you run it like this the execution will first stop at line 19, then once the the QFileSystemModel has finished working in the background, the directoryLoaded signal is emitted. It is caught by the slot and the execution stops at line 26. You can excute the step 26 and you can verify that rowCount() sends the right number of element under C:/ (meaning that the data the index is loaded).
Now if you replace line 16 by:

QModelIndex root = QModelIndex();
QModelIndex() beeing the top-item for any tree structue, It won't work. The execution will stop at line 19, but will never stop at line 25 FOR THAT FETCHMORE() CALL...

Guett_31
5th April 2013, 08:19
Sorry, I meant: m_model->fetchMore(root); on line 19 of course :)

wysota
6th April 2013, 10:10
And how did you implement the proxy model for your model?

Guett_31
8th April 2013, 22:14
I have implemented the proxi model in the view itself, because only that view needs that trick with an artificial index to display the rootindex.
I create the proxi model when I call setModel(). SetModel() is called with the source model.


void FileSysSelectView::setModel(QAbstractItemModel * model)
{

m_sourceModel = static_cast<FileSysSelectModel *> (model);
m_proxiModel = new QSortFilterProxyModel();
m_proxiModel->setSourceModel(m_sourceModel);

QTreeView::setModel(m_proxiModel);

// Limit the view to the File name Column (1st Column)
for (int i(1); i < m_proxiModel->columnCount(QModelIndex::QModelIndex()); i++) this->setColumnHidden(i,true);
}
At that point everything works well, my proxi model sits bettween my view and the source model, and it acts transparently.
I try to insert the artificial index when I call setRootIndex().

For exemple, if I want to show what is under C:/, I have to do the folowing:

before:
- root
--C:\
---Program Files
---Windows
---Users
--D:\
--X:\

after:
- root
-- artififical index
---C:\
----Program Files
----Windows
---Users
--D:\
--X:\

void FileSysSelectView::setRootIndex(const QModelIndex & index)
{

// insert a new index under the specified root index.
QModelIndex idxParent = m_proxiModel->mapFromSource(index.parent());
m_proxiModel->insertRow(0, idxParent);

// move the the root index under the new index
QModelIndex idxNew = m_proxiModel->index(0,0, idxParent);
QModelIndex idx = m_proxiModel->mapFromSource(index);
int idxPosition = idx.row();
m_proxiModel->moveRow(idxParent, idxPosition, idxNew, 0);
QTreeView::setRootIndex(idx);
}
Actually int idxPosition = idx.row() at line 11 doesn't work for the reasons I mentioned earlier in the thread. The underlying QFileSystemModel needs to be populated before idx.row() is called. That means I have to call fetchMore() and check for directroyLoaded() signal in that situation too...

Guett_31
9th April 2013, 00:51
Also, I have found another old thread from a different forum that said:

"Regarding folder sorting on Windows: I think I got it. The damn model only sorts items below its "root path()" as the statrting point which is "/" on Linux /UNIX / Mac Os X, but on windows it's the system driver's root directory. Effectively, only "c:/" and it's sub-folders were sorted...
Now I'm using "QFileSystemModel::myComputer" as the model's root and as a result everything is sorted as expected."

http://forums.bannister.org/ubbthreads.php?ubb=showflat&Number=68709&page=289

That might be related to my issue. I don't know how that person managed to use "QFileSystemModel::myComputer" as the model's root, though... it does not retrun a QModelIndex.

wysota
9th April 2013, 07:37
A sort-filter proxy model can't do what you require. You have to implement your own proxy model derived either from QAbstractProxyModel or from QIdentityProxyModel.

Guett_31
10th April 2013, 00:46
QIdentityProxyModel is what I tried in the first place. It didn't work either. I'm not familiar whith proxi models. why do I need my own proxi? Could you give my some guidance or some useful links...
I search the internet without any success for that...

wysota
10th April 2013, 07:15
QIdentityProxyModel is what I tried in the first place. It didn't work either.
It won't "work" because it is a transparent proxy. You need to subclass it and implement the functionality you need.


I'm not familiar whith proxi models. why do I need my own proxi?
Because you want to add an artificial item to an existing model without changing the original model itself.