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
|
QtCore
|
||||||
QtQuick
|
QtQuick
|
||||||
SOURCES
|
SOURCES
|
||||||
|
calendarlistmodel.cpp calendarlistmodel.h
|
||||||
database.cpp database.h
|
database.cpp database.h
|
||||||
mnemonicattached.cpp mnemonicattached.h
|
mnemonicattached.cpp mnemonicattached.h
|
||||||
QML_FILES
|
QML_FILES
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
@ -15,6 +16,18 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
delegate: Text {
|
||||||
|
required property string name
|
||||||
|
|
||||||
|
text: name
|
||||||
|
}
|
||||||
|
model: CalendarListModel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MnemonicAction {
|
MnemonicAction {
|
||||||
id: logoutAction
|
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 <QSqlDatabase>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
#include <QtConcurrent>
|
|
||||||
|
|
||||||
Database::Database(QObject *parent)
|
Database::Database(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
|
@ -12,6 +11,29 @@ Database::Database(QObject *parent)
|
||||||
m_pool.setExpiryTimeout(-1);
|
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,
|
QFuture<void> Database::open(const QString &user,
|
||||||
const QString &password,
|
const QString &password,
|
||||||
const QString &hostName,
|
const QString &hostName,
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
|
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QtQmlIntegration>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
class Database : public QObject
|
class Database : public QObject
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,9 @@ class Database : public QObject
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Database(QObject *parent = nullptr);
|
static Database &getInstance();
|
||||||
|
|
||||||
|
static Database *create(QQmlEngine *qmlEngine, QJSEngine *);
|
||||||
|
|
||||||
Q_INVOKABLE QFuture<void> open(const QString &user,
|
Q_INVOKABLE QFuture<void> open(const QString &user,
|
||||||
const QString &password,
|
const QString &password,
|
||||||
|
@ -24,12 +27,21 @@ public:
|
||||||
const QString &connectOptions);
|
const QString &connectOptions);
|
||||||
Q_INVOKABLE QFuture<void> close();
|
Q_INVOKABLE QFuture<void> close();
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
static auto query(Function &&f)
|
||||||
|
{
|
||||||
|
return QtConcurrent::run(&getInstance().m_pool, f);
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void closed();
|
void closed();
|
||||||
void errorOcurred(const QString &errorMessage);
|
void errorOcurred(const QString &errorMessage);
|
||||||
void opened();
|
void opened();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit Database(QObject *parent = nullptr);
|
||||||
|
Q_DISABLE_COPY_MOVE(Database)
|
||||||
|
|
||||||
QThreadPool m_pool;
|
QThreadPool m_pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -8,6 +9,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
Database::getInstance(); // return ignored; create instance before QML engine
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
&engine,
|
&engine,
|
||||||
|
|
Loading…
Reference in New Issue