Qt model drag & drop - Unable to save type QJsonValue

1.3k Views Asked by At

I have a QAbstractListModel to display a QJsonArray, with drag & drop implementation:

class NoteListModel : public QAbstractListModel
{
    Q_OBJECT

public:
    explicit NoteListModel(QObject *parent = nullptr);
    ~NoteListModel() override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    Qt::ItemFlags flags(const QModelIndex& index) const override;
    // Drag & Drop:
    bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
    bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
    QStringList mimeTypes() const override {
        QStringList mimes = QAbstractListModel::mimeTypes();
        mimes.prepend("application/flynote_json");
        return mimes;
    }
    QMimeData *mimeData(const QModelIndexList &indexes) const override;
    Qt::DropActions supportedDropActions() const override;

private:
    QJsonArray noteArray;

};

When I call the base implementation in my mimeData() method, I have this error:

QVariant::save: unable to save type 'QJsonValue' (type id: 45)
ASSERT failure in QVariant::save: "Invalid type to save"

QMimeData *NoteListModel::mimeData(const QModelIndexList &indexes) const
{
    QMimeData *ret = nullptr;
    if (indexes.size() == 1){
        QModelIndex mi = indexes.first();
        if (mi.isValid()){
            ret = QAbstractListModel::mimeData(indexes);
            QJsonDocument json_mime(noteArray.at(mi.row()).toObject());
            ret->setData("application/flynote_json", json_mime.toJson());
        }
    }
    return ret;
}

So no problem, like is describe in the doc I add these lines:

// In the header (outside the class)
Q_DECLARE_METATYPE(QJsonValue)
QDataStream &operator<<(QDataStream &out, const QJsonValue &myObj){ /*...*/ }
QDataStream &operator>>(QDataStream &in, QJsonValue &myObj){ /*...*/ }

// In the constructor
qRegisterMetaType<QJsonValue>("QJsonValue");
qRegisterMetaTypeStreamOperators<QJsonValue>("QJsonValue");

But I have the same problem, What I'm doing wrong ?

1

There are 1 best solutions below

7
On

I tried to reproduce your example, because I really couldn't explain this behavior by looking at your code. I compiled the project with Qt 5.5 and I was able to reproduce the error message:

QVariant::save: unable to save type 'QJsonValue' (type id: 45).

Interestingly, the error vanishes with Qt 5.13, as QVariant already includes the QJson-Types in this version.

It seems, that I found a possible workaround for this kind of defect, which is the following:

#include <QApplication>
#include <QDebug>
#include <QDataStream>
#include <QJsonDocument>

QDataStream& operator<<(QDataStream& out, const QJsonDocument& myObj) {
    return out;
}

QDataStream& operator >> (QDataStream & in, QJsonDocument& myObj) {
    return in;
}
Q_DECLARE_METATYPE(QJsonDocument)


int main(int argc, char** args) {
    qDebug() << qRegisterMetaTypeStreamOperators<QJsonDocument>();
    QVariant var = QVariant::fromValue(QJsonDocument());
    qDebug() << var.type();
    qDebug() << var.typeName();
    QDataStream stream;
    var.load(stream);   // Workaround: Just call load at least once before any save 
    var.save(stream);
    var.save(stream);
}

If you call load at least once before all calls of save the error vanishes. At least for Qt 5.5.

Unfortunately, I don't have the sources of Qt 5.5 at hand to really find the reason for this odd behavior. I also don't know what makes QJsonDocument so special among other classes, which don't need the call to load.