adzajac
27th October 2010, 09:26
Hi everybody.
I know that similar posts were here on the forum but as I saw usually threads were finished with the conclusion that maybe different model should be used instead of QAbstractProxyModel.
The problem :
Right now I've a tree model based on QAbstractItemModel which is used to hold objects of TreeModelItem type ( obvious isn't it ? ). There is no problem to create such a model here is the model and item code.
BaseTreeModel.cpp
#include "BaseTreeModel.h"
#include "TreeModelItem.h"
#include <QDebug>
BaseTreeModel::BaseTreeModel() {
// fake structure
QList<QVariant *> fakeData1;
fakeData1.push_back(new QVariant("fakeData11"));
fakeData1.push_back(new QVariant("fakeData22"));
QList<QVariant *> fakeData2;
fakeData2.push_back(new QVariant(1111));
fakeData2.push_back(new QVariant(2222));
rootItem = new TreeModelItem(fakeData1, 0);
for (int i = 0;i<1;i++){
TreeModelItem *item = new TreeModelItem(fakeData1, rootItem);
rootItem->appendChild(item);
for (int j=0;j<1;j++)
item->appendChild( new TreeModelItem(fakeData2, item) );
}
}
BaseTreeModel::~BaseTreeModel() {
}
// Minimum implementation for ReadOnly model
QModelIndex BaseTreeModel::index ( int row, int column, const QModelIndex & parent ) const {
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeModelItem *parent_item;
if (!parent.isValid()){
parent_item = rootItem;
} else {
parent_item = static_cast<TreeModelItem*>(parent.internalPointer());
}
TreeModelItem *child_item = parent_item->childAt(row);
if (child_item) {
return createIndex(row, column, child_item);
} else {
return QModelIndex();
}
}
QModelIndex BaseTreeModel::parent ( const QModelIndex & index ) const {
if (!index.isValid())
return QModelIndex();
TreeModelItem* child_item = static_cast<TreeModelItem*>(index.internalPointer());
TreeModelItem* parent_item = child_item->parent();
if (parent_item == rootItem)
return QModelIndex();
return createIndex(parent_item->row(), 0, parent_item);
}
QVariant BaseTreeModel::data ( const QModelIndex & index, int role) const {
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeModelItem* item = static_cast<TreeModelItem*>(index.internalPointer());
QModelIndex p = index.parent();
if( item->childCount() && index.column() != 0)
return QVariant();
else
return item->data( index.column() );
}
int BaseTreeModel::columnCount ( const QModelIndex & parent) const {
if ( parent.isValid() ) {
return static_cast<TreeModelItem*>(parent.internalPointer())->columnCount();
} else {
return rootItem ? rootItem->columnCount(): 0;
}
}
QVariant BaseTreeModel::headerData ( int section, Qt::Orientation orientation, int role ) const {
if ( orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return rootItem->data(section);
}
return QVariant();
}
int BaseTreeModel::rowCount ( const QModelIndex & parent ) const {
TreeModelItem* parent_item;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parent_item = rootItem;
else
parent_item = static_cast<TreeModelItem*>(parent.internalPointer());
return parent_item->childCount();
}
bool BaseTreeModel::hasChildren ( const QModelIndex & parent ) const {
if ( parent.isValid() ) {
bool retVal = static_cast<TreeModelItem*>(parent.internalPointer())->childCount();
return retVal;
} else {
return (bool)(rootItem->childCount());
}
}
Qt::ItemFlags BaseTreeModel::flags ( const QModelIndex & index ) const {
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
BaseTreeModel.h
class TreeModelItem;
#ifndef BASETREEMODEL_H
#define BASETREEMODEL_H
#include <QAbstractItemModel>
class BaseTreeModel : public QAbstractItemModel {
public :
BaseTreeModel();
~BaseTreeModel();
// Minimum implementation for ReadOnly model
virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
virtual QModelIndex parent ( const QModelIndex & index ) const ;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const ;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const ;
virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const ;
virtual Qt::ItemFlags flags ( const QModelIndex & index ) const ;
private :
// internal model structure let's name it cache :)
TreeModelItem *rootItem;
};
#endif // BASETREEMODEL_H
And the model item that is stored internally
TreeModelItem.cpp
#include "TreeModelItem.h"
#include <QDebug>
TreeModelItem::TreeModelItem(QList<QVariant *> data, TreeModelItem *parent) : itemData(data), parentItem(parent) {
}
TreeModelItem::~TreeModelItem(){
}
void TreeModelItem::appendChild(TreeModelItem * child){
childItems.append(child);
}
void TreeModelItem::removeChild(TreeModelItem * child){
childItems.removeOne( child );
}
TreeModelItem * TreeModelItem::childAt(int row){
if ( childItems.count() > row )
return childItems.at( row );
else
return NULL;
}
int TreeModelItem::childCount() const {
return childItems.count();
}
int TreeModelItem::columnCount() const {
return itemData.count();
}
QVariant TreeModelItem::data(int column) const {
return *itemData.at( column );
}
int TreeModelItem::row() const {
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeModelItem*>(this));
return 0;
}
TreeModelItem * TreeModelItem::parent(){
return parentItem;
}
void TreeModelItem::clear(){
this->itemData.clear();
}
TreeModelItem.h
#ifndef TREEMODELITEM_H
#define TREEMODELITEM_H
#include <QList>
#include <QVariant>
class TreeModelItem {
public:
TreeModelItem(QList<QVariant *> data, TreeModelItem *parent = 0);
~TreeModelItem();
void appendChild(TreeModelItem * child);
void removeChild(TreeModelItem * child);
TreeModelItem *childAt(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeModelItem *parent();
void updateColumn(int column, QVariant *data);
void updateItem( const QMap<int, QVariant *> &data);
void clear();
private:
QList<TreeModelItem *> childItems;
QList<QVariant *> itemData;
TreeModelItem *parentItem;
};
#endif // TREEMODELITEM_H
This tree is working. The structure right now is build in the constructor but only for the test purposes.
I want to create the base proxy model which will be transparent. I don't to have any fancy things inside at the firs step. If I've take QSortFilterProxyModel everything is Ok. But with QAbstractProxyModel it wan't work. I've implemented all the necessary virtual methods but I think that I'm doing this wrong. So the first step is to create transparent proxy based on QAbstaractProxyModel to understand the concept of source <-> proxy mapping.
Then later I want to create proxy for different aggregation/grouping, model flatten to table, adding a virtual columns etc..
Could somebody can help me with this issue to guide how to implement mapToSource, mapFromSource and index, parent etc... in this proxy on my model arch.
I know that similar posts were here on the forum but as I saw usually threads were finished with the conclusion that maybe different model should be used instead of QAbstractProxyModel.
The problem :
Right now I've a tree model based on QAbstractItemModel which is used to hold objects of TreeModelItem type ( obvious isn't it ? ). There is no problem to create such a model here is the model and item code.
BaseTreeModel.cpp
#include "BaseTreeModel.h"
#include "TreeModelItem.h"
#include <QDebug>
BaseTreeModel::BaseTreeModel() {
// fake structure
QList<QVariant *> fakeData1;
fakeData1.push_back(new QVariant("fakeData11"));
fakeData1.push_back(new QVariant("fakeData22"));
QList<QVariant *> fakeData2;
fakeData2.push_back(new QVariant(1111));
fakeData2.push_back(new QVariant(2222));
rootItem = new TreeModelItem(fakeData1, 0);
for (int i = 0;i<1;i++){
TreeModelItem *item = new TreeModelItem(fakeData1, rootItem);
rootItem->appendChild(item);
for (int j=0;j<1;j++)
item->appendChild( new TreeModelItem(fakeData2, item) );
}
}
BaseTreeModel::~BaseTreeModel() {
}
// Minimum implementation for ReadOnly model
QModelIndex BaseTreeModel::index ( int row, int column, const QModelIndex & parent ) const {
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeModelItem *parent_item;
if (!parent.isValid()){
parent_item = rootItem;
} else {
parent_item = static_cast<TreeModelItem*>(parent.internalPointer());
}
TreeModelItem *child_item = parent_item->childAt(row);
if (child_item) {
return createIndex(row, column, child_item);
} else {
return QModelIndex();
}
}
QModelIndex BaseTreeModel::parent ( const QModelIndex & index ) const {
if (!index.isValid())
return QModelIndex();
TreeModelItem* child_item = static_cast<TreeModelItem*>(index.internalPointer());
TreeModelItem* parent_item = child_item->parent();
if (parent_item == rootItem)
return QModelIndex();
return createIndex(parent_item->row(), 0, parent_item);
}
QVariant BaseTreeModel::data ( const QModelIndex & index, int role) const {
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeModelItem* item = static_cast<TreeModelItem*>(index.internalPointer());
QModelIndex p = index.parent();
if( item->childCount() && index.column() != 0)
return QVariant();
else
return item->data( index.column() );
}
int BaseTreeModel::columnCount ( const QModelIndex & parent) const {
if ( parent.isValid() ) {
return static_cast<TreeModelItem*>(parent.internalPointer())->columnCount();
} else {
return rootItem ? rootItem->columnCount(): 0;
}
}
QVariant BaseTreeModel::headerData ( int section, Qt::Orientation orientation, int role ) const {
if ( orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return rootItem->data(section);
}
return QVariant();
}
int BaseTreeModel::rowCount ( const QModelIndex & parent ) const {
TreeModelItem* parent_item;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parent_item = rootItem;
else
parent_item = static_cast<TreeModelItem*>(parent.internalPointer());
return parent_item->childCount();
}
bool BaseTreeModel::hasChildren ( const QModelIndex & parent ) const {
if ( parent.isValid() ) {
bool retVal = static_cast<TreeModelItem*>(parent.internalPointer())->childCount();
return retVal;
} else {
return (bool)(rootItem->childCount());
}
}
Qt::ItemFlags BaseTreeModel::flags ( const QModelIndex & index ) const {
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
BaseTreeModel.h
class TreeModelItem;
#ifndef BASETREEMODEL_H
#define BASETREEMODEL_H
#include <QAbstractItemModel>
class BaseTreeModel : public QAbstractItemModel {
public :
BaseTreeModel();
~BaseTreeModel();
// Minimum implementation for ReadOnly model
virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
virtual QModelIndex parent ( const QModelIndex & index ) const ;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const ;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const ;
virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const ;
virtual Qt::ItemFlags flags ( const QModelIndex & index ) const ;
private :
// internal model structure let's name it cache :)
TreeModelItem *rootItem;
};
#endif // BASETREEMODEL_H
And the model item that is stored internally
TreeModelItem.cpp
#include "TreeModelItem.h"
#include <QDebug>
TreeModelItem::TreeModelItem(QList<QVariant *> data, TreeModelItem *parent) : itemData(data), parentItem(parent) {
}
TreeModelItem::~TreeModelItem(){
}
void TreeModelItem::appendChild(TreeModelItem * child){
childItems.append(child);
}
void TreeModelItem::removeChild(TreeModelItem * child){
childItems.removeOne( child );
}
TreeModelItem * TreeModelItem::childAt(int row){
if ( childItems.count() > row )
return childItems.at( row );
else
return NULL;
}
int TreeModelItem::childCount() const {
return childItems.count();
}
int TreeModelItem::columnCount() const {
return itemData.count();
}
QVariant TreeModelItem::data(int column) const {
return *itemData.at( column );
}
int TreeModelItem::row() const {
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeModelItem*>(this));
return 0;
}
TreeModelItem * TreeModelItem::parent(){
return parentItem;
}
void TreeModelItem::clear(){
this->itemData.clear();
}
TreeModelItem.h
#ifndef TREEMODELITEM_H
#define TREEMODELITEM_H
#include <QList>
#include <QVariant>
class TreeModelItem {
public:
TreeModelItem(QList<QVariant *> data, TreeModelItem *parent = 0);
~TreeModelItem();
void appendChild(TreeModelItem * child);
void removeChild(TreeModelItem * child);
TreeModelItem *childAt(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeModelItem *parent();
void updateColumn(int column, QVariant *data);
void updateItem( const QMap<int, QVariant *> &data);
void clear();
private:
QList<TreeModelItem *> childItems;
QList<QVariant *> itemData;
TreeModelItem *parentItem;
};
#endif // TREEMODELITEM_H
This tree is working. The structure right now is build in the constructor but only for the test purposes.
I want to create the base proxy model which will be transparent. I don't to have any fancy things inside at the firs step. If I've take QSortFilterProxyModel everything is Ok. But with QAbstractProxyModel it wan't work. I've implemented all the necessary virtual methods but I think that I'm doing this wrong. So the first step is to create transparent proxy based on QAbstaractProxyModel to understand the concept of source <-> proxy mapping.
Then later I want to create proxy for different aggregation/grouping, model flatten to table, adding a virtual columns etc..
Could somebody can help me with this issue to guide how to implement mapToSource, mapFromSource and index, parent etc... in this proxy on my model arch.