PDA

View Full Version : QAbstractProxyModel , mapToSource() and mapFromSource()



sajis997
27th March 2012, 08:19
Hi forum,


I would like to browse through an example where QAbstractProxyModel is sub-classed and the above mentioned functions are over-ridden.

If any one aware of any open source examples , please refer them to me.


I really like to have some idea of this concept.


Regards
Sajjad

wysota
27th March 2012, 21:56
Here is one: Transpose proxy model

There are others in Qt docs too. Some more are available on this forum in different threads.

sajis997
3rd April 2012, 10:08
Hi forum,

The transpose roxy model example mantains the information hiding while the other example at Qt site didi not do that at all. They customized a tree view with proxy model and while doing that they have used many global variables as follows:



#include <QtGui>

QList<QStandardItem *> list;

class SortProxy : public QAbstractProxyModel
{
Q_OBJECT

public:
SortProxy(QObject *parent = 0) : QAbstractProxyModel(parent), hideThem(false)
{
fixModel();
}

int rowCount(const QModelIndex &parent) const
{
QModelIndex sourceParent;
if (parent.isValid())
sourceParent = mapToSource(parent);
int count = 0;
QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(proxySourceParent);
while (it.hasNext()) {
it.next();
if (it.value() == sourceParent)
count++;
}
return count;
}

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

QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
{
QModelIndex sourceParent;
if (parent.isValid())
sourceParent = mapToSource(parent);
QMapIterator<QPersistentModelIndex, QPersistentModelIndex> it(proxySourceParent);
while (it.hasNext()) {
it.next();
if (it.value() == sourceParent && it.key().row() == row &&
it.key().column() == column)
return it.key();
}
return QModelIndex();
}

QModelIndex parent(const QModelIndex &child) const
{
QModelIndex mi = proxySourceParent.value(child);
if (mi.isValid())
return mapFromSource(mi);
return QModelIndex();
}

QModelIndex mapToSource(const QModelIndex &proxyIndex) const
{
if (!proxyIndex.isValid())
return QModelIndex();
return mapping.key(proxyIndex);
}

QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
{
if (!sourceIndex.isValid())
return QModelIndex();
return mapping.value(sourceIndex);
}

public slots:
void hideEverythingButA1AndChildren()
{
hideThem = !hideThem;
// Now we set up the proxy <-> source mappings
emit layoutAboutToBeChanged();
fixModel();
emit layoutChanged();
}

private:
void fixModel()
{
mapping.clear();
proxySourceParent.clear();

//the following list is already populated
//in the tree view and we shall browse and
//customize it here
for (int i=0;i<list.size();i++)
{
//pull out a standard item
QStandardItem *si = list.at(i);

if (hideThem)
{
//if the hide item flag is true

//check if the standard item's text start with 'A'
//of the item is not parent
if (!si->text().startsWith("A") || !si->parent())
continue;


//means that we have encountered item that does not start with 'A'
//or the item is not the parent

//we pull out the model index by creating the model index with the source items
//row , column
QModelIndex proxy = createIndex(si->row(), si->column(), si->index().internalPointer());

//insert the source model's index and the proxy index into the map
mapping.insert(QPersistentModelIndex(si->index()), proxy);
QModelIndex sourceParent;

if (si->parent()->parent())
sourceParent = si->parent()->index();
proxySourceParent.insert(proxy, sourceParent);
}
else
{
QModelIndex proxy = createIndex(si->row(), si->column(), si->index().internalPointer());
mapping.insert(QPersistentModelIndex(si->index()), proxy);
QModelIndex sourceParent;
if (si->parent())
sourceParent = si->parent()->index();
proxySourceParent.insert(proxy, sourceParent);
}
}
}

QMap<QPersistentModelIndex, QPersistentModelIndex> mapping;
QMap<QPersistentModelIndex, QPersistentModelIndex> proxySourceParent;
bool hideThem;
};

SortProxy *proxyModel = 0;

class Tree : public QTreeView
{
Q_OBJECT

public:
Tree(QWidget *parent = 0) : QTreeView(parent)
{
QStandardItemModel *sourceModel = new QStandardItemModel(this);

QStandardItem *parentA = sourceModel->invisibleRootItem();
for (int i = 0; i < 2; ++i) {
itemA = new QStandardItem(QString("A %0").arg(i));
parentA->appendRow(itemA);
parentA = itemA;
list.append(itemA);
}
itemA = new QStandardItem(QString("A 2"));
parentA->appendRow(itemA);
list.append(itemA);
itemA3 = new QStandardItem(QString("A 3"));
list.append(itemA3);
parentA->appendRow(itemA3);
itemA4 = new QStandardItem(QString("A 4"));
list.append(itemA4);
parentA->appendRow(itemA4);
itemNonA = new QStandardItem(QString("Non A"));
list.append(itemNonA);
parentA->appendRow(itemNonA);

QStandardItem *parentB = sourceModel->invisibleRootItem();
for (int i = 0; i < 3; ++i) {
itemB = new QStandardItem(QString("B %0").arg(i));
parentB->appendRow(itemB);
parentB = itemB;
list.append(itemB);
}

QStandardItem *parentC = sourceModel->invisibleRootItem();
for (int i = 0; i < 3; ++i) {
itemC = new QStandardItem(QString("C %0").arg(i));
parentC->appendRow(itemC);
parentC = itemC;
list.append(itemC);

}

proxyModel = new SortProxy(this);
proxyModel->setSourceModel(sourceModel);
setModel(proxyModel);
expandAll();
}
QStandardItem *itemA;
QStandardItem *itemA3;
QStandardItem *itemA4;
QStandardItem *itemNonA;
QStandardItem *itemB;
QStandardItem *itemC;
};


#include "main.moc"

int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget widget;
QPushButton *button = new QPushButton("Make only A1 + 'A' children visible", &widget);
Tree *tree = new Tree(&widget);
QVBoxLayout *lay = new QVBoxLayout(&widget);
lay->addWidget(button);
QObject::connect(button, SIGNAL(clicked()), proxyModel, SLOT(hideEverythingButA1AndChildren()));
lay->addWidget(tree);
widget.show();
return app.exec();
}




How do i access to those data if i want to remove the global variables that they have declared. In my own project i do not have any global variable that let the proxy model and main source model to interact with.


Need your suggestion.


Regards
Sajjad

wysota
3rd April 2012, 11:06
The proxy has access to the source model data using QAbstractProxyModel::sourceModel(). There is no need for any global variables and I can't see any relevant global variables in the code you posted.

sajis997
3rd April 2012, 12:04
At the beginning of the code snippet :



QList<QStandardItem *> list;


Both the view and the model is accessing this , the source model is populating it and the proxy model is customizing it. Wouldnt you consider is global. I should be residing only inside the Source Model's scope, isnt it ?

wysota
3rd April 2012, 12:09
At the beginning of the code snippet :



QList<QStandardItem *> list;


Both the view and the model is accessing this ,
Not really. The view indeed is accessing it however creating the model in the view's constructor is a silly approach by itself and besides doing that the view doesn't access the variable anymore. If you move model creation outside the view class and discard the global variable in favour of a local variable, the program will work exactly the same way. I'm not commenting bad C++ practices here :)


the source model is populating it and the proxy model is customizing it.
The proxy doesn't access the "list" variable anywhere.

sajis997
3rd April 2012, 12:37
SortProxy does access the list variable inside the private function called fixModel()

wysota
3rd April 2012, 12:42
Ahh... indeed it does. In that case don't look at this code anymore since it's inherently broken. Find a better example :)