Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

combine QAbstractItemModels

I have a map = std::map<std::string, myItemModel *>, where myItemModel inherits QAbstractItemModel.

I want now to combine all myItemModel in one single myItemModel (every other item model would be fine too). So that there is one big myItemModel.

Is there a 'qt-way' to do this?

like image 671
user2699453 Avatar asked Sep 04 '14 09:09

user2699453


2 Answers

It can be done, but it's not trivial. It depends on your implementation of QAbstractItemModel and that's why it hasn't been done in Qt.

Here are steps to implement a model which is a collection of models:

  1. Create a new class inherited from QAbstractItemModel
  2. Add methods to add other models to that
  3. Process all signals from child models which contains indexes (you'll need to change them, look #10)
  4. Forward all signals which doesn't contain indexes.
  5. Implement rowCount and provide a sum of all models rows.
  6. Implement columnCount and provide a number of columns in your models.
  7. Implement index, return createIndex(row, column, NULL);
  8. Implement parent, return QModelIndex(); I hope your models are not trees
  9. Implement data,setData etc. addressing calls to the right model. Use methods from #10 to convert indexes.
  10. Create methods to convert a child model index to a base model index and back.
     Example (indexes):  
     BaseModel ChildModel1 ChildModel2
        0,0       0,0         
        1,0       1,0         
        2,0                   0,0
        3,0                   1,0
        4,0                   2,0

p.s. Think about creating a cache of indexes mapping.

This is an example of a method to convert a base model index to a child model index:

const QModelIndex childModelIndex(const QModelIndex& baseModelIndex) const
{
  if (!baseModelIndex.isValid())
  {
    return QModelIndex();
  }

  int count = 0;
  const int row = baseModelIndex.row();

  for (QList<QAbstractTableModel*>::const_iterator it = m_models.begin();
    it != m_models.end(); it++)
  {
    const int currentCount = (*it)->rowCount();     

    if (row >= count && row < count + currentCount)
    {       
        return (*it)->index(row - count, 0);
    }

    count += currentCount;
}

ASSERT(false);

return QModelIndex();

}

This is an example of a method to convert a child model index to a base model index:

QModelIndex baseModelIndex(const QModelIndex& childModelIndex) const
{
    int row = childModelIndex.row();

    for (QList<QAbstractTableModel*>::const_iterator it = m_models.begin();
        it != m_models.end(); it++)
    {
        if (childModelIndex.model() == *it)
        {
            return index(row, ind.column());
        }

        row += (*it)->rowCount();
    }

    return QModelIndex();
}
like image 95
Ezee Avatar answered Nov 02 '22 14:11

Ezee


The KDE Frameworks project contains a module called KItemModels, which includes a class called KConcatenateRowsProxyModel. It does exactly what you want. The library is released every month as part of the [KDE Frameworks releases], the code is continuously unit tested on https://build.kde.org. All this is licensed under LGPL v2 or later.

like image 3
dhaumann Avatar answered Nov 02 '22 15:11

dhaumann