Thank you all for your help. I decided to follow some of your advices and try to use a vector only for now, before I make it work the way I expect.
Now, I tried to use const reference, but I was unable to do this, because I would have to pass it during model's initialization and this is just not going to happen (since my model instance is created before the database / file is loaded). I decided not to play around with so called "naked" pointer and instead used a std::shared_ptr.
I thought I'd share my code here (at least what I have so far).
main.cpp
Code:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h:
Code:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "testitemlistmodel.h"
#include <QDataWidgetMapper>
#include <QMainWindow>
#include <QStandardItem>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
TestItemListModel *model;
QDataWidgetMapper *mapper;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
Code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "testclass.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// removed irrelevant code
model = new TestItemListModel();
std::vector<TestClass> data;
for(uint8_t i = 1; i < 11; i++) {
TestClass item;
item.setName("Name " + std::to_string(i));
item.setDescription("Description " + std::to_string(i));
item.setIdentifier(i);
data.push_back(item);
}
model->initializeData(std::make_shared< std::vector<TestClass> >(data));
ui->listView->setModel(model);
}
MainWindow::~MainWindow()
{
delete ui;
}
testclass.h (header only):
Code:
#ifndef TESTCLASS_H
#define TESTCLASS_H
class TestClass
{
private:
uint16_t identifier;
std::string name;
std::string description;
public:
// setters
void setIdentifier(uint16_t identifier) { this->identifier = identifier; }
void setName(std::string name) {this->name = name; }
void setDescription(std::string description) {this->description = description; }
// getters
uint16_t getIdentifier() { return identifier; }
std::string getName() { return name; }
std::string getDescription() { return description; }
};
#endif // TESTCLASS_H
testitemlistmodel.h:
Code:
#ifndef TestITEMLISTMODEL_H
#define TestITEMLISTMODEL_H
#include <QAbstractListModel>
#include <testclass.h>
#include <memory>
class TestItemListModel : public QAbstractListModel
{
Q_OBJECT
std::shared_ptr<std::vector<TestClass>> myData;
enum : uint8_t {
IDENTIFIER = 0x00,
NAME = 0x01,
DESCRIPTION = 0x02,
FIRST = IDENTIFIER,
LAST = DESCRIPTION
};
public:
explicit TestItemListModel(QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
void initializeData(std::shared_ptr<std::vector<TestClass>> data);
};
#endif // TestITEMLISTMODEL_H
testitemlistmodel.cpp:
Code:
#include "testitemlistmodel.h"
TestItemListModel::TestItemListModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void TestItemListModel::initializeData(std::shared_ptr<std::vector<TestClass>> data)
{
if(nullptr != data) {
this->myData = data;
}
}
QVariant TestItemListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
int row = index.row();
if(myData->size() < row || 0 > row) {
return QVariant();
}
int column = index.column();
if((Qt::DisplayRole == role || Qt::EditRole == role) && LAST >= column && FIRST <= column) {
switch(index.column()) {
case IDENTIFIER:
{
return QVariant((*myData)[row].getIdentifier());
}
case NAME:
{
return QVariant(QString::fromStdString((*myData)[row].getName()));
//return QVariant::fromValue<std::string>();;
}
case DESCRIPTION:
{
return QVariant(QString::fromStdString((*myData)[row].getDescription()));
}
}
}
return QVariant();
}
bool TestItemListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (data(index, role) == value) {
return false;
}
int row = index.row();
if(!index.isValid() || Qt::EditRole != role || myData->size() < row || 0 > row) {
return false;
}
int column = index.column();
switch(column) {
case IDENTIFIER:
if(uint16_t val = value.value<uint16_t>()) {
(*myData)[row].setIdentifier(val);
} else {
// throw exception ??
}
break;
case NAME:
(*myData)[row].setName(value.toString().toStdString());
break;
case DESCRIPTION:
(*myData)[row].setDescription(value.toString().toStdString());
break;
}
emit dataChanged(index, index);
return true;
}
I did remove all code that was irrelevant here (I really only left initializing part, because this is what I focused on at this moment). I'm also aware of few things missing here (despite using shared_ptr I probably should check for nullptr anyway before accessing it). It does what it is expected to do, I did only use mockup data here to test it.
Anyway, the main point of me posting it here is to ask for any kind of review and comments on how I could improve this code. Just to make sure it's clear, normally the data will be loaded inside MainWindow function that will create instance of my Loader, load data, extract the pointer (or reference or whatever will be suitable) and assign it to the model using TestItemListModel::initializeData function. So the model will exist by then.