1

I have subclassed QAbstractProxyModel and its source model is a subclass of QSqlTableModel. The proxy model must show just one row of the source model at a time. Here's the code:

bool SensorDisplayModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid())
        return false;

    QModelIndex sourceIdx = mapToSource(index);

    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
        if(sourceIdx.isValid())
        {
            if(sourceModel()->setData(sourceIdx, value, role))
            {
//                emit dataChanged(index, index);
                return true;
            }
            return false;
        }
        else
            return false;
    }

    return false;
}

Source Model:

bool SensorModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid())
        return false;

    if(role == Qt::EditRole || role == Qt::DisplayRole)
    {
        if(index.column() != 0)
            return QSqlTableModel::setData(index, value, Qt::EditRole)  &&
                QSqlTableModel::setData(index, value, Qt::DisplayRole);
        else
            return QSqlTableModel::setData(index, value, role);
    }

    return false;
}

The following is called when a new row has to be added to the source model:

void SensorDisplayModel::addSensor()
{
    QString ro_id;
    bool success = false;

    if(sensorModel->insertRows(sensorModel->rowCount(), 1))
    {
        selectedRow = sensorModel->rowCount() - 1;
        ro_id = "DB-" + QString("%1").arg(SensorDisplayModel::id_no,
                                          3, 10, QChar('0'));
        comboBoxItems.append(ro_id);
        success = setData(createIndex(0, 0), QVariant(comboBoxItems), Qt::EditRole);
        success &= setData(createIndex(0, 0), QVariant(ro_id), Qt::DisplayRole);
        SensorDisplayModel::id_no++;
        success &= setData(createIndex(0, 1), QVariant(QString("Name")));
        success &= setData(createIndex(0, 2), QVariant(-1));
        success &= setData(createIndex(0, 3), QVariant(-1));
        success &= setData(createIndex(0, 4), QVariant((long long)0));
        success &= setData(createIndex(0, 5), QVariant(QString("??")));
        success &= setData(createIndex(0, 6), QVariant(QString("??")));

        if(success)
            emit dataChanged(createIndex(0, 0), createIndex(0, columnCount() - 1));

        ID2Row[data(createIndex(0, 0)).toString()] = selectedRow;
    }
}

selectedRow is a private member that saves the current row of the source model.

The setData() always returns false. The source model is set to manual submit. What am I doing wrong?

Edit:

I figured out the problem. The source model I use is a subclass of QSqlTableModel, which calls QSqlQueryModel's setData for any role other than EditRole. Since QSqlQueryModel in itself does not reimplement setData, it call QAbstractItemModel's setData which always returns false.

So, I now make all setData() calls with EditRole and data() returns values from the source model stored under EditRole.

user2522981
  • 163
  • 3
  • 18
  • Which of the two `setData()` methods returns `false`? I.e. is the proxy's method returning `false` on its own or because the source model's mehod did? – Kevin Krammer Jan 03 '17 at 10:22
  • 1
    Which `false` is returned? You have three "falses" in proxy model.and two in main model. –  Jan 03 '17 at 10:22
  • All setData methods for both the main and proxy model are returning false. sourceModel()->setData() returns false. – user2522981 Jan 03 '17 at 11:36
  • The behaviour varies..setData(createIndex(0, 0), QVariant(comboBoxItems), Qt::EditRole) seems to be returning true. – user2522981 Jan 03 '17 at 12:01
  • Try it without overriding either setData – Caleth Jan 03 '17 at 14:33

1 Answers1

1

Here you set data only for EditRole and DisplayRole. Other roles, such as ForegroundRole, don't set because you return false. Apparently you don't need to subclass both models, because your code does nothing other than the standard classes do. If you want to add some code later, at least change your last return false in first block to

return QAbstractProxyModel::setData(index,value,role);

and last return false in second block to

return QSqlTableModel::setData(index,value,role);

Also, this:

    if(index.column() != 0)
        return QSqlTableModel::setData(index, value, Qt::EditRole)  &&
            QSqlTableModel::setData(index, value, Qt::DisplayRole);
    else
        return QSqlTableModel::setData(index, value, role);

doesn't have any sense.

  • I am sorry..but I am new to model/view programming with Qt. I want to set the same values for both the Edit and Display Role for all except the first column. Can you explain what I am doing wrong there? – user2522981 Jan 03 '17 at 13:28
  • You have a condition relating to these two roles. Here you set data anyway, be it 0th column or any other one. If/else block doesn't have sense because in both cases you're doing same job. –  Jan 03 '17 at 13:36
  • But the value I pass will be different for either roles in the first column. If I were to remove the else, wouldn't the value for both roles be set to whichever role setData() is called with last? – user2522981 Jan 03 '17 at 13:41
  • What Qt engine does: it sequentially checks how roles are processed. Fro example, there is `EditRole`. Qt calls `setData(...,...,Qt::EditRole)` and checks what is returning for whis role. Next role is, for example, `DisplayRole`. Qt calls `setData(...,...,Qt::DisplayRole)` and so on. If some roles in subclass are not mentioned, they should be processed by default, i.e. by the function of the parent class, which I mentioned in my answer. –  Jan 03 '17 at 13:51