Transparent QAbstractProxyModel for tree models
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
Code:
#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
if (!hasIndex(row, column, parent))
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 {
}
}
if (!index.isValid())
TreeModelItem* child_item = static_cast<TreeModelItem*>(index.internalPointer());
TreeModelItem* parent_item = child_item->parent();
if (parent_item == rootItem)
return createIndex(parent_item->row(), 0, parent_item);
}
if (!index.isValid())
if (role != Qt::DisplayRole)
TreeModelItem* item = static_cast<TreeModelItem*>(index.internalPointer());
if( item->childCount() && index.column() != 0)
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);
}
}
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
Code:
class TreeModelItem;
#ifndef BASETREEMODEL_H
#define BASETREEMODEL_H
#include <QAbstractItemModel>
public :
BaseTreeModel();
~BaseTreeModel();
// Minimum implementation for ReadOnly model
virtual QVariant headerData
( int section, Qt
::Orientation orientation,
int role
= Qt
::DisplayRole ) 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
Code:
#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
Code:
#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;
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.
Re: Transparent QAbstractProxyModel for tree models
For tree models these two methods are quite complex so it is really easier to base your proxy model on QSortFilterProxyModel. If you really want to implement your own mapping then you have to come up with a mapping algorithm. You will probably need some internal map that will contain enough information to map between source and target models and you would have to update this map every time anything changes in the base model. But since QSortFilterProxyModel already does that I don't see a point in repeating it especially that it's really not something you can implement in 5 minutes.
Re: Transparent QAbstractProxyModel for tree models
Yes I know that.
The first issue that I want to fix is a behaviour of the branch column. It looks strange when you've a branch column somewhere in the middle in view. So my idea is to create a proxy which will be able to hole branch column always on the most left side and if the user will want to swap the column with this particular one the proxy should change the indexes in the way that data that was before in the branch column should be shown in the swapped column and the data from this column which is dropped to the branch should be presented with with column zero.
I don't know that I'm clear enough ?
Theoretically it should be possible with QSortFilterProxyModel when we reimplement index and data an I right ? Maybe this is the right way ?
Re: Transparent QAbstractProxyModel for tree models
I would do it by reimplementing the view that is responsible for drawing the branches but what do I know...
Re: Transparent QAbstractProxyModel for tree models
Yes maybe this is the god idea, but it's even less described in doc than models sub classing :( It should be rather a combination of proxy and view. Where in view column moving policy should be changed. To not allow of the most left column moving. But only the other column will be allowed to drop in to it. Ill try.
By the way have you read a priv. message that I've sent to you this morning (this one written in Polish) ?
Re: Transparent QAbstractProxyModel for tree models
Quote:
Originally Posted by
adzajac
Yes maybe this is the god idea, but it's even less described in doc than models sub classing :( It should be rather a combination of proxy and view. Where in view column moving policy should be changed. To not allow of the most left column moving. But only the other column will be allowed to drop in to it. Ill try.
If you want to prevent a column from being moved then do just that. It's enough to subclass QHeaderView and prevent the first column from being moved.
Quote:
By the way have you read a priv. message that I've sent to you this morning (this one written in Polish) ?
It's a visitor message and not a private message. I'll read it in a moment.