PDA

View Full Version : Issues with Qfilesystemmodel proxies



Guett_31
25th July 2013, 08:24
I have been trying to use proxy models with a QFileSystemModel for a while and I have not been very successful.
The idea is to use a QFileSystemModel for my entire application and several layers of proxies on top of it to display the data different ways in different views. One of these views is a selection view that allows me to select folders and files. The selection of any folder would automatically select all its subfolders and files.
I have been successful designing that selection mechanism by directly subclassing the QFileSystemModel class, but I was not able to implement it in a proxy that would be used in series with other proxies on the QFileSystemModel.

Here is the Selection_Proxy code: (might not be necessary to understand the overall issue)

class SelectItemProxyModel : public IdentityFileSystemProxyModel
{
Q_OBJECT
protected:

QSet<QPersistentModelIndex> m_checkTable;
QVariant m_noData;
QVariant m_checkValueToUpdate;

QModelIndex m_loadAllDataUnderIndex;
bool m_dataFetchingInProgress;
std::vector<QPersistentModelIndex> m_indexesToBeFetched;
void loadAllDataUnder(const QModelIndex &index);
void loadAllDataUnder_itteration(const QString &currentPath);

public:
SelectItemProxyModel(QObject *parent = 0);

//re-arranged relays.
QVariant data(const QModelIndex &index, int role) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);

signals:
void allDataFetchingStart(const QModelIndex &index);
void allDataFetchingStop(const QModelIndex &index);

public slots:
void dataReady(const QString &currentPath);
};

#include "SelectItemProxyModel.h"

SelectItemProxyModel::SelectItemProxyModel(QObject *parent) : IdentityFileSystemProxyModel(parent),
m_dataFetchingInProgress(false),
m_loadAllDataUnderIndex(QModelIndex())
{
QObject::connect(this,SIGNAL(directoryLoaded(QStri ng)),this,SLOT(dataReady(QString)));
}

QVariant SelectItemProxyModel::data(const QModelIndex &index, int role) const
{
//Returns data from the source model.
if (role == Qt::CheckStateRole) return m_checkTable.contains(index)? Qt::Checked : Qt::Unchecked;
//Removes all decoration are removed from the source model.
if (role == Qt::DecorationRole) return m_noData;
//Returns data from the source model.
return m_model->data(mapToSource(index), role);
}

Qt::ItemFlags SelectItemProxyModel::flags(const QModelIndex &index) const
{
if (m_dataFetchingInProgress == true)
{
// Prevents the data to be modified by the user when it is being updated by loadAllDataUnder()
return Qt::NoItemFlags;
}
else
{
//Sets all elements as user checkable.
return m_model->flags(mapToSource(index)) | Qt::ItemIsUserCheckable;
}
}

bool SelectItemProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
//Sets check state (checked or unchecked) on the specified proxy's item and all items under.
if (role == Qt::CheckStateRole)
{
//Sets check state (checked or unchecked) of the specified proxy's item.
if(value == Qt::Checked) m_checkTable.insert(index); else m_checkTable.remove(index);
emit dataChanged(index, index);
//Sets check state (checked or unchecked) of all the items under.
loadAllDataUnder(index);
return true;
}
// regular QFileSystemModel case.
return m_model->setData(mapToSource(index), value, role);
}

void SelectItemProxyModel::loadAllDataUnder(const QModelIndex &index)
{
m_loadAllDataUnderIndex = index;
//If the specifed index does not have children if a "data loading process" is already running, do not
//start a new one.
if ((hasChildren(index))||(m_dataFetchingInProgress == false))
{
m_checkValueToUpdate = data(index, Qt::CheckStateRole);
m_dataFetchingInProgress = true;
emit allDataFetchingStart(index);
m_indexesToBeFetched.push_back(QPersistentModelInd ex(index));
if (canFetchMore(index))
{
fetchMore(index);
}
else
{
// If the data of the current index has alreday been loaded, send a directoryLoaded signal so the item can
// still be processed in loadAllDataUnder_itteration().
emit directoryLoaded(filePath(m_loadAllDataUnderIndex)) ;
}
}
}

// Processes the data of the last elmt of m_indexesToBeFetched and feeds m_indexesToBeFetched with the next items to be fetched until
// m_indexesToBeFetched is empty.
void SelectItemProxyModel::loadAllDataUnder_itteration( const QString &currentPath)
{
//Check if the loaded data is relevant for loadAllDataUnder_itteration()
if(m_dataFetchingInProgress == false)return;
QModelIndex currentIndex = m_indexesToBeFetched[m_indexesToBeFetched.size()-1];
if(filePath(currentIndex) != currentPath) return;

//Remove currentIndex from the m_indexesToBeFetched queue.
m_indexesToBeFetched.pop_back();
int elmtCount = rowCount(currentIndex);
QModelIndex indexFirst = index(0,0,currentIndex);
QModelIndex indexLast = index(elmtCount-1,0,currentIndex);
//Examine the children of the current index.
for (int i(0); i < elmtCount; i++)
{
QModelIndex currentChildIndex = index(i,0,currentIndex);
//Check or uncheck elmts depending on m_checkValueToUpdate value. (value of the top parent set by the user)
if (m_checkValueToUpdate == Qt::Checked) m_checkTable.insert(currentChildIndex); else m_checkTable.remove(currentChildIndex);
//Queue the elmts that have chidren (directories) in m_indexesToBeFetched for next rounds.
if (hasChildren(currentChildIndex))m_indexesToBeFetch ed.push_back(currentChildIndex);
}
emit dataChanged(indexFirst, indexLast);

if (m_indexesToBeFetched.empty())
{
//All the nodes and branches branches have been explored. All the data has been loaded into the view.
m_dataFetchingInProgress = false;
emit allDataFetchingStop(m_loadAllDataUnderIndex);
}
else
{
// Fetch the data of the last element in m_indexesToBeFetched.
currentIndex = m_indexesToBeFetched[m_indexesToBeFetched.size()-1];
if(canFetchMore(currentIndex))
{
fetchMore(currentIndex);
}
else
{
// If the data of the current index has alreday been loaded, send a directoryLoaded signal so the next item in the process
// can be processed else fetch data of the current index.
emit directoryLoaded(filePath(currentIndex));
}
}
}

//Slot called when the model has finished loading data under an index.
void SelectItemProxyModel::dataReady(const QString &currentPath)
{
loadAllDataUnder_itteration(currentPath);
}
If I use that proxy alone between the QFileSystemModel and my view (such as Model->Selection_Proxy->View), it works.
If I use it with other proxies (like these Model->Proxy1->Proxy2->Selection_Proxy->View) then the Selection_Proxy acts weird. It doesn't select some of the subfolders and some of the files. it always misses the same ones.
One important thing is that all my Proxies are subclassed from the IdentityFileSystemProxyModel Class, which is subclassed itself from the QIdentityProxyModel class.

Here is the IdentityFileSystemProxyModel code:

class IdentityFileSystemProxyModel : public QIdentityProxyModel
{
Q_OBJECT

protected:
QAbstractItemModel * m_model;

public:
IdentityFileSystemProxyModel(QObject *parent = 0);
void setSourceModel(QAbstractItemModel * sourceModel);
virtual int columnCount(const QModelIndex & parent) const;
virtual QString filePath(const QModelIndex & index) const;

signals:
void directoryLoaded(const QString &path);

public slots:
void directoryLoadedSlot(const QString &path);
};

#include "IdentityFileSystemProxyModel.h"

IdentityFileSystemProxyModel::IdentityFileSystemPr oxyModel(QObject *parent) : QIdentityProxyModel(parent)
{
}

void IdentityFileSystemProxyModel::setSourceModel(QAbst ractItemModel * sourceModel)
{
m_model = sourceModel;
QIdentityProxyModel::setSourceModel(m_model);
QObject::connect(m_model,SIGNAL(directoryLoaded(QS tring)),this,SLOT(directoryLoadedSlot(QString)));
}

int IdentityFileSystemProxyModel::columnCount(const QModelIndex & parent) const
{
return 1;
}

QString IdentityFileSystemProxyModel::filePath(const QModelIndex & index) const
{
return QIdentityProxyModel::data(index, Qt::UserRole + 1).toString();
}

void IdentityFileSystemProxyModel::directoryLoadedSlot( const QString &path)
{
emit directoryLoaded(path);
}
The reason for the IdentityFileSystemProxyModel class is that I have to deal with the fact that a QFileSystemModel model populates incrementally and its loading process is asynchronous. Therefore, I have to relay the QFileSystemModel’s directoryLoaded() signal throughout the proxy chain because some of the proxies call fectchMore() and have to “wait” until the data is loaded to use them. (That is the case with my Selection_Proxy)
I tried to narrow down the problem and I figured out that the problem was still the same when I did this:
Model->IdentityFileSystemProxyModel->Selection_Proxy->View.
Therefore, I really think that the problem has to do with the IdentityFileSystemProxyModel class and the way I relay the QFileSystemModel specific information throughout the he proxy chain.

I would really appreciate some help! Thanks