Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QAbstractProxyModel not updating on dataChanged() signal

Tags:

c++

qt

Here is my setData in source model:

bool TreeModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (!index.isValid() || role != Qt::EditRole)
        return false;

    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
    item->setData(index.column(), value);
    emit dataChanged(index, index);

    return true;
}

I connected dataChanged signal from source model to dataChanged signal of proxy model but the table view which shows proxy model updates only if I click on it. What can be wrong in this situation? Should I somehow emit dataChanged signal manually in proxy model?

Data from model:

QVariant TreeModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole)
        return {};

    TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
    return item->dataAt(index.column());
}

And from TreeItem:

QVariant TreeItem::dataAt(int n) const
{
    if (n < m_data.size())
        return m_data[n];
    else
        return {};
}

Update: I supposed that proxy model should use mapFromSource on indices that came from TreeModel::dataChanged but it seems proxy doesn't call mapFromSource, so I don't understand how updating happens.

Also the same behaviour when I try to edit tree item through proxy model - source model doesn't update it's view. However in that case I can set data in proxy using source model:

bool ProxyModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
//    if (!index.isValid() || role != Qt::EditRole)
//        return false;

//    TreeItem* item = static_cast<TreeItem*>(mapToSource(index).internalPointer());
//    item->setData(index.column(), value);
//    emit dataChanged(index, index);

//    return true;

    return sourceModel()->setData(mapToSource(index), value, role);
}

UPDATE: Finally, it seems that I'm almost got it. KDE's KDescendantsProxyModel model emitting dataChanged signal itself, so I also created onSourceDataChanged slot and connected it to source's dataChanged signal (it updates only first index now):

void ProxyModel::onSourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
                                     const QVector<int>& roleNames)
{
    auto index = mapFromSource(topLeft);
    emit dataChanged(index, index);
}

The only question: is it a right way or I do something wrong?

like image 482
qloq Avatar asked May 18 '17 08:05

qloq


1 Answers

I connected dataChanged signal from source model to dataChanged signal of proxy mode

You cannot re-emit the source model's signal, as that signal has the index to a wrong model. Remember dataChanged's contract: the index it emits is a valid index on the model the signal comes from. Yet you're emitting an index that's not valid on your proxy model.

You need to connect the source's signal to a slot or functor that then maps the index to the proxy's index and emits that.

like image 179
Kuba hasn't forgotten Monica Avatar answered Sep 21 '22 12:09

Kuba hasn't forgotten Monica