bool QVtkTableModelRawVector::setData(const QModelIndex & index, const QVariant & value, int role)
{
    if (role != Qt::EditRole || index.column() == 0 || !m_data)
    {
        return false;
    }

    bool ok;
    const double f_value = value.toDouble(&ok);
    if (!ok)
    {
        return false;
    }

    const vtkIdType tupleId = index.row(), component = index.column() - 1;
    int components = m_data->GetNumberOfComponents();

    assert(component < components && tupleId < m_data->GetNumberOfTuples());

    std::vector<double> tupleData(components);

    m_data->GetTuple(tupleId, tupleData.data());
    tupleData[component] = f_value;
    m_data->SetTuple(tupleId, tupleData.data());

    m_data->Modified();

    return true;
}
// apply to each row in buffer from START to END, but stop after CT rows
void ExecStreamBufTupleFunctor::foreachRow(
    ExecStreamBufAccessor &bufAccessor,
    PConstBuffer start, PConstBuffer end, int ct)
{
    TupleDescriptor const &tupleDesc = bufAccessor.getTupleDesc();
    TupleData tupleData(tupleDesc);
    TupleAccessor &tupleAccessor = bufAccessor.getScratchTupleAccessor();

    for (PConstBuffer pTuple = start;
         ct > 0 && pTuple != end;
         ct--, pTuple += tupleAccessor.getCurrentByteCount())
    {
        tupleAccessor.setCurrentTupleBuf(pTuple);
        // while we're here, we might as well sanity-check the content
        assert(pTuple + tupleAccessor.getCurrentByteCount()
            <= bufAccessor.getConsumptionEnd());
        tupleAccessor.unmarshal(tupleData);
        // TODO:  sanity-check individual data values?
        (*this)(tupleDesc, tupleData);
    }
}