qtqmlqtquick2qabstractlistmodel

Unable to assign [undefined] to QUrl


I have a model and a qml.

Model.cpp:

Model::Model(QObject *parent): QAbstractListModel(parent)
{
}

void Model::addIcon(const QString &iconName, const QString &iconPath)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    if(!indexMap.contains(iconName)) {
        paths.append(iconPath);
        indexMap.insert(iconName,paths.indexOf(iconPath));
    }
    else {

        //Update the icon for the designated icon
        paths[indexMap.value(iconName)] = iconPath;
        QModelIndex index = createIndex(indexMap.value(iconName),1);
        emit dataChanged(index,index);
    }

    endInsertRows();
}

QVariant Model::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= indexMap.count())
        return QVariant();

    return paths.at(index.row());
}

int Model::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return paths.count();
}

QHash<int, QByteArray> Model::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[PathRole] = "iconImage";
    return roles;
}

Model.h

class Model : public QAbstractListModel {
    Q_OBJECT
public:

    enum MyRoles {
        PathRole = Qt::UserRole + 1
    };
    Q_ENUM(MyRoles)


    explicit Model(QObject *parent = 0);


    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    QHash<int, QByteArray> roleNames() const;

    void addIcon(const QString &iconName, const QString &iconPath);

private:
    QList<QString> paths;
    QMap<QString,int> indexMap;

};

Wrapper:

Q_PROPERTY(MyModel* modelProperty READ getModel NOTIFY modelChanged)

Qml:

import QtQuick 2.5

Rectangle{
width:100
height:30

    ListView{
        id:icons

        property alias myModel: myService.modelProperty

        anchors.fill: parent
        anchors.topMargin: 10
        anchors.rightMargin: 20

        model: myModel

        delegate: Image{source: iconImage}
    }
}

When I set the icon for the first time, it gives me no error message. Put after the first assignment I get the error "unable to assign [undefined] to QUrl".

I add the new icon path with addIcon method in the model.

Do you have any idea why this could be happening?

Thanks in advance.


Solution

  • The warning means you returned invalid value from data.

    #include <QAbstractListModel>
    
    #define Invalid -1
    
    class Model : public QAbstractListModel
    {
        Q_OBJECT
    public:
        struct Icon {
            QString name;
            QString path;
        };
        Q_INVOKABLE void add(QString name, QString path) {
            add({name, path});
        }
        void add(const Icon& icon) {
            const int& i = find(icon.name);
            if(i != Invalid) {
                mIconPaths[i].path = icon.path;
                emit dataChanged(index(i), index(i)); // Do not add beginInsertRows
            } else {
                beginInsertRows(QModelIndex(), rowCount(), rowCount());
                mIconPaths.push_back(icon);
                endInsertRows();
            }
        }
    
        int find(const QString& name) {
            for(int i = 0; i < mIconPaths.size(); i++)
                if(mIconPaths[i].name == name)
                    return i;
            return Invalid;
        }
    
        QVariant data(const QModelIndex &index, int role) const
        {
            Q_UNUSED(role)
            if (index.row() < 0 || index.row() >= rowCount())
                return QVariant();
            return mIconPaths.at(index.row()).path;
        }
    
        int rowCount(const QModelIndex &parent = QModelIndex()) const
        {
            Q_UNUSED(parent)
            return mIconPaths.count();
        }
    
        QHash<int, QByteArray> roleNames() const
        {
            QHash<int, QByteArray> roles;
            roles[0] = "icon";
            return roles;
        }
    
    private:
        QList<Icon> mIconPaths;
    };
    

    Test QML:

    Window
    {
        visible: true
        height: 640
        width: 480
    
        ListView {
            anchors.fill: parent
            model: myModel
            delegate: Text{
                text: icon
            }
            Component.onCompleted: {
                myModel.add("test", "test")
                myModel.add("test", "modified")
                myModel.add("test2", "added")
            }
        }
    }