List the labels of all lodgings in QML
To query the database, i have to run the query inside the same thread where the database was created, which means that Database should be a singleton not only within QML, but also in C++, and has to be the _same_ singleton in both worlds. Although i expose an object that i have created, i followed the same section titled “Exposing an existing object as a singleton” from Qt’s documentation[0]. The only difference is that i do not have to declare the element as a foreign type, because it is a bona fide QObject. [0]: https://doc.qt.io/qt-6/qml-singleton.html#exposing-an-existing- object-as-a-singleton
This commit is contained in:
parent
7eeccbb033
commit
d0e2659c30
|
@ -9,6 +9,7 @@ qt_add_qml_module(${PROJECT_NAME}
|
|||
QtCore
|
||||
QtQuick
|
||||
SOURCES
|
||||
calendarlistmodel.cpp calendarlistmodel.h
|
||||
database.cpp database.h
|
||||
mnemonicattached.cpp mnemonicattached.h
|
||||
QML_FILES
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
@ -15,6 +16,18 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
|
||||
delegate: Text {
|
||||
required property string name
|
||||
|
||||
text: name
|
||||
}
|
||||
model: CalendarListModel {
|
||||
}
|
||||
}
|
||||
|
||||
MnemonicAction {
|
||||
id: logoutAction
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
#include "calendarlistmodel.h"
|
||||
#include <QSqlQuery>
|
||||
#include <QVariant>
|
||||
#include "database.h"
|
||||
|
||||
struct CalendarListModel::Calendar
|
||||
{
|
||||
QString name;
|
||||
};
|
||||
|
||||
CalendarListModel::CalendarListModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
, m_calendars{}
|
||||
{
|
||||
fetch();
|
||||
}
|
||||
|
||||
CalendarListModel::~CalendarListModel()
|
||||
{
|
||||
qDeleteAll(m_calendars);
|
||||
}
|
||||
|
||||
QVariant CalendarListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole) {
|
||||
return {};
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
int CalendarListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_calendars.count();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CalendarListModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[Name] = "name";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void CalendarListModel::fetch()
|
||||
{
|
||||
Database::query([]() {
|
||||
QSqlQuery query("select label from campsite order by label");
|
||||
QVector<Calendar> calendars;
|
||||
while (query.next()) {
|
||||
Calendar calendar{query.value(0).toString()};
|
||||
calendars.append(calendar);
|
||||
}
|
||||
return calendars;
|
||||
}).then([this](const QVector<Calendar> &calendars) {
|
||||
if (calendars.empty()) {
|
||||
return;
|
||||
}
|
||||
beginInsertRows(QModelIndex(), 0, calendars.count() - 1);
|
||||
for (const Calendar &calendar : calendars) {
|
||||
m_calendars.append(new Calendar(calendar));
|
||||
}
|
||||
endInsertRows();
|
||||
});
|
||||
}
|
||||
|
||||
QVariant CalendarListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!checkIndex(index,
|
||||
QAbstractItemModel::CheckIndexOption::IndexIsValid
|
||||
| QAbstractItemModel::CheckIndexOption::ParentIsInvalid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Calendar *calendar = m_calendars.at(index.row());
|
||||
switch (role) {
|
||||
case Name:
|
||||
return calendar->name;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#include "moc_calendarlistmodel.cpp"
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef CALENDARLISTMODEL_H
|
||||
#define CALENDARLISTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
class CalendarListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
Name = Qt::UserRole,
|
||||
};
|
||||
|
||||
explicit CalendarListModel(QObject *parent = nullptr);
|
||||
~CalendarListModel() override;
|
||||
|
||||
QVariant headerData(int section,
|
||||
Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
struct Calendar;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(CalendarListModel)
|
||||
|
||||
void fetch();
|
||||
|
||||
QVector<Calendar *> m_calendars;
|
||||
};
|
||||
|
||||
#endif // CALENDARLISTMODEL_H
|
|
@ -2,7 +2,6 @@
|
|||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QtConcurrent>
|
||||
|
||||
Database::Database(QObject *parent)
|
||||
: QObject{parent}
|
||||
|
@ -12,6 +11,29 @@ Database::Database(QObject *parent)
|
|||
m_pool.setExpiryTimeout(-1);
|
||||
}
|
||||
|
||||
Database &Database::getInstance()
|
||||
{
|
||||
static Database instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Database *Database::create(QQmlEngine *qmlEngine, QJSEngine *)
|
||||
{
|
||||
Database &instance = getInstance();
|
||||
Q_ASSERT(qmlEngine->thread() == instance.thread());
|
||||
|
||||
static QQmlEngine *engine = nullptr;
|
||||
if (engine) {
|
||||
Q_ASSERT(qmlEngine == engine);
|
||||
} else {
|
||||
engine = qmlEngine;
|
||||
}
|
||||
|
||||
QJSEngine::setObjectOwnership(&instance, QJSEngine::CppOwnership);
|
||||
|
||||
return &instance;
|
||||
}
|
||||
|
||||
QFuture<void> Database::open(const QString &user,
|
||||
const QString &password,
|
||||
const QString &hostName,
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
#include <QFuture>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QThreadPool>
|
||||
#include <QtQmlIntegration>
|
||||
#include <QtConcurrent>
|
||||
|
||||
class Database : public QObject
|
||||
{
|
||||
|
@ -13,7 +14,9 @@ class Database : public QObject
|
|||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
explicit Database(QObject *parent = nullptr);
|
||||
static Database &getInstance();
|
||||
|
||||
static Database *create(QQmlEngine *qmlEngine, QJSEngine *);
|
||||
|
||||
Q_INVOKABLE QFuture<void> open(const QString &user,
|
||||
const QString &password,
|
||||
|
@ -24,12 +27,21 @@ public:
|
|||
const QString &connectOptions);
|
||||
Q_INVOKABLE QFuture<void> close();
|
||||
|
||||
template<class Function>
|
||||
static auto query(Function &&f)
|
||||
{
|
||||
return QtConcurrent::run(&getInstance().m_pool, f);
|
||||
}
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
void errorOcurred(const QString &errorMessage);
|
||||
void opened();
|
||||
|
||||
private:
|
||||
explicit Database(QObject *parent = nullptr);
|
||||
Q_DISABLE_COPY_MOVE(Database)
|
||||
|
||||
QThreadPool m_pool;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include "database.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -8,6 +9,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
Database::getInstance(); // return ignored; create instance before QML engine
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(
|
||||
&engine,
|
||||
|
|
Loading…
Reference in New Issue