Compare commits
3 Commits
5cc7192387
...
392d993c8a
Author | SHA1 | Date |
---|---|---|
jordi fita mas | 392d993c8a | |
jordi fita mas | 268f4329c0 | |
jordi fita mas | ca882f992b |
|
@ -5,13 +5,18 @@ qt_add_executable(${PROJECT_NAME}
|
||||||
qt_add_qml_module(${PROJECT_NAME}
|
qt_add_qml_module(${PROJECT_NAME}
|
||||||
URI Camper
|
URI Camper
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
DEPENDENCIES QtCore
|
DEPENDENCIES
|
||||||
|
QtCore
|
||||||
|
QtQuick
|
||||||
SOURCES
|
SOURCES
|
||||||
database.cpp database.h
|
database.cpp database.h
|
||||||
|
mnemonicattached.cpp mnemonicattached.h
|
||||||
QML_FILES
|
QML_FILES
|
||||||
ErrorNotification.qml
|
ErrorNotification.qml
|
||||||
LoginPage.qml
|
LoginPage.qml
|
||||||
Main.qml
|
Main.qml
|
||||||
|
MnemonicAction.qml
|
||||||
|
MnemonicLabel.qml
|
||||||
ReservationsPage.qml
|
ReservationsPage.qml
|
||||||
SelectableLabel.qml
|
SelectableLabel.qml
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,36 +9,26 @@ Page {
|
||||||
title: qsTr("Login")
|
title: qsTr("Login")
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Label {
|
MnemonicLabel {
|
||||||
text: qsTr("&User:")
|
buddy: user
|
||||||
|
mnemonic: qsTr("&User:")
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: user
|
id: user
|
||||||
|
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
validator: RegularExpressionValidator {
|
|
||||||
regularExpression: /[^s].*/
|
|
||||||
}
|
|
||||||
|
|
||||||
onAccepted: function () {
|
|
||||||
loginAction.trigger();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
MnemonicLabel {
|
||||||
text: qsTr("&Password:")
|
buddy: password
|
||||||
|
mnemonic: qsTr("&Password:")
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: password
|
id: password
|
||||||
|
|
||||||
echoMode: TextInput.Password
|
echoMode: TextInput.Password
|
||||||
|
|
||||||
onAccepted: function () {
|
|
||||||
loginAction.trigger();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -46,11 +36,10 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Action {
|
MnemonicAction {
|
||||||
id: loginAction
|
id: loginAction
|
||||||
|
|
||||||
enabled: user.acceptableInput
|
mnemonic: qsTr("Log &in")
|
||||||
text: "&Login"
|
|
||||||
|
|
||||||
onTriggered: function () {
|
onTriggered: function () {
|
||||||
Database.open(user.text, password.text);
|
Database.open(user.text, password.text);
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
required property string mnemonic
|
||||||
|
|
||||||
|
Mnemonic.label: mnemonic
|
||||||
|
shortcut: Mnemonic.sequence
|
||||||
|
text: Mnemonic.richTextLabel
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
required property Item buddy
|
||||||
|
required property string mnemonic
|
||||||
|
|
||||||
|
Mnemonic.label: control.mnemonic
|
||||||
|
text: Mnemonic.richTextLabel
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
sequence: control.Mnemonic.sequence
|
||||||
|
|
||||||
|
onActivated: function () {
|
||||||
|
control.buddy.forceActiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,19 @@ Page {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
icon.name: "system-log-out"
|
action: logoutAction
|
||||||
text: qsTr("&Log out")
|
|
||||||
|
|
||||||
onClicked: function () {
|
|
||||||
Database.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MnemonicAction {
|
||||||
|
id: logoutAction
|
||||||
|
|
||||||
|
icon.name: "system-log-out"
|
||||||
|
mnemonic: qsTr("Log &out")
|
||||||
|
|
||||||
|
onTriggered: function () {
|
||||||
|
Database.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
Database::Database(QObject *parent)
|
Database::Database(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
, m_pool{}
|
, m_pool{}
|
||||||
, m_connectionName{"main"}
|
|
||||||
{
|
{
|
||||||
m_pool.setMaxThreadCount(1);
|
m_pool.setMaxThreadCount(1);
|
||||||
m_pool.setExpiryTimeout(-1);
|
m_pool.setExpiryTimeout(-1);
|
||||||
|
@ -15,28 +14,36 @@ Database::Database(QObject *parent)
|
||||||
QFuture<void> Database::open(const QString &user, const QString &password)
|
QFuture<void> Database::open(const QString &user, const QString &password)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run(&m_pool, [this, user, password]() {
|
return QtConcurrent::run(&m_pool, [this, user, password]() {
|
||||||
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", m_connectionName);
|
QString errorMessage;
|
||||||
db.setConnectOptions("service=camper; options=-csearch_path=camper,public");
|
QString connectionName;
|
||||||
if (db.open(user, password)) {
|
{
|
||||||
emit opened();
|
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
|
||||||
} else {
|
db.setConnectOptions("service=camper; options=-csearch_path=camper,public");
|
||||||
const QString errorMessage(db.lastError().text());
|
if (db.open(user, password)) {
|
||||||
db = QSqlDatabase(); // Otherwise removeDatabase complains is still being used.
|
emit opened();
|
||||||
QSqlDatabase::removeDatabase(m_connectionName);
|
return;
|
||||||
emit errorOcurred(errorMessage);
|
}
|
||||||
|
errorMessage = db.lastError().text();
|
||||||
|
connectionName = db.connectionName();
|
||||||
}
|
}
|
||||||
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
|
emit errorOcurred(errorMessage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<void> Database::close()
|
QFuture<void> Database::close()
|
||||||
{
|
{
|
||||||
return QtConcurrent::run(&m_pool, [this]() {
|
return QtConcurrent::run(&m_pool, [this]() {
|
||||||
QSqlDatabase db = QSqlDatabase::database(m_connectionName);
|
QString connectionName;
|
||||||
if (!db.isValid()) {
|
{
|
||||||
return;
|
QSqlDatabase db = QSqlDatabase::database();
|
||||||
|
if (!db.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connectionName = db.connectionName();
|
||||||
|
db.close();
|
||||||
}
|
}
|
||||||
db.close();
|
QSqlDatabase::removeDatabase(connectionName);
|
||||||
QSqlDatabase::removeDatabase(m_connectionName);
|
|
||||||
emit closed();
|
emit closed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThreadPool m_pool;
|
QThreadPool m_pool;
|
||||||
QString m_connectionName;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATABASE_H
|
#endif // DATABASE_H
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
#include "mnemonicattached.h"
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
using namespace Qt::Literals::StringLiterals;
|
||||||
|
|
||||||
|
class MnemonicEventFilter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static MnemonicEventFilter &instance()
|
||||||
|
{
|
||||||
|
static MnemonicEventFilter s_instance;
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAltPressed() const { return m_altPressed; }
|
||||||
|
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override
|
||||||
|
{
|
||||||
|
Q_UNUSED(watched);
|
||||||
|
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||||
|
if (ke->key() == Qt::Key_Alt) {
|
||||||
|
m_altPressed = true;
|
||||||
|
emit altPressed();
|
||||||
|
}
|
||||||
|
} else if (event->type() == QEvent::KeyRelease) {
|
||||||
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||||
|
if (ke->key() == Qt::Key_Alt) {
|
||||||
|
m_altPressed = false;
|
||||||
|
emit altReleased();
|
||||||
|
}
|
||||||
|
} else if (event->type() == QEvent::ApplicationStateChange) {
|
||||||
|
if (m_altPressed) {
|
||||||
|
m_altPressed = false;
|
||||||
|
emit altReleased();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void altPressed();
|
||||||
|
void altReleased();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MnemonicEventFilter()
|
||||||
|
: QObject(nullptr)
|
||||||
|
{
|
||||||
|
qGuiApp->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m_altPressed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
MnemonicAttached::MnemonicAttached(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
, m_label{}
|
||||||
|
, m_richTextLabel{}
|
||||||
|
, m_active{MnemonicEventFilter::instance().isAltPressed()}
|
||||||
|
{
|
||||||
|
connect(&MnemonicEventFilter::instance(),
|
||||||
|
&MnemonicEventFilter::altPressed,
|
||||||
|
this,
|
||||||
|
&MnemonicAttached::onAltPressed);
|
||||||
|
connect(&MnemonicEventFilter::instance(),
|
||||||
|
&MnemonicEventFilter::altReleased,
|
||||||
|
this,
|
||||||
|
&MnemonicAttached::onAltReleased);
|
||||||
|
}
|
||||||
|
|
||||||
|
MnemonicAttached *MnemonicAttached::qmlAttachedProperties(QObject *object)
|
||||||
|
{
|
||||||
|
return new MnemonicAttached(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MnemonicAttached::label() const
|
||||||
|
{
|
||||||
|
return m_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MnemonicAttached::setLabel(const QString &label)
|
||||||
|
{
|
||||||
|
if (m_label == label) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_label = label;
|
||||||
|
emit labelChanged();
|
||||||
|
emit sequenceChanged();
|
||||||
|
|
||||||
|
updateRichText();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MnemonicAttached::richTextLabel() const
|
||||||
|
{
|
||||||
|
return m_richTextLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
QKeySequence MnemonicAttached::sequence() const
|
||||||
|
{
|
||||||
|
return QKeySequence::mnemonic(m_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MnemonicAttached::onAltPressed()
|
||||||
|
{
|
||||||
|
if (m_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_active = true;
|
||||||
|
updateRichText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MnemonicAttached::onAltReleased()
|
||||||
|
{
|
||||||
|
if (!m_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_active = false;
|
||||||
|
updateRichText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MnemonicAttached::updateRichText()
|
||||||
|
{
|
||||||
|
QString richTextLabel;
|
||||||
|
qsizetype pos = m_label.indexOf('&'_L1);
|
||||||
|
if (pos < 0 || pos + 1 == m_label.length()) {
|
||||||
|
richTextLabel = m_label;
|
||||||
|
} else if (m_active) {
|
||||||
|
richTextLabel = m_label.left(pos) + "<u>"_L1 + m_label.at(pos + 1) + "</u>"
|
||||||
|
+ m_label.mid(pos + 2);
|
||||||
|
} else {
|
||||||
|
richTextLabel = m_label.left(pos) + m_label.mid(pos + 1);
|
||||||
|
}
|
||||||
|
if (m_richTextLabel == richTextLabel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_richTextLabel = richTextLabel;
|
||||||
|
emit richTextLabelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "mnemonicattached.moc"
|
||||||
|
#include "moc_mnemonicattached.cpp"
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef MNEMONICATTACHED_H
|
||||||
|
#define MNEMONICATTACHED_H
|
||||||
|
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QtQmlIntegration>
|
||||||
|
|
||||||
|
class MnemonicAttached : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged FINAL)
|
||||||
|
Q_PROPERTY(QString richTextLabel READ richTextLabel NOTIFY richTextLabelChanged FINAL)
|
||||||
|
Q_PROPERTY(QKeySequence sequence READ sequence NOTIFY sequenceChanged FINAL)
|
||||||
|
|
||||||
|
QML_NAMED_ELEMENT(Mnemonic)
|
||||||
|
QML_UNCREATABLE("Mnemonic is only available via attached properties")
|
||||||
|
QML_ATTACHED(MnemonicAttached)
|
||||||
|
public:
|
||||||
|
explicit MnemonicAttached(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
static MnemonicAttached *qmlAttachedProperties(QObject *object);
|
||||||
|
|
||||||
|
QString label() const;
|
||||||
|
void setLabel(const QString &label);
|
||||||
|
|
||||||
|
QString richTextLabel() const;
|
||||||
|
|
||||||
|
QKeySequence sequence() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void enabledChanged();
|
||||||
|
void labelChanged();
|
||||||
|
void richTextLabelChanged();
|
||||||
|
void sequenceChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onAltPressed();
|
||||||
|
void onAltReleased();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateRichText();
|
||||||
|
|
||||||
|
QString m_label;
|
||||||
|
QString m_richTextLabel;
|
||||||
|
bool m_active;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MNEMONICATTACHED_H
|
Loading…
Reference in New Issue