Search code examples
c++qtproxyqabstractitemmodel

Create a proxy of QAbstractModelItem


I'm writing a Qt application to allow the visualization of very heavy data sets.

So, I have a SourceDataModel class, inheriting from QAbstractItemModel that seems to work properly (currently, I only display it in QTableView/QTreeView but later on, I'll create some custom views).

Now, I would like to be able to filter this data, that is

  1. being able to have different data resolution (i.e. only exposing 1 data item out of 2)

  2. being able to apply some filters on the data (i.e. displaying unix timestamps as dd/MM/yyyy hh:mm:ss)

So I started to create a ProxySourceDataModel class, which inherits from my SourceDataModel and stores one instance, and basically delegates everything to the instance. From this ProxySourceDataModel, I noticed that no data was displayed when I used it in a QTableView. After some investigation, it seems that it was because i had to forward the signals and slots from the underlying SourceDataModel. No problem, i did it.

But still 2 problems remain, and I can't figure out how to handle them:

  1. I am not able to select the data in the views. If I use the SourceDataModel directly, no problem. But using the ProxySourceDataModel i can't select anything.

  2. The data is not filtered at all! I overloaded data() in ProxySourceDataModel, and forward all the other calls to the underlying SourceDataModel. But still, only SourceDataModel::data() is called.

Here is some code to illustrate what I'm doing:

class SourceDataModel : public QAbstractItemModel
{
  //...
};

class ProxySourceDataModel : public SourceDataModel
{
public:
  ProxySourceDataModel(SourceDataModel& model)
    : model_(model)
  {
    // For all QAbstractItemModel's signals emitted by the underlying model,
    // I propagate them like this
    QObject::connect( &model_, SIGNAL(        the_signal()),
                      this,    SLOT  (forward_the_signal())) ;
  }

slots:
  void forward_the_signal()
  {
    emit the_signal();
  }

public:
  // For all QAbstractItemModel's virtual function, I do something like this
  virtual void the_function()
  {
    model_.the_function();
  }

  // This is where I was hoping to do the filtering
  virtual QVariant data( const QModelIndex& index,int role=Qt::DisplayRole )
  {
    return filter( model_.data(index,role) );
  }

private:
  SourceDataModel& model_;
};

SourceDataModel sourceDataModel;
QTableView      view;
view.setModel( new ProxySourceDataModel(sourceDataModel) );

Any help or advice greatly appreciated, thanks for reading!

-------------------- EDIT ------------------------

I found it!

The problem was that the view do not use QAbstractItemModel::data() from its model, but rather calls QModelIndex::data() on its items, which in turn calls the QAbstractItemModel::data() of the item's underlying model. And since my proxy returned model indexes from the underlying model, that is why the SourceDataModel::data() was always called instead of ProxySourceDataModel()!

I just reimplemented ProxySourceDataModel::index() to return local indexes, and it works like a charm. Visit In QT, chaining models does not work as expected for more informations.

Thanks!


Solution

  • The problem was that the view do not use QAbstractItemModel::data() from its model, but rather calls QModelIndex::data() on its items, which in turn calls the QAbstractItemModel::data() of the item's underlying model. And since my proxy returned model indexes from the underlying model, that is why the SourceDataModel::data() was always called instead of ProxySourceDataModel()!

    I just reimplemented ProxySourceDataModel::index() to return local indexes, and it works like a charm. Visit In QT, chaining models does not work as expected for more informations.