qtmodelqjson

Programmaticaly updating subclassed QAbstractTableModel model and refreshing subclassed QTableView


I have subclassed QAbstractTableModel with QJsonDocument as data source. Here is header file:

#ifndef UEJSONPLACESTABLEMODEL_H
#define UEJSONPLACESTABLEMODEL_H

#include <QAbstractTableModel>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QVariant>
#include <QVariantMap>
#include <QVariantList>

class UeJsonPlacesTableModel : public QAbstractTableModel
{
private:
    /**
     * @brief m_ueJsonData
     */
    QJsonDocument m_ueJsonData;

/*protected:*/
public:
    /**
     * @brief ueSetJsonData
     * @param jsonData
     */
    void ueSetJsonData(const QJsonDocument& jsonData);

public:
    /**
     * @brief UeJsonPlacesTableModel
     * @param parent
     */
    UeJsonPlacesTableModel(QObject* parent=Q_NULLPTR);

    /**
     * @brief ueJsonData
     * @return pointer to object representing JSON document
     */
    const QJsonDocument& ueJsonData()
        { return this->m_ueJsonData; }

    /**
     * @brief rowCount
     * @param parent
     * @return number of rows
     */
    int rowCount(const QModelIndex& parent=QModelIndex()) const;

    /**
     * @brief columnCount
     * @param parent
     * @return number of columns
     */
    int columnCount(const QModelIndex& parent=QModelIndex()) const;

    /**
     * @brief data
     * @param index
     * @param role
     * @return data
     */
    QVariant data(const QModelIndex& index,
                  int role=Qt::DisplayRole) const;

    /**
     * @brief headerData
     * @param section
     * @param orientation
     * @param role
     * @return header data
     */
    QVariant headerData(int section,
                        Qt::Orientation orientation,
                        int role=Qt::DisplayRole) const;

    /**
     * @brief flags
     * @param index
     * @return flags for index's cell
     */
    Qt::ItemFlags flags(const QModelIndex& index) const;

    /**
     * @brief setData
     * @param index
     * @param value
     * @param role
     * @return true if succesfull, otherwise false
     */
    bool setData(const QModelIndex& index,
                 const QVariant& value,
                 int role=Qt::EditRole);

    /**
     * @brief insertRows
     * @param row
     * @param count
     * @param parent
     * @return true if succesfull, otherwise false
     */
    bool insertRows(int row,
                    int count,
                    const QModelIndex& parent=QModelIndex());

    /**
     * @brief removeRows
     * @param row
     * @param count
     * @param parent
     * @return true if succesfull, otherwise false
     */
    bool removeRows(int row,
                    int count,
                    const QModelIndex& parent=QModelIndex());
};

#endif // UEJSONPLACESTABLEMODEL_H

and here is its implemenation:

#include "uejsonplacestablemodel.h"

UeJsonPlacesTableModel::UeJsonPlacesTableModel(QObject* parent)
    : QAbstractTableModel(parent)
{
}   // constructor

int UeJsonPlacesTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    return this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size():0;
}   // rowCount

void UeJsonPlacesTableModel::ueSetJsonData(const QJsonDocument& jsonData)
{
    this->beginResetModel();

    this->m_ueJsonData=jsonData;
    emit dataChanged(QModelIndex(),
                     QModelIndex());

    this->endResetModel();
}   // ueSetJsonData

int UeJsonPlacesTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    return this->m_ueJsonData.isArray()?this->m_ueJsonData.array().at(0).toObject().keys().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().keys().size():0;
}   // columnCount

QVariant UeJsonPlacesTableModel::data(const QModelIndex& index,
                                      int role) const
{
    if(role!=Qt::DisplayRole||
             index.row()<0||
             index.row()>=this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size():0||
             index.column()<0||
             index.column()>=this->m_ueJsonData.isArray()?this->m_ueJsonData.array().at(0).toObject().keys().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().keys().size():0)
    {
        return QVariant();
    }    // if

    return this->m_ueJsonData.isArray()?this->m_ueJsonData.array().at(index.row()).toObject().value(this->m_ueJsonData.array().at(index.row()).toObject().keys().at(index.column())).toString():
                                        this->m_ueJsonData.isObject()?this->m_ueJsonData.object().value(this->m_ueJsonData.array().at(index.row()).toObject().keys().at(index.column())).toString():
                                        QVariant();
}   // data

QVariant UeJsonPlacesTableModel::headerData(int section,
                                            Qt::Orientation orientation,
                                            int role) const
{
    if(role!=Qt::DisplayRole||
             section<0||
             section>=this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size()>0?this->m_ueJsonData.object().size():0:0)
    {
        return QVariant();
    }   // if

    switch(orientation)
    {
        case Qt::Horizontal:
        {
            return this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size()>0?this->m_ueJsonData.array().at(0).toObject().keys().at(section):
                                                this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size()>0?this->m_ueJsonData.object().keys().at(section):
                                                QVariant():
                                                QVariant():
                                                QVariant();
        }   // case

        case Qt::Vertical:
        {
            return QAbstractTableModel::headerData(section,
                                                   orientation,
                                                   role);
        }   // case
    }   // switch

    return QVariant();
}   // headerData

Qt::ItemFlags UeJsonPlacesTableModel::flags(const QModelIndex& index) const
{
    return index.column()==0?QAbstractTableModel::flags(index)^Qt::ItemIsEditable:QAbstractTableModel::flags(index);
}   // flags

bool UeJsonPlacesTableModel::setData(const QModelIndex& index,
                                     const QVariant& value,
                                     int role)
{
    if(role!=Qt::EditRole||
             index.row()<0||
             index.row()>=this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size():0||
             index.column()<0||
             index.column()>=this->m_ueJsonData.isArray()?this->m_ueJsonData.array().size():this->m_ueJsonData.isObject()?this->m_ueJsonData.object().size()>0?this->m_ueJsonData.object().size():0:0)
    {
        return false;
    }   // if

    QVariantList dataList=this->m_ueJsonData.toVariant().toList();
    QVariantMap dataVariantMap=this->m_ueJsonData.toVariant().toList().at(index.row()).toMap();
    QVariantMap::const_iterator dataIterator=dataVariantMap.constBegin();
    int dataIndex=0;
    QString keyName=QString();
    QString dataValue=QString();

    while(dataIterator!=dataVariantMap.constEnd())
    {
        if(dataIndex==index.column())
        {
            keyName=dataVariantMap.keys().at(dataIndex);
        }
        else
        {
            dataIterator++;
            dataIndex++;
        }   // if
    }   // while

    QVariantMap changedData;

    changedData.insert(keyName,
                       value.toString());

    dataList.replace(index.row(),
                     changedData);

    this->m_ueJsonData=QJsonDocument::fromVariant(dataList);

    emit(dataChanged(index,
                     index));

    return true;
}   // setData

bool UeJsonPlacesTableModel::insertRows(int row,
                                        int count,
                                        const QModelIndex& parent)
{
    Q_UNUSED(parent)

    this->beginInsertRows(QModelIndex(),
                          row,
                          row+count-1);

    for(int index=row; index<row+count; ++index)
    {
        this->m_ueJsonData.toVariant().toList().insert(row,
                                                       this->m_ueJsonData.toVariant());
    }   // for

    this->endInsertRows();

    return true;
}   // insertRows

bool UeJsonPlacesTableModel::removeRows(int row,
                                        int count,
                                        const QModelIndex& parent)
{
    Q_UNUSED(parent)

    this->beginRemoveRows(QModelIndex(),
                          row,
                          row+count-1);

    for(int index=row; index<row+count; ++index)
    {
        this->m_ueJsonData.toVariant().toList().removeAt(index);
    }   // for

    this->endRemoveRows();

    return true;
}   // removeRows

Now, when new data arrives, I save it into QJsonDocument, but then I do not know how to update a model. Here is my try from MainWindow's slot, whic IS BEING fired (I've triple checked), nevertheless, the QTableView, responsible for showing data from model, is empty:

void MainWindow::ueSlotUpdatePlacesView(const QJsonDocument& newData)
{
    this->uePlacesViewDialog()->uePlacesTableView()->ueTablePlacesModel()->ueSetJsonData(newData);

//    qDebug() << Q_FUNC_INFO
//             << this->uePlacesViewDialog()->uePlacesTableView()->ueTablePlacesModel()->rowCount();
}   // ueSlotUpdatePlacesView

How do I update subclassewd QAbstractTableModel and then refresh subclassed QTableView?


Solution

  • Make sure to use the QObject MAcro when declaring your class

    class UeJsonPlacesTableModel : public QAbstractTableModel
    {
        Q_OBJECT
    
    private:
        QJsonDocument m_ueJsonData;