PDA

View Full Version : QAbstractProxyModel to do a Tree



xgoan
17th November 2008, 13:12
Hi,

I have this code:


#include <QAbstractProxyModel> #include <QMap>
class ImageLandmarkTableModel;
class ImageLandmarkProxyModel : public QAbstractProxyModel
{
Q_OBJECT
public:
ImageLandmarkProxyModel(QObject *parent=0);
virtual QModelIndex index(int row, int column,
const QModelIndex &parent=QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex &index) const;
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const;
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
virtual void setSourceModel(ImageLandmarkTableModel *sourceModel);
ImageLandmarkTableModel* sourceModel() const;
QVariant data(const QModelIndex &index, int role) const;
protected slots:
void countRowsInserted(const QModelIndex &parent, int srcStart, int srcEnd);
void countRowsRemoved(const QModelIndex &parent, int srcStart, int srcEnd);
private:
struct ProxyLink {
int sourceRow; // Source row
QList<int> points; // List of source rows from the childs
};
typedef QMap<int,ProxyLink> MappingData;
MappingData m_mapping;
};

#include "imagelandmarkproxymodel.h" #include <QtSql>
#include "imagelandmarktablemodel.h"
ImageLandmarkProxyModel::ImageLandmarkProxyModel(Q Object *parent)
: QAbstractProxyModel(parent)
{
}
QModelIndex ImageLandmarkProxyModel::index(int row, int column,
const QModelIndex &parent) const
{
if(!parent.isValid()) // Root
return createIndex(row, column);
int id=m_mapping.keys().at(parent.row());
const ProxyLink &link=m_mapping[id];
return createIndex(link.points.at(row), column);
}
QModelIndex ImageLandmarkProxyModel::parent(const QModelIndex &index) const
{
return QModelIndex();
}
int ImageLandmarkProxyModel::rowCount(const QModelIndex &parent) const
{
const MappingData &m=m_mapping;
if(parent.isValid())
{
bool ok;
int id=parent.data().toInt(&ok); Q_ASSERT(ok);
return m[id].points.count();
}
return m.count();
}
int ImageLandmarkProxyModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QModelIndex ImageLandmarkProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
QModelIndex parent=proxyIndex.parent();
if(parent.isValid()){
int parentRow=parent.row();
int id=m_mapping.keys().at(parentRow);
const QList<int> &points=m_mapping[id].points;
return sourceModel()->index(points.at(proxyIndex.row()), 1);
}
int row=proxyIndex.row();
int id=m_mapping.keys().at(row);
const ProxyLink &link=m_mapping[id];
return sourceModel()->index(link.sourceRow, 0);
}
QModelIndex ImageLandmarkProxyModel::mapFromSource(
const QModelIndex &sourceIndex) const
{
return index(sourceIndex.row(), sourceIndex.column());
}
void ImageLandmarkProxyModel::setSourceModel(
ImageLandmarkTableModel *sourceModel)
{
disconnect();
QAbstractProxyModel::setSourceModel(sourceModel);
connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
SLOT(countRowsInserted(QModelIndex,int,int)));
connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
SLOT(countRowsRemoved(QModelIndex,int,int)));
}
ImageLandmarkTableModel* ImageLandmarkProxyModel::sourceModel() const
{
QAbstractItemModel *ptr=QAbstractProxyModel::sourceModel();
return static_cast<ImageLandmarkTableModel*>(ptr);
}
QVariant ImageLandmarkProxyModel::data(const QModelIndex &index, int role)
const
{
if(!index.isValid()) return QVariant();
QModelIndex parent=index.parent();
if(parent.isValid())
return mapToSource(index).data(role);
}
void ImageLandmarkProxyModel::countRowsInserted(const QModelIndex &parent,
int srcStart, int srcEnd)
{
const int idImageColumn=sourceModel()->column(
ImageLandmarkTableModel::IdImage);
const int idPointColumn=sourceModel()->column(
ImageLandmarkTableModel::IdPoint);
MappingData &m=m_mapping;
for(int i=srcStart;i<=srcEnd;i++)
{
QModelIndex col1=sourceModel()->index(i, idImageColumn);
QModelIndex col2=sourceModel()->index(i, idPointColumn);
bool ok;
int id=col1.data().toInt(&ok);
MappingData::iterator it=m.find(id);
Q_ASSERT(ok);
if(it!=m.end()) it->points.append(i);
else if(!col2.data().isNull()){
ProxyLink proxyLink;
proxyLink.sourceRow=i;
proxyLink.points.append(i);
m.insert(id, proxyLink);
}
else{
ProxyLink proxyLink;
proxyLink.sourceRow=i;
m.insert(id, proxyLink);
}
}
}
void ImageLandmarkProxyModel::countRowsRemoved(const QModelIndex &parent, int srcStart, int srcEnd)
{
// TODO: Do this slot
qCritical()<<"ImageLandmarkProxyModel::countRowsRemoved"<<"Unimplemented slot";
}
http://img126.imageshack.us/img126/8306/treeviewyr6.png

I can't solve this problem, I think the childs are pointing to the parents or something else.
Someone can help me?

xgoan
17th November 2008, 13:25
I think that the problem is with the QAbstractItemView:: parent (http://doc.trolltech.com/latest/qabstractitemview.html#parent), I don't know how to implement it.

caduel
17th November 2008, 22:10
If you describe what the code should do (rather than let us guess what your buggy code should be doing...) we would better be able to help.

You have to encode enough information when creating an index so you can find the information in your model.
In index() you have to encode the information about the parent. The parent() function basically is the inverse function to that. Given a node, unwrap the index and determine the parent.
There are several ways to do that. These differ in complexity and speed. It depends on the model which can be used. (E.g. for models with root-node-child but no grandchildren this is easy. It is not as simple for arbitrary hierarchies.) If we know what you want to achieve, we shall be able to advise you.

xgoan
18th November 2008, 17:31
I want to convert a plain QSqlTableModel that loads this view:


CREATE VIEW [dbo].[ImageLandmark] AS
SELECT [i].[Id] AS [IdImage], [l].[Id] AS [IdPoint],
[l].[X], [l].[Y], [l].[Size], [i].[Name], [i].[Thumbnail]
FROM [Image] AS [i]
LEFT JOIN [Landmark] AS [l] ON [i].[Id]=[l].[IdImage]
LEFT JOIN [User] AS [u] ON [u].[Id]=[l].[IdUser];

Into a tree view where the parent will be the IdImage and the childs the diferent Points.

Thanks