After hours of google, trial and error I'm proud to finally have solved it myself as I am still pretty new to Qt!
To help people with a similar problem I'll quickly sum up all I had to do to make it work:
turn the internal QList<Message> into a QList<QSharedPointer<Message>>
define a QMap<QString, QSharedPointer<Message>> to hold index ids to the individual messages
when inserting, insert in the indexMap as well
define a method in the QAbstractListModel derived MessageList which simply returns a QVariantMap
P.S. Below is the new working version of the example app, in case anyone notices any misconceptions, please let me know
MessageList.hpp:
#ifndef MESSAGELIST_HPP
#define MESSAGELIST_HPP
#include "Message.hpp"
#include <QObject>
#include <QAbstractListModel>
#include <QModelIndex>
#include <QList>
#include <QHash>
#include <QVariant>
#include <QMap>
#include <QSharedPointer>
class MessageList : public QAbstractListModel {
Q_OBJECT
public:
typedef QSharedPointer<Message> MessagePointer;
typedef QList<MessagePointer> MessagePointerList;
typedef QMap<QString, MessagePointer> IndexMap;
enum Roles {
IdentifierRole,
TitleRole,
MessageRole,
};
protected:
MessagePointerList _list;
IndexMap _indexMap;
public:
MessageList();
int rowCount(const QModelIndex& parent) const;
QHash<int, QByteArray> roleNames() const;
QVariant data(const QModelIndex& index, int role) const;
bool insert(
const QList<Message>& messages,
int position = 0
);
bool reset();
Q_INVOKABLE QVariantMap get(const QString& identifier) const;
const Message& at(int index) const;
};
#endif // MESSAGELIST_HPP
MessageList.cpp:
#include "MessageList.hpp"
#include <QObject>
#include <QModelIndex>
#include <QVariant>
#include <QHash>
#include <QByteArray>
MessageList::MessageList() :
QAbstractListModel(nullptr)
{
}
int MessageList::rowCount(const QModelIndex& parent) const {
Q_UNUSED(parent)
return _list.size();
}
QHash<int, QByteArray> MessageList::roleNames() const {
QHash<int, QByteArray> roles;
roles[IdentifierRole] = "identifier";
roles[TitleRole] = "title";
roles[MessageRole] = "message";
return roles;
}
QVariant MessageList::data(const QModelIndex& index, int role) const {
if(!index.isValid()
|| index.row() >= _list.size()
|| index.row() < 0
) {
return QVariant();
}
switch(role) {
case IdentifierRole:
return _list.at(index.row())->identifier();
break;
case TitleRole:
return _list.at(index.row())->title();
break;
case MessageRole:
return _list.at(index.row())->message();
break;
default:
return QVariant();
}
}
bool MessageList::insert(
const QList<Message>& messages,
int position
) {
beginInsertRows(QModelIndex(), position, position + messages.size() - 1);
for(int row = 0; row < messages.size(); ++row) {
IndexMap::const_iterator indexMapItr(_indexMap.constFind(messages.at(row).identifier()));
if(indexMapItr == _indexMap.constEnd()) {
MessagePointer newMessage(new Message(messages.at(row)));
_list.insert(position, newMessage);
_indexMap.insert(messages.at(row).identifier(), newMessage);
}
}
endInsertRows();
return true;
}
bool MessageList::reset() {
beginResetModel();
_list.clear();
__indexMap.clear();
endResetModel();
return true;
}
QVariantMap MessageList::get(const QString& identifier) const {
QVariantMap result;
IndexMap::const_iterator indexMapItr(_indexMap.constFind(identifier));
if(indexMapItr != _indexMap.constEnd()) {
result["identifier"] = QVariant(indexMapItr->data()->identifier());
result["title"] = QVariant(indexMapItr->data()->title());
result["message"] = QVariant(indexMapItr->data()->message());
}
return result;
}
const Message& MessageList::at(int index) const {
return *(_list.at(index).data());
}
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "Message.hpp"
#include "MessageList.hpp"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
MessageList messageList;
messageList.insert(QList<Message> {
Message("a", "first message", "this is a sample text message of the first message"),
Message("b", "second message", "another sample text message of the second message"),
Message("c", "third message", "yet a third text message sample"),
Message("d", "fouth message", "last sample message")
});
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("MessageList", &messageList);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
main.qml:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Messages")
Rectangle {
id: menu
color: Qt.rgba(0.9, 0.9, 0.9, 1)
height: 32
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Text {
anchors.left: parent.left
anchors.margins: 8
anchors.verticalCenter: parent.verticalCenter
text: "at id 'b' there is: " + MessageList.get("b").title
}
}
ListView {
model: MessageList
anchors.top: menu.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true
delegate: Rectangle {
height: 32
Column {
anchors.fill: parent
anchors.margins: 8
spacing: 2
Text {
text: title + " (" + identifier + ")"
font.bold: true
}
Text {
text: message
}
}
}
}
}