From 62442721193576ddd1516c8df0611918fa23a63f Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 3 Nov 2025 11:12:15 +0100 Subject: [PATCH 01/83] Add libshv dependency to enable QxEvent service implementation --- .clang-tidy | 1 + .gitmodules | 3 + 3rdparty/libshv | 1 + CMakeLists.txt | 4 + .../libqfgui/src/framework/datadialogwidget.h | 2 +- quickevent/app/quickevent/CMakeLists.txt | 8 + .../Event/src/services/qx/qxclientservice.cpp | 187 ++++++++++++++---- .../Event/src/services/qx/qxclientservice.h | 16 ++ .../Event/src/services/serviceswidget.cpp | 7 +- .../Event/src/services/servicewidget.cpp | 11 +- .../Event/src/services/servicewidget.h | 2 +- 11 files changed, 188 insertions(+), 54 deletions(-) create mode 160000 3rdparty/libshv diff --git a/.clang-tidy b/.clang-tidy index fd21b3531..64c3c28fa 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,6 +40,7 @@ Checks: -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-special-member-functions, + -cppcoreguidelines-use-enum-class -hicpp-avoid-c-arrays, -hicpp-avoid-goto, -hicpp-braces-around-statements, diff --git a/.gitmodules b/.gitmodules index 6e2bec6bb..5006631e0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "3rdparty/necrolog"] path = 3rdparty/necrolog url = https://github.com/fvacek/necrolog.git +[submodule "3rdparty/libshv"] + path = 3rdparty/libshv + url = https://github.com/silicon-heaven/libshv.git diff --git a/3rdparty/libshv b/3rdparty/libshv new file mode 160000 index 000000000..3cbe496ea --- /dev/null +++ b/3rdparty/libshv @@ -0,0 +1 @@ +Subproject commit 3cbe496ea4d2c48695994850a09c2cc794c3f80b diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a214da86..b5b73faa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.18.4) set(QF_BUILD_QML_PLUGINS ON CACHE BOOL "Build with QML Plugins support") +set(QF_WITH_LIBSHV OFF CACHE BOOL "Build with libshv") project(quickbox LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 20) @@ -34,6 +35,9 @@ endif (WIN32) if (NOT TARGET libnecrolog) add_subdirectory(3rdparty/necrolog) endif() +if (QF_WITH_LIBSHV) + add_subdirectory(3rdparty/libshv) +endif() set(USE_QT6 ON) find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui Sql Qml Xml LinguistTools PrintSupport Svg SerialPort Multimedia Network) diff --git a/libqf/libqfgui/src/framework/datadialogwidget.h b/libqf/libqfgui/src/framework/datadialogwidget.h index 37c4c1d91..ec4cca8e0 100644 --- a/libqf/libqfgui/src/framework/datadialogwidget.h +++ b/libqf/libqfgui/src/framework/datadialogwidget.h @@ -26,7 +26,7 @@ class QFGUI_DECL_EXPORT DataDialogWidget : public DialogWidget qf::gui::model::DataDocument* dataDocument(bool throw_exc = qf::core::Exception::Throw); - Q_SLOT virtual bool load(const QVariant &id = QVariant(), int mode = qf::gui::model::DataDocument::ModeEdit); + virtual bool load(const QVariant &id = QVariant(), int mode = qf::gui::model::DataDocument::ModeEdit); bool acceptDialogDone(int result) Q_DECL_OVERRIDE; diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index b6218790e..13549e64f 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -273,6 +273,14 @@ qt6_add_lupdate(quickevent TS_FILES target_sources(quickevent PRIVATE ${QM_FILES}) target_include_directories(quickevent PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src) target_link_libraries(quickevent PUBLIC libquickeventcore libquickeventgui libqfgui libsiut) +if (QF_WITH_LIBSHV) + target_link_libraries(quickevent PUBLIC libshviotqt) + target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) +endif() + +foreach(plugin IN ITEMS Classes Runs Relays Receipts shared) + install(DIRECTORY plugins/${plugin}/qml/reports DESTINATION ${CMAKE_INSTALL_BINDIR}/reports/${plugin}/qml) +endforeach() # Extract version from appversion.h file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/appversion.h" APP_VERSION_H) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index 502483522..7a9acb8fd 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -9,6 +9,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -24,6 +28,10 @@ #include #include +using namespace shv::chainpack; +using namespace shv::iotqt::rpc; +using namespace shv::iotqt::node; + using namespace qf::core; using namespace qf::gui; using namespace qf::gui::dialogs; @@ -66,28 +74,41 @@ QString QxClientService::serviceId() } void QxClientService::run() { + using namespace shv::iotqt::rpc; + auto ss = settings(); - auto *reply = getRemoteEventInfo(ss.exchangeServerUrl(), apiToken()); - connect(reply, &QNetworkReply::finished, this, [this, reply, ss]() { - if (reply->error() == QNetworkReply::NetworkError::NoError) { - auto data = reply->readAll(); - auto doc = QJsonDocument::fromJson(data); - EventInfo event_info(doc.toVariant().toMap()); - setStatusMessage(event_info.name() + (event_info.stage_count() > 1? QStringLiteral(" E%1").arg(event_info.stage()): QString())); - m_eventId = event_info.id(); - connectToSSE(m_eventId); - if (!m_pollChangesTimer) { - m_pollChangesTimer = new QTimer(this); - connect(m_pollChangesTimer, &QTimer::timeout, this, &QxClientService::pollQxChanges); - } - pollQxChanges(); - m_pollChangesTimer->start(10000); - Super::run(); - } - else { - qfWarning() << "Cannot run QX service, network error:" << reply->errorString(); - } - }); + + delete m_rpcConnection; + m_rpcConnection = new ClientConnection(this); + m_rpcConnection->setConnectionString(ss.exchangeServerUrl()); + + connect(m_rpcConnection, &ClientConnection::brokerConnectedChanged, this, &QxClientService::onBrokerConnectedChanged); + connect(m_rpcConnection, &ClientConnection::socketError, this, &QxClientService::onBrokerSocketError); + connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxClientService::onBrokerLoginError); + connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxClientService::onRpcMessageReceived); + + m_rpcConnection->open(); + +// connect(reply, &QNetworkReply::finished, this, [this, reply, ss]() { +// if (reply->error() == QNetworkReply::NetworkError::NoError) { +// auto data = reply->readAll(); +// auto doc = QJsonDocument::fromJson(data); +// EventInfo event_info(doc.toVariant().toMap()); +// setStatusMessage(event_info.name() + (event_info.stage_count() > 1? QStringLiteral(" E%1").arg(event_info.stage()): QString())); +// m_eventId = event_info.id(); +// connectToSSE(m_eventId); +// if (!m_pollChangesTimer) { +// m_pollChangesTimer = new QTimer(this); +// connect(m_pollChangesTimer, &QTimer::timeout, this, &QxClientService::pollQxChanges); +// } +// pollQxChanges(); +// m_pollChangesTimer->start(10000); +// Super::run(); +// } +// else { +// qfWarning() << "Cannot run QX service, network error:" << reply->errorString(); +// } +// }); } void QxClientService::stop() @@ -537,35 +558,115 @@ EventInfo QxClientService::eventInfo() const // qfInfo() << qf::core::Utils::qvariantToJson(ei, false); return ei; } -/* -namespace { -auto query_to_json_csv(QSqlQuery &q) +//namespace { +//auto query_to_json_csv(QSqlQuery &q) +//{ +// QVariantList csv; +// { +// // QStringList columns{"name", "control_count", "length", "climb", "start_time", "interval", "start_slot_count"}; +// QStringList columns; +// auto rec = q.record(); +// for (auto i = 0; i < rec.count(); ++i) { +// columns << rec.field(i).name(); +// } +// csv.insert(csv.length(), columns); +// } +// while (q.next()) { +// QVariantList values; +// auto rec = q.record(); +// for (auto i = 0; i < rec.count(); ++i) { +// values << q.value(i); +// } +// csv.insert(csv.length(), values); +// } +// return csv; +//} +//} +int QxClientService::currentConnectionId() { - QVariantList csv; - { - // QStringList columns{"name", "control_count", "length", "climb", "start_time", "interval", "start_slot_count"}; - QStringList columns; - auto rec = q.record(); - for (auto i = 0; i < rec.count(); ++i) { - columns << rec.field(i).name(); - } - csv.insert(csv.length(), columns); + return qf::core::sql::Connection::forName().connectionId(); +} + +void QxClientService::onBrokerConnectedChanged(bool is_connected) +{ + if(is_connected) { + setStatus(Status::Running); + QTimer::singleShot(0, this, [this]() { + subscribeChanges(); +// testRpcCall(); + }); + } else { + setStatus(Status::Stopped); } - while (q.next()) { - QVariantList values; - auto rec = q.record(); - for (auto i = 0; i < rec.count(); ++i) { - values << q.value(i); + +} + +void QxClientService::onBrokerSocketError(const QString &err) +{ + setStatusMessage(tr("Broker socket error: %1").arg(err)); +} + +void QxClientService::onBrokerLoginError(const shv::chainpack::RpcError &err) +{ + setStatusMessage(tr("Broker login error: %1").arg(err.toString())); +} + +void QxClientService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) +{ +// shvLogFuncFrame() << msg.toCpon(); + if(msg.isRequest()) { + RpcRequest rq(msg); + qfMessage() << "RPC request received:" << rq.toPrettyString(); + if(m_shvTree->root()) { + m_shvTree->root()->handleRpcRequest(rq); } - csv.insert(csv.length(), values); } - return csv; + else if(msg.isResponse()) { + RpcResponse rp(msg); + qfMessage() << "RPC response received:" << rp.toPrettyString(); + } + else if(msg.isSignal()) { + RpcSignal nt(msg); + qfMessage() << "RPC signal received:" << nt.toPrettyString(); + } } + +void QxClientService::subscribeChanges() +{ + Q_ASSERT(m_rpcConnection); + QString shv_path = "test"; + QString signal_name = shv::chainpack::Rpc::SIG_VAL_CHANGED; + auto *rpc_call = RpcCall::createSubscriptionRequest(m_rpcConnection, shv_path, signal_name); + connect(rpc_call, &RpcCall::maybeResult, this, [this, shv_path, signal_name](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + if(error.isValid()) { + qfError() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribe error:" << error.toString(); + } + else { + qfMessage() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribed successfully" << result.toCpon(); + // generate data change without ret value check + m_rpcConnection->callShvMethod((shv_path + "/someInt").toStdString(), "set", 123); + QTimer::singleShot(500, this, [this, shv_path]() { + m_rpcConnection->callShvMethod((shv_path + "/someInt").toStdString(), "set", 321); + }); + } + }); + rpc_call->start(); } -*/ -int QxClientService::currentConnectionId() + +void QxClientService::testRpcCall() const { - return qf::core::sql::Connection::forName().connectionId(); + Q_ASSERT(m_rpcConnection); + auto *rpc_call = RpcCall::create(m_rpcConnection) + ->setShvPath("test") + ->setMethod("ls"); +// ->setTimeout(5000); + connect(rpc_call, &RpcCall::maybeResult, [](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + if(error.isValid()) + qfError() << "RPC call error:" << error.toString(); + else + qfInfo() << "Got RPC response, result:" << result.toCpon(); + }); + rpc_call->start(); } } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h index 636a54c4d..7e1f046be 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h @@ -7,6 +7,10 @@ class QNetworkReply; class QUrlQuery; class QTimer; +namespace shv::iotqt::node { class ShvNodeTree; } +namespace shv::iotqt::rpc { class ClientConnection; } +namespace shv::chainpack { class RpcMessage; class RpcError; } + namespace Event::services::qx { class QxClientServiceSettings : public ServiceSettings @@ -68,6 +72,14 @@ class QxClientService : public Service QUrl exchangeServerUrl() const; int eventId() const; +private: // shv + void onBrokerConnectedChanged(bool is_connected); + void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg); + void onBrokerSocketError(const QString &err); + void onBrokerLoginError(const shv::chainpack::RpcError &err); + + void subscribeChanges(); + void testRpcCall() const; private: void loadSettings() override; qf::gui::framework::DialogWidget *createDetailWidget() override; @@ -84,6 +96,10 @@ class QxClientService : public Service void pollQxChanges(); EventInfo eventInfo() const; +private: // shv + shv::iotqt::rpc::ClientConnection *m_rpcConnection = nullptr; + shv::iotqt::node::ShvNodeTree *m_shvTree = nullptr; + private: QNetworkAccessManager *m_networkManager = nullptr; QNetworkReply *m_replySSE = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/serviceswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/serviceswidget.cpp index e4c9a604a..324dd0424 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/serviceswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/serviceswidget.cpp @@ -35,12 +35,7 @@ void ServicesWidget::reload() Service *svc = Service::serviceAt(i); auto *sw = new ServiceWidget(); - sw->setStatus(svc->status()); - connect(svc, &Service::statusChanged, sw, &ServiceWidget::setStatus); - sw->setServiceId(svc->serviceId(), svc->serviceDisplayName()); - sw->setMessage(svc->statusMessage()); - connect(svc, &Service::statusMessageChanged, sw, &ServiceWidget::setMessage); - connect(sw, &ServiceWidget::setRunningRequest, svc, &Service::setRunning); + sw->setService(svc); ly2->addWidget(sw); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.cpp index dd4bf8233..3069eb848 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.cpp @@ -45,10 +45,15 @@ void ServiceWidget::setStatus(Service::Status st) } } -void ServiceWidget::setServiceId(const QString &id, const QString &display_name) +void ServiceWidget::setService(Service *service) { - m_serviceId = id; - ui->lblServiceName->setText(display_name.isEmpty()? id: display_name); + m_serviceId = service->serviceId(); + ui->lblServiceName->setText(service->serviceDisplayName()); + setStatus(service->status()); + connect(service, &Service::statusChanged, this, &ServiceWidget::setStatus); + setMessage(service->statusMessage()); + connect(service, &Service::statusMessageChanged, this, &ServiceWidget::setMessage); + connect(this, &ServiceWidget::setRunningRequest, service, &Service::setRunning); } QString ServiceWidget::serviceId() const diff --git a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.h index f659cafde..4d589d2fe 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.h @@ -21,7 +21,7 @@ class ServiceWidget : public QWidget ~ServiceWidget(); void setStatus(Service::Status st); - void setServiceId(const QString &id, const QString &display_name); + void setService(Service *service); QString serviceId() const; void setMessage(const QString &m); From dce19697a992c45780b2f869dcace7d2930cbdc9 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 8 Nov 2025 11:47:27 +0100 Subject: [PATCH 02/83] Rename QxClientService to QxEventService --- quickevent/app/quickevent/CMakeLists.txt | 7 +- .../plugins/Event/src/eventplugin.cpp | 4 +- ...qxclientservice.cpp => qxeventservice.cpp} | 84 +++++++++---------- .../{qxclientservice.h => qxeventservice.h} | 10 +-- ...icewidget.cpp => qxeventservicewidget.cpp} | 46 +++++----- ...servicewidget.h => qxeventservicewidget.h} | 14 ++-- ...rvicewidget.ui => qxeventservicewidget.ui} | 4 +- .../services/qx/qxlateregistrationswidget.cpp | 6 +- .../services/qx/qxlateregistrationswidget.h | 4 +- .../Event/src/services/qx/runchangedialog.cpp | 8 +- .../Event/src/services/qx/runchangedialog.h | 4 +- 11 files changed, 94 insertions(+), 97 deletions(-) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxclientservice.cpp => qxeventservice.cpp} (87%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxclientservice.h => qxeventservice.h} (91%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxclientservicewidget.cpp => qxeventservicewidget.cpp} (76%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxclientservicewidget.h => qxeventservicewidget.h} (65%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxclientservicewidget.ui => qxeventservicewidget.ui} (97%) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 13549e64f..b502afa91 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -89,11 +89,8 @@ add_executable(quickevent plugins/Event/src/services/serviceswidget.cpp plugins/Event/src/services/servicewidget.cpp plugins/Event/src/services/servicewidget.ui - plugins/Event/src/services/qx/qxclientservice.cpp - plugins/Event/src/services/qx/qxclientservice.h - plugins/Event/src/services/qx/qxclientservicewidget.cpp - plugins/Event/src/services/qx/qxclientservicewidget.h - plugins/Event/src/services/qx/qxclientservicewidget.ui + plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h + plugins/Event/src/services/qx/qxeventservicewidget.ui plugins/Event/src/services/qx/qxlateregistrationswidget.h plugins/Event/src/services/qx/qxlateregistrationswidget.cpp plugins/Event/src/services/qx/qxlateregistrationswidget.ui diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 796c38221..6f7accfcc 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -11,7 +11,7 @@ #include "services/serviceswidget.h" #include "services/emmaclient.h" -#include "services/qx/qxclientservice.h" +#include "services/qx/qxeventservice.h" #include #include @@ -380,7 +380,7 @@ void EventPlugin::onInstalled() auto *emma_client = new services::EmmaClient(this); services::Service::addService(emma_client); - auto shvapi_client = new services::qx::QxClientService(this); + auto shvapi_client = new services::qx::QxEventService(this); services::Service::addService(shvapi_client); { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp similarity index 87% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 7a9acb8fd..6b673328e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -1,5 +1,5 @@ -#include "qxclientservice.h" -#include "qxclientservicewidget.h" +#include "qxeventservice.h" +#include "qxeventservicewidget.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -56,24 +56,24 @@ namespace Event::services::qx { //=============================================== // QxClientService //=============================================== -QxClientService::QxClientService(QObject *parent) - : Super(QxClientService::serviceId(), parent) +QxEventService::QxEventService(QObject *parent) + : Super(QxEventService::serviceId(), parent) { auto *event_plugin = getPlugin(); - connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &QxClientService::onDbEventNotify, Qt::QueuedConnection); + connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &QxEventService::onDbEventNotify, Qt::QueuedConnection); } -QString QxClientService::serviceDisplayName() const +QString QxEventService::serviceDisplayName() const { return tr("QE Exchange"); } -QString QxClientService::serviceId() +QString QxEventService::serviceId() { return QStringLiteral("qx"); } -void QxClientService::run() { +void QxEventService::run() { using namespace shv::iotqt::rpc; auto ss = settings(); @@ -82,10 +82,10 @@ void QxClientService::run() { m_rpcConnection = new ClientConnection(this); m_rpcConnection->setConnectionString(ss.exchangeServerUrl()); - connect(m_rpcConnection, &ClientConnection::brokerConnectedChanged, this, &QxClientService::onBrokerConnectedChanged); - connect(m_rpcConnection, &ClientConnection::socketError, this, &QxClientService::onBrokerSocketError); - connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxClientService::onBrokerLoginError); - connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxClientService::onRpcMessageReceived); + connect(m_rpcConnection, &ClientConnection::brokerConnectedChanged, this, &QxEventService::onBrokerConnectedChanged); + connect(m_rpcConnection, &ClientConnection::socketError, this, &QxEventService::onBrokerSocketError); + connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxEventService::onBrokerLoginError); + connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxEventService::onRpcMessageReceived); m_rpcConnection->open(); @@ -111,7 +111,7 @@ void QxClientService::run() { // }); } -void QxClientService::stop() +void QxEventService::stop() { disconnectSSE(); if (m_pollChangesTimer) { @@ -120,13 +120,13 @@ void QxClientService::stop() Super::stop(); } -qf::gui::framework::DialogWidget *QxClientService::createDetailWidget() +qf::gui::framework::DialogWidget *QxEventService::createDetailWidget() { - auto *w = new QxClientServiceWidget(); + auto *w = new QxEventServiceWidget(); return w; } -void QxClientService::loadSettings() +void QxEventService::loadSettings() { Super::loadSettings(); auto ss = settings(); @@ -136,7 +136,7 @@ void QxClientService::loadSettings() m_settings = ss; } -void QxClientService::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) +void QxEventService::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) { Q_UNUSED(connection_id) Q_UNUSED(data) @@ -183,7 +183,7 @@ void QxClientService::onDbEventNotify(const QString &domain, int connection_id, } } -QNetworkAccessManager *QxClientService::networkManager() +QNetworkAccessManager *QxEventService::networkManager() { if (!m_networkManager) { m_networkManager = new QNetworkAccessManager(this); @@ -191,7 +191,7 @@ QNetworkAccessManager *QxClientService::networkManager() return m_networkManager; } -QNetworkReply *QxClientService::getRemoteEventInfo(const QString &qxhttp_host, const QString &api_token) +QNetworkReply *QxEventService::getRemoteEventInfo(const QString &qxhttp_host, const QString &api_token) { auto *nm = networkManager(); QNetworkRequest request; @@ -202,7 +202,7 @@ QNetworkReply *QxClientService::getRemoteEventInfo(const QString &qxhttp_host, c return nm->get(request); } -QNetworkReply *QxClientService::postEventInfo(const QString &qxhttp_host, const QString &api_token) +QNetworkReply *QxEventService::postEventInfo(const QString &qxhttp_host, const QString &api_token) { auto *nm = networkManager(); QNetworkRequest request; @@ -218,7 +218,7 @@ QNetworkReply *QxClientService::postEventInfo(const QString &qxhttp_host, const return nm->post(request, data); } -void QxClientService::postStartListIofXml3(QObject *context, std::function call_back) +void QxEventService::postStartListIofXml3(QObject *context, std::function call_back) { auto *ep = getPlugin(); int current_stage = ep->currentStageId(); @@ -229,7 +229,7 @@ void QxClientService::postStartListIofXml3(QObject *context, std::function call_back) +void QxEventService::postRuns(QObject *context, std::function call_back) { auto *ep = getPlugin(); int current_stage = ep->currentStageId(); @@ -241,7 +241,7 @@ void QxClientService::postRuns(QObject *context, std::function c } } -void QxClientService::getHttpJson(const QString &path, const QUrlQuery &query, QObject *context, const std::function &call_back) +void QxEventService::getHttpJson(const QString &path, const QUrlQuery &query, QObject *context, const std::function &call_back) { auto url = exchangeServerUrl(); url.setPath(path); @@ -270,7 +270,7 @@ void QxClientService::getHttpJson(const QString &path, const QUrlQuery &query, Q }); } -QNetworkReply* QxClientService::getQxChangesReply(int from_id) +QNetworkReply* QxEventService::getQxChangesReply(int from_id) { auto url = exchangeServerUrl(); @@ -282,7 +282,7 @@ QNetworkReply* QxClientService::getQxChangesReply(int from_id) return networkManager()->get(request); } -int QxClientService::eventId() const +int QxEventService::eventId() const { if (m_eventId == 0) { throw qf::core::Exception(tr("Event ID is not loaded, service is not probably running.")); @@ -290,7 +290,7 @@ int QxClientService::eventId() const return m_eventId; } -QByteArray QxClientService::apiToken() const +QByteArray QxEventService::apiToken() const { // API token must not be cached to enable service point // always to current stage event on qxhttpd @@ -299,13 +299,13 @@ QByteArray QxClientService::apiToken() const return event_plugin->stageData(current_stage).qxApiToken().toUtf8(); } -QUrl QxClientService::exchangeServerUrl() const +QUrl QxEventService::exchangeServerUrl() const { auto ss = settings(); return QUrl(ss.exchangeServerUrl()); } -void QxClientService::postFileCompressed(std::optional path, std::optional name, QByteArray data, QObject *context , std::function call_back) +void QxEventService::postFileCompressed(std::optional path, std::optional name, QByteArray data, QObject *context , std::function call_back) { auto url = exchangeServerUrl(); @@ -333,7 +333,7 @@ void QxClientService::postFileCompressed(std::optional path, std::optio }); } -void QxClientService::uploadSpecFile(SpecFile file, QByteArray data, QObject *context, const std::function &call_back) +void QxEventService::uploadSpecFile(SpecFile file, QByteArray data, QObject *context, const std::function &call_back) { switch (file) { case SpecFile::StartListIofXml3: @@ -345,7 +345,7 @@ void QxClientService::uploadSpecFile(SpecFile file, QByteArray data, QObject *co } } -QByteArray QxClientService::zlibCompress(QByteArray data) +QByteArray QxEventService::zlibCompress(QByteArray data) { QByteArray compressedData = qCompress(data); // strip the 4-byte length put on by qCompress @@ -354,7 +354,7 @@ QByteArray QxClientService::zlibCompress(QByteArray data) return compressedData; } -void QxClientService::httpPostJson(const QString &path, const QString &query, QVariantMap json, QObject *context, const std::function &call_back) +void QxEventService::httpPostJson(const QString &path, const QString &query, QVariantMap json, QObject *context, const std::function &call_back) { if (!isRunning()) { return; @@ -394,7 +394,7 @@ void QxClientService::httpPostJson(const QString &path, const QString &query, QV } } -void QxClientService::connectToSSE(int event_id) +void QxEventService::connectToSSE(int event_id) { Q_UNUSED(event_id); // auto url = exchangeServerUrl(); @@ -417,7 +417,7 @@ void QxClientService::connectToSSE(int event_id) // }); } -void QxClientService::disconnectSSE() +void QxEventService::disconnectSSE() { if (m_replySSE) { qfInfo() << "Disconnecting SSE:" << m_replySSE; @@ -426,7 +426,7 @@ void QxClientService::disconnectSSE() } } -void QxClientService::pollQxChanges() +void QxEventService::pollQxChanges() { auto event_plugin = getPlugin(); if(!getPlugin()->isEventOpen()) { @@ -501,7 +501,7 @@ void QxClientService::pollQxChanges() } } -EventInfo QxClientService::eventInfo() const +EventInfo QxEventService::eventInfo() const { auto *event_plugin = getPlugin(); auto *event_config = event_plugin->eventConfig(); @@ -582,12 +582,12 @@ EventInfo QxClientService::eventInfo() const // return csv; //} //} -int QxClientService::currentConnectionId() +int QxEventService::currentConnectionId() { return qf::core::sql::Connection::forName().connectionId(); } -void QxClientService::onBrokerConnectedChanged(bool is_connected) +void QxEventService::onBrokerConnectedChanged(bool is_connected) { if(is_connected) { setStatus(Status::Running); @@ -601,17 +601,17 @@ void QxClientService::onBrokerConnectedChanged(bool is_connected) } -void QxClientService::onBrokerSocketError(const QString &err) +void QxEventService::onBrokerSocketError(const QString &err) { setStatusMessage(tr("Broker socket error: %1").arg(err)); } -void QxClientService::onBrokerLoginError(const shv::chainpack::RpcError &err) +void QxEventService::onBrokerLoginError(const shv::chainpack::RpcError &err) { setStatusMessage(tr("Broker login error: %1").arg(err.toString())); } -void QxClientService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) +void QxEventService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) { // shvLogFuncFrame() << msg.toCpon(); if(msg.isRequest()) { @@ -631,7 +631,7 @@ void QxClientService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg } } -void QxClientService::subscribeChanges() +void QxEventService::subscribeChanges() { Q_ASSERT(m_rpcConnection); QString shv_path = "test"; @@ -653,7 +653,7 @@ void QxClientService::subscribeChanges() rpc_call->start(); } -void QxClientService::testRpcCall() const +void QxEventService::testRpcCall() const { Q_ASSERT(m_rpcConnection); auto *rpc_call = RpcCall::create(m_rpcConnection) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h similarity index 91% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 7e1f046be..1ab8d14b7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -13,13 +13,13 @@ namespace shv::chainpack { class RpcMessage; class RpcError; } namespace Event::services::qx { -class QxClientServiceSettings : public ServiceSettings +class QxEventServiceSettings : public ServiceSettings { using Super = ServiceSettings; QF_VARIANTMAP_FIELD2(QString, e, setE, xchangeServerUrl, "http://localhost:8000") public: - QxClientServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} + QxEventServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} }; class EventInfo : public QVariantMap @@ -38,7 +38,7 @@ class EventInfo : public QVariantMap EventInfo(const QVariantMap &data = QVariantMap()) : QVariantMap(data) {} }; -class QxClientService : public Service +class QxEventService : public Service { Q_OBJECT @@ -46,14 +46,14 @@ class QxClientService : public Service public: static constexpr auto QX_API_TOKEN = "qx-api-token"; public: - QxClientService(QObject *parent); + QxEventService(QObject *parent); static QString serviceId(); QString serviceDisplayName() const override; void run() override; void stop() override; - QxClientServiceSettings settings() const {return QxClientServiceSettings(m_settings);} + QxEventServiceSettings settings() const {return QxEventServiceSettings(m_settings);} void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); QNetworkAccessManager* networkManager(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp similarity index 76% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index e9a04902e..ede33ffb4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -1,6 +1,6 @@ -#include "qxclientservicewidget.h" -#include "ui_qxclientservicewidget.h" -#include "qxclientservice.h" +#include "qxeventservicewidget.h" +#include "ui_qxeventservicewidget.h" +#include "qxeventservice.h" #include @@ -19,14 +19,14 @@ using qf::gui::framework::getPlugin; namespace Event::services::qx { -QxClientServiceWidget::QxClientServiceWidget(QWidget *parent) +QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) : Super(parent) - , ui(new Ui::QxClientServiceWidget) + , ui(new Ui::QxEventServiceWidget) { setPersistentSettingsId("QxClientServiceWidget"); ui->setupUi(this); - connect(ui->edServerUrl, &QLineEdit::textChanged, this, &QxClientServiceWidget::updateOCheckListPostUrl); - connect(ui->edApiToken, &QLineEdit::textChanged, this, &QxClientServiceWidget::updateOCheckListPostUrl); + connect(ui->edServerUrl, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); + connect(ui->edApiToken, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); setMessage(""); @@ -38,18 +38,18 @@ QxClientServiceWidget::QxClientServiceWidget(QWidget *parent) ui->edServerUrl->setText(settings.exchangeServerUrl()); ui->edApiToken->setText(svc->apiToken()); ui->edCurrentStage->setValue(current_stage); - connect(ui->btTestConnection, &QAbstractButton::clicked, this, &QxClientServiceWidget::testConnection); - connect(ui->btExportEventInfo, &QAbstractButton::clicked, this, &QxClientServiceWidget::exportEventInfo); - connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxClientServiceWidget::exportStartList); - connect(ui->btExportRuns, &QAbstractButton::clicked, this, &QxClientServiceWidget::exportRuns); + connect(ui->btTestConnection, &QAbstractButton::clicked, this, &QxEventServiceWidget::testConnection); + connect(ui->btExportEventInfo, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportEventInfo); + connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportStartList); + connect(ui->btExportRuns, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportRuns); } -QxClientServiceWidget::~QxClientServiceWidget() +QxEventServiceWidget::~QxEventServiceWidget() { delete ui; } -void QxClientServiceWidget::setMessage(const QString &msg, MessageType msg_type) +void QxEventServiceWidget::setMessage(const QString &msg, MessageType msg_type) { if (msg.isEmpty()) { ui->lblStatus->setStyleSheet({}); @@ -70,7 +70,7 @@ void QxClientServiceWidget::setMessage(const QString &msg, MessageType msg_type) ui->lblStatus->setText(msg); } -bool QxClientServiceWidget::acceptDialogDone(int result) +bool QxEventServiceWidget::acceptDialogDone(int result) { if(result == QDialog::Accepted) { if(!saveSettings()) { @@ -80,14 +80,14 @@ bool QxClientServiceWidget::acceptDialogDone(int result) return true; } -QxClientService *QxClientServiceWidget::service() +QxEventService *QxEventServiceWidget::service() { - auto *svc = qobject_cast(Service::serviceByName(QxClientService::serviceId())); - QF_ASSERT(svc, QxClientService::serviceId() + " doesn't exist", return nullptr); + auto *svc = qobject_cast(Service::serviceByName(QxEventService::serviceId())); + QF_ASSERT(svc, QxEventService::serviceId() + " doesn't exist", return nullptr); return svc; } -bool QxClientServiceWidget::saveSettings() +bool QxEventServiceWidget::saveSettings() { auto *svc = service(); if(svc) { @@ -104,14 +104,14 @@ bool QxClientServiceWidget::saveSettings() return true; } -void QxClientServiceWidget::updateOCheckListPostUrl() +void QxEventServiceWidget::updateOCheckListPostUrl() { auto url = QStringLiteral("%1/api/event/current/oc").arg(ui->edServerUrl->text()); ui->edOChecklistUrl->setText(url); ui->edOChecklistUrlHeader->setText(QStringLiteral("qx-api-token=%1").arg(ui->edApiToken->text())); } -void QxClientServiceWidget::testConnection() +void QxEventServiceWidget::testConnection() { auto *svc = service(); Q_ASSERT(svc); @@ -131,7 +131,7 @@ void QxClientServiceWidget::testConnection() }); } -void QxClientServiceWidget::exportEventInfo() +void QxEventServiceWidget::exportEventInfo() { auto *svc = service(); Q_ASSERT(svc); @@ -151,7 +151,7 @@ void QxClientServiceWidget::exportEventInfo() }); } -void QxClientServiceWidget::exportStartList() +void QxEventServiceWidget::exportStartList() { auto *svc = service(); Q_ASSERT(svc); @@ -167,7 +167,7 @@ void QxClientServiceWidget::exportStartList() }); } -void QxClientServiceWidget::exportRuns() +void QxEventServiceWidget::exportRuns() { auto *svc = service(); Q_ASSERT(svc); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h similarity index 65% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.h rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h index f1b108a30..19454ad86 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h @@ -5,23 +5,23 @@ namespace Event::services::qx { namespace Ui { -class QxClientServiceWidget; +class QxEventServiceWidget; } -class QxClientService; +class QxEventService; -class QxClientServiceWidget : public qf::gui::framework::DialogWidget +class QxEventServiceWidget : public qf::gui::framework::DialogWidget { Q_OBJECT using Super = qf::gui::framework::DialogWidget; public: - explicit QxClientServiceWidget(QWidget *parent = nullptr); - ~QxClientServiceWidget() override; + explicit QxEventServiceWidget(QWidget *parent = nullptr); + ~QxEventServiceWidget() override; private: enum class MessageType { Ok, Error, Progress }; void setMessage(const QString &msg = {}, MessageType msg_type = MessageType::Ok); - QxClientService* service(); + QxEventService* service(); bool saveSettings(); void updateOCheckListPostUrl(); void testConnection(); @@ -29,7 +29,7 @@ class QxClientServiceWidget : public qf::gui::framework::DialogWidget void exportStartList(); void exportRuns(); private: - Ui::QxClientServiceWidget *ui; + Ui::QxEventServiceWidget *ui; bool acceptDialogDone(int result) override; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui similarity index 97% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.ui rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui index d8824707e..261a65af9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -1,7 +1,7 @@ - Event::services::qx::QxClientServiceWidget - + Event::services::qx::QxEventServiceWidget + 0 diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp index f0747e77a..083af5d69 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp @@ -1,7 +1,7 @@ #include "qxlateregistrationswidget.h" #include "ui_qxlateregistrationswidget.h" -#include "qxclientservice.h" +#include "qxeventservice.h" #include "runchangedialog.h" #include "runchange.h" @@ -152,9 +152,9 @@ void QxLateRegistrationsWidget::onVisibleChanged(bool is_visible) } } -QxClientService *QxLateRegistrationsWidget::service() +QxEventService *QxLateRegistrationsWidget::service() { - auto *svc = qobject_cast(Event::services::Service::serviceByName(QxClientService::serviceId())); + auto *svc = qobject_cast(Event::services::Service::serviceByName(QxEventService::serviceId())); Q_ASSERT(svc); return svc; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h index 6c972c739..ea906b649 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h @@ -10,7 +10,7 @@ namespace Ui { class QxLateRegistrationsWidget; } -class QxClientService; +class QxEventService; class QxLateRegistrationsWidget : public QWidget { @@ -23,7 +23,7 @@ class QxLateRegistrationsWidget : public QWidget void onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload); void onVisibleChanged(bool is_visible); private: - QxClientService* service(); + QxEventService* service(); void reload(); void addQxChangeRow(int sql_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp index c44c38a94..789cb44e0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp @@ -1,7 +1,7 @@ #include "runchangedialog.h" #include "ui_runchangedialog.h" -#include "qxclientservice.h" +#include "qxeventservice.h" #include "runchange.h" #include @@ -72,9 +72,9 @@ RunChangeDialog::~RunChangeDialog() delete ui; } -QxClientService *RunChangeDialog::service() +QxEventService *RunChangeDialog::service() { - auto *svc = qobject_cast(Service::serviceByName(QxClientService::serviceId())); + auto *svc = qobject_cast(Service::serviceByName(QxEventService::serviceId())); Q_ASSERT(svc); return svc; } @@ -220,7 +220,7 @@ void RunChangeDialog::resolveChanges(bool is_accepted) url.setQuery(query); request.setUrl(url); - request.setRawHeader(QxClientService::QX_API_TOKEN, svc->apiToken()); + request.setRawHeader(QxEventService::QX_API_TOKEN, svc->apiToken()); auto *reply = nm->get(request); connect(reply, &QNetworkReply::finished, this, [this, reply]() { if (reply->error() == QNetworkReply::NetworkError::NoError) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h index d704a1d48..15a9bf147 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h @@ -14,7 +14,7 @@ class RunChangeDialog; } struct RunChange; -class QxClientService; +class QxEventService; class RunChangeDialog : public QDialog { @@ -25,7 +25,7 @@ class RunChangeDialog : public QDialog ~RunChangeDialog() override; private: - QxClientService* service(); + QxEventService* service(); void setMessage(const QString &msg, bool error); void loadOrigValues(); From 2b49c7c82854a1915ffba38f814d1d0951bc3a10 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 9 Nov 2025 18:34:22 +0100 Subject: [PATCH 03/83] Fix DesktopUtils::moveRectToVisibleDesktopScreen --- libqf/libqfgui/src/framework/dialogwidget.cpp | 15 ++++-------- libqf/libqfgui/src/framework/dialogwidget.h | 2 +- .../src/framework/ipersistentsettings.cpp | 23 ++++++++----------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/libqf/libqfgui/src/framework/dialogwidget.cpp b/libqf/libqfgui/src/framework/dialogwidget.cpp index f46cd8f23..8d5769997 100644 --- a/libqf/libqfgui/src/framework/dialogwidget.cpp +++ b/libqf/libqfgui/src/framework/dialogwidget.cpp @@ -9,13 +9,13 @@ using namespace qf::gui::framework; -DialogWidget::DialogWidget(QWidget *parent) : - Super(parent), IPersistentSettings(this) +DialogWidget::DialogWidget(QWidget *parent) + : Super(parent) + , IPersistentSettings(this) { } -DialogWidget::~DialogWidget() -= default; +DialogWidget::~DialogWidget() = default; bool DialogWidget::acceptDialogDone(int result) { @@ -23,12 +23,7 @@ bool DialogWidget::acceptDialogDone(int result) Q_UNUSED(result); return true; } -/* -QVariant DialogWidget::acceptDialogDone_qml(const QVariant &result) -{ - return acceptDialogDone(result.toBool()); -} -*/ + void DialogWidget::settleDownInDialog_qml(const QVariant &dlg) { auto *o = dlg.value(); diff --git a/libqf/libqfgui/src/framework/dialogwidget.h b/libqf/libqfgui/src/framework/dialogwidget.h index 13893c8a0..611be6b95 100644 --- a/libqf/libqfgui/src/framework/dialogwidget.h +++ b/libqf/libqfgui/src/framework/dialogwidget.h @@ -32,7 +32,7 @@ class QFGUI_DECL_EXPORT DialogWidget : public Frame, public IPersistentSettings typedef Frame Super; public: explicit DialogWidget(QWidget *parent = nullptr); - ~DialogWidget() Q_DECL_OVERRIDE; + ~DialogWidget() override; QF_PROPERTY_IMPL(QString, t, T, itle) QF_PROPERTY_IMPL(QString, i, I, conSource) diff --git a/libqf/libqfgui/src/framework/ipersistentsettings.cpp b/libqf/libqfgui/src/framework/ipersistentsettings.cpp index c639c374c..7fff48174 100644 --- a/libqf/libqfgui/src/framework/ipersistentsettings.cpp +++ b/libqf/libqfgui/src/framework/ipersistentsettings.cpp @@ -48,7 +48,7 @@ static void callMethodRecursively(QObject *obj, const char *method_name) QMetaMethod mm = obj->metaObject()->method(ix); mm.invoke(obj); } - Q_FOREACH(auto *o, obj->children()) { + for (auto *o : obj->children()) { //static int level = 0; //level++; //QString indent = QString(level, ' '); @@ -103,25 +103,20 @@ QString IPersistentSettings::rawPersistentSettingsPath() QString persistent_id = persistentSettingsId(); QStringList raw_path; if(!persistent_id.isEmpty()) { - for(QObject *obj=m_controlledObject->parent(); obj!=nullptr; obj=obj->parent()) { + for(QObject* obj = m_controlledObject->parent(); obj != nullptr; obj = obj->parent()) { auto *ps = dynamic_cast(obj); if(ps) { QString pp = ps->rawPersistentSettingsPath(); - if(!pp.isEmpty()) + if(!pp.isEmpty()) { raw_path.insert(0, pp); - //qfWarning() << "reading property 'persistentSettingsId' error" << obj << "casted to IPersistentSettings" << ps; - //qfWarning() << "\tcorrect value should be:" << parent_id; + } break; } - QVariant vid = obj->property("persistentSettingsId"); - QString parent_id = vid.toString(); - if(!parent_id.isEmpty()) { - raw_path.insert(0, parent_id); - } - - // reading property using QQmlProperty is crashing my app Qt 5.3.1 commit a83826dad0f62d7a96f5a6093240e4c8f7f2e06e - //QQmlProperty p(obj, "persistentSettingsId"); - //QVariant v2 = p.read(); + QVariant vid = obj->property("persistentSettingsId"); + QString parent_id = vid.toString(); + if(!parent_id.isEmpty()) { + raw_path.insert(0, parent_id); + } } raw_path.append(persistent_id); } From 4b1f96f3e85cb7f92002ca2c6558735ee0236c0b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 9 Nov 2025 18:34:34 +0100 Subject: [PATCH 04/83] Update libshv --- 3rdparty/libshv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/libshv b/3rdparty/libshv index 3cbe496ea..40f0b3cf2 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit 3cbe496ea4d2c48695994850a09c2cc794c3f80b +Subproject commit 40f0b3cf213ab799fb17bf6a31ce527a8851ee30 From 317424d02edd070e67ae6fde98f0db3e13c053c9 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 9 Nov 2025 18:35:51 +0100 Subject: [PATCH 05/83] Add QX event SHV nodes --- .../src/reportoptionsdialog.h | 8 +- quickevent/app/quickevent/CMakeLists.txt | 17 +- .../plugins/Event/src/services/qx/nodes.cpp | 300 ++++++++++++++++++ .../plugins/Event/src/services/qx/nodes.h | 103 ++++++ .../Event/src/services/qx/qxeventservice.cpp | 74 +++-- .../Event/src/services/qx/qxeventservice.h | 14 +- .../src/services/qx/qxeventservicewidget.cpp | 6 +- .../src/services/qx/qxeventservicewidget.ui | 2 +- .../plugins/Event/src/services/qx/qxnode.cpp | 36 +++ .../plugins/Event/src/services/qx/qxnode.h | 23 ++ .../Event/src/services/qx/runchangedialog.cpp | 2 +- .../Event/src/services/qx/sqlapinode.cpp | 119 +++++++ .../Event/src/services/qx/sqlapinode.h | 27 ++ 13 files changed, 682 insertions(+), 49 deletions(-) create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.h create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h diff --git a/libquickevent/libquickeventgui/src/reportoptionsdialog.h b/libquickevent/libquickeventgui/src/reportoptionsdialog.h index e4b22c6f9..bdccb558b 100644 --- a/libquickevent/libquickeventgui/src/reportoptionsdialog.h +++ b/libquickevent/libquickeventgui/src/reportoptionsdialog.h @@ -86,13 +86,13 @@ class QUICKEVENTGUI_DECL_EXPORT ReportOptionsDialog : public QDialog, public qf: explicit ReportOptionsDialog(QWidget *parent = nullptr); ~ReportOptionsDialog() override; - int exec() Q_DECL_OVERRIDE; + int exec() override; void setStartListPrintVacantsVisible(bool b); void setStartListForRelays(); - QString persistentSettingsPath() Q_DECL_OVERRIDE; - bool setPersistentSettingsId(const QString &id) Q_DECL_OVERRIDE; + QString persistentSettingsPath() override; + bool setPersistentSettingsId(const QString &id) override; Q_SIGNAL void persistentSettingsIdChanged(const QString &id); void setOptions(const Options &options); @@ -127,7 +127,7 @@ class QUICKEVENTGUI_DECL_EXPORT ReportOptionsDialog : public QDialog, public qf: static QString sqlWhereExpression(const Options &opts, const int stage_id); static QString getClassesForStartNumber(const int number, const int stage_id); protected: - //void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; + //void showEvent(QShowEvent *event) override; private: Ui::ReportOptionsDialog *ui; }; diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index b502afa91..33b7c3607 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -1,3 +1,5 @@ +find_package(Qt6 REQUIRED COMPONENTS Core) + add_executable(quickevent plugins/CardReader/src/cardchecker.cpp plugins/CardReader/src/cardcheckerclassiccpp.cpp @@ -89,11 +91,13 @@ add_executable(quickevent plugins/Event/src/services/serviceswidget.cpp plugins/Event/src/services/servicewidget.cpp plugins/Event/src/services/servicewidget.ui - plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h - plugins/Event/src/services/qx/qxeventservicewidget.ui - plugins/Event/src/services/qx/qxlateregistrationswidget.h - plugins/Event/src/services/qx/qxlateregistrationswidget.cpp - plugins/Event/src/services/qx/qxlateregistrationswidget.ui + + plugins/Event/src/services/qx/qxnode.cpp + plugins/Event/src/services/qx/sqlapinode.cpp + plugins/Event/src/services/qx/nodes.cpp + plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h + plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h plugins/Event/src/services/qx/qxeventservicewidget.ui + plugins/Event/src/services/qx/qxlateregistrationswidget.h plugins/Event/src/services/qx/qxlateregistrationswidget.cpp plugins/Event/src/services/qx/qxlateregistrationswidget.ui plugins/Event/src/services/qx/runchangedialog.h plugins/Event/src/services/qx/runchangedialog.cpp plugins/Event/src/services/qx/runchangedialog.ui plugins/Event/src/services/qx/runchange.h plugins/Event/src/services/qx/runchange.cpp @@ -272,7 +276,8 @@ target_include_directories(quickevent PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAK target_link_libraries(quickevent PUBLIC libquickeventcore libquickeventgui libqfgui libsiut) if (QF_WITH_LIBSHV) target_link_libraries(quickevent PUBLIC libshviotqt) - target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) +target_link_libraries(quickevent PRIVATE Qt6::Core) +target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) endif() foreach(plugin IN ITEMS Classes Runs Relays Receipts shared) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp new file mode 100644 index 000000000..07c57d53d --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp @@ -0,0 +1,300 @@ +#include "nodes.h" + +#include "sqlapinode.h" +#include "../../eventplugin.h" +#include "../../../../Runs/src/runsplugin.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace qf::core::sql; +using namespace shv::chainpack; +using qf::gui::framework::getPlugin; +using Event::EventPlugin; +using Runs::RunsPlugin; + +namespace Event::services::qx { + +//========================================================= +// DotAppNode +//========================================================= +namespace { +auto METH_NAME = "name"; +} +const std::vector &DotAppNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {Rpc::METH_PING, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Browse}, + {METH_NAME, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Browse}, + }; + return meta_methods; +} + +RpcValue DotAppNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); + if(shv_path.empty()) { + if(method == Rpc::METH_PING) { + return nullptr; + } + if(method == METH_NAME) { + return "QuickEvent"; + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +//========================================================= +// EventNode +//========================================================= +static const auto METH_CURRENT_STAGE = "currentStage"; +static const auto METH_EVENT_CONFIG = "eventConfig"; + +EventNode::EventNode(shv::iotqt::node::ShvNode *parent) +: Super("event", parent) +{ +} + +const std::vector &EventNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {METH_NAME, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, + {METH_CURRENT_STAGE, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, + {METH_EVENT_CONFIG, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, + }; + return meta_methods; +} + +RpcValue EventNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + if(shv_path.empty()) { + if(method == METH_NAME) { + return getPlugin()->eventConfig()->eventName().toStdString(); + } + if(method == METH_CURRENT_STAGE) { + return getPlugin()->currentStageId(); + } + if(method == METH_EVENT_CONFIG) { + auto cfg = getPlugin()->eventConfig(); + return shv::coreqt::rpc::qVariantToRpcValue(cfg->values()); + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +//========================================================= +// StartListNode +//========================================================= +static const auto METH_TABLE = "table"; +static const auto METH_RECORD = "record"; +//static const auto SIG_REC_CHNG = "recchng"; + +void SqlViewNode::setQueryBuilder(const qf::core::sql::QueryBuilder &qb) +{ + m_queryBuilder = qb; +} + +qf::core::sql::QueryBuilder SqlViewNode::effectiveQueryBuilder() +{ + return m_queryBuilder; +} + +const std::vector &SqlViewNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {METH_TABLE, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Read}, + {METH_RECORD, MetaMethod::Flag::None, "RpcValue", "RpcValue", AccessLevel::Read }, + //{METH_SET_RECORD, MetaMethod::Flag::None, "RpcValue", {}, AccessLevel::Write}, + }; + return meta_methods; +} + +RpcValue SqlViewNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); + if(shv_path.empty()) { + if(method == METH_TABLE) { + const auto &m = params.asMap(); + auto qb = effectiveQueryBuilder(); + if (auto where = m.value("where").to(); !where.isEmpty()) { + qb.where(where); + } + if (auto order_by = m.value("orderBy").to(); !order_by.isEmpty()) { + qb.orderBy(order_by); + } + qf::core::sql::Query q; + QString qs = qb.toString(); + q.exec(qs, qf::core::Exception::Throw); + auto res = SqlApiNode::rpcSqlResultFromQuery(q); + return res.toRpcValue(); + } + if(method == METH_RECORD) { + auto id = params.toInt(); + auto qb = effectiveQueryBuilder(); + qb.where("runs.id = " + QString::number(id)); + qf::core::sql::Query q; + QString qs = qb.toString(); + qfDebug() << qs; + q.exec(qs, qf::core::Exception::Throw); + if (q.next()) { + return SqlApiNode::recordToMap(q.record()); + } + return RpcValue::Map{}; + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +//========================================================= +// CurrentStageConfigNode +//========================================================= +const std::vector &CurrentStageConfigNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {Rpc::METH_GET, MetaMethod::Flag::IsGetter, {}, "Map", AccessLevel::Read}, + }; + return meta_methods; +} + +RpcValue CurrentStageConfigNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); + if(shv_path.empty()) { + if(method == Rpc::METH_GET) { + auto *event_plugin = getPlugin(); + QVariantMap data = event_plugin->stageData(event_plugin->currentStageId()); + data.remove("drawingConfig"); // remove internal key + return shv::coreqt::rpc::qVariantToRpcValue(data); + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +//========================================================= +// CurrentStageStartListNode +//========================================================= +CurrentStageStartListNode::CurrentStageStartListNode(shv::iotqt::node::ShvNode *parent) + : Super("startList", parent) +{ + auto qb = getPlugin()->startListQuery(); + //qb.orderBy("runs.startTimeMs"); + setQueryBuilder(qb); +} + +qf::core::sql::QueryBuilder CurrentStageStartListNode::effectiveQueryBuilder() +{ + auto qb = Super::effectiveQueryBuilder(); + auto *event_plugin = getPlugin(); + qb.where(QStringLiteral("runs.stageId=%1").arg(event_plugin->currentStageId())); + return qb; +} + +//========================================================= +// CurrentStageRunsNode +//========================================================= +CurrentStageRunsNode::CurrentStageRunsNode(shv::iotqt::node::ShvNode *parent) + : Super("runs", parent) +{ +} + +QueryBuilder CurrentStageRunsNode::effectiveQueryBuilder() +{ + auto *event_plugin = getPlugin(); + auto qb = getPlugin()->runsQuery(event_plugin->currentStageId()); + return qb; +} + +static const auto METH_SET_RECORD = "setRecord"; +//static const auto METH_RUN_CHANGED = "runchng"; +static const auto SIG_RUN_CHANGED = "runchng"; + +const std::vector &CurrentStageRunsNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {METH_TABLE, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Read}, + {METH_RECORD, MetaMethod::Flag::None, "Int", "Map", AccessLevel::Read, {{SIG_RUN_CHANGED, "[Int, RpcValue]"}} }, + {METH_SET_RECORD, MetaMethod::Flag::None, "[Int, RpcValue]", {}, AccessLevel::Write}, + }; + return meta_methods; + static auto s_meta_methods = [this]() { + auto mm = Super::metaMethods(); + mm.push_back({METH_SET_RECORD, MetaMethod::Flag::None, "[int, Map]", {}, AccessLevel::Write }); + return mm; + }(); + return s_meta_methods; +} + +RpcValue CurrentStageRunsNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + if(shv_path.empty()) { + if(method == METH_SET_RECORD) { + auto *plugin = getPlugin(); + const auto &lst = params.asList(); + plugin->setRunsRecord(lst.value(0).toInt(), shv::coreqt::rpc::rpcValueToQVariant(lst.value(1))); + return nullptr; + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +void CurrentStageRunsNode::sendRunChangedSignal(const QVariant &qparam) +{ + auto param = shv::coreqt::rpc::qVariantToRpcValue(qparam); + Q_ASSERT(param.isList()); + Q_ASSERT(param.asList().value(0).toInt() > 0); // run.id + RpcSignal sig; + sig.setShvPath(shvPath().asString()); + sig.setMethod(SIG_RUN_CHANGED); + sig.setSource(METH_RECORD); + sig.setParams(param); + qfDebug() << "emit:" << sig.toPrettyString(); + emitSendRpcMessage(sig); +} + +//========================================================= +// CurrentStageClassesNode +//========================================================= +CurrentStageClassesNode::CurrentStageClassesNode(shv::iotqt::node::ShvNode *parent) + : Super("classes", parent) +{ +} + +QueryBuilder CurrentStageClassesNode::effectiveQueryBuilder() +{ + auto *event_plugin = getPlugin(); + QueryBuilder qb; + qb.select2("classes", "*") + .select2("classdefs", "*") + .select2("courses", "id, name, length, climb") + .from("classes") + .joinRestricted("classes.id", "classdefs.classId", "classdefs.stageId=" QF_IARG(event_plugin->currentStageId())) + .join("classdefs.courseId", "courses.id") + .orderBy("classes.name");//.limit(10); + return qb; +} + + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h new file mode 100644 index 000000000..917a75f2c --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h @@ -0,0 +1,103 @@ +#pragma once + +#include "qxnode.h" + +#include + +namespace Event::services::qx { + +class DotAppNode : public QxNode +{ + Q_OBJECT + + using Super = QxNode; +public: + explicit DotAppNode(shv::iotqt::node::ShvNode *parent) : Super(".app", parent) {} +private: + //shv::chainpack::RpcValue callMethodRq(const shv::chainpack::RpcRequest &rq) override; + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +}; + +class EventNode : public QxNode +{ + Q_OBJECT + + using Super = QxNode; +public: + explicit EventNode(shv::iotqt::node::ShvNode *parent); +private: + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +}; + +class SqlViewNode : public QxNode +{ + Q_OBJECT + + using Super = QxNode; +public: + explicit SqlViewNode(const std::string &name, shv::iotqt::node::ShvNode *parent) + : Super(name, parent) + {} + void setQueryBuilder(const qf::core::sql::QueryBuilder &qb); +protected: + virtual qf::core::sql::QueryBuilder effectiveQueryBuilder(); + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +private: + qf::core::sql::QueryBuilder m_queryBuilder; +}; + +class CurrentStageConfigNode : public QxNode +{ + Q_OBJECT + + using Super = QxNode; +public: + explicit CurrentStageConfigNode(shv::iotqt::node::ShvNode *parent) + : Super("config", parent) + {} +protected: + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +}; + +class CurrentStageStartListNode : public SqlViewNode +{ + Q_OBJECT + + using Super = SqlViewNode; +public: + explicit CurrentStageStartListNode(shv::iotqt::node::ShvNode *parent); +protected: + qf::core::sql::QueryBuilder effectiveQueryBuilder() override; +}; + +class CurrentStageRunsNode : public SqlViewNode +{ + Q_OBJECT + + using Super = SqlViewNode; +public: + explicit CurrentStageRunsNode(shv::iotqt::node::ShvNode *parent); + void sendRunChangedSignal(const QVariant &qparam); +protected: + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; + qf::core::sql::QueryBuilder effectiveQueryBuilder() override; +}; + +class CurrentStageClassesNode : public SqlViewNode +{ + Q_OBJECT + + using Super = SqlViewNode; +public: + explicit CurrentStageClassesNode(shv::iotqt::node::ShvNode *parent); + +protected: + qf::core::sql::QueryBuilder effectiveQueryBuilder() override; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 6b673328e..e693f4b45 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -1,5 +1,7 @@ #include "qxeventservice.h" #include "qxeventservicewidget.h" +#include "nodes.h" +#include "sqlapinode.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -9,7 +11,7 @@ #include #include -#include +#include #include #include @@ -41,31 +43,39 @@ using Event::EventPlugin; using Runs::RunsPlugin; namespace Event::services::qx { -//=============================================== -// QxClientServiceSettings -//=============================================== -// QString QxClientServiceSettings::eventKey() const -// { -// auto *event_plugin = getPlugin(); -// auto *cfg = event_plugin->eventConfig(); -// auto key = cfg->apiKey(); -// auto current_stage = cfg->currentStageId(); -// return QStringLiteral("%1%2").arg(key).arg(current_stage); -// } //=============================================== // QxClientService //=============================================== QxEventService::QxEventService(QObject *parent) : Super(QxEventService::serviceId(), parent) + , m_rootNode(new shv::iotqt::node::ShvRootNode(this)) { auto *event_plugin = getPlugin(); - connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &QxEventService::onDbEventNotify, Qt::QueuedConnection); + // connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &QxEventService::onDbEventNotify, Qt::QueuedConnection); + + new DotAppNode(m_rootNode); + connect(event_plugin, &EventPlugin::eventOpenChanged, this, [this](bool is_open) { + if (is_open) { + new SqlApiNode(m_rootNode); + auto *event = new EventNode(m_rootNode); + auto *current_stage = new shv::iotqt::node::ShvNode("currentStage", event); + new CurrentStageConfigNode(current_stage); + //new CurrentStageStartListNode(current_stage); + new CurrentStageRunsNode(current_stage); + new CurrentStageClassesNode(current_stage); + } + else { + qDeleteAll(m_rootNode->findChildren()); + } + }); + + connect(m_rootNode, &shv::iotqt::node::ShvNode::sendRpcMessage, this, &QxEventService::sendRpcMessage); } QString QxEventService::serviceDisplayName() const { - return tr("QE Exchange"); + return tr("QX Event"); } QString QxEventService::serviceId() @@ -79,8 +89,13 @@ void QxEventService::run() { auto ss = settings(); delete m_rpcConnection; - m_rpcConnection = new ClientConnection(this); - m_rpcConnection->setConnectionString(ss.exchangeServerUrl()); + m_rpcConnection = new DeviceConnection(this); + m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); + RpcValue::Map opts; + RpcValue::Map device; + device["mountPoint"] = "test/quickbox"; + opts["device"] = device; + m_rpcConnection->setConnectionOptions(opts); connect(m_rpcConnection, &ClientConnection::brokerConnectedChanged, this, &QxEventService::onBrokerConnectedChanged); connect(m_rpcConnection, &ClientConnection::socketError, this, &QxEventService::onBrokerSocketError); @@ -130,8 +145,8 @@ void QxEventService::loadSettings() { Super::loadSettings(); auto ss = settings(); - if (ss.exchangeServerUrl().isEmpty()) { - ss.setExchangeServerUrl("http://localhost:8000"); + if (ss.shvBrokerUrl().isEmpty()) { + ss.setShvBrokerUrl("tcp://localhost?user=test&password=test"); } m_settings = ss; } @@ -243,7 +258,7 @@ void QxEventService::postRuns(QObject *context, std::function ca void QxEventService::getHttpJson(const QString &path, const QUrlQuery &query, QObject *context, const std::function &call_back) { - auto url = exchangeServerUrl(); + auto url = shvBrokerUrl(); url.setPath(path); url.setQuery(query); // qfInfo() << url.toString(); @@ -272,7 +287,7 @@ void QxEventService::getHttpJson(const QString &path, const QUrlQuery &query, QO QNetworkReply* QxEventService::getQxChangesReply(int from_id) { - auto url = exchangeServerUrl(); + auto url = shvBrokerUrl(); url.setPath(QStringLiteral("/api/event/%1/changes").arg(eventId())); url.setQuery(QStringLiteral("from_id=%1").arg(from_id)); @@ -299,15 +314,15 @@ QByteArray QxEventService::apiToken() const return event_plugin->stageData(current_stage).qxApiToken().toUtf8(); } -QUrl QxEventService::exchangeServerUrl() const +QUrl QxEventService::shvBrokerUrl() const { auto ss = settings(); - return QUrl(ss.exchangeServerUrl()); + return QUrl(ss.shvBrokerUrl()); } void QxEventService::postFileCompressed(std::optional path, std::optional name, QByteArray data, QObject *context , std::function call_back) { - auto url = exchangeServerUrl(); + auto url = shvBrokerUrl(); url.setPath(path.value_or("/api/event/current/file")); if (name.has_value()) { @@ -359,7 +374,7 @@ void QxEventService::httpPostJson(const QString &path, const QString &query, QVa if (!isRunning()) { return; } - auto url = exchangeServerUrl(); + auto url = shvBrokerUrl(); url.setPath(path); url.setQuery(query); @@ -617,9 +632,7 @@ void QxEventService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) if(msg.isRequest()) { RpcRequest rq(msg); qfMessage() << "RPC request received:" << rq.toPrettyString(); - if(m_shvTree->root()) { - m_shvTree->root()->handleRpcRequest(rq); - } + m_rootNode->handleRpcRequest(rq); } else if(msg.isResponse()) { RpcResponse rp(msg); @@ -631,6 +644,13 @@ void QxEventService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) } } +void QxEventService::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) +{ + if(m_rpcConnection && m_rpcConnection->isBrokerConnected()) { + m_rpcConnection->sendRpcMessage(rpc_msg); + } +} + void QxEventService::subscribeChanges() { Q_ASSERT(m_rpcConnection); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 1ab8d14b7..2a103a9d7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -7,8 +7,8 @@ class QNetworkReply; class QUrlQuery; class QTimer; -namespace shv::iotqt::node { class ShvNodeTree; } -namespace shv::iotqt::rpc { class ClientConnection; } +namespace shv::iotqt::node { class ShvNodeTree; class ShvRootNode; } +namespace shv::iotqt::rpc { class DeviceConnection; } namespace shv::chainpack { class RpcMessage; class RpcError; } namespace Event::services::qx { @@ -17,7 +17,7 @@ class QxEventServiceSettings : public ServiceSettings { using Super = ServiceSettings; - QF_VARIANTMAP_FIELD2(QString, e, setE, xchangeServerUrl, "http://localhost:8000") + QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "http://localhost:8000") public: QxEventServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} }; @@ -69,12 +69,13 @@ class QxEventService : public Service QByteArray apiToken() const; static int currentConnectionId(); - QUrl exchangeServerUrl() const; + QUrl shvBrokerUrl() const; int eventId() const; private: // shv void onBrokerConnectedChanged(bool is_connected); void onRpcMessageReceived(const shv::chainpack::RpcMessage &msg); + void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg); void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); @@ -97,9 +98,8 @@ class QxEventService : public Service EventInfo eventInfo() const; private: // shv - shv::iotqt::rpc::ClientConnection *m_rpcConnection = nullptr; - shv::iotqt::node::ShvNodeTree *m_shvTree = nullptr; - + shv::iotqt::rpc::DeviceConnection *m_rpcConnection = nullptr; + shv::iotqt::node::ShvRootNode *m_rootNode; private: QNetworkAccessManager *m_networkManager = nullptr; QNetworkReply *m_replySSE = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index ede33ffb4..416bb25b4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -23,7 +23,7 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) : Super(parent) , ui(new Ui::QxEventServiceWidget) { - setPersistentSettingsId("QxClientServiceWidget"); + setPersistentSettingsId("QxEventServiceWidget"); ui->setupUi(this); connect(ui->edServerUrl, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); connect(ui->edApiToken, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); @@ -35,7 +35,7 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); auto settings = svc->settings(); - ui->edServerUrl->setText(settings.exchangeServerUrl()); + ui->edServerUrl->setText(settings.shvBrokerUrl()); ui->edApiToken->setText(svc->apiToken()); ui->edCurrentStage->setValue(current_stage); connect(ui->btTestConnection, &QAbstractButton::clicked, this, &QxEventServiceWidget::testConnection); @@ -92,7 +92,7 @@ bool QxEventServiceWidget::saveSettings() auto *svc = service(); if(svc) { auto ss = svc->settings(); - ss.setExchangeServerUrl(ui->edServerUrl->text()); + ss.setShvBrokerUrl(ui->edServerUrl->text()); svc->setSettings(ss); auto *event_plugin = getPlugin(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui index 261a65af9..5f4a41e1a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -19,7 +19,7 @@ - Exchange server url + SHV broker url diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.cpp new file mode 100644 index 000000000..dfcea61fd --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.cpp @@ -0,0 +1,36 @@ +#include "qxnode.h" + +#include +#include + +#include + +using namespace shv::chainpack; + +namespace Event::services::qx { + +QxNode::QxNode(const std::string &name, shv::iotqt::node::ShvNode *parent) + : Super(name, parent) +{ + +} + +size_t QxNode::methodCount(const StringViewList &shv_path) +{ + if(shv_path.empty()) { + return metaMethods().size(); + } + return Super::methodCount(shv_path); +} + +const MetaMethod *QxNode::metaMethod(const StringViewList &shv_path, size_t ix) +{ + if(shv_path.empty()) { + if(metaMethods().size() <= ix) + QF_EXCEPTION("Invalid method index: " + QString::number(ix) + " of: " + QString::number(metaMethods().size())); + return &(metaMethods()[ix]); + } + return Super::metaMethod(shv_path, ix); +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.h new file mode 100644 index 000000000..79e42c174 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxnode.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace Event::services::qx { + +class QxNode : public shv::iotqt::node::ShvNode +{ + Q_OBJECT + + using Super = shv::iotqt::node::ShvNode; +public: + explicit QxNode(const std::string &name, shv::iotqt::node::ShvNode *parent); + + size_t methodCount(const StringViewList &shv_path) override; + const shv::chainpack::MetaMethod* metaMethod(const StringViewList &shv_path, size_t ix) override; +protected: + //shv::chainpack::RpcValue callMethodRq(const shv::chainpack::RpcRequest &rq) override; + //shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; + virtual const std::vector &metaMethods() = 0; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp index 789cb44e0..1c16121ce 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp @@ -208,7 +208,7 @@ void RunChangeDialog::resolveChanges(bool is_accepted) auto *svc = service(); auto *nm = svc->networkManager(); QNetworkRequest request; - auto url = svc->exchangeServerUrl(); + auto url = svc->shvBrokerUrl(); // qfInfo() << "url " << url.toString(); url.setPath("/api/event/current/changes/resolve-change"); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp new file mode 100644 index 000000000..ac90ce45f --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -0,0 +1,119 @@ +#include "sqlapinode.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace shv::chainpack; +using namespace shv::coreqt::data; + +namespace Event::services::qx { +namespace { + +/* + +RpcSqlResult RpcSqlResult::fromRpcValue(const shv::chainpack::RpcValue &rv) +{ + RpcSqlResult ret; + const RpcValue::Map &map = rv.asMap(); + const RpcValue::List &flds = map.value("fields").asList(); + if(flds.empty()) { + ret.numRowsAffected = map.value("numRowsAffected").toInt(); + ret.lastInsertId = map.value("lastInsertId").toInt(); + } + else { + + } + return ret; + +} +*/ +} + +SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) + : Super("sql", parent) +{ + +} + +shv::chainpack::RpcValue::Map SqlApiNode::recordToMap(const QSqlRecord &rec) +{ + RpcValue::Map record; + for (int i = 0; i < rec.count(); ++i) { + QSqlField fld = rec.field(i); + auto fld_name = fld.name(); + fld_name.replace("__", "."); + record[fld_name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(fld.value()); + } + return record; +} + +RpcSqlResult SqlApiNode::rpcSqlResultFromQuery(QSqlQuery &q) +{ + RpcSqlResult ret; + if(q.isSelect()) { + QSqlRecord rec = q.record(); + for (int i = 0; i < rec.count(); ++i) { + QSqlField fld = rec.field(i); + RpcSqlField rfld; + rfld.name = fld.name(); + rfld.name.replace("__", "."); + rfld.type = fld.metaType().id(); + ret.fields.append(rfld); + } + while(q.next()) { + RpcSqlResult::Row row; + for (int i = 0; i < rec.count(); ++i) { + const QVariant v = q.value(i); + if (v.isNull()) + row.append(QVariant()); + else + row.append(v); + //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); + } + ret.rows.insert(ret.rows.count(), row); + } + } + else { + ret.numRowsAffected = q.numRowsAffected(); + ret.lastInsertId = q.lastInsertId().toInt(); + } + return ret; +} + +static auto METH_EXEC_SQL = "execSql"; + +const std::vector &SqlApiNode::metaMethods() +{ + static std::vector meta_methods { + methods::DIR, + methods::LS, + {METH_EXEC_SQL, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Write}, + }; + return meta_methods; +} + +RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +{ + qfLogFuncFrame() << shv_path.join('/') << method; + //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); + if(shv_path.empty()) { + if(method == METH_EXEC_SQL) { + qf::core::sql::Query q; + QString qs = params.to(); + q.exec(qs, qf::core::Exception::Throw); + auto res = rpcSqlResultFromQuery(q); + return res.toRpcValue(); + } + } + return Super::callMethod(shv_path, method, params, user_id); +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h new file mode 100644 index 000000000..c2e112f26 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h @@ -0,0 +1,27 @@ +#pragma once + +#include "qxnode.h" + +class QSqlQuery; +class QSqlRecord; + +namespace shv::coreqt::data { class RpcSqlResult; } + +namespace Event::services::qx { + +class SqlApiNode : public QxNode +{ + Q_OBJECT + + using Super = QxNode; +public: + explicit SqlApiNode(shv::iotqt::node::ShvNode *parent); + + static shv::coreqt::data::RpcSqlResult rpcSqlResultFromQuery(QSqlQuery &q); + static shv::chainpack::RpcValue::Map recordToMap(const QSqlRecord &rec); +protected: + const std::vector &metaMethods() override; + shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +}; + +} From 8972a3ea4ce6a65fc9db08372a5de972020884b8 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 9 Nov 2025 18:43:07 +0100 Subject: [PATCH 06/83] Remove unused shv odes --- .../plugins/Event/src/services/qx/nodes.cpp | 249 ------------------ .../plugins/Event/src/services/qx/nodes.h | 81 ------ .../Event/src/services/qx/qxeventservice.cpp | 18 +- 3 files changed, 1 insertion(+), 347 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp index 07c57d53d..6a4db4533 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.cpp @@ -1,9 +1,5 @@ #include "nodes.h" -#include "sqlapinode.h" -#include "../../eventplugin.h" -#include "../../../../Runs/src/runsplugin.h" - #include #include #include @@ -17,9 +13,6 @@ using namespace qf::core::sql; using namespace shv::chainpack; -using qf::gui::framework::getPlugin; -using Event::EventPlugin; -using Runs::RunsPlugin; namespace Event::services::qx { @@ -55,246 +48,4 @@ RpcValue DotAppNode::callMethod(const StringViewList &shv_path, const std::strin return Super::callMethod(shv_path, method, params, user_id); } -//========================================================= -// EventNode -//========================================================= -static const auto METH_CURRENT_STAGE = "currentStage"; -static const auto METH_EVENT_CONFIG = "eventConfig"; - -EventNode::EventNode(shv::iotqt::node::ShvNode *parent) -: Super("event", parent) -{ -} - -const std::vector &EventNode::metaMethods() -{ - static std::vector meta_methods { - methods::DIR, - methods::LS, - {METH_NAME, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, - {METH_CURRENT_STAGE, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, - {METH_EVENT_CONFIG, MetaMethod::Flag::IsGetter, {}, "RpcValue", AccessLevel::Read}, - }; - return meta_methods; -} - -RpcValue EventNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) -{ - qfLogFuncFrame() << shv_path.join('/') << method; - if(shv_path.empty()) { - if(method == METH_NAME) { - return getPlugin()->eventConfig()->eventName().toStdString(); - } - if(method == METH_CURRENT_STAGE) { - return getPlugin()->currentStageId(); - } - if(method == METH_EVENT_CONFIG) { - auto cfg = getPlugin()->eventConfig(); - return shv::coreqt::rpc::qVariantToRpcValue(cfg->values()); - } - } - return Super::callMethod(shv_path, method, params, user_id); -} - -//========================================================= -// StartListNode -//========================================================= -static const auto METH_TABLE = "table"; -static const auto METH_RECORD = "record"; -//static const auto SIG_REC_CHNG = "recchng"; - -void SqlViewNode::setQueryBuilder(const qf::core::sql::QueryBuilder &qb) -{ - m_queryBuilder = qb; -} - -qf::core::sql::QueryBuilder SqlViewNode::effectiveQueryBuilder() -{ - return m_queryBuilder; -} - -const std::vector &SqlViewNode::metaMethods() -{ - static std::vector meta_methods { - methods::DIR, - methods::LS, - {METH_TABLE, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Read}, - {METH_RECORD, MetaMethod::Flag::None, "RpcValue", "RpcValue", AccessLevel::Read }, - //{METH_SET_RECORD, MetaMethod::Flag::None, "RpcValue", {}, AccessLevel::Write}, - }; - return meta_methods; -} - -RpcValue SqlViewNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) -{ - qfLogFuncFrame() << shv_path.join('/') << method; - //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); - if(shv_path.empty()) { - if(method == METH_TABLE) { - const auto &m = params.asMap(); - auto qb = effectiveQueryBuilder(); - if (auto where = m.value("where").to(); !where.isEmpty()) { - qb.where(where); - } - if (auto order_by = m.value("orderBy").to(); !order_by.isEmpty()) { - qb.orderBy(order_by); - } - qf::core::sql::Query q; - QString qs = qb.toString(); - q.exec(qs, qf::core::Exception::Throw); - auto res = SqlApiNode::rpcSqlResultFromQuery(q); - return res.toRpcValue(); - } - if(method == METH_RECORD) { - auto id = params.toInt(); - auto qb = effectiveQueryBuilder(); - qb.where("runs.id = " + QString::number(id)); - qf::core::sql::Query q; - QString qs = qb.toString(); - qfDebug() << qs; - q.exec(qs, qf::core::Exception::Throw); - if (q.next()) { - return SqlApiNode::recordToMap(q.record()); - } - return RpcValue::Map{}; - } - } - return Super::callMethod(shv_path, method, params, user_id); -} - -//========================================================= -// CurrentStageConfigNode -//========================================================= -const std::vector &CurrentStageConfigNode::metaMethods() -{ - static std::vector meta_methods { - methods::DIR, - methods::LS, - {Rpc::METH_GET, MetaMethod::Flag::IsGetter, {}, "Map", AccessLevel::Read}, - }; - return meta_methods; -} - -RpcValue CurrentStageConfigNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) -{ - qfLogFuncFrame() << shv_path.join('/') << method; - //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); - if(shv_path.empty()) { - if(method == Rpc::METH_GET) { - auto *event_plugin = getPlugin(); - QVariantMap data = event_plugin->stageData(event_plugin->currentStageId()); - data.remove("drawingConfig"); // remove internal key - return shv::coreqt::rpc::qVariantToRpcValue(data); - } - } - return Super::callMethod(shv_path, method, params, user_id); -} - -//========================================================= -// CurrentStageStartListNode -//========================================================= -CurrentStageStartListNode::CurrentStageStartListNode(shv::iotqt::node::ShvNode *parent) - : Super("startList", parent) -{ - auto qb = getPlugin()->startListQuery(); - //qb.orderBy("runs.startTimeMs"); - setQueryBuilder(qb); -} - -qf::core::sql::QueryBuilder CurrentStageStartListNode::effectiveQueryBuilder() -{ - auto qb = Super::effectiveQueryBuilder(); - auto *event_plugin = getPlugin(); - qb.where(QStringLiteral("runs.stageId=%1").arg(event_plugin->currentStageId())); - return qb; -} - -//========================================================= -// CurrentStageRunsNode -//========================================================= -CurrentStageRunsNode::CurrentStageRunsNode(shv::iotqt::node::ShvNode *parent) - : Super("runs", parent) -{ -} - -QueryBuilder CurrentStageRunsNode::effectiveQueryBuilder() -{ - auto *event_plugin = getPlugin(); - auto qb = getPlugin()->runsQuery(event_plugin->currentStageId()); - return qb; -} - -static const auto METH_SET_RECORD = "setRecord"; -//static const auto METH_RUN_CHANGED = "runchng"; -static const auto SIG_RUN_CHANGED = "runchng"; - -const std::vector &CurrentStageRunsNode::metaMethods() -{ - static std::vector meta_methods { - methods::DIR, - methods::LS, - {METH_TABLE, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Read}, - {METH_RECORD, MetaMethod::Flag::None, "Int", "Map", AccessLevel::Read, {{SIG_RUN_CHANGED, "[Int, RpcValue]"}} }, - {METH_SET_RECORD, MetaMethod::Flag::None, "[Int, RpcValue]", {}, AccessLevel::Write}, - }; - return meta_methods; - static auto s_meta_methods = [this]() { - auto mm = Super::metaMethods(); - mm.push_back({METH_SET_RECORD, MetaMethod::Flag::None, "[int, Map]", {}, AccessLevel::Write }); - return mm; - }(); - return s_meta_methods; -} - -RpcValue CurrentStageRunsNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) -{ - qfLogFuncFrame() << shv_path.join('/') << method; - if(shv_path.empty()) { - if(method == METH_SET_RECORD) { - auto *plugin = getPlugin(); - const auto &lst = params.asList(); - plugin->setRunsRecord(lst.value(0).toInt(), shv::coreqt::rpc::rpcValueToQVariant(lst.value(1))); - return nullptr; - } - } - return Super::callMethod(shv_path, method, params, user_id); -} - -void CurrentStageRunsNode::sendRunChangedSignal(const QVariant &qparam) -{ - auto param = shv::coreqt::rpc::qVariantToRpcValue(qparam); - Q_ASSERT(param.isList()); - Q_ASSERT(param.asList().value(0).toInt() > 0); // run.id - RpcSignal sig; - sig.setShvPath(shvPath().asString()); - sig.setMethod(SIG_RUN_CHANGED); - sig.setSource(METH_RECORD); - sig.setParams(param); - qfDebug() << "emit:" << sig.toPrettyString(); - emitSendRpcMessage(sig); -} - -//========================================================= -// CurrentStageClassesNode -//========================================================= -CurrentStageClassesNode::CurrentStageClassesNode(shv::iotqt::node::ShvNode *parent) - : Super("classes", parent) -{ -} - -QueryBuilder CurrentStageClassesNode::effectiveQueryBuilder() -{ - auto *event_plugin = getPlugin(); - QueryBuilder qb; - qb.select2("classes", "*") - .select2("classdefs", "*") - .select2("courses", "id, name, length, climb") - .from("classes") - .joinRestricted("classes.id", "classdefs.classId", "classdefs.stageId=" QF_IARG(event_plugin->currentStageId())) - .join("classdefs.courseId", "courses.id") - .orderBy("classes.name");//.limit(10); - return qb; -} - - } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h index 917a75f2c..58cf1125e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/nodes.h @@ -19,85 +19,4 @@ class DotAppNode : public QxNode shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; }; -class EventNode : public QxNode -{ - Q_OBJECT - - using Super = QxNode; -public: - explicit EventNode(shv::iotqt::node::ShvNode *parent); -private: - const std::vector &metaMethods() override; - shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; -}; - -class SqlViewNode : public QxNode -{ - Q_OBJECT - - using Super = QxNode; -public: - explicit SqlViewNode(const std::string &name, shv::iotqt::node::ShvNode *parent) - : Super(name, parent) - {} - void setQueryBuilder(const qf::core::sql::QueryBuilder &qb); -protected: - virtual qf::core::sql::QueryBuilder effectiveQueryBuilder(); - const std::vector &metaMethods() override; - shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; -private: - qf::core::sql::QueryBuilder m_queryBuilder; -}; - -class CurrentStageConfigNode : public QxNode -{ - Q_OBJECT - - using Super = QxNode; -public: - explicit CurrentStageConfigNode(shv::iotqt::node::ShvNode *parent) - : Super("config", parent) - {} -protected: - const std::vector &metaMethods() override; - shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; -}; - -class CurrentStageStartListNode : public SqlViewNode -{ - Q_OBJECT - - using Super = SqlViewNode; -public: - explicit CurrentStageStartListNode(shv::iotqt::node::ShvNode *parent); -protected: - qf::core::sql::QueryBuilder effectiveQueryBuilder() override; -}; - -class CurrentStageRunsNode : public SqlViewNode -{ - Q_OBJECT - - using Super = SqlViewNode; -public: - explicit CurrentStageRunsNode(shv::iotqt::node::ShvNode *parent); - void sendRunChangedSignal(const QVariant &qparam); -protected: - const std::vector &metaMethods() override; - shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; - qf::core::sql::QueryBuilder effectiveQueryBuilder() override; -}; - -class CurrentStageClassesNode : public SqlViewNode -{ - Q_OBJECT - - using Super = SqlViewNode; -public: - explicit CurrentStageClassesNode(shv::iotqt::node::ShvNode *parent); - -protected: - qf::core::sql::QueryBuilder effectiveQueryBuilder() override; -}; - } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index e693f4b45..8aa7f5642 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -51,24 +51,8 @@ QxEventService::QxEventService(QObject *parent) : Super(QxEventService::serviceId(), parent) , m_rootNode(new shv::iotqt::node::ShvRootNode(this)) { - auto *event_plugin = getPlugin(); - // connect(event_plugin, &Event::EventPlugin::dbEventNotify, this, &QxEventService::onDbEventNotify, Qt::QueuedConnection); - new DotAppNode(m_rootNode); - connect(event_plugin, &EventPlugin::eventOpenChanged, this, [this](bool is_open) { - if (is_open) { - new SqlApiNode(m_rootNode); - auto *event = new EventNode(m_rootNode); - auto *current_stage = new shv::iotqt::node::ShvNode("currentStage", event); - new CurrentStageConfigNode(current_stage); - //new CurrentStageStartListNode(current_stage); - new CurrentStageRunsNode(current_stage); - new CurrentStageClassesNode(current_stage); - } - else { - qDeleteAll(m_rootNode->findChildren()); - } - }); + new SqlApiNode(m_rootNode); connect(m_rootNode, &shv::iotqt::node::ShvNode::sendRpcMessage, this, &QxEventService::sendRpcMessage); } From f0d2a693f53c254b27d6c11db2357eae0d05be8c Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 9 Nov 2025 22:10:51 +0100 Subject: [PATCH 07/83] QX SQL API node implemented --- .../Event/src/services/qx/sqlapinode.cpp | 244 +++++++++++++++--- .../Event/src/services/qx/sqlapinode.h | 3 - 2 files changed, 203 insertions(+), 44 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index ac90ce45f..846e6c7e6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,32 +11,12 @@ #include #include +#include using namespace shv::chainpack; using namespace shv::coreqt::data; namespace Event::services::qx { -namespace { - -/* - -RpcSqlResult RpcSqlResult::fromRpcValue(const shv::chainpack::RpcValue &rv) -{ - RpcSqlResult ret; - const RpcValue::Map &map = rv.asMap(); - const RpcValue::List &flds = map.value("fields").asList(); - if(flds.empty()) { - ret.numRowsAffected = map.value("numRowsAffected").toInt(); - ret.lastInsertId = map.value("lastInsertId").toInt(); - } - else { - - } - return ret; - -} -*/ -} SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) : Super("sql", parent) @@ -43,20 +24,60 @@ SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) } -shv::chainpack::RpcValue::Map SqlApiNode::recordToMap(const QSqlRecord &rec) +namespace { +class Transaction { - RpcValue::Map record; - for (int i = 0; i < rec.count(); ++i) { - QSqlField fld = rec.field(i); - auto fld_name = fld.name(); - fld_name.replace("__", "."); - record[fld_name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(fld.value()); +public: + Transaction(QSqlDatabase db) : m_db(db) { } - return record; -} + ~Transaction() { + if (m_inTransaction) { + m_db.rollback(); + } + } + void begin() { + if (!m_db.transaction()) { + qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); + throw std::runtime_error("BEGIN transaction error"); + } + m_inTransaction = true; + } + void commit() { + if (m_inTransaction) { + if (!m_db.commit()) { + qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); + throw std::runtime_error("COMMIT transaction error"); + } + m_inTransaction = false; + } + } +private: + QSqlDatabase m_db; + bool m_inTransaction = false; +}; -RpcSqlResult SqlApiNode::rpcSqlResultFromQuery(QSqlQuery &q) +RpcSqlResult rpcSqlQuery(const QString &query, const RpcValue ¶ms, bool in_transaction = false) { + auto conn = qf::core::sql::Connection::forName(); + Transaction tranaction(conn); + if (in_transaction) { + tranaction.begin(); + } + qf::core::sql::Query q(conn); + q.prepare(query, qf::core::Exception::Throw); + for (const auto &[k, v] : params.asMap()) { + bool ok; + QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); + if (!ok) { + QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); + } + q.bindValue(QString::fromStdString(k), val); + } + q.exec(qf::core::Exception::Throw); + if (in_transaction) { + tranaction.commit(); + } + RpcSqlResult ret; if(q.isSelect()) { QSqlRecord rec = q.record(); @@ -72,10 +93,12 @@ RpcSqlResult SqlApiNode::rpcSqlResultFromQuery(QSqlQuery &q) RpcSqlResult::Row row; for (int i = 0; i < rec.count(); ++i) { const QVariant v = q.value(i); - if (v.isNull()) - row.append(QVariant()); - else + if (v.isNull()) { + row.append(QVariant::fromValue(nullptr)); + } + else { row.append(v); + } //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); } ret.rows.insert(ret.rows.count(), row); @@ -88,14 +111,29 @@ RpcSqlResult SqlApiNode::rpcSqlResultFromQuery(QSqlQuery &q) return ret; } -static auto METH_EXEC_SQL = "execSql"; +auto METH_QUERY = "query"; +auto METH_EXEC = "exec"; +auto METH_TRANSACTION = "transaction"; +auto METH_LIST = "list"; +auto METH_CREATE = "create"; +auto METH_READ = "read"; +auto METH_UPDATE = "update"; +auto METH_DELETE = "delete"; +} const std::vector &SqlApiNode::metaMethods() { static std::vector meta_methods { methods::DIR, methods::LS, - {METH_EXEC_SQL, MetaMethod::Flag::None, {}, "RpcValue", AccessLevel::Write}, + {METH_QUERY, MetaMethod::Flag::LargeResultHint, "[s:query,{s|i|b|t|n}:params]", "{{s:name}:fields,[[s|i|b|t|n]]:rows}", AccessLevel::Read}, + {METH_EXEC, MetaMethod::Flag::None, "[s:query,{s|i|b|t|n}:params]", "{i:rows_affected,i|n:insert_id}", AccessLevel::Write}, + {METH_TRANSACTION, MetaMethod::Flag::None, "[s:query,{s|i|b|t|n}:params]", "n", AccessLevel::Write}, + {METH_LIST, MetaMethod::Flag::LargeResultHint, "{s:table,[s]|n:fields,i|n:ids_above,i|n:limit}", "[{s|i|b|t|n}]", AccessLevel::Write}, + {METH_CREATE, MetaMethod::Flag::None, "{s:table,{s|i|b|t|n}:record}", "i", AccessLevel::Write}, + {METH_READ, MetaMethod::Flag::None, "{s:table,i:id,{s}|n:fields}", "{s|i|b|t|n}|n", AccessLevel::Read}, + {METH_UPDATE, MetaMethod::Flag::None, "{s:table,i:id,{s|i|b|t|n}:record}", "b", AccessLevel::Write}, + {METH_DELETE, MetaMethod::Flag::None, "{s:table,i:id}", "b", AccessLevel::Write}, }; return meta_methods; } @@ -105,13 +143,137 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin qfLogFuncFrame() << shv_path.join('/') << method; //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); if(shv_path.empty()) { - if(method == METH_EXEC_SQL) { - qf::core::sql::Query q; - QString qs = params.to(); - q.exec(qs, qf::core::Exception::Throw); - auto res = rpcSqlResultFromQuery(q); + if(method == METH_EXEC) { + auto sql_query = params.asList().valref(0).to(); + const auto &sql_params = params.asList().valref(0); + auto res = rpcSqlQuery(sql_query, sql_params); + return res.toRpcValue(); + } + if(method == METH_QUERY) { + auto sql_query = params.asList().valref(0).to(); + const auto &sql_params = params.asList().valref(0); + auto res = rpcSqlQuery(sql_query, sql_params); return res.toRpcValue(); } + if(method == METH_TRANSACTION) { + auto sql_query = params.asList().valref(0).to(); + const auto &sql_params = params.asList().valref(0); + auto res = rpcSqlQuery(sql_query, sql_params, true); + return RpcValue(nullptr); + } + if(method == METH_LIST) { + const auto &map = params.asMap(); + QStringList fields; + for (const auto &fn : map.valref("fields").asList()) { + fields << fn.to(); + } + if (fields.isEmpty()) { + fields << "*"; + } + QString sql_query = QStringLiteral("SELECT %1 FROM %2").arg(fields.join(',')).arg(map.value("table").to()); + if (auto ids_above = map.value("ids_above"); ids_above.isInt()) { + sql_query += " WHERE id > " + QString::number(ids_above.toInt()); + } + if (auto limit = map.value("limit"); limit.isInt()) { + sql_query += " LIMIT " + QString::number(limit.toInt()); + } + auto res = rpcSqlQuery(sql_query, {}); + if (res.rows.isEmpty()) { + return RpcValue(nullptr); + } + RpcValue::List ret; + for (const auto &row : res.rows) { + auto cells = row.toList(); + RpcValue::Map rec; + int n = 0; + for (const auto &field : res.fields) { + rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(cells.value(n++)); + } + ret.push_back(rec); + } + return ret; + } + if(method == METH_CREATE) { + const auto &map = params.asMap(); + auto table = map.valref("table").to(); + const auto &record = map.valref("record").asMap(); + QStringList fields; + QStringList placeholders; + for (const auto &[k, v] : record) { + auto name = QString::fromStdString(k); + fields << name; + placeholders << ':' + name; + } + QString sql_query = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") + .arg(table) + .arg(fields.join(',')) + .arg(placeholders.join(',')); + qf::core::sql::Query q; + q.prepare(sql_query, qf::core::Exception::Throw); + for (const auto &[k, v] : record) { + q.bindValue(QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); + } + q.exec(qf::core::Exception::Throw); + return q.lastInsertId().toInt(); + } + if(method == METH_READ) { + const auto &map = params.asMap(); + QStringList fields; + for (const auto &fn : map.valref("fields").asList()) { + fields << fn.to(); + } + if (fields.isEmpty()) { + fields << "*"; + } + QString sql_query = QStringLiteral("SELECT %1 FROM %2 WHERE id = %3") + .arg(fields.join(',')) + .arg(map.value("table").to()) + .arg(map.value("id").toInt()) ; + auto res = rpcSqlQuery(sql_query, {}); + if (res.rows.isEmpty()) { + return RpcValue(nullptr); + } + RpcValue::Map rec; + auto cells = res.rows[0].toList(); + int n = 0; + for (const auto &field : res.fields) { + rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(cells.value(n++)); + } + return rec; + } + if(method == METH_UPDATE) { + const auto &map = params.asMap(); + auto table = map.valref("table").to(); + auto id = map.valref("id").toInt(); + const auto &record = map.valref("record").asMap(); + QStringList fields; + for (const auto &[k, v] : record) { + auto name = QString::fromStdString(k); + fields << name + " = :" + name; + } + QString sql_query = QStringLiteral("UPDATE %1 SET %2 WHERE id = %3") + .arg(table) + .arg(fields.join(',')) + .arg(id); + qf::core::sql::Query q; + q.prepare(sql_query, qf::core::Exception::Throw); + for (const auto &[k, v] : record) { + q.bindValue(QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); + } + q.exec(qf::core::Exception::Throw); + return q.numRowsAffected() == 1; + } + if(method == METH_DELETE) { + const auto &map = params.asMap(); + auto table = map.valref("table").to(); + auto id = map.valref("id").toInt(); + QString sql_query = QStringLiteral("DELETE FROM %1 WHERE id = %2") + .arg(table) + .arg(id); + qf::core::sql::Query q; + q.exec(sql_query, qf::core::Exception::Throw); + return q.numRowsAffected() == 1; + } } return Super::callMethod(shv_path, method, params, user_id); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h index c2e112f26..a36f7ed8c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h @@ -16,9 +16,6 @@ class SqlApiNode : public QxNode using Super = QxNode; public: explicit SqlApiNode(shv::iotqt::node::ShvNode *parent); - - static shv::coreqt::data::RpcSqlResult rpcSqlResultFromQuery(QSqlQuery &q); - static shv::chainpack::RpcValue::Map recordToMap(const QSqlRecord &rec); protected: const std::vector &metaMethods() override; shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; From 9e325a7563bbb8988f7c7ec7f2c9fa9b081a0027 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 10 Nov 2025 23:10:32 +0100 Subject: [PATCH 08/83] QxSQL API in QE --- 3rdparty/libshv | 2 +- libqf/libqfgui/src/tableview.cpp | 2 +- quickevent/app/quickevent/CMakeLists.txt | 6 +- .../Event/src/services/qx/qxeventservice.cpp | 54 +-- .../Event/src/services/qx/qxeventservice.h | 6 +- .../src/services/qx/qxeventservicewidget.cpp | 34 +- .../plugins/Event/src/services/qx/sqlapi.cpp | 406 ++++++++++++++++++ .../plugins/Event/src/services/qx/sqlapi.h | 88 ++++ .../Event/src/services/qx/sqlapinode.cpp | 217 ++-------- .../plugins/Runs/src/runstablewidget.cpp | 28 ++ .../plugins/Runs/src/runstablewidget.h | 3 + .../quickevent/plugins/Runs/src/runswidget.h | 15 +- 12 files changed, 601 insertions(+), 260 deletions(-) create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h diff --git a/3rdparty/libshv b/3rdparty/libshv index 40f0b3cf2..f108e5d72 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit 40f0b3cf213ab799fb17bf6a31ce527a8851ee30 +Subproject commit f108e5d72729c16ee5b27ee8a9096182a5ceb7fa diff --git a/libqf/libqfgui/src/tableview.cpp b/libqf/libqfgui/src/tableview.cpp index 72cae3801..bd3183e59 100644 --- a/libqf/libqfgui/src/tableview.cpp +++ b/libqf/libqfgui/src/tableview.cpp @@ -1146,7 +1146,7 @@ void TableView::rowExternallySaved(const QVariant &id) qf::core::sql::Query q; bool ok = q.exec(query_str); if (!ok) { - qfInfo() << "Query:" << query_str; + qfMessage() << "Query:" << query_str; qfWarning() << "SQL error:" << q.lastErrorText(); return; } diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 33b7c3607..b7c6e2e75 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -1,5 +1,3 @@ -find_package(Qt6 REQUIRED COMPONENTS Core) - add_executable(quickevent plugins/CardReader/src/cardchecker.cpp plugins/CardReader/src/cardcheckerclassiccpp.cpp @@ -92,6 +90,7 @@ add_executable(quickevent plugins/Event/src/services/servicewidget.cpp plugins/Event/src/services/servicewidget.ui + plugins/Event/src/services/qx/sqlapi.h plugins/Event/src/services/qx/sqlapi.cpp plugins/Event/src/services/qx/qxnode.cpp plugins/Event/src/services/qx/sqlapinode.cpp plugins/Event/src/services/qx/nodes.cpp @@ -276,8 +275,7 @@ target_include_directories(quickevent PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAK target_link_libraries(quickevent PUBLIC libquickeventcore libquickeventgui libqfgui libsiut) if (QF_WITH_LIBSHV) target_link_libraries(quickevent PUBLIC libshviotqt) -target_link_libraries(quickevent PRIVATE Qt6::Core) -target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) + target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) endif() foreach(plugin IN ITEMS Classes Runs Relays Receipts shared) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 8aa7f5642..320548969 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -2,6 +2,7 @@ #include "qxeventservicewidget.h" #include "nodes.h" #include "sqlapinode.h" +#include "sqlapi.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -77,7 +78,7 @@ void QxEventService::run() { m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); RpcValue::Map opts; RpcValue::Map device; - device["mountPoint"] = "test/quickbox"; + device["mountPoint"] = "test/quickevent"; opts["device"] = device; m_rpcConnection->setConnectionOptions(opts); @@ -86,28 +87,9 @@ void QxEventService::run() { connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxEventService::onBrokerLoginError); connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxEventService::onRpcMessageReceived); - m_rpcConnection->open(); + connect(SqlApi::instance(), &SqlApi::recchng, this, &QxEventService::onRecchg); -// connect(reply, &QNetworkReply::finished, this, [this, reply, ss]() { -// if (reply->error() == QNetworkReply::NetworkError::NoError) { -// auto data = reply->readAll(); -// auto doc = QJsonDocument::fromJson(data); -// EventInfo event_info(doc.toVariant().toMap()); -// setStatusMessage(event_info.name() + (event_info.stage_count() > 1? QStringLiteral(" E%1").arg(event_info.stage()): QString())); -// m_eventId = event_info.id(); -// connectToSSE(m_eventId); -// if (!m_pollChangesTimer) { -// m_pollChangesTimer = new QTimer(this); -// connect(m_pollChangesTimer, &QTimer::timeout, this, &QxClientService::pollQxChanges); -// } -// pollQxChanges(); -// m_pollChangesTimer->start(10000); -// Super::run(); -// } -// else { -// qfWarning() << "Cannot run QX service, network error:" << reply->errorString(); -// } -// }); + m_rpcConnection->open(); } void QxEventService::stop() @@ -615,6 +597,10 @@ void QxEventService::onRpcMessageReceived(const shv::chainpack::RpcMessage &msg) // shvLogFuncFrame() << msg.toCpon(); if(msg.isRequest()) { RpcRequest rq(msg); + if (rq.shvPath().asString().starts_with(".broker/")) { + // ignore broker discovery messages + return; + } qfMessage() << "RPC request received:" << rq.toPrettyString(); m_rootNode->handleRpcRequest(rq); } @@ -641,36 +627,22 @@ void QxEventService::subscribeChanges() QString shv_path = "test"; QString signal_name = shv::chainpack::Rpc::SIG_VAL_CHANGED; auto *rpc_call = RpcCall::createSubscriptionRequest(m_rpcConnection, shv_path, signal_name); - connect(rpc_call, &RpcCall::maybeResult, this, [this, shv_path, signal_name](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + connect(rpc_call, &RpcCall::maybeResult, this, [shv_path, signal_name](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { if(error.isValid()) { qfError() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribe error:" << error.toString(); } else { qfMessage() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribed successfully" << result.toCpon(); - // generate data change without ret value check - m_rpcConnection->callShvMethod((shv_path + "/someInt").toStdString(), "set", 123); - QTimer::singleShot(500, this, [this, shv_path]() { - m_rpcConnection->callShvMethod((shv_path + "/someInt").toStdString(), "set", 321); - }); } }); rpc_call->start(); } -void QxEventService::testRpcCall() const +void QxEventService::onRecchg(const QxRecChng &chng) { - Q_ASSERT(m_rpcConnection); - auto *rpc_call = RpcCall::create(m_rpcConnection) - ->setShvPath("test") - ->setMethod("ls"); -// ->setTimeout(5000); - connect(rpc_call, &RpcCall::maybeResult, [](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { - if(error.isValid()) - qfError() << "RPC call error:" << error.toString(); - else - qfInfo() << "Got RPC response, result:" << result.toCpon(); - }); - rpc_call->start(); + if (isRunning()) { + m_rpcConnection->sendShvSignal("sql", "recchng", chng.toRpcValue()); + } } } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 2a103a9d7..b25076626 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -13,11 +13,13 @@ namespace shv::chainpack { class RpcMessage; class RpcError; } namespace Event::services::qx { +struct QxRecChng; + class QxEventServiceSettings : public ServiceSettings { using Super = ServiceSettings; - QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "http://localhost:8000") + QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "tcp://localhost?user=test&password=test") public: QxEventServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} }; @@ -78,9 +80,9 @@ class QxEventService : public Service void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg); void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); + void onRecchg(const QxRecChng &chng); void subscribeChanges(); - void testRpcCall() const; private: void loadSettings() override; qf::gui::framework::DialogWidget *createDetailWidget() override; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 416bb25b4..125d70f16 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -1,5 +1,6 @@ #include "qxeventservicewidget.h" #include "ui_qxeventservicewidget.h" + #include "qxeventservice.h" #include @@ -8,6 +9,8 @@ #include #include +#include + #include #include #include @@ -113,22 +116,27 @@ void QxEventServiceWidget::updateOCheckListPostUrl() void QxEventServiceWidget::testConnection() { - auto *svc = service(); - Q_ASSERT(svc); - auto *reply = svc->getRemoteEventInfo(ui->edServerUrl->text(), ui->edApiToken->text()); - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - if (reply->error() == QNetworkReply::NetworkError::NoError) { - auto data = reply->readAll(); - auto doc = QJsonDocument::fromJson(data); - EventInfo event_info(doc.toVariant().toMap()); - ui->edEventId->setValue(event_info.id()); + using namespace shv::iotqt::rpc; + using namespace shv::chainpack; + + auto *rpc = new DeviceConnection(this); + rpc->setConnectionString(ui->edServerUrl->text()); + + connect(rpc, &ClientConnection::brokerConnectedChanged, this, [this, rpc](bool is_connected) { + if (is_connected) { + rpc->deleteLater(); setMessage(tr("Connected OK")); } - else { - setMessage(tr("Connection error: %1").arg(reply->errorString()), MessageType::Error); - } - reply->deleteLater(); }); + connect(rpc, &ClientConnection::socketError, this, [this, rpc](const QString &error) { + rpc->deleteLater(); + setMessage(tr("Connection error: %1").arg(error), MessageType::Error); + }); + connect(rpc, &ClientConnection::brokerLoginError, this, [this, rpc](const auto &error) { + rpc->deleteLater(); + setMessage(tr("Login error: %1").arg(QString::fromStdString(error.toString())), MessageType::Error); + }); + rpc->open(); } void QxEventServiceWidget::exportEventInfo() diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp new file mode 100644 index 000000000..fde4ae512 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp @@ -0,0 +1,406 @@ +#include "sqlapi.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace shv::chainpack; + +namespace Event::services::qx { + +//============================================== +// RpcSqlField +//============================================== +RpcValue RpcSqlField::toRpcValue() const +{ + RpcValue::Map ret; + ret["name"] = name; + return RpcValue(std::move(ret)); +} + +RpcSqlField RpcSqlField::fromRpcValue(const shv::chainpack::RpcValue &rv) +{ + RpcSqlField ret; + const RpcValue::Map &map = rv.asMap(); + ret.name = map.value("name").asString(); + return ret; +} + +//============================================== +// RpcSqlResult +//============================================== +const RpcValue &RpcSqlResult::value(size_t row, size_t col) const +{ + if (row < rows.size()) { + const auto &cells = rows[row]; + if (col < cells.size()) { + return cells[col]; + } + } + static RpcValue s; + return s; +} + +const RpcValue& RpcSqlResult::value(size_t row, const std::string &name) const +{ + if (auto ix = columnIndex(name); ix.has_value()) { + return value(row, ix.value()); + } + static RpcValue s; + return s; +} + +void RpcSqlResult::setValue(size_t row, size_t col, const RpcValue &val) +{ + if (row < rows.size()) { + auto &r = rows[row]; + if (col < r.size()) { + r[col] = val; + } + } +} + +void RpcSqlResult::setValue(size_t row, const std::string &name, const RpcValue &val) +{ + if (auto ix = columnIndex(name); ix.has_value()) { + setValue(row, ix.value(), val); + } +} + +RpcValue::List RpcSqlResult::toRecordList() const +{ + RpcValue::List ret; + for (const auto &row : rows) { + SqlRecord rec; + int n = 0; + for (const auto &field : fields) { + rec[field.name] = row[n++]; + } + ret.push_back(rec); + } + return ret; +} + +std::optional RpcSqlResult::columnIndex(const std::string &name) const +{ + for (size_t col = 0; col < fields.size(); ++col) { + const auto &fld = fields[col]; + if (fld.name == name) { + return col; + } + } + return {}; +} + +RpcValue RpcSqlResult::toRpcValue() const +{ + RpcValue::Map ret; + if(isSelect()) { + RpcValue::List flds; + for(const auto &fld : this->fields) + flds.push_back(fld.toRpcValue()); + ret["fields"] = flds; + ret["rows"] = rows; + } + else { + ret["numRowsAffected"] = numRowsAffected; + ret["lastInsertId"] = lastInsertId.has_value()? RpcValue(lastInsertId.value()): RpcValue(nullptr); + } + return ret; +} + +RpcSqlResult RpcSqlResult::fromRpcValue(const RpcValue &rv) +{ + RpcSqlResult ret; + const auto &map = rv.asMap(); + const auto &flds = map.valref("fields").asList(); + if(flds.empty()) { + ret.numRowsAffected = map.value("numRowsAffected").toInt(); + ret.lastInsertId = map.value("lastInsertId").toInt(); + } + else { + for(const auto &fv : flds) { + ret.fields.push_back(RpcSqlField::fromRpcValue(fv)); + } + for (const auto &row : map.value("rows").asList()) { + ret.rows.push_back(row.asList()); + } + } + return ret; +} + +SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue &rv) +{ + auto sql_query = rv.asList().valref(0).asString(); + const auto &sql_params = rv.asList().valref(0); + return SqlQueryAndParams { .query = sql_query, .params = sql_params.asMap() }; +} + +RpcValue QxRecChng::toRpcValue() const +{ + RpcValue::Map ret; + ret["table"] = table.toStdString(); + ret["id"] = id; + ret["record"] = shv::coreqt::rpc::qVariantToRpcValue(record); + auto rec_op_string = [](RecOp op) { + switch (op) { + case RecOp::Insert: return "Insert"; + case RecOp::Update: return "Update"; + case RecOp::Delete: return "Delete"; + } + return ""; + }; + ret["op"] = rec_op_string(op); + return ret; +} + +//============================================== +// SqlApi +//============================================== +SqlApi::SqlApi(QObject *parent) + : QObject{parent} +{ + +} + +SqlApi *SqlApi::instance() +{ + static auto *api = new SqlApi(QCoreApplication::instance()); + return api; +} + +namespace { + +class Transaction +{ +public: + Transaction(QSqlDatabase db) : m_db(db) { + if (!m_db.transaction()) { + qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); + throw std::runtime_error("BEGIN transaction error"); + } + } + ~Transaction() { + if (m_inTransaction) { + m_db.rollback(); + } + } + void commit() { + if (!m_db.commit()) { + qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); + throw std::runtime_error("COMMIT transaction error"); + } + m_inTransaction = false; + } +private: + QSqlDatabase m_db; + bool m_inTransaction = true; +}; + +RpcSqlResult rpcSqlQuery(const SqlQueryAndParams ¶ms) +{ + qf::core::sql::Query q; + q.prepare(QString::fromUtf8(params.query), qf::core::Exception::Throw); + for (const auto &[k, v] : params.params) { + bool ok; + QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); + if (!ok) { + QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); + } + q.bindValue(':' + QString::fromStdString(k), val); + } + q.exec(qf::core::Exception::Throw); + RpcSqlResult ret; + if(q.isSelect()) { + QSqlRecord rec = q.record(); + for (int i = 0; i < rec.count(); ++i) { + QSqlField fld = rec.field(i); + RpcSqlField rfld; + rfld.name = fld.name().toStdString(); + // rfld.name.replace("__", "."); + ret.fields.push_back(rfld); + } + while(q.next()) { + RpcSqlResult::Row row; + for (int i = 0; i < rec.count(); ++i) { + const QVariant v = q.value(i); + if (v.isNull()) { + row.push_back(RpcValue(nullptr)); + } + else { + row.push_back(shv::coreqt::rpc::qVariantToRpcValue(v)); + } + //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); + } + ret.rows.push_back(row); + } + } + else { + ret.numRowsAffected = q.numRowsAffected(); + ret.lastInsertId = q.lastInsertId().toInt(); + } + return ret; +} + +} + +RpcSqlResult SqlApi::exec(const SqlQueryAndParams ¶ms) +{ + return rpcSqlQuery(params); +} + +RpcSqlResult SqlApi::query(const SqlQueryAndParams ¶ms) +{ + return rpcSqlQuery(params); +} + +void SqlApi::transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms) +{ + auto conn = qf::core::sql::Connection::forName(); + Transaction tranaction(conn); + qf::core::sql::Query q(conn); + q.prepare(QString::fromUtf8(query), qf::core::Exception::Throw); + for (const auto ¶m : params) { + for (const auto &[k, v] : param.asMap()) { + bool ok; + QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); + if (!ok) { + QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); + } + q.bindValue(':' + QString::fromStdString(k), val); + } + q.exec(qf::core::Exception::Throw); + } + tranaction.commit(); +} + +RpcSqlResult SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) +{ + QStringList qfields; + for (const auto &fn : fields) { + qfields << QString::fromStdString(fn); + } + if (qfields.isEmpty()) { + qfields << "*"; + } + QString sql_query = QStringLiteral("SELECT %1 FROM %2").arg(qfields.join(',')).arg(QString::fromStdString(table)); + if (ids_above.has_value()) { + sql_query += " WHERE id > " + QString::number(ids_above.value()); + } + if (limit.has_value()) { + sql_query += " LIMIT " + QString::number(limit.value()); + } + auto res = rpcSqlQuery(SqlQueryAndParams { .query = sql_query.toStdString(), .params = {}}); + return res; +} + +int64_t SqlApi::create(const std::string &table, const SqlRecord &record) +{ + QStringList fields; + QStringList placeholders; + for (const auto &[k, v] : record) { + auto name = QString::fromStdString(k); + fields << name; + placeholders << ':' + name; + } + QString sql_query = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") + .arg(table) + .arg(fields.join(',')) + .arg(placeholders.join(',')); + qf::core::sql::Query q; + q.prepare(sql_query, qf::core::Exception::Throw); + for (const auto &[k, v] : record) { + q.bindValue(':' + QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); + } + q.exec(qf::core::Exception::Throw); + auto id = q.lastInsertId().toInt(); + emit SqlApi::instance()->recchng(QxRecChng { + .table = QString::fromStdString(table), + .id = id, + .record = shv::coreqt::rpc::rpcValueToQVariant(record), + .op = RecOp::Insert + }); + return id; +} + +std::optional SqlApi::read(const std::string &table, int64_t id, const std::vector &fields) +{ + QStringList qfields; + for (const auto &fn : fields) { + qfields << QString::fromStdString(fn); + } + if (qfields.isEmpty()) { + qfields << "*"; + } + QString sql_query = QStringLiteral("SELECT %1 FROM %2 WHERE id = %3") + .arg(qfields.join(',')) + .arg(QString::fromStdString(table)) + .arg(id) ; + auto res = rpcSqlQuery(SqlQueryAndParams { .query = sql_query.toStdString(), .params = {}}); + auto lst = res.toRecordList(); + if (lst.empty()) { + return {}; + } + return lst[0].asMap(); +} + +bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &record) +{ + QStringList fields; + for (const auto &[k, v] : record) { + auto name = QString::fromStdString(k); + fields << name + " = :" + name; + } + QString sql_query = QStringLiteral("UPDATE %1 SET %2 WHERE id = %3") + .arg(table) + .arg(fields.join(',')) + .arg(id); + qf::core::sql::Query q; + q.prepare(sql_query, qf::core::Exception::Throw); + for (const auto &[k, v] : record) { + auto qv = shv::coreqt::rpc::rpcValueToQVariant(v); + q.bindValue(':' + QString::fromStdString(k), qv); + } + q.exec(qf::core::Exception::Throw); + bool updated = q.numRowsAffected() == 1; + if (updated) { + emit SqlApi::instance()->recchng(QxRecChng { + .table = QString::fromStdString(table), + .id = id, + .record = shv::coreqt::rpc::rpcValueToQVariant(record), + .op = RecOp::Update + }); + } + return updated; +} + +bool SqlApi::drop(const std::string &table, int64_t id) +{ + QString sql_query = QStringLiteral("DELETE FROM %1 WHERE id = %2") + .arg(table) + .arg(id); + qf::core::sql::Query q; + q.exec(sql_query, qf::core::Exception::Throw); + bool is_drop = q.numRowsAffected() == 1; + if (is_drop) { + emit SqlApi::instance()->recchng(QxRecChng { + .table = QString::fromStdString(table), + .id = id, + .record = {}, + .op = RecOp::Delete + }); + } + return is_drop; +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h new file mode 100644 index 000000000..3594ca510 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h @@ -0,0 +1,88 @@ +#pragma once + +#include + +#include +#include + +namespace Event::services::qx { + +struct RpcSqlField +{ + std::string name; + + //explicit RpcSqlField(const QJsonObject &jo = QJsonObject()) : Super(jo) {} + shv::chainpack::RpcValue toRpcValue() const; + // QVariant toVariant() const; + static RpcSqlField fromRpcValue(const shv::chainpack::RpcValue &rv); + // static RpcSqlField fromVariant(const QVariant &v); +}; + +struct RpcSqlResult +{ + int numRowsAffected = 0; + std::optional lastInsertId = 0; + std::vector fields; + using Row = shv::chainpack::RpcValue::List; + std::vector rows; + + RpcSqlResult() = default; + // explicit RpcSqlResult(const QSqlQuery &q); + + std::optional columnIndex(const std::string &name) const; + const shv::chainpack::RpcValue& value(size_t row, size_t col) const; + const shv::chainpack::RpcValue& value(size_t row, const std::string &name) const; + void setValue(size_t row, size_t col, const shv::chainpack::RpcValue &val); + void setValue(size_t row, const std::string &name, const shv::chainpack::RpcValue &val); + + bool isSelect() const {return !fields.empty();} + shv::chainpack::RpcValue toRpcValue() const; + shv::chainpack::RpcValue::List toRecordList() const; + // QVariant toVariant() const; + // static RpcSqlResult fromVariant(const QVariant &v); + static RpcSqlResult fromRpcValue(const shv::chainpack::RpcValue &rv); +}; + +using SqlRecord = shv::chainpack::RpcValue::Map; + +struct SqlQueryAndParams +{ + std::string query; + SqlRecord params; + + static SqlQueryAndParams fromRpcValue(const shv::chainpack::RpcValue &rv); +}; + +enum class RecOp { Insert, Update, Delete, }; + +struct QxRecChng +{ + QString table; + int64_t id; + QVariant record; + RecOp op; + + shv::chainpack::RpcValue toRpcValue() const; +}; + +class SqlApi : public QObject +{ + Q_OBJECT +public: + static SqlApi* instance(); + + Q_SIGNAL void recchng(const QxRecChng &chng); + + static RpcSqlResult exec(const SqlQueryAndParams ¶ms); + static RpcSqlResult query(const SqlQueryAndParams ¶ms); + static void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); + static RpcSqlResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); + static int64_t create(const std::string &table, const SqlRecord &record); + static std::optional read(const std::string &table, int64_t id, const std::vector &fields); + static bool update(const std::string &table, int64_t id, const SqlRecord &record); + static bool drop(const std::string &table, int64_t id); +private: + explicit SqlApi(QObject *parent = nullptr); +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index 846e6c7e6..d12474363 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -1,4 +1,5 @@ #include "sqlapinode.h" +#include "sqlapi.h" #include #include @@ -21,96 +22,9 @@ namespace Event::services::qx { SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) : Super("sql", parent) { - } namespace { -class Transaction -{ -public: - Transaction(QSqlDatabase db) : m_db(db) { - } - ~Transaction() { - if (m_inTransaction) { - m_db.rollback(); - } - } - void begin() { - if (!m_db.transaction()) { - qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); - throw std::runtime_error("BEGIN transaction error"); - } - m_inTransaction = true; - } - void commit() { - if (m_inTransaction) { - if (!m_db.commit()) { - qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); - throw std::runtime_error("COMMIT transaction error"); - } - m_inTransaction = false; - } - } -private: - QSqlDatabase m_db; - bool m_inTransaction = false; -}; - -RpcSqlResult rpcSqlQuery(const QString &query, const RpcValue ¶ms, bool in_transaction = false) -{ - auto conn = qf::core::sql::Connection::forName(); - Transaction tranaction(conn); - if (in_transaction) { - tranaction.begin(); - } - qf::core::sql::Query q(conn); - q.prepare(query, qf::core::Exception::Throw); - for (const auto &[k, v] : params.asMap()) { - bool ok; - QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); - if (!ok) { - QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); - } - q.bindValue(QString::fromStdString(k), val); - } - q.exec(qf::core::Exception::Throw); - if (in_transaction) { - tranaction.commit(); - } - - RpcSqlResult ret; - if(q.isSelect()) { - QSqlRecord rec = q.record(); - for (int i = 0; i < rec.count(); ++i) { - QSqlField fld = rec.field(i); - RpcSqlField rfld; - rfld.name = fld.name(); - rfld.name.replace("__", "."); - rfld.type = fld.metaType().id(); - ret.fields.append(rfld); - } - while(q.next()) { - RpcSqlResult::Row row; - for (int i = 0; i < rec.count(); ++i) { - const QVariant v = q.value(i); - if (v.isNull()) { - row.append(QVariant::fromValue(nullptr)); - } - else { - row.append(v); - } - //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); - } - ret.rows.insert(ret.rows.count(), row); - } - } - else { - ret.numRowsAffected = q.numRowsAffected(); - ret.lastInsertId = q.lastInsertId().toInt(); - } - return ret; -} - auto METH_QUERY = "query"; auto METH_EXEC = "exec"; auto METH_TRANSACTION = "transaction"; @@ -128,7 +42,7 @@ const std::vector &SqlApiNode::metaMethods() methods::LS, {METH_QUERY, MetaMethod::Flag::LargeResultHint, "[s:query,{s|i|b|t|n}:params]", "{{s:name}:fields,[[s|i|b|t|n]]:rows}", AccessLevel::Read}, {METH_EXEC, MetaMethod::Flag::None, "[s:query,{s|i|b|t|n}:params]", "{i:rows_affected,i|n:insert_id}", AccessLevel::Write}, - {METH_TRANSACTION, MetaMethod::Flag::None, "[s:query,{s|i|b|t|n}:params]", "n", AccessLevel::Write}, + {METH_TRANSACTION, MetaMethod::Flag::None, "[s:query,[{s|i|b|t|n}]:params]", "n", AccessLevel::Write}, {METH_LIST, MetaMethod::Flag::LargeResultHint, "{s:table,[s]|n:fields,i|n:ids_above,i|n:limit}", "[{s|i|b|t|n}]", AccessLevel::Write}, {METH_CREATE, MetaMethod::Flag::None, "{s:table,{s|i|b|t|n}:record}", "i", AccessLevel::Write}, {METH_READ, MetaMethod::Flag::None, "{s:table,i:id,{s}|n:fields}", "{s|i|b|t|n}|n", AccessLevel::Read}, @@ -144,135 +58,66 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); if(shv_path.empty()) { if(method == METH_EXEC) { - auto sql_query = params.asList().valref(0).to(); - const auto &sql_params = params.asList().valref(0); - auto res = rpcSqlQuery(sql_query, sql_params); + auto res = SqlApi::exec(SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_QUERY) { - auto sql_query = params.asList().valref(0).to(); - const auto &sql_params = params.asList().valref(0); - auto res = rpcSqlQuery(sql_query, sql_params); + auto res = SqlApi::exec(SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_TRANSACTION) { - auto sql_query = params.asList().valref(0).to(); + auto sql_query = params.asList().valref(0).asString(); const auto &sql_params = params.asList().valref(0); - auto res = rpcSqlQuery(sql_query, sql_params, true); + SqlApi::transaction(sql_query, sql_params.asList()); return RpcValue(nullptr); } if(method == METH_LIST) { const auto &map = params.asMap(); - QStringList fields; + const auto &table = map.value("table").asString(); + std::vector fields; for (const auto &fn : map.valref("fields").asList()) { - fields << fn.to(); - } - if (fields.isEmpty()) { - fields << "*"; - } - QString sql_query = QStringLiteral("SELECT %1 FROM %2").arg(fields.join(',')).arg(map.value("table").to()); - if (auto ids_above = map.value("ids_above"); ids_above.isInt()) { - sql_query += " WHERE id > " + QString::number(ids_above.toInt()); - } - if (auto limit = map.value("limit"); limit.isInt()) { - sql_query += " LIMIT " + QString::number(limit.toInt()); - } - auto res = rpcSqlQuery(sql_query, {}); - if (res.rows.isEmpty()) { - return RpcValue(nullptr); + fields.push_back(fn.asString()); } - RpcValue::List ret; - for (const auto &row : res.rows) { - auto cells = row.toList(); - RpcValue::Map rec; - int n = 0; - for (const auto &field : res.fields) { - rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(cells.value(n++)); - } - ret.push_back(rec); - } - return ret; + auto ids_above = map.contains("ids_above")? std::optional(map.value("ids_above").toInt64()): std::optional(); + auto limit = map.contains("limit")? std::optional(map.value("limit").toInt64()): std::optional(); + auto res = SqlApi::list(table, fields, ids_above, limit); + return res.toRecordList(); } if(method == METH_CREATE) { const auto &map = params.asMap(); - auto table = map.valref("table").to(); + const auto &table = map.value("table").asString(); const auto &record = map.valref("record").asMap(); - QStringList fields; - QStringList placeholders; - for (const auto &[k, v] : record) { - auto name = QString::fromStdString(k); - fields << name; - placeholders << ':' + name; - } - QString sql_query = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") - .arg(table) - .arg(fields.join(',')) - .arg(placeholders.join(',')); - qf::core::sql::Query q; - q.prepare(sql_query, qf::core::Exception::Throw); - for (const auto &[k, v] : record) { - q.bindValue(QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); - } - q.exec(qf::core::Exception::Throw); - return q.lastInsertId().toInt(); + auto res = SqlApi::create(table, record); + return res; } if(method == METH_READ) { const auto &map = params.asMap(); - QStringList fields; + const auto &table = map.value("table").asString(); + auto id = map.value("id").toInt64(); + std::vector fields; for (const auto &fn : map.valref("fields").asList()) { - fields << fn.to(); - } - if (fields.isEmpty()) { - fields << "*"; - } - QString sql_query = QStringLiteral("SELECT %1 FROM %2 WHERE id = %3") - .arg(fields.join(',')) - .arg(map.value("table").to()) - .arg(map.value("id").toInt()) ; - auto res = rpcSqlQuery(sql_query, {}); - if (res.rows.isEmpty()) { - return RpcValue(nullptr); + fields.push_back(fn.asString()); } - RpcValue::Map rec; - auto cells = res.rows[0].toList(); - int n = 0; - for (const auto &field : res.fields) { - rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(cells.value(n++)); + auto res = SqlApi::read(table, id, fields); + if (res.has_value()) { + return res.value(); } - return rec; + return RpcValue(nullptr); } if(method == METH_UPDATE) { const auto &map = params.asMap(); - auto table = map.valref("table").to(); - auto id = map.valref("id").toInt(); + const auto &table = map.value("table").asString(); + auto id = map.value("id").toInt64(); const auto &record = map.valref("record").asMap(); - QStringList fields; - for (const auto &[k, v] : record) { - auto name = QString::fromStdString(k); - fields << name + " = :" + name; - } - QString sql_query = QStringLiteral("UPDATE %1 SET %2 WHERE id = %3") - .arg(table) - .arg(fields.join(',')) - .arg(id); - qf::core::sql::Query q; - q.prepare(sql_query, qf::core::Exception::Throw); - for (const auto &[k, v] : record) { - q.bindValue(QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); - } - q.exec(qf::core::Exception::Throw); - return q.numRowsAffected() == 1; + auto res = SqlApi::update(table, id, record); + return res; } if(method == METH_DELETE) { const auto &map = params.asMap(); - auto table = map.valref("table").to(); + const auto &table = map.value("table").asString(); auto id = map.valref("id").toInt(); - QString sql_query = QStringLiteral("DELETE FROM %1 WHERE id = %2") - .arg(table) - .arg(id); - qf::core::sql::Query q; - q.exec(sql_query, qf::core::Exception::Throw); - return q.numRowsAffected() == 1; + auto res = SqlApi::drop(table, id); + return res; } } return Super::callMethod(shv_path, method, params, user_id); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index a226ec7f0..4250dd0fe 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -20,6 +20,12 @@ #include #include +#include +#include +#include +#include +#include + #include #include #include @@ -130,6 +136,8 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : } } }, Qt::QueuedConnection); + + connect(Event::services::qx::SqlApi::instance(), &Event::services::qx::SqlApi::recchng, this, &RunsTableWidget::onQxRecChng); } RunsTableWidget::~RunsTableWidget() @@ -431,4 +439,24 @@ void RunsTableWidget::onBadTableDataInput(const QString &message) qf::gui::dialogs::MessageBox::showError(this, message); } +void RunsTableWidget::onQxRecChng(const Event::services::qx::QxRecChng &chng) +{ + std::optional run_id; + if (chng.table == "competitors") { + auto *m = m_runsModel; + for (auto i=0; irowCount(); ++i) { + if (m->table().row(i).value("competitors.id").toInt() == chng.id) { + run_id = m->value(i, "runs.id").toInt(); + break; + } + } + } + else if (chng.table == "runs") { + run_id = chng.id; + } + if (run_id.has_value()) { + ui->tblRuns->rowExternallySaved(run_id.value()); + } +} + diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h index 8ba2e0964..a5379f689 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h @@ -7,6 +7,7 @@ class RunsTableItemDelegate; class CourseItemDelegate; namespace qf::gui { class TableView; } +namespace Event::services::qx { struct QxRecChng; } namespace Ui { class RunsTableWidget; @@ -36,6 +37,8 @@ class RunsTableWidget : public QWidget void onCustomContextMenuRequest(const QPoint &pos); void onTableViewSqlException(const QString &what, const QString &where, const QString &stack_trace); void onBadTableDataInput(const QString &message); + + void onQxRecChng(const Event::services::qx::QxRecChng &chng); private: Ui::RunsTableWidget *ui; RunsTableModel *m_runsModel; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.h b/quickevent/app/quickevent/plugins/Runs/src/runswidget.h index 9be9da658..9335be37d 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.h @@ -11,19 +11,11 @@ class QTextStream; class QLabel; namespace qf { -namespace core { -namespace model { -class SqlTableModel; -} -} -namespace gui { -class ForeignKeyComboBox; -} +namespace core { namespace model { class SqlTableModel; } } +namespace gui { class ForeignKeyComboBox; } } -namespace Event { -class EventPlugin; -} +namespace Event { class EventPlugin; } namespace Ui { class RunsWidget; @@ -69,7 +61,6 @@ class RunsWidget : public QFrame void onDrawRemoveClicked(); void onCbxStageCurrentIndexChanged(); private: - /** * @brief runnersInClubsHistogram * @return list of runs.id for each club sorted by their count, longest list of runners is first From ee2002f29fc06af35531e4248e56c60e72c52086 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 12 Nov 2025 21:15:09 +0100 Subject: [PATCH 09/83] Do not reload whole row on qxSqlApi update recchng --- libqf/libqfcore/src/utils/table.cpp | 4 +++- .../plugins/Event/src/services/qx/sqlapi.cpp | 14 +++++++------- .../plugins/Event/src/services/qx/sqlapi.h | 4 ++-- .../plugins/Runs/src/runstablewidget.cpp | 18 +++++++++++++++++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/libqf/libqfcore/src/utils/table.cpp b/libqf/libqfcore/src/utils/table.cpp index 78d073307..c4210506b 100644 --- a/libqf/libqfcore/src/utils/table.cpp +++ b/libqf/libqfcore/src/utils/table.cpp @@ -1310,7 +1310,8 @@ QVariant Table::sumValue(int field_ix) const return ret; } -static void setDomElementText(QDomDocument &owner_doc, QDomElement &el, const QString &str) +namespace { +void setDomElementText(QDomDocument &owner_doc, QDomElement &el, const QString &str) { QDomNode nd = el.firstChild(); QDomText el_txt = nd.toText(); @@ -1322,6 +1323,7 @@ static void setDomElementText(QDomDocument &owner_doc, QDomElement &el, const QS el_txt.setData(str); } } +} QDomElement Table::toHtmlElement(QDomDocument &owner_doc, const QString & col_names, TextExportOptions opts) const { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp index fde4ae512..2c58823bf 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp @@ -152,11 +152,11 @@ RpcValue QxRecChng::toRpcValue() const ret["table"] = table.toStdString(); ret["id"] = id; ret["record"] = shv::coreqt::rpc::qVariantToRpcValue(record); - auto rec_op_string = [](RecOp op) { + auto rec_op_string = [](QxRecOp op) { switch (op) { - case RecOp::Insert: return "Insert"; - case RecOp::Update: return "Update"; - case RecOp::Delete: return "Delete"; + case QxRecOp::Insert: return "Insert"; + case QxRecOp::Update: return "Update"; + case QxRecOp::Delete: return "Delete"; } return ""; }; @@ -328,7 +328,7 @@ int64_t SqlApi::create(const std::string &table, const SqlRecord &record) .table = QString::fromStdString(table), .id = id, .record = shv::coreqt::rpc::rpcValueToQVariant(record), - .op = RecOp::Insert + .op = QxRecOp::Insert }); return id; } @@ -378,7 +378,7 @@ bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &recor .table = QString::fromStdString(table), .id = id, .record = shv::coreqt::rpc::rpcValueToQVariant(record), - .op = RecOp::Update + .op = QxRecOp::Update }); } return updated; @@ -397,7 +397,7 @@ bool SqlApi::drop(const std::string &table, int64_t id) .table = QString::fromStdString(table), .id = id, .record = {}, - .op = RecOp::Delete + .op = QxRecOp::Delete }); } return is_drop; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h index 3594ca510..b8a8f64b9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h @@ -53,14 +53,14 @@ struct SqlQueryAndParams static SqlQueryAndParams fromRpcValue(const shv::chainpack::RpcValue &rv); }; -enum class RecOp { Insert, Update, Delete, }; +enum class QxRecOp { Insert, Update, Delete, }; struct QxRecChng { QString table; int64_t id; QVariant record; - RecOp op; + QxRecOp op; shv::chainpack::RpcValue toRpcValue() const; }; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 4250dd0fe..0011c3190 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -442,20 +442,36 @@ void RunsTableWidget::onBadTableDataInput(const QString &message) void RunsTableWidget::onQxRecChng(const Event::services::qx::QxRecChng &chng) { std::optional run_id; + int row = 0; if (chng.table == "competitors") { auto *m = m_runsModel; for (auto i=0; irowCount(); ++i) { if (m->table().row(i).value("competitors.id").toInt() == chng.id) { run_id = m->value(i, "runs.id").toInt(); + row = i; break; } } } else if (chng.table == "runs") { run_id = chng.id; + auto *m = m_runsModel; + for (auto i=0; irowCount(); ++i) { + if (m->table().row(i).value("runs.id").toInt() == chng.id) { + row = i; + break; + } + } } if (run_id.has_value()) { - ui->tblRuns->rowExternallySaved(run_id.value()); + if (chng.op == Event::services::qx::QxRecOp::Update) { + for (const auto &[k, v] : chng.record.toMap().asKeyValueRange()) { + m_runsModel->setValue(row, k, v); + m_runsModel->setDirty(row, k, false); + } + } else { + ui->tblRuns->rowExternallySaved(run_id.value()); + } } } From 46e5ff01866497ca18cbf935e890f133d3d02135 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 17 Nov 2025 22:05:33 +0100 Subject: [PATCH 10/83] Recchng is emitted on SqlTableModel::postRow --- .../libqfcore/include/qf/core/sql/qxrecchng.h | 1 + libqf/libqfcore/src/sql/qxrecchng.h | 17 +++++ libqf/libqfgui/src/model/sqldatadocument.h | 8 +- libqf/libqfgui/src/model/sqltablemodel.cpp | 73 ++++++++++++------- libqf/libqfgui/src/model/sqltablemodel.h | 14 ++-- quickevent/app/quickevent/CMakeLists.txt | 5 +- .../Competitors/src/competitordocument.h | 8 +- .../Event/src/services/qx/qxeventservice.cpp | 10 +-- .../Event/src/services/qx/qxeventservice.h | 5 +- .../Event/src/services/qx/sqlapinode.cpp | 18 ++--- .../plugins/Runs/src/runsplugin.cpp | 2 +- .../plugins/Runs/src/runstablemodel.cpp | 10 ++- .../plugins/Runs/src/runstablemodel.h | 6 +- .../plugins/Runs/src/runstablewidget.cpp | 29 +++++--- .../plugins/Runs/src/runstablewidget.h | 4 +- .../Event/src/services => src}/qx/sqlapi.cpp | 64 +++++++++++----- .../Event/src/services => src}/qx/sqlapi.h | 23 ++---- .../app/quickevent/src/qx/sqldatadocument.cpp | 17 +++++ .../app/quickevent/src/qx/sqldatadocument.h | 21 ++++++ .../app/quickevent/src/qx/sqltablemodel.cpp | 13 ++++ .../app/quickevent/src/qx/sqltablemodel.h | 17 +++++ 21 files changed, 252 insertions(+), 113 deletions(-) create mode 100644 libqf/libqfcore/include/qf/core/sql/qxrecchng.h create mode 100644 libqf/libqfcore/src/sql/qxrecchng.h rename quickevent/app/quickevent/{plugins/Event/src/services => src}/qx/sqlapi.cpp (86%) rename quickevent/app/quickevent/{plugins/Event/src/services => src}/qx/sqlapi.h (85%) create mode 100644 quickevent/app/quickevent/src/qx/sqldatadocument.cpp create mode 100644 quickevent/app/quickevent/src/qx/sqldatadocument.h create mode 100644 quickevent/app/quickevent/src/qx/sqltablemodel.cpp create mode 100644 quickevent/app/quickevent/src/qx/sqltablemodel.h diff --git a/libqf/libqfcore/include/qf/core/sql/qxrecchng.h b/libqf/libqfcore/include/qf/core/sql/qxrecchng.h new file mode 100644 index 000000000..7f444660c --- /dev/null +++ b/libqf/libqfcore/include/qf/core/sql/qxrecchng.h @@ -0,0 +1 @@ +#include "../../../../src/sql/qxrecchng.h" diff --git a/libqf/libqfcore/src/sql/qxrecchng.h b/libqf/libqfcore/src/sql/qxrecchng.h new file mode 100644 index 000000000..5ec42a70e --- /dev/null +++ b/libqf/libqfcore/src/sql/qxrecchng.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../core/coreglobal.h" + +namespace qf::core::sql { + +enum class QxRecOp { Insert, Update, Delete, }; + +struct QFCORE_DECL_EXPORT QxRecChng +{ + QString table; + int64_t id; + QVariant record; + QxRecOp op; +}; + +} diff --git a/libqf/libqfgui/src/model/sqldatadocument.h b/libqf/libqfgui/src/model/sqldatadocument.h index ee56ac5b5..2a2b755e1 100644 --- a/libqf/libqfgui/src/model/sqldatadocument.h +++ b/libqf/libqfgui/src/model/sqldatadocument.h @@ -3,9 +3,7 @@ #include "datadocument.h" #include "sqltablemodel.h" -namespace qf { -namespace gui { -namespace model { +namespace qf::gui::model { class QFGUI_DECL_EXPORT SqlDataDocument : public DataDocument { @@ -21,7 +19,7 @@ class QFGUI_DECL_EXPORT SqlDataDocument : public DataDocument qf::core::sql::QueryBuilder queryBuilder(); void setQueryBuilder(const qf::core::sql::QueryBuilder &qb); protected: - SqlTableModel* createModel(QObject *parent) Q_DECL_OVERRIDE; + SqlTableModel* createModel(QObject *parent) override; ///! load model persistent storage via model bool loadData() Q_DECL_OVERRIDE; @@ -35,5 +33,5 @@ class QFGUI_DECL_EXPORT SqlDataDocument : public DataDocument */ }; -}}} +} diff --git a/libqf/libqfgui/src/model/sqltablemodel.cpp b/libqf/libqfgui/src/model/sqltablemodel.cpp index 11075a550..a12705623 100644 --- a/libqf/libqfgui/src/model/sqltablemodel.cpp +++ b/libqf/libqfgui/src/model/sqltablemodel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -150,8 +151,7 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) int serial_ix = -1; bool serial_ix_explicitly_set = false; int primary_ix = -1; - //QSqlIndex pri_ix = ti.primaryIndex(); - //bool has_blob_field = false; + QVariantMap qx_record; Q_FOREACH(const qf::core::utils::Table::Field &fld, row_ref.fields()) { i++; if(fld.tableId() != table_id) @@ -186,6 +186,7 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) new_fld.setValue(v); //qfInfo() << "\t\t" << "val is QString:" << (v.metaType().id() == QMetaType::QString); rec.append(new_fld); + qx_record[fld.shortName().toLower()] = v; } } @@ -201,40 +202,23 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) } else { qs = sqldrv->sqlStatement(QSqlDriver::InsertStatement, table, rec, false); - //qs = fixSerialDefaultValue(qs, serial_ix, rec); } - if(qs.isEmpty()) + if(qs.isEmpty()) { continue; - /* - qfDebug() << "\texecuting prepared query:" << qs; - bool ok = q.prepare(qs); - if(!ok) { - qfError() << "Cannot prepare query:" << qs; } - else { - for(int i=0; i= 0 && !serial_ix_explicitly_set) { - QVariant v = q.lastInsertId(); - qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << v; - if(v.isValid()) { - row_ref.setValue(serial_ix, v); + qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << insert_id; + if(insert_id.isValid()) { + row_ref.setValue(serial_ix, insert_id); row_ref.setDirty(serial_ix, false); } else { @@ -251,6 +235,15 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) qfDebug() << "\tsetting value of foreign key" << slave_key << "to value of master key:" << row_ref.value(master_key).toString(); row_ref.setValue(slave_key, row_ref.value(master_key)); } + if (!qx_record.isEmpty() && master_key == "id") { + qf::core::sql::QxRecChng chng { + .table = table_id, + .id = insert_id.toInt(), + .record = qx_record, + .op = qf::core::sql::QxRecOp::Insert, + }; + emit qxRecChng(chng); + } } } else { @@ -268,7 +261,7 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) QSqlDriver *sqldrv = sql_conn.driver(); Q_FOREACH(QString table_id, tableIds(m_table.fields())) { qfDebug() << "\ttableid:" << table_id; - //table = conn.fullTableNameToQtDriverTableName(table); + QVariantMap qx_record; QSqlRecord edit_rec; int i = -1; Q_FOREACH(qfu::Table::Field fld, row_ref.fields()) { @@ -286,12 +279,13 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) //qfDebug() << "\ttableid:" << tableid << "fullTableName:" << fld.fullTableName(); qfDebug() << "\tdirty field" << fld.name() << "type:" << fld.type().id() << "orig val:" << row_ref.origValue(i).toString() << "new val:" << v.toString(); //qfDebug().noSpace() << "\tdirty value: '" << v.toString() << "' isNull(): " << v.isNull() << " type(): " << v.type(); - QSqlField sqlfld(fld.shortName(), fld.type()); + QSqlField sqlfld(fld.shortName().toLower(), fld.type()); sqlfld.setValue(v); //if(sqlfld.type() == QVariant::ByteArray) // has_blob_field = true; qfDebug() << "\tfield is null: " << sqlfld.isNull(); edit_rec.append(sqlfld); + qx_record[fld.shortName()] = v; } if(!edit_rec.isEmpty()) { qfDebug() << "updating table edits:" << table_id; @@ -300,7 +294,9 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) query_str += " "; QSqlRecord where_rec; qfDebug() << "looking for primary index of table:" << table_id; - Q_FOREACH(auto fld_name, sql_conn.primaryIndexFieldNames(table_id)) { + std::optional id_pri_key_value; + auto pri_keys = sql_conn.primaryIndexFieldNames(table_id); + for (const auto &fld_name : pri_keys) { QString full_fld_name = table_id + '.' + fld_name; qfDebug() << "\t checking value of field:" << full_fld_name; int fld_ix = m_table.fields().fieldIndex(full_fld_name); @@ -313,6 +309,9 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) sqlfld.setValue(row_ref.origValue(fld_ix)); qfDebug() << "\tpri index field" << full_fld_name << "type:" << sqlfld.metaType().id() << "orig val:" << row_ref.origValue(fld_ix) << "current val:" << row_ref.value(fld_ix); where_rec.append(sqlfld); + if (auto id = sqlfld.value().toInt(); id > 0) { + id_pri_key_value = id; + } } QF_ASSERT(!where_rec.isEmpty(), QString("pri keys values not generated for table '%1'").arg(table_id), @@ -335,6 +334,15 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) ret = false; break; } + if (!qx_record.isEmpty() && pri_keys.size() == 1 && pri_keys[0] == "id" && id_pri_key_value.has_value()) { + qf::core::sql::QxRecChng chng { + .table = table_id, + .id = id_pri_key_value.value(), + .record = qx_record, + .op = qf::core::sql::QxRecOp::Update, + }; + emit qxRecChng(chng); + } } } } @@ -437,6 +445,17 @@ bool SqlTableModel::removeTableRow(int row_no, bool throw_exc) ret = false; break; } + if (where_rec.count() == 1 && where_rec.field(0).name() == "id") { + if (auto id = where_rec.field(0).value().toInt(); id < 0) { + qf::core::sql::QxRecChng chng { + .table = table_id, + .id = id, + .record = {}, + .op = qf::core::sql::QxRecOp::Delete, + }; + emit qxRecChng(chng); + } + } } } if(ret) { diff --git a/libqf/libqfgui/src/model/sqltablemodel.h b/libqf/libqfgui/src/model/sqltablemodel.h index 95a2cbebd..e055385f6 100644 --- a/libqf/libqfgui/src/model/sqltablemodel.h +++ b/libqf/libqfgui/src/model/sqltablemodel.h @@ -10,12 +10,10 @@ #include #include -namespace qf { -namespace gui { -namespace sql { -class Connection; -} -namespace model { +namespace qf::core::sql { struct QxRecChng; } +namespace qf::gui::sql { class Connection; } + +namespace qf::gui::model { class QFGUI_DECL_EXPORT SqlTableModel : public TableModel { @@ -51,6 +49,8 @@ class QFGUI_DECL_EXPORT SqlTableModel : public TableModel int reloadRow(int row_no) Q_DECL_OVERRIDE; int reloadInserts(const QString &id_column_name) Q_DECL_OVERRIDE; QString reloadRowQuery(const QVariant &record_id); + + Q_SIGNAL void qxRecChng(const qf::core::sql::QxRecChng &recchng); public: void setQueryBuilder(const qf::core::sql::QueryBuilder &qb, bool clear_columns = false); const qf::core::sql::QueryBuilder& queryBuilder() const; @@ -100,5 +100,5 @@ class QFGUI_DECL_EXPORT SqlTableModel : public TableModel QMap m_foreignKeyDependencies; }; -}}} +} diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index b7c6e2e75..989371c71 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -90,7 +90,6 @@ add_executable(quickevent plugins/Event/src/services/servicewidget.cpp plugins/Event/src/services/servicewidget.ui - plugins/Event/src/services/qx/sqlapi.h plugins/Event/src/services/qx/sqlapi.cpp plugins/Event/src/services/qx/qxnode.cpp plugins/Event/src/services/qx/sqlapinode.cpp plugins/Event/src/services/qx/nodes.cpp @@ -174,6 +173,10 @@ add_executable(quickevent plugins/Runs/Runs.qrc plugins/CardReader/CardReader.qrc + src/qx/sqlapi.cpp src/qx/sqlapi.h + src/qx/sqltablemodel.h src/qx/sqltablemodel.cpp + src/qx/sqldatadocument.h src/qx/sqldatadocument.cpp + src/appclioptions.cpp src/application.cpp src/loggerwidget.cpp diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h index a394edbe4..ebca84986 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h @@ -1,24 +1,22 @@ #ifndef COMPETITORS_COMPETITORDOCUMENT_H #define COMPETITORS_COMPETITORDOCUMENT_H -#include +#include "src/qx/sqldatadocument.h" #include namespace Competitors { -class CompetitorDocument : public qf::gui::model::SqlDataDocument +class CompetitorDocument : public qx::SqlDataDocument { Q_OBJECT private: - typedef qf::gui::model::SqlDataDocument Super; + typedef qx::SqlDataDocument Super; public: CompetitorDocument(QObject *parent = nullptr); - //bool isSaveSiidToRuns() const {return m_saveSiidToRuns;} void setEmitDbEventsOnSave(bool b) {m_isEmitDbEventsOnSave = b;} - //void setSiid(const QVariant &siid, bool save_siid_to_runs); void setSiid(const QVariant &siid); QVariant siid() const; const QVector& runsIds() const {return m_runsIds;} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 320548969..1b8b1d7ec 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -2,7 +2,7 @@ #include "qxeventservicewidget.h" #include "nodes.h" #include "sqlapinode.h" -#include "sqlapi.h" +#include "src/qx/sqlapi.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -78,7 +78,7 @@ void QxEventService::run() { m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); RpcValue::Map opts; RpcValue::Map device; - device["mountPoint"] = "test/quickevent"; + device["mountPoint"] = "test/qx/event/1"; opts["device"] = device; m_rpcConnection->setConnectionOptions(opts); @@ -87,7 +87,7 @@ void QxEventService::run() { connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxEventService::onBrokerLoginError); connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxEventService::onRpcMessageReceived); - connect(SqlApi::instance(), &SqlApi::recchng, this, &QxEventService::onRecchg); + connect(::qx::SqlApi::instance(), &::qx::SqlApi::recchng, this, &QxEventService::sendRecchgShvSignal); m_rpcConnection->open(); } @@ -638,10 +638,10 @@ void QxEventService::subscribeChanges() rpc_call->start(); } -void QxEventService::onRecchg(const QxRecChng &chng) +void QxEventService::sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng) { if (isRunning()) { - m_rpcConnection->sendShvSignal("sql", "recchng", chng.toRpcValue()); + m_rpcConnection->sendShvSignal("sql", "recchng", ::qx::qxRecChngToRpcValue(chng)); } } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index b25076626..2b5e2e1de 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -10,11 +10,10 @@ class QTimer; namespace shv::iotqt::node { class ShvNodeTree; class ShvRootNode; } namespace shv::iotqt::rpc { class DeviceConnection; } namespace shv::chainpack { class RpcMessage; class RpcError; } +namespace qf::core::sql { struct QxRecChng; } namespace Event::services::qx { -struct QxRecChng; - class QxEventServiceSettings : public ServiceSettings { using Super = ServiceSettings; @@ -80,7 +79,7 @@ class QxEventService : public Service void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg); void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); - void onRecchg(const QxRecChng &chng); + void sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng); void subscribeChanges(); private: diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index d12474363..bbeeb3b08 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -1,5 +1,5 @@ #include "sqlapinode.h" -#include "sqlapi.h" +#include "src/qx/sqlapi.h" #include #include @@ -58,17 +58,17 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); if(shv_path.empty()) { if(method == METH_EXEC) { - auto res = SqlApi::exec(SqlQueryAndParams::fromRpcValue(params)); + auto res = ::qx::SqlApi::exec(::qx::SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_QUERY) { - auto res = SqlApi::exec(SqlQueryAndParams::fromRpcValue(params)); + auto res = ::qx::SqlApi::exec(::qx::SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_TRANSACTION) { auto sql_query = params.asList().valref(0).asString(); const auto &sql_params = params.asList().valref(0); - SqlApi::transaction(sql_query, sql_params.asList()); + ::qx::SqlApi::transaction(sql_query, sql_params.asList()); return RpcValue(nullptr); } if(method == METH_LIST) { @@ -80,14 +80,14 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin } auto ids_above = map.contains("ids_above")? std::optional(map.value("ids_above").toInt64()): std::optional(); auto limit = map.contains("limit")? std::optional(map.value("limit").toInt64()): std::optional(); - auto res = SqlApi::list(table, fields, ids_above, limit); + auto res = ::qx::SqlApi::list(table, fields, ids_above, limit); return res.toRecordList(); } if(method == METH_CREATE) { const auto &map = params.asMap(); const auto &table = map.value("table").asString(); const auto &record = map.valref("record").asMap(); - auto res = SqlApi::create(table, record); + auto res = ::qx::SqlApi::create(table, record); return res; } if(method == METH_READ) { @@ -98,7 +98,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin for (const auto &fn : map.valref("fields").asList()) { fields.push_back(fn.asString()); } - auto res = SqlApi::read(table, id, fields); + auto res = ::qx::SqlApi::read(table, id, fields); if (res.has_value()) { return res.value(); } @@ -109,14 +109,14 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin const auto &table = map.value("table").asString(); auto id = map.value("id").toInt64(); const auto &record = map.valref("record").asMap(); - auto res = SqlApi::update(table, id, record); + auto res = ::qx::SqlApi::update(table, id, record); return res; } if(method == METH_DELETE) { const auto &map = params.asMap(); const auto &table = map.value("table").asString(); auto id = map.valref("id").toInt(); - auto res = SqlApi::drop(table, id); + auto res = ::qx::SqlApi::drop(table, id); return res; } } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index da276191f..6163682c3 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -1300,7 +1300,7 @@ qf::core::sql::QueryBuilder RunsPlugin::runsQuery(int stage_id, int class_id, bo qfs::QueryBuilder qb; qb.select2("runs", "*") .select2("classes", "name") - .select2("competitors", "id, iofId, registration, licence, ranking, siId, note") + .select2("competitors", "id, firstName, lastName, iofId, registration, licence, ranking, siId, note") .select("COALESCE(lastName, '') || ' ' || COALESCE(firstName, '') AS competitorName") .select("lentcards.siid IS NOT NULL AS cardInLentTable") diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index fe183294e..5f2dfccda 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -1,8 +1,10 @@ #include "runstablemodel.h" +#include "../../Event/src/eventplugin.h" +#include "src/qx/sqlapi.h" + #include #include -#include "../../Event/src/eventplugin.h" #include #include @@ -81,6 +83,12 @@ QVariant RunsTableModel::data(const QModelIndex &index, int role) const QVariant RunsTableModel::value(int row_ix, int column_ix) const { + if(column_ix == col_competitorName) { + qf::core::utils::TableRow row = tableRow(row_ix); + auto first_name = row.value(QStringLiteral("firstName")).toString(); + auto last_name = row.value(QStringLiteral("lastName")).toString(); + return last_name + ' ' + first_name; + } if(column_ix == col_runFlags) { qf::core::utils::TableRow row = tableRow(row_ix); bool mis_punch = row.value(QStringLiteral("runs.misPunch")).toBool(); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h index 9379bfebd..94b1ca389 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h @@ -1,13 +1,13 @@ #ifndef RUNSTABLEMODEL_H #define RUNSTABLEMODEL_H -#include +#include "src/qx/sqltablemodel.h" -class RunsTableModel : public quickevent::gui::og::SqlTableModel +class RunsTableModel : public ::qx::SqlTableModel { Q_OBJECT private: - using Super = quickevent::gui::og::SqlTableModel; + using Super = ::qx::SqlTableModel; public: enum Columns { col_runs_isRunning = 0, diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 0011c3190..fd3ad352d 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -7,10 +7,14 @@ #include "runflagsdialog.h" #include "cardflagsdialog.h" +#include "src/qx/sqlapi.h" + #include -#include #include #include +#include +#include +#include #include #include @@ -20,11 +24,7 @@ #include #include -#include -#include -#include -#include -#include +#include #include #include @@ -137,7 +137,7 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : } }, Qt::QueuedConnection); - connect(Event::services::qx::SqlApi::instance(), &Event::services::qx::SqlApi::recchng, this, &RunsTableWidget::onQxRecChng); + connect(::qx::SqlApi::instance(), &::qx::SqlApi::recchng, this, &RunsTableWidget::onQxRecChng); } RunsTableWidget::~RunsTableWidget() @@ -439,7 +439,7 @@ void RunsTableWidget::onBadTableDataInput(const QString &message) qf::gui::dialogs::MessageBox::showError(this, message); } -void RunsTableWidget::onQxRecChng(const Event::services::qx::QxRecChng &chng) +void RunsTableWidget::onQxRecChng(const qf::core::sql::QxRecChng &chng) { std::optional run_id; int row = 0; @@ -464,10 +464,17 @@ void RunsTableWidget::onQxRecChng(const Event::services::qx::QxRecChng &chng) } } if (run_id.has_value()) { - if (chng.op == Event::services::qx::QxRecOp::Update) { + if (chng.op == qf::core::sql::QxRecOp::Update) { for (const auto &[k, v] : chng.record.toMap().asKeyValueRange()) { - m_runsModel->setValue(row, k, v); - m_runsModel->setDirty(row, k, false); + if (k == "firstname" || k == "lastname") { + auto &r = m_runsModel->tableRowRef(row); + r.setValue("competitors." + k, v); + auto ix = m_runsModel->index(row, RunsTableModel::col_competitorName); + m_runsModel->dataChanged(ix, ix); + } else { + m_runsModel->setValue(row, k, v); + m_runsModel->setDirty(row, k, false); + } } } else { ui->tblRuns->rowExternallySaved(run_id.value()); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h index a5379f689..d7ed07e6e 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h @@ -7,7 +7,7 @@ class RunsTableItemDelegate; class CourseItemDelegate; namespace qf::gui { class TableView; } -namespace Event::services::qx { struct QxRecChng; } +namespace qf::core::sql { struct QxRecChng; } namespace Ui { class RunsTableWidget; @@ -38,7 +38,7 @@ class RunsTableWidget : public QWidget void onTableViewSqlException(const QString &what, const QString &where, const QString &stack_trace); void onBadTableDataInput(const QString &message); - void onQxRecChng(const Event::services::qx::QxRecChng &chng); + void onQxRecChng(const qf::core::sql::QxRecChng &chng); private: Ui::RunsTableWidget *ui; RunsTableModel *m_runsModel; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp b/quickevent/app/quickevent/src/qx/sqlapi.cpp similarity index 86% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp rename to quickevent/app/quickevent/src/qx/sqlapi.cpp index 2c58823bf..2fd65b9d8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/src/qx/sqlapi.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -16,7 +17,7 @@ using namespace shv::chainpack; -namespace Event::services::qx { +namespace qx { //============================================== // RpcSqlField @@ -146,21 +147,22 @@ SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue return SqlQueryAndParams { .query = sql_query, .params = sql_params.asMap() }; } -RpcValue QxRecChng::toRpcValue() const + +RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng) { RpcValue::Map ret; - ret["table"] = table.toStdString(); - ret["id"] = id; - ret["record"] = shv::coreqt::rpc::qVariantToRpcValue(record); - auto rec_op_string = [](QxRecOp op) { + ret["table"] = chng.table.toStdString(); + ret["id"] = chng.id; + ret["record"] = shv::coreqt::rpc::qVariantToRpcValue(chng.record); + auto rec_op_string = [](qf::core::sql::QxRecOp op) { switch (op) { - case QxRecOp::Insert: return "Insert"; - case QxRecOp::Update: return "Update"; - case QxRecOp::Delete: return "Delete"; + case qf::core::sql::QxRecOp::Insert: return "Insert"; + case qf::core::sql::QxRecOp::Update: return "Update"; + case qf::core::sql::QxRecOp::Delete: return "Delete"; } return ""; }; - ret["op"] = rec_op_string(op); + ret["op"] = rec_op_string(chng.op); return ret; } @@ -179,6 +181,12 @@ SqlApi *SqlApi::instance() return api; } +void SqlApi::emitRecChng(const qf::core::sql::QxRecChng &chng) +{ + qfInfo() << "REC_CHNG:" << qxRecChngToRpcValue(chng).toCpon(); + emit recchng(chng); +} + namespace { class Transaction @@ -303,7 +311,27 @@ RpcSqlResult SqlApi::list(const std::string &table, const std::vectorrecchng(QxRecChng { + SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { .table = QString::fromStdString(table), .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(record), - .op = QxRecOp::Insert + .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)), + .op = qf::core::sql::QxRecOp::Insert }); return id; } @@ -374,11 +402,11 @@ bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &recor q.exec(qf::core::Exception::Throw); bool updated = q.numRowsAffected() == 1; if (updated) { - emit SqlApi::instance()->recchng(QxRecChng { + SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { .table = QString::fromStdString(table), .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(record), - .op = QxRecOp::Update + .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)), + .op = qf::core::sql::QxRecOp::Update }); } return updated; @@ -393,11 +421,11 @@ bool SqlApi::drop(const std::string &table, int64_t id) q.exec(sql_query, qf::core::Exception::Throw); bool is_drop = q.numRowsAffected() == 1; if (is_drop) { - emit SqlApi::instance()->recchng(QxRecChng { + SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { .table = QString::fromStdString(table), .id = id, .record = {}, - .op = QxRecOp::Delete + .op = qf::core::sql::QxRecOp::Delete }); } return is_drop; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h b/quickevent/app/quickevent/src/qx/sqlapi.h similarity index 85% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h rename to quickevent/app/quickevent/src/qx/sqlapi.h index b8a8f64b9..80bee09b2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h +++ b/quickevent/app/quickevent/src/qx/sqlapi.h @@ -1,11 +1,15 @@ #pragma once #include +// #include +#include #include #include -namespace Event::services::qx { +namespace qf::core::sql { struct QxRecChng; } + +namespace qx { struct RpcSqlField { @@ -27,7 +31,6 @@ struct RpcSqlResult std::vector rows; RpcSqlResult() = default; - // explicit RpcSqlResult(const QSqlQuery &q); std::optional columnIndex(const std::string &name) const; const shv::chainpack::RpcValue& value(size_t row, size_t col) const; @@ -38,8 +41,6 @@ struct RpcSqlResult bool isSelect() const {return !fields.empty();} shv::chainpack::RpcValue toRpcValue() const; shv::chainpack::RpcValue::List toRecordList() const; - // QVariant toVariant() const; - // static RpcSqlResult fromVariant(const QVariant &v); static RpcSqlResult fromRpcValue(const shv::chainpack::RpcValue &rv); }; @@ -53,17 +54,8 @@ struct SqlQueryAndParams static SqlQueryAndParams fromRpcValue(const shv::chainpack::RpcValue &rv); }; -enum class QxRecOp { Insert, Update, Delete, }; - -struct QxRecChng -{ - QString table; - int64_t id; - QVariant record; - QxRecOp op; +shv::chainpack::RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng); - shv::chainpack::RpcValue toRpcValue() const; -}; class SqlApi : public QObject { @@ -71,7 +63,8 @@ class SqlApi : public QObject public: static SqlApi* instance(); - Q_SIGNAL void recchng(const QxRecChng &chng); + Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); + void emitRecChng(const qf::core::sql::QxRecChng &chng); static RpcSqlResult exec(const SqlQueryAndParams ¶ms); static RpcSqlResult query(const SqlQueryAndParams ¶ms); diff --git a/quickevent/app/quickevent/src/qx/sqldatadocument.cpp b/quickevent/app/quickevent/src/qx/sqldatadocument.cpp new file mode 100644 index 000000000..1f7040921 --- /dev/null +++ b/quickevent/app/quickevent/src/qx/sqldatadocument.cpp @@ -0,0 +1,17 @@ +#include "sqldatadocument.h" + + +namespace qx { + +SqlDataDocument::SqlDataDocument(QObject *parent) + : Super{parent} +{ + +} + +SqlTableModel *SqlDataDocument::createModel(QObject *parent) +{ + return new ::qx::SqlTableModel(parent); +} + +} // namespace qx diff --git a/quickevent/app/quickevent/src/qx/sqldatadocument.h b/quickevent/app/quickevent/src/qx/sqldatadocument.h new file mode 100644 index 000000000..cea298076 --- /dev/null +++ b/quickevent/app/quickevent/src/qx/sqldatadocument.h @@ -0,0 +1,21 @@ +#pragma once + +#include "sqltablemodel.h" + +#include + +namespace qx { + +class SqlDataDocument : public qf::gui::model::SqlDataDocument +{ + Q_OBJECT + + using Super = qf::gui::model::SqlDataDocument; +public: + explicit SqlDataDocument(QObject *parent = nullptr); +protected: + ::qx::SqlTableModel* createModel(QObject *parent) override; +}; + +} // namespace qx + diff --git a/quickevent/app/quickevent/src/qx/sqltablemodel.cpp b/quickevent/app/quickevent/src/qx/sqltablemodel.cpp new file mode 100644 index 000000000..0bad5b1fc --- /dev/null +++ b/quickevent/app/quickevent/src/qx/sqltablemodel.cpp @@ -0,0 +1,13 @@ +#include "sqltablemodel.h" +#include "sqlapi.h" + +namespace qx { + +SqlTableModel::SqlTableModel(QObject *parent) + : Super{parent} +{ + auto *sql_api = SqlApi::instance(); + connect(this, &qf::gui::model::SqlTableModel::qxRecChng, sql_api, &SqlApi::emitRecChng); +} + +} // namespace qx diff --git a/quickevent/app/quickevent/src/qx/sqltablemodel.h b/quickevent/app/quickevent/src/qx/sqltablemodel.h new file mode 100644 index 000000000..1581be19e --- /dev/null +++ b/quickevent/app/quickevent/src/qx/sqltablemodel.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace qx { + +class SqlTableModel : public quickevent::gui::og::SqlTableModel +{ + Q_OBJECT + + using Super = quickevent::gui::og::SqlTableModel; +public: + explicit SqlTableModel(QObject *parent = nullptr); +}; + +} // namespace qx + From 3581d8a42eb6ce42212f758e843500eaa74b5f47 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 23 Nov 2025 14:17:39 +0100 Subject: [PATCH 11/83] Fix CardReader model id column name --- .../app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 9fd066be2..f9a6a90fa 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -112,6 +112,7 @@ class Model : public quickevent::gui::og::SqlTableModel Model::Model(QObject *parent) : Super(parent) { + setIdColumnName("cards.id"); clearColumns(col_COUNT); setColumn(col_cards_id, ColumnDefinition("cards.id", "id").setReadOnly(true)); setColumn(col_cards_siId, ColumnDefinition("cards.siId", tr("SI")).setReadOnly(true).setCastType(qMetaTypeId())); From e780bf8d2604700cce6291302548c4ae95dd7d4b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 30 Nov 2025 20:36:51 +0100 Subject: [PATCH 12/83] Change default SHV mount point --- .../quickevent/plugins/Event/src/services/qx/qxeventservice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 1b8b1d7ec..e098be777 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -78,7 +78,7 @@ void QxEventService::run() { m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); RpcValue::Map opts; RpcValue::Map device; - device["mountPoint"] = "test/qx/event/1"; + device["mountPoint"] = "test/hsh2025"; opts["device"] = device; m_rpcConnection->setConnectionOptions(opts); From 7904e27dc8819fffbde4cd4b7fbabcdd1040a9a2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 19 Dec 2025 11:09:53 +0100 Subject: [PATCH 13/83] Enable QF_WITH_LIBSHV option in CMake action --- .github/actions/cmake/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/cmake/action.yml b/.github/actions/cmake/action.yml index 4ff81aa9e..ac208298e 100644 --- a/.github/actions/cmake/action.yml +++ b/.github/actions/cmake/action.yml @@ -66,6 +66,7 @@ runs: -B '${{github.workspace}}/build' \ -DCMAKE_BUILD_TYPE=Release \ -DQF_BUILD_QML_PLUGINS=ON \ + -DQF_WITH_LIBSHV=ON \ -DBUILD_TESTING=OFF \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DUSE_QT6=${{ inputs.use_qt6 }} \ From c91655c22a2a6882905b46335225b6501c31d722 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 24 Dec 2025 00:08:01 +0100 Subject: [PATCH 14/83] Make service status text expandable --- .../plugins/Event/src/services/qx/qxeventservice.cpp | 2 ++ .../app/quickevent/plugins/Event/src/services/servicewidget.ui | 3 +++ 2 files changed, 5 insertions(+) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index e098be777..de1c055b2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -584,11 +584,13 @@ void QxEventService::onBrokerConnectedChanged(bool is_connected) void QxEventService::onBrokerSocketError(const QString &err) { + qfWarning() << "onBrokerSocketError:" << err; setStatusMessage(tr("Broker socket error: %1").arg(err)); } void QxEventService::onBrokerLoginError(const shv::chainpack::RpcError &err) { + qfWarning() << "onBrokerLoginError:" << err.toString(); setStatusMessage(tr("Broker login error: %1").arg(err.toString())); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.ui index cdff60fa1..510d437a7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/servicewidget.ui @@ -87,6 +87,9 @@ neco neco + + true + From 603522be6eb7a0db2b0c18dcec2d0b72f82f822f Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 30 Jan 2026 23:51:09 +0100 Subject: [PATCH 15/83] Rebased on multi-course --- .clang-tidy | 2 +- 3rdparty/libshv | 2 +- .../quickevent/plugins/Classes/src/classeswidget.cpp | 10 +++++++--- .../plugins/Event/src/services/qx/qxeventservice.cpp | 2 +- .../Event/src/services/qx/qxeventservicewidget.cpp | 2 +- .../quickevent/plugins/Runs/src/runstablewidget.cpp | 1 - 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 64c3c28fa..543d5ca53 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,7 +40,7 @@ Checks: -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-special-member-functions, - -cppcoreguidelines-use-enum-class + -cppcoreguidelines-use-enum-class, -hicpp-avoid-c-arrays, -hicpp-avoid-goto, -hicpp-braces-around-statements, diff --git a/3rdparty/libshv b/3rdparty/libshv index f108e5d72..f77c05674 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit f108e5d72729c16ee5b27ee8a9096182a5ceb7fa +Subproject commit f77c05674413e5bd5a1a98c894385e89805406d0 diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index 8da479d89..c4750dadc 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -390,7 +390,8 @@ void ClassesWidget::importCourses(const QList &course_defs, con reload(); } -static QString normalize_course_name(const QString &course_name) +namespace { +QString normalize_course_name(const QString &course_name) { QString ret = qf::core::Collator::toAscii7(QLocale::Czech, course_name, false); ret.replace(' ', QString()); @@ -400,6 +401,7 @@ static QString normalize_course_name(const QString &course_name) ret.replace('-', '+'); return ret; } +} void ClassesWidget::import_ocad_txt() { @@ -566,7 +568,8 @@ void ClassesWidget::import_ocad_v8() } } -static QString element_text(const QDomElement &parent, const QString &tag_name) +namespace { +QString element_text(const QDomElement &parent, const QString &tag_name) { QDomElement el = parent.firstChildElement(tag_name); if(el.isNull()) @@ -574,13 +577,14 @@ static QString element_text(const QDomElement &parent, const QString &tag_name) return el.text(); } -static QString dump_element(const QDomElement &el) +QString dump_element(const QDomElement &el) { QString ret; QTextStream s(&ret); el.save(s, QDomNode::EncodingFromDocument); return ret; } +} void ClassesWidget::import_ocad_iofxml_2() { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index de1c055b2..e691cd9b8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -74,7 +74,7 @@ void QxEventService::run() { auto ss = settings(); delete m_rpcConnection; - m_rpcConnection = new DeviceConnection(this); + m_rpcConnection = new DeviceConnection("QuickEvent", this); m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); RpcValue::Map opts; RpcValue::Map device; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 125d70f16..4d0e0bcbb 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -119,7 +119,7 @@ void QxEventServiceWidget::testConnection() using namespace shv::iotqt::rpc; using namespace shv::chainpack; - auto *rpc = new DeviceConnection(this); + auto *rpc = new DeviceConnection("QuickEventTest", this); rpc->setConnectionString(ui->edServerUrl->text()); connect(rpc, &ClientConnection::brokerConnectedChanged, this, [this, rpc](bool is_connected) { diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index fd3ad352d..217182124 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include From d542aaaf6248975cbe272de52bdeaf59745c1dea Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 2 Feb 2026 14:49:36 +0100 Subject: [PATCH 16/83] Update CI linter ubuntu version --- .github/workflows/lint.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d41591f4c..312183ca7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,8 +8,8 @@ on: jobs: clang-tidy: - name: clang-tidy / Ubuntu 22.04 - runs-on: ubuntu-22.04 + name: clang-tidy / Ubuntu 24.04 + runs-on: ubuntu-24.04 env: CC: clang CXX: clang++ @@ -26,8 +26,8 @@ jobs: exclude_files_pattern: ^quickevent/app/quickevent/plugins/Receipts/src/thirdparty/qrcodegen\.cpp$ clazy: - name: clazy / Ubuntu 22.04 - runs-on: ubuntu-22.04 + name: clazy / Ubuntu 24.04 + runs-on: ubuntu-24.04 env: CC: clang CXX: clang++ From 74aa2d0ca818083e6210a1d81cfb3d882fb42ae4 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 2 Feb 2026 14:50:26 +0100 Subject: [PATCH 17/83] Fix QxService login procedure --- .../Event/src/services/qx/qxeventservice.cpp | 48 ++++++++++++++----- .../Event/src/services/qx/qxeventservice.h | 3 +- .../src/services/qx/qxeventservicewidget.cpp | 35 +++++++++++--- .../Event/src/services/qx/runchangedialog.cpp | 2 +- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index e691cd9b8..24f6bab19 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -74,11 +74,19 @@ void QxEventService::run() { auto ss = settings(); delete m_rpcConnection; + m_eventId = 0; + + auto api_token = apiToken(); + if (api_token.isEmpty()) { + setStatus(Status::Stopped); + setStatusMessage(tr("API token is not set.")); + } + m_rpcConnection = new DeviceConnection("QuickEvent", this); m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); RpcValue::Map opts; RpcValue::Map device; - device["mountPoint"] = "test/hsh2025"; + device["deviceId"] = api_token.toStdString(); opts["device"] = device; m_rpcConnection->setConnectionOptions(opts); @@ -94,6 +102,7 @@ void QxEventService::run() { void QxEventService::stop() { + m_eventId = 0; disconnectSSE(); if (m_pollChangesTimer) { m_pollChangesTimer->stop(); @@ -265,19 +274,19 @@ QNetworkReply* QxEventService::getQxChangesReply(int from_id) int QxEventService::eventId() const { - if (m_eventId == 0) { - throw qf::core::Exception(tr("Event ID is not loaded, service is not probably running.")); - } + // if (m_eventId == 0) { + // throw qf::core::Exception(tr("Event ID is not loaded, service is not probably running.")); + // } return m_eventId; } -QByteArray QxEventService::apiToken() const +QString QxEventService::apiToken() const { - // API token must not be cached to enable service point + // API token must not be cached to enable service to point // always to current stage event on qxhttpd auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - return event_plugin->stageData(current_stage).qxApiToken().toUtf8(); + return event_plugin->stageData(current_stage).qxApiToken(); } QUrl QxEventService::shvBrokerUrl() const @@ -296,7 +305,7 @@ void QxEventService::postFileCompressed(std::optional path, std::option } QNetworkRequest request; request.setUrl(url); - request.setRawHeader(QX_API_TOKEN, apiToken()); + request.setRawHeader(QX_API_TOKEN, apiToken().toUtf8()); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/zip")); auto zdata = zlibCompress(data); QNetworkReply *reply = networkManager()->post(request, zdata); @@ -347,7 +356,7 @@ void QxEventService::httpPostJson(const QString &path, const QString &query, QVa QNetworkRequest request; request.setUrl(url); - request.setRawHeader(QX_API_TOKEN, apiToken()); + request.setRawHeader(QX_API_TOKEN, apiToken().toUtf8()); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json")); auto data = QJsonDocument::fromVariant(json).toJson(QJsonDocument::Compact); qfInfo() << "HTTP POST JSON:" << url.toString() << "data:" << QString::fromUtf8(data); @@ -571,11 +580,24 @@ int QxEventService::currentConnectionId() void QxEventService::onBrokerConnectedChanged(bool is_connected) { if(is_connected) { - setStatus(Status::Running); - QTimer::singleShot(0, this, [this]() { - subscribeChanges(); -// testRpcCall(); + auto *rpc_call = shv::iotqt::rpc::RpcCall::create(m_rpcConnection) + ->setShvPath(".broker/currentClient") + ->setMethod("info"); + connect(rpc_call, &shv::iotqt::rpc::RpcCall::maybeResult, this, [this](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + if (error.isValid()) { + setStatus(Status::Stopped); + setStatusMessage(tr("Client info discovery error: %1").arg(error.toString())); + } + else { + const auto &info = result.asMap(); + m_eventMountPoint = info.value("mountPoint").to(); + m_eventId = m_eventMountPoint.section('/', -1, -1).toInt(); + setStatus(Status::Running); + setStatusMessage(tr("Event ID: %1").arg(m_eventId)); + subscribeChanges(); + } }); + rpc_call->start(); } else { setStatus(Status::Stopped); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 2b5e2e1de..add24852e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -68,7 +68,7 @@ class QxEventService : public Service QNetworkReply* getQxChangesReply(int from_id); - QByteArray apiToken() const; + QString apiToken() const; static int currentConnectionId(); QUrl shvBrokerUrl() const; @@ -105,6 +105,7 @@ class QxEventService : public Service QNetworkAccessManager *m_networkManager = nullptr; QNetworkReply *m_replySSE = nullptr; int m_eventId = 0; + QString m_eventMountPoint; QTimer *m_pollChangesTimer = nullptr; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 4d0e0bcbb..d18cd0e38 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -41,6 +43,7 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) ui->edServerUrl->setText(settings.shvBrokerUrl()); ui->edApiToken->setText(svc->apiToken()); ui->edCurrentStage->setValue(current_stage); + ui->edEventId->setValue(svc->eventId()); connect(ui->btTestConnection, &QAbstractButton::clicked, this, &QxEventServiceWidget::testConnection); connect(ui->btExportEventInfo, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportEventInfo); connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportStartList); @@ -119,21 +122,41 @@ void QxEventServiceWidget::testConnection() using namespace shv::iotqt::rpc; using namespace shv::chainpack; + delete findChild(); + auto *rpc = new DeviceConnection("QuickEventTest", this); rpc->setConnectionString(ui->edServerUrl->text()); + RpcValue::Map opts; + RpcValue::Map device; + device["deviceId"] = ui->edApiToken->text().toStdString(); + opts["device"] = device; + rpc->setConnectionOptions(opts); connect(rpc, &ClientConnection::brokerConnectedChanged, this, [this, rpc](bool is_connected) { if (is_connected) { - rpc->deleteLater(); - setMessage(tr("Connected OK")); + setMessage(tr("Broker connected OK")); + auto *rpc_call = shv::iotqt::rpc::RpcCall::create(rpc) + ->setShvPath(".broker/currentClient") + ->setMethod("info"); + connect(rpc_call, &shv::iotqt::rpc::RpcCall::maybeResult, this, [this](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + if (error.isValid()) { + setMessage(tr("Client info discovery error: %1").arg(error.toString()), MessageType::Error); + } + else { + const auto &info = result.asMap(); + auto mount_point = info.value("mountPoint").to(); + auto event_id = mount_point.section('/', -1, -1).toInt(); + ui->edEventId->setValue(event_id); + setMessage(tr("Event mounted at: %1, event id: %2").arg(mount_point).arg(event_id)); + } + }); + rpc_call->start(); } }); - connect(rpc, &ClientConnection::socketError, this, [this, rpc](const QString &error) { - rpc->deleteLater(); + connect(rpc, &ClientConnection::socketError, this, [this](const QString &error) { setMessage(tr("Connection error: %1").arg(error), MessageType::Error); }); - connect(rpc, &ClientConnection::brokerLoginError, this, [this, rpc](const auto &error) { - rpc->deleteLater(); + connect(rpc, &ClientConnection::brokerLoginError, this, [this](const auto &error) { setMessage(tr("Login error: %1").arg(QString::fromStdString(error.toString())), MessageType::Error); }); rpc->open(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp index 1c16121ce..e2c50edd5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp @@ -220,7 +220,7 @@ void RunChangeDialog::resolveChanges(bool is_accepted) url.setQuery(query); request.setUrl(url); - request.setRawHeader(QxEventService::QX_API_TOKEN, svc->apiToken()); + request.setRawHeader(QxEventService::QX_API_TOKEN, svc->apiToken().toUtf8()); auto *reply = nm->get(request); connect(reply, &QNetworkReply::finished, this, [this, reply]() { if (reply->error() == QNetworkReply::NetworkError::NoError) { From e338eedc4ef95ffdd7aa950f994dfd31b2edb0e0 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 2 Feb 2026 17:13:02 +0100 Subject: [PATCH 18/83] Fix CI linter --- .github/actions/run-linter/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/run-linter/action.yml b/.github/actions/run-linter/action.yml index ec63c078a..0d1ddaf1b 100644 --- a/.github/actions/run-linter/action.yml +++ b/.github/actions/run-linter/action.yml @@ -24,7 +24,7 @@ runs: - uses: mjp41/workaround8649@c8550b715ccdc17f89c8d5c28d7a48eeff9c94a8 if: runner.os == 'Linux' with: - os: ubuntu-latest + os: ubuntu-24.04 - name: Build autogenerated stuff shell: bash From 60c37b41d0a425b124b309b73aba0f8b81aa7e8b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 8 Apr 2026 22:20:22 +0200 Subject: [PATCH 19/83] Rebased to origin/main --- quickevent/app/quickevent/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 989371c71..3aae94906 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -114,10 +114,11 @@ add_executable(quickevent plugins/Receipts/src/receiptssettings.cpp plugins/Receipts/src/receiptssettingspage.cpp plugins/Receipts/src/receiptssettingspage.ui - plugins/Receipts/src/thirdparty/qrcodegen.cpp plugins/Receipts/src/receiptswidget.cpp plugins/Receipts/src/receiptswidget.ui + plugins/Receipts/src/thirdparty/qrcodegen.cpp + plugins/Relays/src/addlegdialogwidget.cpp plugins/Relays/src/addlegdialogwidget.ui plugins/Relays/src/relaydocument.cpp From 27fba468b2d278c6048e49a017073f2cc31bead6 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 8 Apr 2026 23:03:53 +0200 Subject: [PATCH 20/83] Remove duplicate include --- quickevent/app/quickevent/CMakeLists.txt | 4 ---- .../app/quickevent/plugins/Runs/src/runstablewidget.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 3aae94906..999a783d0 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -282,10 +282,6 @@ if (QF_WITH_LIBSHV) target_compile_definitions(quickevent PRIVATE QF_WITH_LIBSHV) endif() -foreach(plugin IN ITEMS Classes Runs Relays Receipts shared) - install(DIRECTORY plugins/${plugin}/qml/reports DESTINATION ${CMAKE_INSTALL_BINDIR}/reports/${plugin}/qml) -endforeach() - # Extract version from appversion.h file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/appversion.h" APP_VERSION_H) string(REGEX MATCH "#define APP_VERSION \"([0-9.]+)\"" _ ${APP_VERSION_H}) diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 217182124..80e5cf2a3 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include From a3a1a13ad2b27054e324546d654bbd1c957660af Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 9 Apr 2026 09:15:40 +0200 Subject: [PATCH 21/83] Fix clang-tidy warnings --- libqf/libqfgui/src/framework/ipersistentsettings.cpp | 7 +++++-- libqf/libqfgui/src/framework/ipersistentsettings.h | 6 ++---- .../plugins/CardReader/src/cardreaderwidget.cpp | 8 +++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libqf/libqfgui/src/framework/ipersistentsettings.cpp b/libqf/libqfgui/src/framework/ipersistentsettings.cpp index 7fff48174..2d66f0235 100644 --- a/libqf/libqfgui/src/framework/ipersistentsettings.cpp +++ b/libqf/libqfgui/src/framework/ipersistentsettings.cpp @@ -5,7 +5,7 @@ #include #include -using namespace qf::gui::framework; +namespace qf::gui::framework { IPersistentSettings::IPersistentSettings(QObject *controlled_object) : m_controlledObject(controlled_object) @@ -39,7 +39,8 @@ QString IPersistentSettings::persistentSettingsPath() return m_persistentSettingsPath; } -static void callMethodRecursively(QObject *obj, const char *method_name) +namespace { +void callMethodRecursively(QObject *obj, const char *method_name) { if(!obj) return; @@ -57,6 +58,7 @@ static void callMethodRecursively(QObject *obj, const char *method_name) //level--; } } +} void IPersistentSettings::loadPersistentSettingsRecursively() { @@ -123,3 +125,4 @@ QString IPersistentSettings::rawPersistentSettingsPath() return raw_path.join('/'); } +} diff --git a/libqf/libqfgui/src/framework/ipersistentsettings.h b/libqf/libqfgui/src/framework/ipersistentsettings.h index 239dae588..272bd7efd 100644 --- a/libqf/libqfgui/src/framework/ipersistentsettings.h +++ b/libqf/libqfgui/src/framework/ipersistentsettings.h @@ -7,9 +7,7 @@ class QObject; -namespace qf { -namespace gui { -namespace framework { +namespace qf::gui::framework { class QFGUI_DECL_EXPORT IPersistentSettings { @@ -38,6 +36,6 @@ class QFGUI_DECL_EXPORT IPersistentSettings QString m_persistentSettingsPath; }; -}}} +} #endif diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index f9a6a90fa..c5f3ac33a 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -842,13 +842,14 @@ CardReaderSettings::ReaderMode CardReaderWidget::currentReaderMode() const return s.readerModeEnum(); } -static int msecToSISec(int msec) +namespace { +int msecToSISec(int msec) { //static constexpr int secs_to_noon = 12 * 60 * 60; return (msec / 1000);// % secs_to_noon; } -static int obStringTosec(const QString &time_str) +int obStringTosec(const QString &time_str) { bool ok; int min = time_str.section('.', 0, 0).toInt(&ok); @@ -864,7 +865,7 @@ static int obStringTosec(const QString &time_str) return (60 * min + sec) * 1000; } -static QList codesForClassName(const QString &class_name, int stage_id) +QList codesForClassName(const QString &class_name, int stage_id) { QList ret; int course_id = 0; @@ -899,6 +900,7 @@ static QList codesForClassName(const QString &class_name, int stage_id) QF_ASSERT_EX(ret.count() > 0, QString("Cannot load codes for class %1 and stage %2").arg(class_name).arg(stage_id)); return ret; } +} void CardReaderWidget::importCards_lapsOnlyCsv() { From a6d3fbaecbcda97785b2c8206af977fc904db7f0 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 9 Apr 2026 12:01:53 +0200 Subject: [PATCH 22/83] Add workaround for clazy in action.yml Added a workaround step to remove gcc-14 for clazy. --- .github/actions/run-linter/action.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/actions/run-linter/action.yml b/.github/actions/run-linter/action.yml index 0d1ddaf1b..fe0e71558 100644 --- a/.github/actions/run-linter/action.yml +++ b/.github/actions/run-linter/action.yml @@ -20,6 +20,13 @@ runs: modules: qtserialport qtmultimedia additional_cmake_args: -DCMAKE_GLOBAL_AUTOGEN_TARGET=ON -DCMAKE_AUTOGEN_ORIGIN_DEPENDS=OFF + # https://bugs.launchpad.net/ubuntu/+source/clazy/+bug/2086665/comments/4 + - name: Workaround for clazy + shell: bash + run: | + sudo apt-get remove gcc-14 + sudo apt-get autoremove + # workaround for clang-tidy false positive - uses: mjp41/workaround8649@c8550b715ccdc17f89c8d5c28d7a48eeff9c94a8 if: runner.os == 'Linux' From 833dc773973279d245c6492454016b15cc0f012d Mon Sep 17 00:00:00 2001 From: lukaskett Date: Tue, 21 Apr 2026 22:28:32 +0200 Subject: [PATCH 23/83] fix: add missing -DQF_WITH_LIBSHV=ON for macOS --- .github/workflows/macos.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 204e971dc..56a5bf5af 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -37,6 +37,7 @@ jobs: -B '${{github.workspace}}/build' \ -DCMAKE_BUILD_TYPE=Release \ -DQF_BUILD_QML_PLUGINS=ON \ + -DQF_WITH_LIBSHV=ON \ -DBUILD_TESTING=OFF \ -DUSE_QT6=ON \ -DCOMMIT_SHA=${{ env.COMMIT_SHA }} \ From 98f57f26f25e069b43db1cf6d8e2441acb08eb88 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 1 Jun 2026 21:44:11 +0200 Subject: [PATCH 24/83] Update libshv --- 3rdparty/libshv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/libshv b/3rdparty/libshv index f77c05674..6d4367ff6 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit f77c05674413e5bd5a1a98c894385e89805406d0 +Subproject commit 6d4367ff6d06de670ea1f49fe534730c3605fbf5 From b0f2e39b5a534ce499aa12753dcf0c9e551d224b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 1 Jun 2026 21:44:42 +0200 Subject: [PATCH 25/83] Fix broken build --- libqf/libqfcore/src/utils/treetable.cpp | 8 ++-- libqf/libqfgui/src/model/sqltablemodel.cpp | 36 ++------------- libqf/libqfgui/src/model/sqltablemodel.h | 2 - quickevent/app/quickevent/CMakeLists.txt | 2 - .../Competitors/src/competitordocument.h | 10 ++-- .../plugins/Runs/src/runstablemodel.h | 10 ++-- .../plugins/Runs/src/runstablewidget.cpp | 46 ------------------- .../plugins/Runs/src/runstablewidget.h | 2 - quickevent/app/quickevent/src/qx/sqlapi.cpp | 29 ++++-------- .../app/quickevent/src/qx/sqldatadocument.cpp | 17 ------- .../app/quickevent/src/qx/sqldatadocument.h | 21 --------- .../app/quickevent/src/qx/sqltablemodel.cpp | 13 ------ .../app/quickevent/src/qx/sqltablemodel.h | 17 ------- 13 files changed, 26 insertions(+), 187 deletions(-) delete mode 100644 quickevent/app/quickevent/src/qx/sqldatadocument.cpp delete mode 100644 quickevent/app/quickevent/src/qx/sqldatadocument.h delete mode 100644 quickevent/app/quickevent/src/qx/sqltablemodel.cpp delete mode 100644 quickevent/app/quickevent/src/qx/sqltablemodel.h diff --git a/libqf/libqfcore/src/utils/treetable.cpp b/libqf/libqfcore/src/utils/treetable.cpp index c18b2fdee..5641dea4f 100644 --- a/libqf/libqfcore/src/utils/treetable.cpp +++ b/libqf/libqfcore/src/utils/treetable.cpp @@ -581,8 +581,8 @@ QVariantMap TreeTable::keyvals(int row_ix) const { return rows().value(row_ix).toMap().value(KEY_KEYVALS).toMap(); } - -static inline QString line_indent(const QString &ind, int level) +namespace { +QString line_indent(const QString &ind, int level) { QString s; for(int i=0; i= 0 && !serial_ix_explicitly_set) { - qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << insert_id; - if(insert_id.isValid()) { - row_ref.setValue(serial_ix, insert_id); + QVariant v = q.lastInsertId(); + qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << v; + if(v.isValid()) { + row_ref.setValue(serial_ix, v); row_ref.setDirty(serial_ix, false); if (auto *app = qobject_cast(QApplication::instance()); app) { app->emitDbRecInserted(table_id, v.value(), record_to_map(rec), this); @@ -250,15 +251,6 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) qfDebug() << "\tsetting value of foreign key" << slave_key << "to value of master key:" << row_ref.value(master_key).toString(); row_ref.setValue(slave_key, row_ref.value(master_key)); } - if (!qx_record.isEmpty() && master_key == "id") { - qf::core::sql::QxRecChng chng { - .table = table_id, - .id = insert_id.toInt(), - .record = qx_record, - .op = qf::core::sql::QxRecOp::Insert, - }; - emit qxRecChng(chng); - } } } else { @@ -355,15 +347,6 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) ret = false; break; } - if (!qx_record.isEmpty() && pri_keys.size() == 1 && pri_keys[0] == "id" && id_pri_key_value.has_value()) { - qf::core::sql::QxRecChng chng { - .table = table_id, - .id = id_pri_key_value.value(), - .record = qx_record, - .op = qf::core::sql::QxRecOp::Update, - }; - emit qxRecChng(chng); - } } } } @@ -472,17 +455,6 @@ bool SqlTableModel::removeTableRow(int row_no, bool throw_exc) ret = false; break; } - if (where_rec.count() == 1 && where_rec.field(0).name() == "id") { - if (auto id = where_rec.field(0).value().toInt(); id < 0) { - qf::core::sql::QxRecChng chng { - .table = table_id, - .id = id, - .record = {}, - .op = qf::core::sql::QxRecOp::Delete, - }; - emit qxRecChng(chng); - } - } } } if(ret) { diff --git a/libqf/libqfgui/src/model/sqltablemodel.h b/libqf/libqfgui/src/model/sqltablemodel.h index dc2f93082..ce9e2313f 100644 --- a/libqf/libqfgui/src/model/sqltablemodel.h +++ b/libqf/libqfgui/src/model/sqltablemodel.h @@ -49,8 +49,6 @@ class QFGUI_DECL_EXPORT SqlTableModel : public TableModel int reloadRow(int row_no) override; int reloadInserts(const QString &id_column_name) override; QString reloadRowQuery(const QVariant &record_id); - - Q_SIGNAL void qxRecChng(const qf::core::sql::QxRecChng &recchng); public: void setQueryBuilder(const qf::core::sql::QueryBuilder &qb, bool clear_columns = false); const qf::core::sql::QueryBuilder& queryBuilder() const; diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index cc071641a..0d89b41dc 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -178,8 +178,6 @@ add_executable(quickevent plugins/CardReader/CardReader.qrc src/qx/sqlapi.cpp src/qx/sqlapi.h - src/qx/sqltablemodel.h src/qx/sqltablemodel.cpp - src/qx/sqldatadocument.h src/qx/sqldatadocument.cpp src/appclioptions.cpp src/application.cpp diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h index ebca84986..b282d4ebb 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h @@ -1,17 +1,16 @@ -#ifndef COMPETITORS_COMPETITORDOCUMENT_H -#define COMPETITORS_COMPETITORDOCUMENT_H +#pragma once -#include "src/qx/sqldatadocument.h" +#include #include namespace Competitors { -class CompetitorDocument : public qx::SqlDataDocument +class CompetitorDocument : public qf::gui::model::SqlDataDocument { Q_OBJECT private: - typedef qx::SqlDataDocument Super; + typedef qf::gui::model::SqlDataDocument Super; public: CompetitorDocument(QObject *parent = nullptr); @@ -31,4 +30,3 @@ class CompetitorDocument : public qx::SqlDataDocument } -#endif // COMPETITORS_COMPETITORDOCUMENT_H diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h index ffdcdfea9..08bc5a67c 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h @@ -1,15 +1,14 @@ -#ifndef RUNSTABLEMODEL_H -#define RUNSTABLEMODEL_H +#pragma once -#include "src/qx/sqltablemodel.h" +#include namespace qf::core::sql { struct QxRecChng; } -class RunsTableModel : public ::qx::SqlTableModel +class RunsTableModel : public quickevent::gui::og::SqlTableModel { Q_OBJECT private: - using Super = ::qx::SqlTableModel; + using Super = quickevent::gui::og::SqlTableModel; public: enum Columns { col_runs_isRunning = 0, @@ -67,4 +66,3 @@ class RunsTableModel : public ::qx::SqlTableModel void onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); }; -#endif // RUNSTABLEMODEL_H diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 80e5cf2a3..1b8604a65 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -134,8 +134,6 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : } } }, Qt::QueuedConnection); - - connect(::qx::SqlApi::instance(), &::qx::SqlApi::recchng, this, &RunsTableWidget::onQxRecChng); } RunsTableWidget::~RunsTableWidget() @@ -437,47 +435,3 @@ void RunsTableWidget::onBadTableDataInput(const QString &message) qf::gui::dialogs::MessageBox::showError(this, message); } -void RunsTableWidget::onQxRecChng(const qf::core::sql::QxRecChng &chng) -{ - std::optional run_id; - int row = 0; - if (chng.table == "competitors") { - auto *m = m_runsModel; - for (auto i=0; irowCount(); ++i) { - if (m->table().row(i).value("competitors.id").toInt() == chng.id) { - run_id = m->value(i, "runs.id").toInt(); - row = i; - break; - } - } - } - else if (chng.table == "runs") { - run_id = chng.id; - auto *m = m_runsModel; - for (auto i=0; irowCount(); ++i) { - if (m->table().row(i).value("runs.id").toInt() == chng.id) { - row = i; - break; - } - } - } - if (run_id.has_value()) { - if (chng.op == qf::core::sql::QxRecOp::Update) { - for (const auto &[k, v] : chng.record.toMap().asKeyValueRange()) { - if (k == "firstname" || k == "lastname") { - auto &r = m_runsModel->tableRowRef(row); - r.setValue("competitors." + k, v); - auto ix = m_runsModel->index(row, RunsTableModel::col_competitorName); - m_runsModel->dataChanged(ix, ix); - } else { - m_runsModel->setValue(row, k, v); - m_runsModel->setDirty(row, k, false); - } - } - } else { - ui->tblRuns->rowExternallySaved(run_id.value()); - } - } -} - - diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h index d7ed07e6e..263ddbd5c 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.h @@ -37,8 +37,6 @@ class RunsTableWidget : public QWidget void onCustomContextMenuRequest(const QPoint &pos); void onTableViewSqlException(const QString &what, const QString &where, const QString &stack_trace); void onBadTableDataInput(const QString &message); - - void onQxRecChng(const qf::core::sql::QxRecChng &chng); private: Ui::RunsTableWidget *ui; RunsTableModel *m_runsModel; diff --git a/quickevent/app/quickevent/src/qx/sqlapi.cpp b/quickevent/app/quickevent/src/qx/sqlapi.cpp index 2fd65b9d8..4782b259c 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/src/qx/sqlapi.cpp @@ -150,20 +150,8 @@ SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng) { - RpcValue::Map ret; - ret["table"] = chng.table.toStdString(); - ret["id"] = chng.id; - ret["record"] = shv::coreqt::rpc::qVariantToRpcValue(chng.record); - auto rec_op_string = [](qf::core::sql::QxRecOp op) { - switch (op) { - case qf::core::sql::QxRecOp::Insert: return "Insert"; - case qf::core::sql::QxRecOp::Update: return "Update"; - case qf::core::sql::QxRecOp::Delete: return "Delete"; - } - return ""; - }; - ret["op"] = rec_op_string(chng.op); - return ret; + auto m = chng.toVariantMap(); + return shv::coreqt::rpc::qVariantToRpcValue(m); } //============================================== @@ -355,8 +343,9 @@ int64_t SqlApi::create(const std::string &table, const SqlRecord &record) SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { .table = QString::fromStdString(table), .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)), - .op = qf::core::sql::QxRecOp::Insert + .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), + .op = qf::core::sql::RecOp::Insert, + .issuer = {} }); return id; } @@ -405,8 +394,9 @@ bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &recor SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { .table = QString::fromStdString(table), .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)), - .op = qf::core::sql::QxRecOp::Update + .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), + .op = qf::core::sql::RecOp::Update, + .issuer = {} }); } return updated; @@ -425,7 +415,8 @@ bool SqlApi::drop(const std::string &table, int64_t id) .table = QString::fromStdString(table), .id = id, .record = {}, - .op = qf::core::sql::QxRecOp::Delete + .op = qf::core::sql::RecOp::Delete, + .issuer = {} }); } return is_drop; diff --git a/quickevent/app/quickevent/src/qx/sqldatadocument.cpp b/quickevent/app/quickevent/src/qx/sqldatadocument.cpp deleted file mode 100644 index 1f7040921..000000000 --- a/quickevent/app/quickevent/src/qx/sqldatadocument.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "sqldatadocument.h" - - -namespace qx { - -SqlDataDocument::SqlDataDocument(QObject *parent) - : Super{parent} -{ - -} - -SqlTableModel *SqlDataDocument::createModel(QObject *parent) -{ - return new ::qx::SqlTableModel(parent); -} - -} // namespace qx diff --git a/quickevent/app/quickevent/src/qx/sqldatadocument.h b/quickevent/app/quickevent/src/qx/sqldatadocument.h deleted file mode 100644 index cea298076..000000000 --- a/quickevent/app/quickevent/src/qx/sqldatadocument.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "sqltablemodel.h" - -#include - -namespace qx { - -class SqlDataDocument : public qf::gui::model::SqlDataDocument -{ - Q_OBJECT - - using Super = qf::gui::model::SqlDataDocument; -public: - explicit SqlDataDocument(QObject *parent = nullptr); -protected: - ::qx::SqlTableModel* createModel(QObject *parent) override; -}; - -} // namespace qx - diff --git a/quickevent/app/quickevent/src/qx/sqltablemodel.cpp b/quickevent/app/quickevent/src/qx/sqltablemodel.cpp deleted file mode 100644 index 0bad5b1fc..000000000 --- a/quickevent/app/quickevent/src/qx/sqltablemodel.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "sqltablemodel.h" -#include "sqlapi.h" - -namespace qx { - -SqlTableModel::SqlTableModel(QObject *parent) - : Super{parent} -{ - auto *sql_api = SqlApi::instance(); - connect(this, &qf::gui::model::SqlTableModel::qxRecChng, sql_api, &SqlApi::emitRecChng); -} - -} // namespace qx diff --git a/quickevent/app/quickevent/src/qx/sqltablemodel.h b/quickevent/app/quickevent/src/qx/sqltablemodel.h deleted file mode 100644 index 1581be19e..000000000 --- a/quickevent/app/quickevent/src/qx/sqltablemodel.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -namespace qx { - -class SqlTableModel : public quickevent::gui::og::SqlTableModel -{ - Q_OBJECT - - using Super = quickevent::gui::og::SqlTableModel; -public: - explicit SqlTableModel(QObject *parent = nullptr); -}; - -} // namespace qx - From c6072f3a8682ae92153428fd489c1e7945e28b18 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 1 Jun 2026 21:54:47 +0200 Subject: [PATCH 26/83] Fix linter warnings --- quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp | 6 +++--- quickevent/app/quickevent/src/qx/sqlapi.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index c4e14910b..5eeb13cd8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -1362,8 +1362,8 @@ void EventPlugin::deleteEvent(const QString &event_name) .arg(event_name, q.lastErrorText())); } } - -static void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) +namespace { +void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) { dst.setHostName(src.hostName()); dst.setPort(src.port()); @@ -1371,7 +1371,7 @@ static void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) dst.setPassword(src.password()); dst.setDatabaseName(src.databaseName()); } - +} bool EventPlugin::importEventFromFile(const QString &src_file, const QString &dest_event_name) { qfLogFuncFrame(); diff --git a/quickevent/app/quickevent/src/qx/sqlapi.cpp b/quickevent/app/quickevent/src/qx/sqlapi.cpp index 4782b259c..0581d77e0 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/src/qx/sqlapi.cpp @@ -14,6 +14,7 @@ #include #include #include +#include using namespace shv::chainpack; @@ -305,7 +306,7 @@ std::string to_lower(const std::string &s) std::string result; result.reserve(s.size()); - std::transform(s.begin(), s.end(), std::back_inserter(result), + std::ranges::transform(s, std::back_inserter(result), [](unsigned char c) { return std::tolower(c); }); return result; From 0d20550dd22c5901aca7bceb87b24ee12c80dd45 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 1 Jun 2026 22:11:12 +0200 Subject: [PATCH 27/83] Fix broken build --- 3rdparty/libshv | 2 +- .../Event/src/services/qx/qxeventservice.cpp | 2 +- quickevent/app/quickevent/src/qx/sqlapi.cpp | 55 ++++++++++--------- quickevent/app/quickevent/src/qx/sqlapi.h | 4 +- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/3rdparty/libshv b/3rdparty/libshv index 6d4367ff6..b1c3721d5 160000 --- a/3rdparty/libshv +++ b/3rdparty/libshv @@ -1 +1 @@ -Subproject commit 6d4367ff6d06de670ea1f49fe534730c3605fbf5 +Subproject commit b1c3721d53f7390598e8f4fd8e5a3b225b58e5d0 diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 24f6bab19..92eb101c5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -95,7 +95,7 @@ void QxEventService::run() { connect(m_rpcConnection, &ClientConnection::brokerLoginError, this, &QxEventService::onBrokerLoginError); connect(m_rpcConnection, &ClientConnection::rpcMessageReceived, this, &QxEventService::onRpcMessageReceived); - connect(::qx::SqlApi::instance(), &::qx::SqlApi::recchng, this, &QxEventService::sendRecchgShvSignal); + // connect(::qx::SqlApi::instance(), &::qx::SqlApi::recchng, this, &QxEventService::sendRecchgShvSignal); m_rpcConnection->open(); } diff --git a/quickevent/app/quickevent/src/qx/sqlapi.cpp b/quickevent/app/quickevent/src/qx/sqlapi.cpp index 0581d77e0..a3329ef51 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/src/qx/sqlapi.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -161,7 +162,7 @@ RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng) SqlApi::SqlApi(QObject *parent) : QObject{parent} { - + // connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, ) } SqlApi *SqlApi::instance() @@ -170,11 +171,11 @@ SqlApi *SqlApi::instance() return api; } -void SqlApi::emitRecChng(const qf::core::sql::QxRecChng &chng) -{ - qfInfo() << "REC_CHNG:" << qxRecChngToRpcValue(chng).toCpon(); - emit recchng(chng); -} +// void SqlApi::emitRecChng(const qf::core::sql::QxRecChng &chng) +// { +// qfInfo() << "REC_CHNG:" << qxRecChngToRpcValue(chng).toCpon(); +// emit recchng(chng); +// } namespace { @@ -341,13 +342,13 @@ int64_t SqlApi::create(const std::string &table, const SqlRecord &record) } q.exec(qf::core::Exception::Throw); auto id = q.lastInsertId().toInt(); - SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - .table = QString::fromStdString(table), - .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), - .op = qf::core::sql::RecOp::Insert, - .issuer = {} - }); + // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { + // .table = QString::fromStdString(table), + // .id = id, + // .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), + // .op = qf::core::sql::RecOp::Insert, + // .issuer = {} + // }); return id; } @@ -392,13 +393,13 @@ bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &recor q.exec(qf::core::Exception::Throw); bool updated = q.numRowsAffected() == 1; if (updated) { - SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - .table = QString::fromStdString(table), - .id = id, - .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), - .op = qf::core::sql::RecOp::Update, - .issuer = {} - }); + // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { + // .table = QString::fromStdString(table), + // .id = id, + // .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), + // .op = qf::core::sql::RecOp::Update, + // .issuer = {} + // }); } return updated; } @@ -412,13 +413,13 @@ bool SqlApi::drop(const std::string &table, int64_t id) q.exec(sql_query, qf::core::Exception::Throw); bool is_drop = q.numRowsAffected() == 1; if (is_drop) { - SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - .table = QString::fromStdString(table), - .id = id, - .record = {}, - .op = qf::core::sql::RecOp::Delete, - .issuer = {} - }); + // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { + // .table = QString::fromStdString(table), + // .id = id, + // .record = {}, + // .op = qf::core::sql::RecOp::Delete, + // .issuer = {} + // }); } return is_drop; } diff --git a/quickevent/app/quickevent/src/qx/sqlapi.h b/quickevent/app/quickevent/src/qx/sqlapi.h index 80bee09b2..413b302dd 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.h +++ b/quickevent/app/quickevent/src/qx/sqlapi.h @@ -63,8 +63,8 @@ class SqlApi : public QObject public: static SqlApi* instance(); - Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); - void emitRecChng(const qf::core::sql::QxRecChng &chng); + // Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); + // void emitRecChng(const qf::core::sql::QxRecChng &chng); static RpcSqlResult exec(const SqlQueryAndParams ¶ms); static RpcSqlResult query(const SqlQueryAndParams ¶ms); From efe865e374b2948548a8c10eee88594537fa2938 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 1 Jun 2026 22:45:07 +0200 Subject: [PATCH 28/83] SqlApi rewrite --- .../Event/src/services/qx/sqlapinode.cpp | 2 +- quickevent/app/quickevent/src/qx/sqlapi.cpp | 242 ++++++++++-------- quickevent/app/quickevent/src/qx/sqlapi.h | 56 ++-- 3 files changed, 165 insertions(+), 135 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index bbeeb3b08..037061733 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -100,7 +100,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin } auto res = ::qx::SqlApi::read(table, id, fields); if (res.has_value()) { - return res.value(); + return shv::coreqt::rpc::qVariantToRpcValue(res.value()); } return RpcValue(nullptr); } diff --git a/quickevent/app/quickevent/src/qx/sqlapi.cpp b/quickevent/app/quickevent/src/qx/sqlapi.cpp index a3329ef51..d70dfc1a3 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/src/qx/sqlapi.cpp @@ -24,25 +24,45 @@ namespace qx { //============================================== // RpcSqlField //============================================== -RpcValue RpcSqlField::toRpcValue() const +RpcValue DbField::toRpcValue() const { RpcValue::Map ret; - ret["name"] = name; + ret["name"] = name.toStdString(); return RpcValue(std::move(ret)); } -RpcSqlField RpcSqlField::fromRpcValue(const shv::chainpack::RpcValue &rv) +DbField DbField::fromRpcValue(const shv::chainpack::RpcValue &rv) { - RpcSqlField ret; + DbField ret; const RpcValue::Map &map = rv.asMap(); - ret.name = map.value("name").asString(); + ret.name = QString::fromStdString(map.value("name").asString()); return ret; } //============================================== -// RpcSqlResult +// ExecResult //============================================== -const RpcValue &RpcSqlResult::value(size_t row, size_t col) const +RpcValue ExecResult::toRpcValue() const +{ + RpcValue::Map ret; + ret["numRowsAffected"] = numRowsAffected; + ret["lastInsertId"] = lastInsertId.has_value()? RpcValue(lastInsertId.value()): RpcValue(nullptr); + return ret; +} + +ExecResult ExecResult::fromRpcValue(const shv::chainpack::RpcValue &rv) +{ + ExecResult ret; + const auto &map = rv.asMap(); + ret.numRowsAffected = map.value("numRowsAffected").toInt(); + ret.lastInsertId = map.value("lastInsertId").toInt(); + return ret; +} + +//============================================== +// QueryResult +//============================================== +QVariant QueryResult::value(qsizetype row, qsizetype col) const { if (row < rows.size()) { const auto &cells = rows[row]; @@ -50,20 +70,18 @@ const RpcValue &RpcSqlResult::value(size_t row, size_t col) const return cells[col]; } } - static RpcValue s; - return s; + return {}; } -const RpcValue& RpcSqlResult::value(size_t row, const std::string &name) const +QVariant QueryResult::value(qsizetype row, const std::string &name) const { if (auto ix = columnIndex(name); ix.has_value()) { return value(row, ix.value()); } - static RpcValue s; - return s; + return {}; } -void RpcSqlResult::setValue(size_t row, size_t col, const RpcValue &val) +void QueryResult::setValue(qsizetype row, qsizetype col, const QVariant &val) { if (row < rows.size()) { auto &r = rows[row]; @@ -73,80 +91,81 @@ void RpcSqlResult::setValue(size_t row, size_t col, const RpcValue &val) } } -void RpcSqlResult::setValue(size_t row, const std::string &name, const RpcValue &val) +void QueryResult::setValue(qsizetype row, const std::string &name, const QVariant &val) { if (auto ix = columnIndex(name); ix.has_value()) { setValue(row, ix.value(), val); } } -RpcValue::List RpcSqlResult::toRecordList() const +RpcValue::List QueryResult::toRecordList() const { RpcValue::List ret; for (const auto &row : rows) { - SqlRecord rec; + RpcValue::Map rec; int n = 0; for (const auto &field : fields) { - rec[field.name] = row[n++]; + rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(row.value(n++)); } ret.push_back(rec); } return ret; } -std::optional RpcSqlResult::columnIndex(const std::string &name) const +std::optional QueryResult::columnIndex(const std::string &name) const { for (size_t col = 0; col < fields.size(); ++col) { const auto &fld = fields[col]; - if (fld.name == name) { + if (fld.name.toStdString() == name) { return col; } } return {}; } -RpcValue RpcSqlResult::toRpcValue() const +RpcValue QueryResult::toRpcValue() const { RpcValue::Map ret; - if(isSelect()) { - RpcValue::List flds; - for(const auto &fld : this->fields) - flds.push_back(fld.toRpcValue()); - ret["fields"] = flds; - ret["rows"] = rows; - } - else { - ret["numRowsAffected"] = numRowsAffected; - ret["lastInsertId"] = lastInsertId.has_value()? RpcValue(lastInsertId.value()): RpcValue(nullptr); + RpcValue::List flds; + for(const auto &fld : this->fields) + flds.push_back(fld.toRpcValue()); + RpcValue::List rpc_rows; + for (const auto &row : rows) { + RpcValue::List rpc_row; + for (const auto &cell : row) { + rpc_row.push_back(shv::coreqt::rpc::qVariantToRpcValue(cell)); + } + rpc_rows.push_back(std::move(rpc_row)); } + ret["fields"] = flds; + ret["rows"] = std::move(rpc_rows); return ret; } -RpcSqlResult RpcSqlResult::fromRpcValue(const RpcValue &rv) +QueryResult QueryResult::fromRpcValue(const RpcValue &rv) { - RpcSqlResult ret; + QueryResult ret; const auto &map = rv.asMap(); const auto &flds = map.valref("fields").asList(); - if(flds.empty()) { - ret.numRowsAffected = map.value("numRowsAffected").toInt(); - ret.lastInsertId = map.value("lastInsertId").toInt(); + for(const auto &fv : flds) { + ret.fields.push_back(DbField::fromRpcValue(fv)); } - else { - for(const auto &fv : flds) { - ret.fields.push_back(RpcSqlField::fromRpcValue(fv)); - } - for (const auto &row : map.value("rows").asList()) { - ret.rows.push_back(row.asList()); + for (const auto &rpc_row : map.value("rows").asList()) { + QueryResult::Row row; + for (const auto &cell : rpc_row.asList()) { + row.push_back(shv::coreqt::rpc::rpcValueToQVariant(cell)); } + ret.rows.push_back(row); } return ret; } SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue &rv) { - auto sql_query = rv.asList().valref(0).asString(); - const auto &sql_params = rv.asList().valref(0); - return SqlQueryAndParams { .query = sql_query, .params = sql_params.asMap() }; + const auto &lst = rv.asList(); + auto sql_query = QString::fromStdString(lst.valref(0).asString()); + const auto &sql_params = lst.valref(1); + return SqlQueryAndParams { .query = sql_query, .params = shv::coreqt::rpc::rpcValueToQVariant(sql_params).toMap() }; } @@ -205,61 +224,63 @@ class Transaction bool m_inTransaction = true; }; -RpcSqlResult rpcSqlQuery(const SqlQueryAndParams ¶ms) +void bindParams(qf::core::sql::Query &q, const Record ¶ms) { - qf::core::sql::Query q; - q.prepare(QString::fromUtf8(params.query), qf::core::Exception::Throw); - for (const auto &[k, v] : params.params) { - bool ok; - QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); - if (!ok) { - QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); - } - q.bindValue(':' + QString::fromStdString(k), val); + for (const auto &[k, v] : params.asKeyValueRange()) { + q.bindValue(':' + k, v); } +} + +QueryResult sqlQuery(const SqlQueryAndParams ¶ms) +{ + qf::core::sql::Query q; + q.prepare(params.query, qf::core::Exception::Throw); + bindParams(q, params.params); q.exec(qf::core::Exception::Throw); - RpcSqlResult ret; - if(q.isSelect()) { - QSqlRecord rec = q.record(); + + QueryResult ret; + QSqlRecord rec = q.record(); + for (int i = 0; i < rec.count(); ++i) { + QSqlField fld = rec.field(i); + DbField rfld; + rfld.name = fld.name(); + // rfld.name.replace("__", "."); + ret.fields.push_back(rfld); + } + while(q.next()) { + QueryResult::Row row; for (int i = 0; i < rec.count(); ++i) { - QSqlField fld = rec.field(i); - RpcSqlField rfld; - rfld.name = fld.name().toStdString(); - // rfld.name.replace("__", "."); - ret.fields.push_back(rfld); + row.push_back(q.value(i)); + //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); } - while(q.next()) { - RpcSqlResult::Row row; - for (int i = 0; i < rec.count(); ++i) { - const QVariant v = q.value(i); - if (v.isNull()) { - row.push_back(RpcValue(nullptr)); - } - else { - row.push_back(shv::coreqt::rpc::qVariantToRpcValue(v)); - } - //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); - } - ret.rows.push_back(row); - } - } - else { - ret.numRowsAffected = q.numRowsAffected(); - ret.lastInsertId = q.lastInsertId().toInt(); + ret.rows.insert(ret.rows.size(), row); } return ret; } +ExecResult sqlExec(const SqlQueryAndParams ¶ms) +{ + qf::core::sql::Query q; + q.prepare(params.query, qf::core::Exception::Throw); + bindParams(q, params.params); + q.exec(qf::core::Exception::Throw); + + ExecResult ret; + ret.numRowsAffected = q.numRowsAffected(); + ret.lastInsertId = q.lastInsertId().toInt(); + return ret; } -RpcSqlResult SqlApi::exec(const SqlQueryAndParams ¶ms) +} + +ExecResult SqlApi::exec(const SqlQueryAndParams ¶ms) { - return rpcSqlQuery(params); + return sqlExec(params); } -RpcSqlResult SqlApi::query(const SqlQueryAndParams ¶ms) +QueryResult SqlApi::query(const SqlQueryAndParams ¶ms) { - return rpcSqlQuery(params); + return sqlQuery(params); } void SqlApi::transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms) @@ -282,7 +303,7 @@ void SqlApi::transaction(const std::string &query, const shv::chainpack::RpcValu tranaction.commit(); } -RpcSqlResult SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) +QueryResult SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) { QStringList qfields; for (const auto &fn : fields) { @@ -298,7 +319,7 @@ RpcSqlResult SqlApi::list(const std::string &table, const std::vector SqlApi::read(const std::string &table, int64_t id, const std::vector &fields) +std::optional SqlApi::read(const std::string &table, int64_t id, const std::vector &fields) { QStringList qfields; for (const auto &fn : fields) { @@ -365,30 +387,34 @@ std::optional SqlApi::read(const std::string &table, int64_t id, cons .arg(qfields.join(',')) .arg(QString::fromStdString(table)) .arg(id) ; - auto res = rpcSqlQuery(SqlQueryAndParams { .query = sql_query.toStdString(), .params = {}}); - auto lst = res.toRecordList(); - if (lst.empty()) { + auto res = sqlQuery(SqlQueryAndParams { .query = sql_query, .params = {}}); + if (res.rows.empty()) { return {}; } - return lst[0].asMap(); + Record ret; + const auto &row = res.rows.first(); + for (qsizetype i = 0; i < std::ssize(res.fields); ++i) { + ret[res.fields[i].name] = row.value(i); + } + return ret; } -bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &record) +bool SqlApi::update(const std::string &table, int64_t id, const RpcValue::Map &record) { QStringList fields; for (const auto &[k, v] : record) { - auto name = QString::fromStdString(k); - fields << name + " = :" + name; + Q_UNUSED(v) + auto qk = QString::fromStdString(k); + fields << qk + " = :" + qk; } QString sql_query = QStringLiteral("UPDATE %1 SET %2 WHERE id = %3") - .arg(table) + .arg(QString::fromStdString(table)) .arg(fields.join(',')) .arg(id); qf::core::sql::Query q; q.prepare(sql_query, qf::core::Exception::Throw); for (const auto &[k, v] : record) { - auto qv = shv::coreqt::rpc::rpcValueToQVariant(v); - q.bindValue(':' + QString::fromStdString(k), qv); + q.bindValue(':' + QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); } q.exec(qf::core::Exception::Throw); bool updated = q.numRowsAffected() == 1; @@ -407,7 +433,7 @@ bool SqlApi::update(const std::string &table, int64_t id, const SqlRecord &recor bool SqlApi::drop(const std::string &table, int64_t id) { QString sql_query = QStringLiteral("DELETE FROM %1 WHERE id = %2") - .arg(table) + .arg(QString::fromStdString(table)) .arg(id); qf::core::sql::Query q; q.exec(sql_query, qf::core::Exception::Throw); diff --git a/quickevent/app/quickevent/src/qx/sqlapi.h b/quickevent/app/quickevent/src/qx/sqlapi.h index 413b302dd..fe15ed6f2 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.h +++ b/quickevent/app/quickevent/src/qx/sqlapi.h @@ -11,45 +11,49 @@ namespace qf::core::sql { struct QxRecChng; } namespace qx { -struct RpcSqlField +struct DbField { - std::string name; + QString name; - //explicit RpcSqlField(const QJsonObject &jo = QJsonObject()) : Super(jo) {} + //explicit DbField(const QJsonObject &jo = QJsonObject()) : Super(jo) {} shv::chainpack::RpcValue toRpcValue() const; // QVariant toVariant() const; - static RpcSqlField fromRpcValue(const shv::chainpack::RpcValue &rv); - // static RpcSqlField fromVariant(const QVariant &v); + static DbField fromRpcValue(const shv::chainpack::RpcValue &rv); + // static DbField fromVariant(const QVariant &v); }; -struct RpcSqlResult +struct ExecResult { int numRowsAffected = 0; std::optional lastInsertId = 0; - std::vector fields; - using Row = shv::chainpack::RpcValue::List; - std::vector rows; - RpcSqlResult() = default; + shv::chainpack::RpcValue toRpcValue() const; + static ExecResult fromRpcValue(const shv::chainpack::RpcValue &rv); +}; + +struct QueryResult +{ + std::vector fields; + using Row = QVariantList; + QList rows; - std::optional columnIndex(const std::string &name) const; - const shv::chainpack::RpcValue& value(size_t row, size_t col) const; - const shv::chainpack::RpcValue& value(size_t row, const std::string &name) const; - void setValue(size_t row, size_t col, const shv::chainpack::RpcValue &val); - void setValue(size_t row, const std::string &name, const shv::chainpack::RpcValue &val); + std::optional columnIndex(const std::string &name) const; + QVariant value(qsizetype row, qsizetype col) const; + QVariant value(qsizetype row, const std::string &name) const; + void setValue(qsizetype row, qsizetype col, const QVariant &val); + void setValue(qsizetype row, const std::string &name, const QVariant &val); - bool isSelect() const {return !fields.empty();} shv::chainpack::RpcValue toRpcValue() const; + static QueryResult fromRpcValue(const shv::chainpack::RpcValue &rv); shv::chainpack::RpcValue::List toRecordList() const; - static RpcSqlResult fromRpcValue(const shv::chainpack::RpcValue &rv); }; -using SqlRecord = shv::chainpack::RpcValue::Map; +using Record = QVariantMap; struct SqlQueryAndParams { - std::string query; - SqlRecord params; + QString query; + Record params; static SqlQueryAndParams fromRpcValue(const shv::chainpack::RpcValue &rv); }; @@ -66,13 +70,13 @@ class SqlApi : public QObject // Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); // void emitRecChng(const qf::core::sql::QxRecChng &chng); - static RpcSqlResult exec(const SqlQueryAndParams ¶ms); - static RpcSqlResult query(const SqlQueryAndParams ¶ms); + static ExecResult exec(const SqlQueryAndParams ¶ms); + static QueryResult query(const SqlQueryAndParams ¶ms); static void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); - static RpcSqlResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); - static int64_t create(const std::string &table, const SqlRecord &record); - static std::optional read(const std::string &table, int64_t id, const std::vector &fields); - static bool update(const std::string &table, int64_t id, const SqlRecord &record); + static QueryResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); + static int64_t create(const std::string &table, const shv::chainpack::RpcValue::Map &record); + static std::optional read(const std::string &table, int64_t id, const std::vector &fields); + static bool update(const std::string &table, int64_t id, const shv::chainpack::RpcValue::Map &record); static bool drop(const std::string &table, int64_t id); private: explicit SqlApi(QObject *parent = nullptr); From 2b216441e15621b768e37ede64ed51f95a824ad3 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 3 Jun 2026 14:59:41 +0200 Subject: [PATCH 29/83] Move SqlApi to EventPlugin --- quickevent/app/quickevent/CMakeLists.txt | 3 +-- .../Event/src/services/qx/qxeventservice.cpp | 14 ++++++------- .../Event/src/services/qx/qxeventservice.h | 2 +- .../Event/src/services}/qx/sqlapi.cpp | 8 +------ .../Event/src/services}/qx/sqlapi.h | 21 +++++++++---------- .../Event/src/services/qx/sqlapinode.cpp | 19 +++++++++-------- .../Event/src/services/qx/sqlapinode.h | 4 ++++ .../plugins/Runs/src/runstablemodel.cpp | 1 - .../plugins/Runs/src/runstablewidget.cpp | 2 -- 9 files changed, 34 insertions(+), 40 deletions(-) rename quickevent/app/quickevent/{src => plugins/Event/src/services}/qx/sqlapi.cpp (98%) rename quickevent/app/quickevent/{src => plugins/Event/src/services}/qx/sqlapi.h (69%) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 0d89b41dc..94fbaec8c 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -95,6 +95,7 @@ add_executable(quickevent plugins/Event/src/services/qx/qxnode.cpp plugins/Event/src/services/qx/sqlapinode.cpp + plugins/Event/src/services/qx/sqlapi.cpp plugins/Event/src/services/qx/sqlapi.h plugins/Event/src/services/qx/nodes.cpp plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -177,8 +178,6 @@ add_executable(quickevent plugins/Runs/Runs.qrc plugins/CardReader/CardReader.qrc - src/qx/sqlapi.cpp src/qx/sqlapi.h - src/appclioptions.cpp src/application.cpp src/loggerwidget.cpp diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 92eb101c5..be06570b9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -2,7 +2,7 @@ #include "qxeventservicewidget.h" #include "nodes.h" #include "sqlapinode.h" -#include "src/qx/sqlapi.h" +#include "sqlapi.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -662,11 +662,11 @@ void QxEventService::subscribeChanges() rpc_call->start(); } -void QxEventService::sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng) -{ - if (isRunning()) { - m_rpcConnection->sendShvSignal("sql", "recchng", ::qx::qxRecChngToRpcValue(chng)); - } -} +// void QxEventService::sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng) +// { +// if (isRunning()) { +// m_rpcConnection->sendShvSignal("sql", "recchng", ::qx::qxRecChngToRpcValue(chng)); +// } +// } } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index add24852e..fc5af4120 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -79,7 +79,7 @@ class QxEventService : public Service void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg); void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); - void sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng); + // void sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng); void subscribeChanges(); private: diff --git a/quickevent/app/quickevent/src/qx/sqlapi.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp similarity index 98% rename from quickevent/app/quickevent/src/qx/sqlapi.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp index d70dfc1a3..859e29c82 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp @@ -19,7 +19,7 @@ using namespace shv::chainpack; -namespace qx { +namespace Event::services::qx { //============================================== // RpcSqlField @@ -184,12 +184,6 @@ SqlApi::SqlApi(QObject *parent) // connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, ) } -SqlApi *SqlApi::instance() -{ - static auto *api = new SqlApi(QCoreApplication::instance()); - return api; -} - // void SqlApi::emitRecChng(const qf::core::sql::QxRecChng &chng) // { // qfInfo() << "REC_CHNG:" << qxRecChngToRpcValue(chng).toCpon(); diff --git a/quickevent/app/quickevent/src/qx/sqlapi.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h similarity index 69% rename from quickevent/app/quickevent/src/qx/sqlapi.h rename to quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h index fe15ed6f2..d02966a7e 100644 --- a/quickevent/app/quickevent/src/qx/sqlapi.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h @@ -9,7 +9,7 @@ namespace qf::core::sql { struct QxRecChng; } -namespace qx { +namespace Event::services::qx { struct DbField { @@ -65,21 +65,20 @@ class SqlApi : public QObject { Q_OBJECT public: - static SqlApi* instance(); + explicit SqlApi(QObject *parent = nullptr); // Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); // void emitRecChng(const qf::core::sql::QxRecChng &chng); - static ExecResult exec(const SqlQueryAndParams ¶ms); - static QueryResult query(const SqlQueryAndParams ¶ms); - static void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); - static QueryResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); - static int64_t create(const std::string &table, const shv::chainpack::RpcValue::Map &record); - static std::optional read(const std::string &table, int64_t id, const std::vector &fields); - static bool update(const std::string &table, int64_t id, const shv::chainpack::RpcValue::Map &record); - static bool drop(const std::string &table, int64_t id); + ExecResult exec(const SqlQueryAndParams ¶ms); + QueryResult query(const SqlQueryAndParams ¶ms); + void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); + QueryResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); + int64_t create(const std::string &table, const shv::chainpack::RpcValue::Map &record); + std::optional read(const std::string &table, int64_t id, const std::vector &fields); + bool update(const std::string &table, int64_t id, const shv::chainpack::RpcValue::Map &record); + bool drop(const std::string &table, int64_t id); private: - explicit SqlApi(QObject *parent = nullptr); }; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index 037061733..e18c89d97 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -1,5 +1,5 @@ #include "sqlapinode.h" -#include "src/qx/sqlapi.h" +#include "sqlapi.h" #include #include @@ -21,6 +21,7 @@ namespace Event::services::qx { SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) : Super("sql", parent) + , m_sqlApi(new SqlApi(this)) { } @@ -58,17 +59,17 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin //eyascore::utils::UserId user_id = eyascore::utils::UserId::makeUserName(QString::fromStdString(rq.userId().toMap().value("userName").toString())); if(shv_path.empty()) { if(method == METH_EXEC) { - auto res = ::qx::SqlApi::exec(::qx::SqlQueryAndParams::fromRpcValue(params)); + auto res = m_sqlApi->exec(SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_QUERY) { - auto res = ::qx::SqlApi::exec(::qx::SqlQueryAndParams::fromRpcValue(params)); + auto res = m_sqlApi->exec(SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_TRANSACTION) { auto sql_query = params.asList().valref(0).asString(); const auto &sql_params = params.asList().valref(0); - ::qx::SqlApi::transaction(sql_query, sql_params.asList()); + m_sqlApi->transaction(sql_query, sql_params.asList()); return RpcValue(nullptr); } if(method == METH_LIST) { @@ -80,14 +81,14 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin } auto ids_above = map.contains("ids_above")? std::optional(map.value("ids_above").toInt64()): std::optional(); auto limit = map.contains("limit")? std::optional(map.value("limit").toInt64()): std::optional(); - auto res = ::qx::SqlApi::list(table, fields, ids_above, limit); + auto res = m_sqlApi->list(table, fields, ids_above, limit); return res.toRecordList(); } if(method == METH_CREATE) { const auto &map = params.asMap(); const auto &table = map.value("table").asString(); const auto &record = map.valref("record").asMap(); - auto res = ::qx::SqlApi::create(table, record); + auto res = m_sqlApi->create(table, record); return res; } if(method == METH_READ) { @@ -98,7 +99,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin for (const auto &fn : map.valref("fields").asList()) { fields.push_back(fn.asString()); } - auto res = ::qx::SqlApi::read(table, id, fields); + auto res = m_sqlApi->read(table, id, fields); if (res.has_value()) { return shv::coreqt::rpc::qVariantToRpcValue(res.value()); } @@ -109,14 +110,14 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin const auto &table = map.value("table").asString(); auto id = map.value("id").toInt64(); const auto &record = map.valref("record").asMap(); - auto res = ::qx::SqlApi::update(table, id, record); + auto res = m_sqlApi->update(table, id, record); return res; } if(method == METH_DELETE) { const auto &map = params.asMap(); const auto &table = map.value("table").asString(); auto id = map.valref("id").toInt(); - auto res = ::qx::SqlApi::drop(table, id); + auto res = m_sqlApi->drop(table, id); return res; } } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h index a36f7ed8c..d461ae689 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.h @@ -9,6 +9,8 @@ namespace shv::coreqt::data { class RpcSqlResult; } namespace Event::services::qx { +class SqlApi; + class SqlApiNode : public QxNode { Q_OBJECT @@ -19,6 +21,8 @@ class SqlApiNode : public QxNode protected: const std::vector &metaMethods() override; shv::chainpack::RpcValue callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) override; +private: + SqlApi *m_sqlApi = nullptr; }; } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 17e70cae1..52b93fad2 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -1,7 +1,6 @@ #include "runstablemodel.h" #include "../../Event/src/eventplugin.h" -#include "src/qx/sqlapi.h" #include #include diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 1b8604a65..9f7377b97 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -7,8 +7,6 @@ #include "runflagsdialog.h" #include "cardflagsdialog.h" -#include "src/qx/sqlapi.h" - #include #include #include From ec77db0a99b71b7939ba53a8d160c164496d3201 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 5 Jun 2026 22:44:59 +0200 Subject: [PATCH 30/83] Move QxSqlApi from qf::gui::framework::Application to SqlApi class --- libqf/libqfcore/src/sql/qxsql.cpp | 98 +++++++++++++---- libqf/libqfcore/src/sql/qxsql.h | 35 ++++-- libqf/libqfgui/src/framework/application.cpp | 104 +++++++----------- libqf/libqfgui/src/framework/application.h | 19 ++-- libqf/libqfgui/src/model/sqltablemodel.cpp | 7 +- .../CardReader/src/cardreaderplugin.cpp | 13 ++- .../CardReader/src/cardreaderwidget.cpp | 7 +- .../Competitors/src/competitordocument.cpp | 7 +- .../plugins/Event/src/eventplugin.cpp | 5 +- .../Event/src/services/qx/qxeventservice.cpp | 41 ++++--- .../Event/src/services/qx/sqlapinode.cpp | 2 +- .../plugins/Runs/src/runstablemodel.cpp | 3 +- quickevent/app/quickevent/src/main.cpp | 3 +- 13 files changed, 200 insertions(+), 144 deletions(-) diff --git a/libqf/libqfcore/src/sql/qxsql.cpp b/libqf/libqfcore/src/sql/qxsql.cpp index 844ffbf2d..11601fa32 100644 --- a/libqf/libqfcore/src/sql/qxsql.cpp +++ b/libqf/libqfcore/src/sql/qxsql.cpp @@ -106,15 +106,9 @@ QList QxSqlApi::listOneOrMoreRecords(const QString &table, const std::op } //================================================================ -// QxSql +// QxSqlApiImpl //================================================================ -QxSql::QxSql(const QSqlDatabase &db) - : m_db(db) -{ - -} - -QueryResult QxSql::query(const QString &query, const QVariantMap ¶ms) +QueryResult QxSqlApiImpl::query(const QString &query, const QVariantMap ¶ms) { QSqlQuery q(m_db); q.prepare(query); @@ -138,7 +132,7 @@ QueryResult QxSql::query(const QString &query, const QVariantMap ¶ms) return result; } -ExecResult QxSql::exec(const QString &query, const QVariantMap ¶ms) +ExecResult QxSqlApiImpl::exec(const QString &query, const QVariantMap ¶ms) { QSqlQuery q(m_db); q.prepare(query); @@ -153,40 +147,102 @@ ExecResult QxSql::exec(const QString &query, const QVariantMap ¶ms) return result; } -qint64 QxSql::createRecord(const QString &table, const Record &record, const QString &issuer) +//================================================================ +// QxSql +//================================================================ +QxSql::QxSql(const QString &issuer, const QSqlDatabase &db, QObject *parent) + : QObject(parent) + , m_issuer(issuer) + , m_sqlApi(db) +{ +} + +QueryResult QxSql::query(const QString &query, const QVariantMap ¶ms) +{ + return m_sqlApi.query(query, params); +} + +ExecResult QxSql::exec(const QString &query, const QVariantMap ¶ms) { - auto id = QxSqlApi::createRecord(table, record, issuer); - emit dbRecChng(qf::core::sql::QxRecChng{.table = table, + return m_sqlApi.exec(query, params); +} + +qint64 QxSql::createRecord(const QString &table, const Record &record, QObject *source) +{ + auto id = m_sqlApi.createRecord(table, record, m_issuer); + emit recChng(qf::core::sql::QxRecChng{.table = table, .id = id, .record = record, .op = qf::core::sql::RecOp::Insert, - .issuer = issuer}); + .issuer = m_issuer}, + source); return id; } -bool QxSql::updateRecord(const QString &table, qint64 id, const Record &record, const QString &issuer) +bool QxSql::updateRecord(const QString &table, qint64 id, const Record &record, QObject *source) { - auto ok = QxSqlApi::updateRecord(table, id, record, issuer); + auto ok = m_sqlApi.updateRecord(table, id, record, m_issuer); if (ok) { - emit dbRecChng(qf::core::sql::QxRecChng{.table = table, + emit recChng(qf::core::sql::QxRecChng{.table = table, .id = id, .record = record, .op = qf::core::sql::RecOp::Update, - .issuer = issuer}); + .issuer = m_issuer}, + source); } return ok; } -bool QxSql::deleteRecord(const QString &table, qint64 id, const QString &issuer) +bool QxSql::deleteRecord(const QString &table, qint64 id, QObject *source) { - auto ok = QxSqlApi::deleteRecord(table, id, issuer); + auto ok = m_sqlApi.deleteRecord(table, id, m_issuer); if (ok) { - emit dbRecChng(qf::core::sql::QxRecChng{.table = table, + emit recChng(qf::core::sql::QxRecChng{.table = table, .id = id, .record = {}, .op = qf::core::sql::RecOp::Delete, - .issuer = issuer}); + .issuer = m_issuer}, + source); } return ok; } + +void QxSql::emitRecInserted(const QString &table, qint64 id, const QVariantMap &record, QObject *source) +{ + emit recChng(qf::core::sql::QxRecChng{ + .table = table, + .id = id, + .record = record, + .op = qf::core::sql::RecOp::Insert, + .issuer = m_issuer + }, source); +} + +void QxSql::emitRecUpdated(const QString &table, qint64 id, const QVariantMap &record, QObject *source) +{ + emit recChng(qf::core::sql::QxRecChng{ + .table = table, + .id = id, + .record = record, + .op = qf::core::sql::RecOp::Update, + .issuer = m_issuer + }, source); +} + +void QxSql::emitRecDeleted(const QString &table, qint64 id, QObject *source) +{ + emit recChng(qf::core::sql::QxRecChng{ + .table = table, + .id = id, + .record = {}, + .op = qf::core::sql::RecOp::Delete, + .issuer = m_issuer + }, source); +} + +void QxSql::emitRecChng(const core::sql::QxRecChng &recchng, QObject *source) +{ + emit recChng(recchng, source); +} + } diff --git a/libqf/libqfcore/src/sql/qxsql.h b/libqf/libqfcore/src/sql/qxsql.h index 51e7c6fd0..c1f6101f3 100644 --- a/libqf/libqfcore/src/sql/qxsql.h +++ b/libqf/libqfcore/src/sql/qxsql.h @@ -67,23 +67,40 @@ class QFCORE_DECL_EXPORT QxSqlApi const std::optional &limit); }; -class QFCORE_DECL_EXPORT QxSql : public QObject, public QxSqlApi +class QxSqlApiImpl : public QxSqlApi +{ +public: + QxSqlApiImpl(QSqlDatabase db) : m_db(db) {} + + QueryResult query(const QString &query, const QVariantMap ¶ms) override; + ExecResult exec(const QString &query, const QVariantMap ¶ms) override; +private: + QSqlDatabase m_db; +}; + +class QFCORE_DECL_EXPORT QxSql : public QObject { Q_OBJECT public: - QxSql(const QSqlDatabase &db = QSqlDatabase()); + QxSql(const QString &issuer, const QSqlDatabase &db = {}, QObject *parent = nullptr); ~QxSql() override = default; - Q_SIGNAL void dbRecChng(const qf::core::sql::QxRecChng &recchng); + Q_SIGNAL void recChng(const qf::core::sql::QxRecChng &recchng, QObject *source); - QueryResult query(const QString &query, const QVariantMap ¶ms) override; - ExecResult exec(const QString &query, const QVariantMap ¶ms) override; + QueryResult query(const QString &query, const QVariantMap ¶ms); + ExecResult exec(const QString &query, const QVariantMap ¶ms); + + qint64 createRecord(const QString &table, const Record &record, QObject *source); + bool updateRecord(const QString &table, qint64 id, const Record &record, QObject *source); + bool deleteRecord(const QString &table, qint64 id, QObject *source); - qint64 createRecord(const QString &table, const Record &record, const QString &issuer) override; - bool updateRecord(const QString &table, qint64 id, const Record &record, const QString &issuer) override; - bool deleteRecord(const QString &table, qint64 id, const QString &issuer) override; + void emitRecInserted(const QString &table, qint64 id, const QVariantMap &record, QObject *source); + void emitRecUpdated(const QString &table, qint64 id, const QVariantMap &record, QObject *source); + void emitRecDeleted(const QString &table, qint64 id, QObject *source); + void emitRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); private: - QSqlDatabase m_db; + QString m_issuer; + QxSqlApiImpl m_sqlApi; }; } // namespace qf::core::sql diff --git a/libqf/libqfgui/src/framework/application.cpp b/libqf/libqfgui/src/framework/application.cpp index 5f323c370..ea866c76b 100644 --- a/libqf/libqfgui/src/framework/application.cpp +++ b/libqf/libqfgui/src/framework/application.cpp @@ -19,80 +19,50 @@ Application::Application(int &argc, char **argv) : { } -qint64 Application::createDbRecord(const QString &table, const QVariantMap &record, QObject *source) +qf::core::sql::QxSql *Application::qxSql() { - using namespace qf::core::sql; - QxSql sql; - connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); - return sql.createRecord(table, record, uuidString()); -} - -std::optional Application::readDbRecord(const QString &table, qint64 id, const std::optional &fields) const -{ - using namespace qf::core::sql; - QxSql sql; - return sql.readRecord(table, id, fields); -} - -bool Application::updateDbRecord(const QString &table, qint64 id, const QVariantMap &record, QObject *source) -{ - using namespace qf::core::sql; - QxSql sql; - connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); - return sql.updateRecord(table, id, record, uuidString()); -} - -bool Application::deleteDbRecord(const QString &table, qint64 id, QObject *source) -{ - using namespace qf::core::sql; - QxSql sql; - connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); - return sql.deleteRecord(table, id, uuidString()); -} + if (m_qxSql == nullptr) { + m_qxSql = new qf::core::sql::QxSql(uuidString(), {}, this); + } + return m_qxSql; +} + +// qint64 Application::createDbRecord(const QString &table, const QVariantMap &record, QObject *source) +// { +// using namespace qf::core::sql; +// QxSql sql; +// connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); +// return sql.createRecord(table, record, uuidString()); +// } + +// std::optional Application::readDbRecord(const QString &table, qint64 id, const std::optional &fields) const +// { +// using namespace qf::core::sql; +// QxSql sql; +// return sql.readRecord(table, id, fields); +// } + +// bool Application::updateDbRecord(const QString &table, qint64 id, const QVariantMap &record, QObject *source) +// { +// using namespace qf::core::sql; +// QxSql sql; +// connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); +// return sql.updateRecord(table, id, record, uuidString()); +// } + +// bool Application::deleteDbRecord(const QString &table, qint64 id, QObject *source) +// { +// using namespace qf::core::sql; +// QxSql sql; +// connect(&sql, &QxSql::dbRecChng, this, [this, source](const qf::core::sql::QxRecChng &recchng) { emit qxRecChng(recchng, source); }); +// return sql.deleteRecord(table, id, uuidString()); +// } QString Application::versionString() const { return QCoreApplication::applicationVersion(); } -void Application::emitDbRecInserted(const QString &table, qint64 id, const QVariantMap &record, QObject *source) -{ - emit qxRecChng(qf::core::sql::QxRecChng{ - .table = table, - .id = id, - .record = record, - .op = qf::core::sql::RecOp::Insert, - .issuer = uuidString() - }, source); -} - -void Application::emitDbRecUpdated(const QString &table, qint64 id, const QVariantMap &record, QObject *source) -{ - emit qxRecChng(qf::core::sql::QxRecChng{ - .table = table, - .id = id, - .record = record, - .op = qf::core::sql::RecOp::Update, - .issuer = uuidString() - }, source); -} - -void Application::emitDbRecDeleted(const QString &table, qint64 id, QObject *source) -{ - emit qxRecChng(qf::core::sql::QxRecChng{ - .table = table, - .id = id, - .record = {}, - .op = qf::core::sql::RecOp::Delete, - .issuer = uuidString() - }, source); -} - -void Application::emitQxRecChng(const core::sql::QxRecChng &recchng, QObject *source) -{ - emit qxRecChng(recchng, source); -} - Application *Application::instance(bool must_exist) { auto *ret = qobject_cast(Super::instance()); diff --git a/libqf/libqfgui/src/framework/application.h b/libqf/libqfgui/src/framework/application.h index 6b3893a8c..513007e7d 100644 --- a/libqf/libqfgui/src/framework/application.h +++ b/libqf/libqfgui/src/framework/application.h @@ -12,6 +12,8 @@ class QQmlEngine; +namespace qf::core::sql { class QxSql; } + namespace qf { namespace gui { namespace framework { @@ -28,15 +30,13 @@ class QFGUI_DECL_EXPORT Application : public QApplication explicit Application(int & argc, char ** argv); ~Application() override = default; - Q_SIGNAL void qxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); - qint64 createDbRecord(const QString &table, const QVariantMap &record, QObject *source); - std::optional readDbRecord(const QString &table, qint64 id, const std::optional &fields = std::nullopt) const; - bool updateDbRecord(const QString &table, qint64 id, const QVariantMap &record, QObject *source); - bool deleteDbRecord(const QString &table, qint64 id, QObject *source); - void emitDbRecInserted(const QString &table, qint64 id, const QVariantMap &record, QObject *source); - void emitDbRecUpdated(const QString &table, qint64 id, const QVariantMap &record, QObject *source); - void emitDbRecDeleted(const QString &table, qint64 id, QObject *source); - void emitQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); + qf::core::sql::QxSql *qxSql(); + + // Q_SIGNAL void qxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); + // qint64 createDbRecord(const QString &table, const QVariantMap &record, QObject *source); + // std::optional readDbRecord(const QString &table, qint64 id, const std::optional &fields = std::nullopt) const; + // bool updateDbRecord(const QString &table, qint64 id, const QVariantMap &record, QObject *source); + // bool deleteDbRecord(const QString &table, qint64 id, QObject *source); Q_INVOKABLE QString versionString() const; public: @@ -53,6 +53,7 @@ class QFGUI_DECL_EXPORT Application : public QApplication static QString uuidString(); protected: MainWindow* m_frameWork = nullptr; + qf::core::sql::QxSql *m_qxSql = nullptr; }; }}} diff --git a/libqf/libqfgui/src/model/sqltablemodel.cpp b/libqf/libqfgui/src/model/sqltablemodel.cpp index 91ff50340..e61a1e0d9 100644 --- a/libqf/libqfgui/src/model/sqltablemodel.cpp +++ b/libqf/libqfgui/src/model/sqltablemodel.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -234,7 +235,7 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) row_ref.setValue(serial_ix, v); row_ref.setDirty(serial_ix, false); if (auto *app = qobject_cast(QApplication::instance()); app) { - app->emitDbRecInserted(table_id, v.value(), record_to_map(rec), this); + app->qxSql()->emitRecInserted(table_id, v.value(), record_to_map(rec), this); } } else { @@ -338,7 +339,7 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) if (num_rows_affected == 1) { if (where_rec.count() == 1) { if (auto *app = qobject_cast(QApplication::instance()); app) { - app->emitDbRecUpdated(table_id, where_rec.value(0).value(), record_to_map(edit_rec), this); + app->qxSql()->emitRecUpdated(table_id, where_rec.value(0).value(), record_to_map(edit_rec), this); } } } @@ -447,7 +448,7 @@ bool SqlTableModel::removeTableRow(int row_no, bool throw_exc) if (num_rows_affected == 1) { if (where_rec.count() == 1) { if (auto *app = qobject_cast(QApplication::instance()); app) { - app->emitDbRecDeleted(table_id, where_rec.value(0).value(), this); + app->qxSql()->emitRecDeleted(table_id, where_rec.value(0).value(), this); } } } else { diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp index 418ecf9dd..9ebf1820b 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -280,7 +281,7 @@ int CardReaderPlugin::saveCardToSql(const quickevent::core::si::ReadCard &read_c {"runIdAssignError", read_card.runIdAssignError()}, {"data", qf::core::Utils::qvariantToJson(read_card.data())}, }; - auto id = app->createDbRecord("cards", rec, this); + auto id = app->qxSql()->createRecord("cards", rec, this); return id; } catch (const std::exception &e) { @@ -333,7 +334,7 @@ int CardReaderPlugin::savePunchRecordToSql(const quickevent::core::si::PunchReco {"timeMs", punch.timems()}, {"runTimeMs", punch.runtimems_isset()? punch.runtimems(): QVariant()}, }; - auto id = app->createDbRecord("punches", rec, this); + auto id = app->qxSql()->createRecord("punches", rec, this); return id; } catch (const std::exception &e) { @@ -406,7 +407,7 @@ void CardReaderPlugin::updateCheckedCardValuesSql(int card_id, const quickevent: {"notStart", false}, {"penaltyTimeMs", {}}, }; - app->updateDbRecord("runs", run_id, rec, this); + app->qxSql()->updateRecord("runs", run_id, rec, this); } if (auto missing_codes = checked_card.missingCodes(); !missing_codes.isEmpty()) { QStringList missing_str; @@ -417,7 +418,7 @@ void CardReaderPlugin::updateCheckedCardValuesSql(int card_id, const quickevent: QVariantMap rec { {"runIdAssignError", missing_str.join(',')}, }; - app->updateDbRecord("cards", card_id, rec, this); + app->qxSql()->updateRecord("cards", card_id, rec, this); } } catch (const std::exception &e) { @@ -463,7 +464,7 @@ bool CardReaderPlugin::saveCardAssignedRunnerIdSql(int card_id, int run_id) {"runId", run_id}, {"runIdAssignTS", QDateTime::currentDateTime()}, }; - app->updateDbRecord("cards", card_id, rec, this); + app->qxSql()->updateRecord("cards", card_id, rec, this); return true; } catch (const std::exception &e) { @@ -540,7 +541,7 @@ void CardReaderPlugin::setStartTime(int relay_id, int leg, int start_time) { {"startTimeMs", start_time}, }; auto run_id = q.value(0).toInt(); - app->updateDbRecord("runs", run_id, rec, this); + app->qxSql()->updateRecord("runs", run_id, rec, this); } catch (const std::exception &e) { qfError() << "setStartTime(): Update runs error, query:" << e.what(); diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 9701c0e10..2c3db126d 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -262,7 +263,7 @@ CardReaderWidget::CardReaderWidget(QWidget *parent) } }, Qt::QueuedConnection); - connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, this, &CardReaderWidget::onQxRecChng, Qt::QueuedConnection); + connect(qf::gui::framework::Application::instance()->qxSql(), &qf::core::sql::QxSql::recChng, this, &CardReaderWidget::onQxRecChng, Qt::QueuedConnection); } CardReaderWidget::~CardReaderWidget() @@ -818,7 +819,7 @@ void CardReaderWidget::assignRunnerToSelectedCard() QVariantMap rec { {"isRunning", true}, }; - app->updateDbRecord("runs", run_id, rec, this); + app->qxSql()->updateRecord("runs", run_id, rec, this); // QString qs = "UPDATE runs SET isRunning=true WHERE competitorId=" QF_IARG(competitor_id) " AND stageId=" QF_IARG(stage_id); // q.execThrow(qs); } @@ -835,7 +836,7 @@ void CardReaderWidget::assignRunnerToSelectedCard() QVariantMap rec { {"siId", si_id}, }; auto run_id = q.value(0).toInt(); if (n++ == 0 || use_si_in_next_stages) { - app->updateDbRecord("runs", run_id, rec, this); + app->qxSql()->updateRecord("runs", run_id, rec, this); } } // QString qs = "UPDATE runs SET siId=" QF_IARG(si_id) " WHERE competitorId=" QF_IARG(competitor_id) " AND stageId=" QF_IARG(stage_id); diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp index 3c678da43..98ed30b64 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -92,7 +93,7 @@ bool CompetitorDocument::saveData() getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, rec}); // new update API auto *app = qf::gui::framework::Application::instance(); - app->emitDbRecInserted( "runs", run_id, rec, this); + app->qxSql()->emitRecInserted( "runs", run_id, rec, this); } } } @@ -103,7 +104,7 @@ bool CompetitorDocument::saveData() auto *app = qf::gui::framework::Application::instance(); QVariantMap rec { {"siId", siid()}, }; for (const auto &[run_id, _] : old_records.asKeyValueRange()) { - app->updateDbRecord("runs", run_id, rec, this); + app->qxSql()->updateRecord("runs", run_id, rec, this); } // int competitor_id = dataId().toInt(); // qf::core::sql::Query q(sqlModel()->connectionName()); @@ -171,7 +172,7 @@ bool CompetitorDocument::dropData() getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, {}}); // new update API auto *app = qf::gui::framework::Application::instance(); - app->emitDbRecDeleted("runs", run_id, this); + app->qxSql()->emitRecDeleted("runs", run_id, this); } } } diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 5eeb13cd8..1a124970e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -194,7 +195,7 @@ EventPlugin::EventPlugin(QObject *parent) setEventOpen(!event_name.isEmpty()); }); connect(this, &Event::EventPlugin::dbEventNotify, this, &Event::EventPlugin::onDbEventNotify, Qt::QueuedConnection); - connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, this, &EventPlugin::onRecChng); + connect(qf::gui::framework::Application::instance()->qxSql(), &qf::core::sql::QxSql::recChng, this, &EventPlugin::onRecChng); } void EventPlugin::initEventConfig() @@ -669,7 +670,7 @@ void EventPlugin::onDbEvent(const QString &name, QSqlDriver::NotificationSource qfWarning() << "RecChng loopback detected, issuer:" << recchng.issuer; return; } - qf::gui::framework::Application::instance()->emitQxRecChng(recchng, this); + qf::gui::framework::Application::instance()->qxSql()->emitRecChng(recchng, this); return; } qfMessage() << "emitting domain:" << domain << "data:" << data; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index be06570b9..6d43c3b4c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -580,18 +580,23 @@ int QxEventService::currentConnectionId() void QxEventService::onBrokerConnectedChanged(bool is_connected) { if(is_connected) { + auto *event_plugin = getPlugin(); + auto current_stage = event_plugin->currentStageId(); + auto stage_data = event_plugin->stageData(current_stage); + auto api_token = stage_data.qxApiToken().toStdString(); auto *rpc_call = shv::iotqt::rpc::RpcCall::create(m_rpcConnection) - ->setShvPath(".broker/currentClient") - ->setMethod("info"); + ->setShvPath("test/qx/qxeventd/eventctl") + ->setMethod("openEventApiKey") + ->setParams(RpcValue(api_token)); connect(rpc_call, &shv::iotqt::rpc::RpcCall::maybeResult, this, [this](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { if (error.isValid()) { setStatus(Status::Stopped); setStatusMessage(tr("Client info discovery error: %1").arg(error.toString())); } else { - const auto &info = result.asMap(); - m_eventMountPoint = info.value("mountPoint").to(); - m_eventId = m_eventMountPoint.section('/', -1, -1).toInt(); + const auto &info = result.asList(); + m_eventId = info.value(0).toInt(); + m_eventMountPoint = info.value(1).to(); setStatus(Status::Running); setStatusMessage(tr("Event ID: %1").arg(m_eventId)); subscribeChanges(); @@ -647,19 +652,19 @@ void QxEventService::sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg) void QxEventService::subscribeChanges() { - Q_ASSERT(m_rpcConnection); - QString shv_path = "test"; - QString signal_name = shv::chainpack::Rpc::SIG_VAL_CHANGED; - auto *rpc_call = RpcCall::createSubscriptionRequest(m_rpcConnection, shv_path, signal_name); - connect(rpc_call, &RpcCall::maybeResult, this, [shv_path, signal_name](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { - if(error.isValid()) { - qfError() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribe error:" << error.toString(); - } - else { - qfMessage() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribed successfully" << result.toCpon(); - } - }); - rpc_call->start(); + // Q_ASSERT(m_rpcConnection); + // QString shv_path = "test"; + // QString signal_name = shv::chainpack::Rpc::SIG_VAL_CHANGED; + // auto *rpc_call = RpcCall::createSubscriptionRequest(m_rpcConnection, shv_path, signal_name); + // connect(rpc_call, &RpcCall::maybeResult, this, [shv_path, signal_name](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { + // if(error.isValid()) { + // qfError() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribe error:" << error.toString(); + // } + // else { + // qfMessage() << "Signal:" << signal_name << "on SHV path:" << shv_path << "subscribed successfully" << result.toCpon(); + // } + // }); + // rpc_call->start(); } // void QxEventService::sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index e18c89d97..9e4b5845f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -63,7 +63,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin return res.toRpcValue(); } if(method == METH_QUERY) { - auto res = m_sqlApi->exec(SqlQueryAndParams::fromRpcValue(params)); + auto res = m_sqlApi->query(SqlQueryAndParams::fromRpcValue(params)); return res.toRpcValue(); } if(method == METH_TRANSACTION) { diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 52b93fad2..ab322c97c 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -51,7 +52,7 @@ RunsTableModel::RunsTableModel(QObject *parent) setColumn(col_competitors_note, ColumnDefinition("competitors.note", tr("Note"))); connect(this, &RunsTableModel::dataChanged, this, &RunsTableModel::onDataChanged, Qt::QueuedConnection); - connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, this, &RunsTableModel::onQxRecChng, Qt::QueuedConnection); + connect(qf::gui::framework::Application::instance()->qxSql(), &qf::core::sql::QxSql::recChng, this, &RunsTableModel::onQxRecChng, Qt::QueuedConnection); } Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const diff --git a/quickevent/app/quickevent/src/main.cpp b/quickevent/app/quickevent/src/main.cpp index 3e6036e3d..efb9704a4 100644 --- a/quickevent/app/quickevent/src/main.cpp +++ b/quickevent/app/quickevent/src/main.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -189,7 +190,7 @@ int main(int argc, char *argv[]) main_window.show(); emit main_window.applicationLaunched(); - QObject::connect(&app, &Application::qxRecChng, &app, [](const qf::core::sql::QxRecChng &recchng) { + QObject::connect(app.qxSql(), &qf::core::sql::QxSql::recChng, &app, [](const qf::core::sql::QxRecChng &recchng) { auto dump_map = [](const QVariantMap &m) { QStringList rows; for (const auto &[k, v] : m.asKeyValueRange()) { From 1dac94131922177ef3652062fd97cacc2cebefc5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 8 Jun 2026 21:02:07 +0200 Subject: [PATCH 31/83] Change qxchanges table structure, QE 3.6.0 --- libqf/libqfcore/src/sql/qxsql.cpp | 77 +++- libqf/libqfcore/src/sql/qxsql.h | 31 +- quickevent/app/quickevent/CMakeLists.txt | 2 +- .../quickevent/plugins/Event/qml/DbSchema.qml | 14 +- .../plugins/Event/sql/create_db_psql.sql | 10 +- .../plugins/Event/sql/create_db_sqlite.sql | 10 +- ...ionswidget.cpp => qxlateentrieswidget.cpp} | 50 +- ...trationswidget.h => qxlateentrieswidget.h} | 10 +- ...ationswidget.ui => qxlateentrieswidget.ui} | 4 +- .../plugins/Event/src/services/qx/sqlapi.cpp | 428 +++++------------- .../plugins/Event/src/services/qx/sqlapi.h | 51 +-- .../Event/src/services/qx/sqlapinode.cpp | 8 +- .../plugins/Runs/src/runsplugin.cpp | 12 +- quickevent/app/quickevent/src/appversion.h | 2 +- 14 files changed, 289 insertions(+), 420 deletions(-) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxlateregistrationswidget.cpp => qxlateentrieswidget.cpp} (84%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxlateregistrationswidget.h => qxlateentrieswidget.h} (75%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{qxlateregistrationswidget.ui => qxlateentrieswidget.ui} (96%) diff --git a/libqf/libqfcore/src/sql/qxsql.cpp b/libqf/libqfcore/src/sql/qxsql.cpp index 11601fa32..dac711b02 100644 --- a/libqf/libqfcore/src/sql/qxsql.cpp +++ b/libqf/libqfcore/src/sql/qxsql.cpp @@ -1,6 +1,8 @@ #include "qxsql.h" #include +#include +#include #include #include @@ -11,6 +13,49 @@ namespace qf::core::sql { //================================================================ // QxSqlApi //================================================================ +namespace { + +class Transaction +{ +public: + Transaction(QSqlDatabase db) : m_db(db) { + if (!m_db.transaction()) { + qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); + throw std::runtime_error("BEGIN transaction error"); + } + } + ~Transaction() { + if (m_inTransaction) { + m_db.rollback(); + } + } + void commit() { + if (!m_db.commit()) { + qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); + throw std::runtime_error("COMMIT transaction error"); + } + m_inTransaction = false; + } +private: + QSqlDatabase m_db; + bool m_inTransaction = true; +}; +} +void QxSqlApi::transaction(const QString &query, const QVariantList ¶ms, QSqlDatabase db) +{ + Transaction transaction(db); + qf::core::sql::Query q(db); + q.prepare(query, qf::core::Exception::Throw); + for (const auto ¶m : params) { + auto m = param.toMap(); + for (const auto &[k, v] : m.asKeyValueRange()) { + q.bindValue(':' + k, v); + } + q.exec(qf::core::Exception::Throw); + } + transaction.commit(); +} + qint64 QxSqlApi::createRecord(const QString &table, const Record &record, const QString &issuer) { Q_UNUSED(issuer) @@ -63,7 +108,7 @@ bool QxSqlApi::updateRecord(const QString &table, qint64 id, const Record &recor .arg(table, keyVals.join(", "), QString::number(id)); ExecResult res = exec(qs, record); - return res.rowsAffected == 1; + return res.numRowsAffected == 1; } bool QxSqlApi::deleteRecord(const QString &table, qint64 id, const QString &issuer) @@ -72,7 +117,7 @@ bool QxSqlApi::deleteRecord(const QString &table, qint64 id, const QString &issu QString qs = QString("DELETE FROM %1 WHERE id = %2").arg(table, QString::number(id)); ExecResult res = exec(qs, {}); - return res.rowsAffected == 1; + return res.numRowsAffected == 1; } QList QxSqlApi::listOneOrMoreRecords(const QString &table, const std::optional &fields, const std::optional &id, const std::optional &limit) @@ -110,6 +155,7 @@ QList QxSqlApi::listOneOrMoreRecords(const QString &table, const std::op //================================================================ QueryResult QxSqlApiImpl::query(const QString &query, const QVariantMap ¶ms) { + // qDebug() << query << params; QSqlQuery q(m_db); q.prepare(query); for (const auto &[key, val] : params.asKeyValueRange()) { @@ -120,7 +166,7 @@ QueryResult QxSqlApiImpl::query(const QString &query, const QVariantMap ¶ms) } QueryResult result; for (int i = 0; i < q.record().count(); ++i) { - result.columns.append(q.record().fieldName(i).toLower()); + result.fields.append(DbField{.name = q.record().fieldName(i).toLower()}); } while (q.next()) { QList row; @@ -143,10 +189,18 @@ ExecResult QxSqlApiImpl::exec(const QString &query, const QVariantMap ¶ms) throw qf::core::Exception(q.lastError().text()); } ExecResult result; - result.rowsAffected = q.numRowsAffected(); + result.numRowsAffected = q.numRowsAffected(); + if (auto id = q.lastInsertId().toLongLong(); id > 0) { + result.lastInsertId = id; + } return result; } +void QxSqlApiImpl::transaction(const QString &query, const QVariantList ¶ms) +{ + QxSqlApi::transaction(query, params, m_db); +} + //================================================================ // QxSql //================================================================ @@ -167,6 +221,16 @@ ExecResult QxSql::exec(const QString &query, const QVariantMap ¶ms) return m_sqlApi.exec(query, params); } +QList QxSql::listRecords(const QString &table, const std::optional &fields, const std::optional &fromId, const std::optional &limit) +{ + return m_sqlApi.listRecords(table, fields, fromId, limit); +} + +void QxSql::transaction(const QString &query, const QVariantList ¶ms) +{ + m_sqlApi.transaction(query, params); +} + qint64 QxSql::createRecord(const QString &table, const Record &record, QObject *source) { auto id = m_sqlApi.createRecord(table, record, m_issuer); @@ -179,6 +243,11 @@ qint64 QxSql::createRecord(const QString &table, const Record &record, QObject * return id; } +std::optional QxSql::readRecord(const QString &table, qint64 id, const std::optional &fields) +{ + return m_sqlApi.readRecord(table, id, fields); +} + bool QxSql::updateRecord(const QString &table, qint64 id, const Record &record, QObject *source) { auto ok = m_sqlApi.updateRecord(table, id, record, m_issuer); diff --git a/libqf/libqfcore/src/sql/qxsql.h b/libqf/libqfcore/src/sql/qxsql.h index c1f6101f3..04d493eeb 100644 --- a/libqf/libqfcore/src/sql/qxsql.h +++ b/libqf/libqfcore/src/sql/qxsql.h @@ -15,9 +15,14 @@ namespace qf::core::sql { using Record = QVariantMap; +struct DbField +{ + QString name; +}; + struct QFCORE_DECL_EXPORT QueryResult { - QStringList columns; + QList fields; QList> rows; std::optional record(int i) const @@ -27,8 +32,8 @@ struct QFCORE_DECL_EXPORT QueryResult } Record r; const auto &row = rows[i]; - for (int j = 0; j < columns.size(); ++j) { - r[columns[j]] = row.value(j); + for (int j = 0; j < fields.size(); ++j) { + r[fields[j].name] = row.value(j); } return r; } @@ -36,7 +41,8 @@ struct QFCORE_DECL_EXPORT QueryResult struct QFCORE_DECL_EXPORT ExecResult { - qint64 rowsAffected = 0; + qint64 numRowsAffected = 0; + std::optional lastInsertId = 0; }; class QFCORE_DECL_EXPORT QxSqlApi @@ -54,11 +60,12 @@ class QFCORE_DECL_EXPORT QxSqlApi { return listOneOrMoreRecords(table, fields, fromId, limit); } + void transaction(const QString &query, const QVariantList ¶ms, QSqlDatabase db); - virtual qint64 createRecord(const QString &table, const Record &record, const QString &issuer); - virtual std::optional readRecord(const QString &table, qint64 id, const std::optional &fields = std::nullopt); - virtual bool updateRecord(const QString &table, qint64 id, const Record &record, const QString &issuer); - virtual bool deleteRecord(const QString &table, qint64 id, const QString &issuer); + qint64 createRecord(const QString &table, const Record &record, const QString &issuer); + std::optional readRecord(const QString &table, qint64 id, const std::optional &fields = std::nullopt); + bool updateRecord(const QString &table, qint64 id, const Record &record, const QString &issuer); + bool deleteRecord(const QString &table, qint64 id, const QString &issuer); protected: QList listOneOrMoreRecords( const QString &table, @@ -74,6 +81,7 @@ class QxSqlApiImpl : public QxSqlApi QueryResult query(const QString &query, const QVariantMap ¶ms) override; ExecResult exec(const QString &query, const QVariantMap ¶ms) override; + void transaction(const QString &query, const QVariantList ¶ms); private: QSqlDatabase m_db; }; @@ -89,8 +97,15 @@ class QFCORE_DECL_EXPORT QxSql : public QObject QueryResult query(const QString &query, const QVariantMap ¶ms); ExecResult exec(const QString &query, const QVariantMap ¶ms); + QList listRecords( + const QString &table, + const std::optional &fields = std::nullopt, + const std::optional &fromId = std::nullopt, + const std::optional &limit = std::nullopt); + void transaction(const QString &query, const QVariantList ¶ms); qint64 createRecord(const QString &table, const Record &record, QObject *source); + std::optional readRecord(const QString &table, qint64 id, const std::optional &fields = std::nullopt); bool updateRecord(const QString &table, qint64 id, const Record &record, QObject *source); bool deleteRecord(const QString &table, qint64 id, QObject *source); diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 94fbaec8c..bd86ad635 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -99,7 +99,7 @@ add_executable(quickevent plugins/Event/src/services/qx/nodes.cpp plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h plugins/Event/src/services/qx/qxeventservicewidget.ui - plugins/Event/src/services/qx/qxlateregistrationswidget.h plugins/Event/src/services/qx/qxlateregistrationswidget.cpp plugins/Event/src/services/qx/qxlateregistrationswidget.ui + plugins/Event/src/services/qx/qxlateentrieswidget.h plugins/Event/src/services/qx/qxlateentrieswidget.cpp plugins/Event/src/services/qx/qxlateentrieswidget.ui plugins/Event/src/services/qx/runchangedialog.h plugins/Event/src/services/qx/runchangedialog.cpp plugins/Event/src/services/qx/runchangedialog.ui plugins/Event/src/services/qx/runchange.h plugins/Event/src/services/qx/runchange.cpp diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index c06846d00..55222da4a 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -494,22 +494,26 @@ Schema { fields: [ Field { name: 'id'; type: Serial { primaryKey: true } }, Field { name: 'stage_id'; type: Int { } }, - Field { name: 'change_id'; type: Int { } }, - Field { name: 'data_id'; type: Int { } }, + // Field { name: 'change_id'; type: Int { } }, // not used + Field { name: 'data_id'; type: Int { } }, // not used Field { name: 'data_type'; type: String { } }, Field { name: 'data'; type: String { } }, Field { name: 'orig_data'; type: String { } comment: 'Store data overriden by change here to enable change rollback.' }, - Field { name: 'source'; type: String { } }, + Field { name: 'source'; type: String { } }, // issuer Field { name: 'user_id'; type: String { } }, Field { name: 'status'; type: String { } }, Field { name: 'status_message'; type: String { } }, - Field { name: 'created'; type: DateTime { } }, + Field { name: 'created'; type: DateTime { } + notNull: true + defaultValue: 'CURRENT_TIMESTAMP' + }, Field { name: 'lock_number'; type: Int { } } ] indexes: [ - Index {fields: ['stage_id', 'change_id']; unique: true } + Index {fields: ['data_type', 'data_id']; unique: false }, + Index {fields: ['status']; unique: false } ] } ] diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql index 93a1837cb..f294be580 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql @@ -290,7 +290,6 @@ CREATE TABLE {{eventId}}.lentcards ( CREATE TABLE {{eventId}}.qxchanges ( id serial PRIMARY KEY, stage_id integer, - change_id integer, data_id integer, data_type character varying, data character varying, @@ -299,10 +298,11 @@ CREATE TABLE {{eventId}}.qxchanges ( user_id character varying, status character varying, status_message character varying, - created timestamp with time zone, - lock_number integer, - CONSTRAINT qxchanges_unique0 UNIQUE (stage_id, change_id) + created timestamp with time zone NOT NULL DEFAULT 'CURRENT_TIMESTAMP', + lock_number integer ); +CREATE INDEX qxchanges_ix0 ON {{eventId}}.qxchanges (data_type, data_id); +CREATE INDEX qxchanges_ix1 ON {{eventId}}.qxchanges (status); COMMENT ON COLUMN {{eventId}}.qxchanges.orig_data IS 'Store data overriden by change here to enable change rollback.'; ; ------------------------------------; @@ -311,4 +311,4 @@ COMMENT ON COLUMN {{eventId}}.qxchanges.orig_data IS 'Store data overriden by ch ; -- insert into table: {{eventId}}.config; INSERT INTO {{eventId}}.config (ckey, cname, cvalue, ctype) VALUES -('db.version', 'Data version', '30500', 'int'); +('db.version', 'Data version', '30600', 'int'); diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql index f358a6663..f4f050f6d 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql @@ -317,7 +317,6 @@ CREATE TABLE lentcards ( CREATE TABLE qxchanges ( id integer PRIMARY KEY, stage_id integer, - change_id integer, data_id integer, data_type character varying, data character varying, @@ -326,10 +325,11 @@ CREATE TABLE qxchanges ( user_id character varying, status character varying, status_message character varying, - created timestamp, - lock_number integer, - CONSTRAINT qxchanges_unique0 UNIQUE (stage_id, change_id) + created timestamp NOT NULL DEFAULT 'CURRENT_TIMESTAMP', + lock_number integer ); +CREATE INDEX qxchanges_ix0 ON qxchanges (data_type, data_id); +CREATE INDEX qxchanges_ix1 ON qxchanges (status); -- comments not suported for driver: SQLITE -- COMMENT ON COLUMN qxchanges.orig_data IS 'Store data overriden by change here to enable change rollback.'; ; @@ -339,4 +339,4 @@ CREATE TABLE qxchanges ( ; -- insert into table: config; INSERT INTO config (ckey, cname, cvalue, ctype) VALUES -('db.version', 'Data version', '30500', 'int'); +('db.version', 'Data version', '30600', 'int'); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp similarity index 84% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index 083af5d69..b596faa15 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -1,5 +1,5 @@ -#include "qxlateregistrationswidget.h" -#include "ui_qxlateregistrationswidget.h" +#include "qxlateentrieswidget.h" +#include "ui_qxlateentrieswidget.h" #include "qxeventservice.h" #include "runchangedialog.h" @@ -42,18 +42,18 @@ constexpr auto DATA_TYPE_RUN_UPDATE_REQUEST = "RunUpdateRequest"; constexpr auto SOURCE_WWW = "www"; -QxLateRegistrationsWidget::QxLateRegistrationsWidget(QWidget *parent) : +QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : QWidget(parent), - ui(new Ui::QxLateRegistrationsWidget) + ui(new Ui::QxLateEntriesWidget) { ui->setupUi(this); ui->tableView->setReadOnly(true); ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->tableView, &qfw::TableView::customContextMenuRequested, this, &QxLateRegistrationsWidget::onTableCustomContextMenuRequest); - connect(ui->tableView, &qfw::TableView::doubleClicked, this, &QxLateRegistrationsWidget::onTableDoubleClicked); + connect(ui->tableView, &qfw::TableView::customContextMenuRequested, this, &QxLateEntriesWidget::onTableCustomContextMenuRequest); + connect(ui->tableView, &qfw::TableView::doubleClicked, this, &QxLateEntriesWidget::onTableDoubleClicked); - ui->tableView->setPersistentSettingsId("tblQxLateRegistrations"); + ui->tableView->setPersistentSettingsId("tblQxLateEntries"); ui->tableView->setInsertRowEnabled(false); ui->tableView->setCloneRowEnabled(false); ui->tableView->setRemoveRowEnabled(false); @@ -93,7 +93,7 @@ QxLateRegistrationsWidget::QxLateRegistrationsWidget(QWidget *parent) : } }); - connect(getPlugin(), &Event::EventPlugin::dbEventNotify, this, &QxLateRegistrationsWidget::onDbEventNotify, Qt::QueuedConnection); + connect(getPlugin(), &Event::EventPlugin::dbEventNotify, this, &QxLateEntriesWidget::onDbEventNotify, Qt::QueuedConnection); { auto *lst = ui->lstType; @@ -104,13 +104,13 @@ QxLateRegistrationsWidget::QxLateRegistrationsWidget(QWidget *parent) : lst->addItem("RadioPunch"); lst->addItem("CardReadout"); lst->setCurrentIndex(0); - connect(lst, &QComboBox::currentIndexChanged, this, &QxLateRegistrationsWidget::reload); + connect(lst, &QComboBox::currentIndexChanged, this, &QxLateEntriesWidget::reload); } - connect(ui->chkNull, &QCheckBox::checkStateChanged, this, &QxLateRegistrationsWidget::reload); - connect(ui->chkPending, &QCheckBox::checkStateChanged, this, &QxLateRegistrationsWidget::reload); - connect(ui->chkLocked, &QCheckBox::checkStateChanged, this, &QxLateRegistrationsWidget::reload); - connect(ui->chkAccepted, &QCheckBox::checkStateChanged, this, &QxLateRegistrationsWidget::reload); - connect(ui->chkRejected, &QCheckBox::checkStateChanged, this, &QxLateRegistrationsWidget::reload); + connect(ui->chkNull, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); + connect(ui->chkPending, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); + connect(ui->chkLocked, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); + connect(ui->chkAccepted, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); + connect(ui->chkRejected, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); connect(ui->btAll, &QPushButton::clicked, this, [this]() { QSignalBlocker sb1(ui->lstType); @@ -131,12 +131,12 @@ QxLateRegistrationsWidget::QxLateRegistrationsWidget(QWidget *parent) : }); } -QxLateRegistrationsWidget::~QxLateRegistrationsWidget() +QxLateEntriesWidget::~QxLateEntriesWidget() { delete ui; } -void QxLateRegistrationsWidget::onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload) +void QxLateEntriesWidget::onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload) { Q_UNUSED(connection_id) if(domain == QLatin1String(Event::EventPlugin::DBEVENT_QX_CHANGE_RECEIVED)) { @@ -145,27 +145,27 @@ void QxLateRegistrationsWidget::onDbEventNotify(const QString &domain, int conne } } -void QxLateRegistrationsWidget::onVisibleChanged(bool is_visible) +void QxLateEntriesWidget::onVisibleChanged(bool is_visible) { if (is_visible && isEnabled()) { reload(); } } -QxEventService *QxLateRegistrationsWidget::service() +QxEventService *QxLateEntriesWidget::service() { auto *svc = qobject_cast(Event::services::Service::serviceByName(QxEventService::serviceId())); Q_ASSERT(svc); return svc; } -void QxLateRegistrationsWidget::resizeColumns() +void QxLateEntriesWidget::resizeColumns() { auto *tv = ui->tableView; tv->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); } -void QxLateRegistrationsWidget::showMessage(const QString &msg, bool is_error) +void QxLateEntriesWidget::showMessage(const QString &msg, bool is_error) { if (msg.isEmpty()) { ui->lblErrorMsg->hide(); @@ -182,7 +182,7 @@ void QxLateRegistrationsWidget::showMessage(const QString &msg, bool is_error) ui->lblErrorMsg->setText(msg); } -void QxLateRegistrationsWidget::reload() +void QxLateEntriesWidget::reload() { if(!isEnabled()) { return; @@ -225,7 +225,7 @@ void QxLateRegistrationsWidget::reload() m_model->reload(); } -void QxLateRegistrationsWidget::addQxChangeRow(int sql_id) +void QxLateEntriesWidget::addQxChangeRow(int sql_id) { qfDebug() << "reloading qxchanges row id:" << sql_id << "col id:" << COL_ID; if(sql_id <= 0) { @@ -251,7 +251,7 @@ void QxLateRegistrationsWidget::addQxChangeRow(int sql_id) } -void QxLateRegistrationsWidget::applyCurrentChange() +void QxLateEntriesWidget::applyCurrentChange() { auto row = ui->tableView->currentIndex().row(); if (row < 0) { @@ -267,7 +267,7 @@ void QxLateRegistrationsWidget::applyCurrentChange() } -void QxLateRegistrationsWidget::onTableCustomContextMenuRequest(const QPoint &pos) +void QxLateEntriesWidget::onTableCustomContextMenuRequest(const QPoint &pos) { QAction a_neco(tr("Neco"), nullptr); QList lst; @@ -278,7 +278,7 @@ void QxLateRegistrationsWidget::onTableCustomContextMenuRequest(const QPoint &po } } -void QxLateRegistrationsWidget::onTableDoubleClicked(const QModelIndex &ix) +void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { auto row = ix.row(); auto data_type = m_model->value(row, COL_DATA_TYPE).toString(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h similarity index 75% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h index ea906b649..2caed12b8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h @@ -7,18 +7,18 @@ namespace qf::gui::model { class SqlTableModel; } namespace Event::services::qx { namespace Ui { -class QxLateRegistrationsWidget; +class QxLateEntriesWidget; } class QxEventService; -class QxLateRegistrationsWidget : public QWidget +class QxLateEntriesWidget : public QWidget { Q_OBJECT public: - explicit QxLateRegistrationsWidget(QWidget *parent = nullptr); - ~QxLateRegistrationsWidget() override; + explicit QxLateEntriesWidget(QWidget *parent = nullptr); + ~QxLateEntriesWidget() override; void onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload); void onVisibleChanged(bool is_visible); @@ -35,7 +35,7 @@ class QxLateRegistrationsWidget : public QWidget void onTableDoubleClicked(const QModelIndex &ix); private: - Ui::QxLateRegistrationsWidget *ui; + Ui::QxLateEntriesWidget *ui; qf::gui::model::SqlTableModel *m_model; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui similarity index 96% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.ui rename to quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui index 07bf69ed4..70e933293 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateregistrationswidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui @@ -1,7 +1,7 @@ - Event::services::qx::QxLateRegistrationsWidget - + Event::services::qx::QxLateEntriesWidget + 0 diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp index 859e29c82..3e99c1e50 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp @@ -1,6 +1,7 @@ #include "sqlapi.h" #include +#include #include #include #include @@ -21,116 +22,30 @@ using namespace shv::chainpack; namespace Event::services::qx { -//============================================== -// RpcSqlField -//============================================== -RpcValue DbField::toRpcValue() const +RpcValue dbFieldToRpcValue(const DbField &fld) { RpcValue::Map ret; - ret["name"] = name.toStdString(); + ret["name"] = fld.name.toStdString(); return RpcValue(std::move(ret)); } -DbField DbField::fromRpcValue(const shv::chainpack::RpcValue &rv) -{ - DbField ret; - const RpcValue::Map &map = rv.asMap(); - ret.name = QString::fromStdString(map.value("name").asString()); - return ret; -} - -//============================================== -// ExecResult -//============================================== -RpcValue ExecResult::toRpcValue() const +RpcValue execResultToRpcValue(const ExecResult &res) { RpcValue::Map ret; - ret["numRowsAffected"] = numRowsAffected; - ret["lastInsertId"] = lastInsertId.has_value()? RpcValue(lastInsertId.value()): RpcValue(nullptr); - return ret; -} - -ExecResult ExecResult::fromRpcValue(const shv::chainpack::RpcValue &rv) -{ - ExecResult ret; - const auto &map = rv.asMap(); - ret.numRowsAffected = map.value("numRowsAffected").toInt(); - ret.lastInsertId = map.value("lastInsertId").toInt(); - return ret; -} - -//============================================== -// QueryResult -//============================================== -QVariant QueryResult::value(qsizetype row, qsizetype col) const -{ - if (row < rows.size()) { - const auto &cells = rows[row]; - if (col < cells.size()) { - return cells[col]; - } - } - return {}; -} - -QVariant QueryResult::value(qsizetype row, const std::string &name) const -{ - if (auto ix = columnIndex(name); ix.has_value()) { - return value(row, ix.value()); - } - return {}; -} - -void QueryResult::setValue(qsizetype row, qsizetype col, const QVariant &val) -{ - if (row < rows.size()) { - auto &r = rows[row]; - if (col < r.size()) { - r[col] = val; - } - } -} - -void QueryResult::setValue(qsizetype row, const std::string &name, const QVariant &val) -{ - if (auto ix = columnIndex(name); ix.has_value()) { - setValue(row, ix.value(), val); - } -} - -RpcValue::List QueryResult::toRecordList() const -{ - RpcValue::List ret; - for (const auto &row : rows) { - RpcValue::Map rec; - int n = 0; - for (const auto &field : fields) { - rec[field.name.toStdString()] = shv::coreqt::rpc::qVariantToRpcValue(row.value(n++)); - } - ret.push_back(rec); - } + ret["numRowsAffected"] = res.numRowsAffected; + ret["lastInsertId"] = res.lastInsertId.has_value()? RpcValue(res.lastInsertId.value()): RpcValue(nullptr); return ret; } -std::optional QueryResult::columnIndex(const std::string &name) const -{ - for (size_t col = 0; col < fields.size(); ++col) { - const auto &fld = fields[col]; - if (fld.name.toStdString() == name) { - return col; - } - } - return {}; -} - -RpcValue QueryResult::toRpcValue() const +RpcValue queryResultToRpcValue(const QueryResult &res) { RpcValue::Map ret; RpcValue::List flds; - for(const auto &fld : this->fields) - flds.push_back(fld.toRpcValue()); + for(const auto &fld : res.fields) { + flds.push_back(dbFieldToRpcValue(fld)); + } RpcValue::List rpc_rows; - for (const auto &row : rows) { + for (const auto &row : res.rows) { RpcValue::List rpc_row; for (const auto &cell : row) { rpc_row.push_back(shv::coreqt::rpc::qVariantToRpcValue(cell)); @@ -142,23 +57,24 @@ RpcValue QueryResult::toRpcValue() const return ret; } -QueryResult QueryResult::fromRpcValue(const RpcValue &rv) +namespace { +RpcValue::List toShvRecordList(const QList &records) { - QueryResult ret; - const auto &map = rv.asMap(); - const auto &flds = map.valref("fields").asList(); - for(const auto &fv : flds) { - ret.fields.push_back(DbField::fromRpcValue(fv)); - } - for (const auto &rpc_row : map.value("rows").asList()) { - QueryResult::Row row; - for (const auto &cell : rpc_row.asList()) { - row.push_back(shv::coreqt::rpc::rpcValueToQVariant(cell)); - } - ret.rows.push_back(row); + RpcValue::List ret; + for (const auto &rec : records) { + ret.push_back(shv::coreqt::rpc::qVariantToRpcValue(rec)); } return ret; } +QStringList toQStringList(const std::vector &sl) +{ + QStringList qsl; + for (const auto &s : sl) { + qsl << QString::fromStdString(s); + } + return qsl; +} +} SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue &rv) { @@ -168,7 +84,6 @@ SqlQueryAndParams SqlQueryAndParams::fromRpcValue(const shv::chainpack::RpcValue return SqlQueryAndParams { .query = sql_query, .params = shv::coreqt::rpc::rpcValueToQVariant(sql_params).toMap() }; } - RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng) { auto m = chng.toVariantMap(); @@ -190,131 +105,110 @@ SqlApi::SqlApi(QObject *parent) // emit recchng(chng); // } -namespace { - -class Transaction -{ -public: - Transaction(QSqlDatabase db) : m_db(db) { - if (!m_db.transaction()) { - qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); - throw std::runtime_error("BEGIN transaction error"); - } - } - ~Transaction() { - if (m_inTransaction) { - m_db.rollback(); - } - } - void commit() { - if (!m_db.commit()) { - qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); - throw std::runtime_error("COMMIT transaction error"); - } - m_inTransaction = false; - } -private: - QSqlDatabase m_db; - bool m_inTransaction = true; -}; +// namespace { -void bindParams(qf::core::sql::Query &q, const Record ¶ms) -{ - for (const auto &[k, v] : params.asKeyValueRange()) { - q.bindValue(':' + k, v); - } -} +// class Transaction +// { +// public: +// Transaction(QSqlDatabase db) : m_db(db) { +// if (!m_db.transaction()) { +// qfWarning() << "BEGIN transaction error:" << m_db.lastError().text(); +// throw std::runtime_error("BEGIN transaction error"); +// } +// } +// ~Transaction() { +// if (m_inTransaction) { +// m_db.rollback(); +// } +// } +// void commit() { +// if (!m_db.commit()) { +// qfWarning() << "COMMIT transaction error:" << m_db.lastError().text(); +// throw std::runtime_error("COMMIT transaction error"); +// } +// m_inTransaction = false; +// } +// private: +// QSqlDatabase m_db; +// bool m_inTransaction = true; +// }; + +// void bindParams(qf::core::sql::Query &q, const Record ¶ms) +// { +// for (const auto &[k, v] : params.asKeyValueRange()) { +// q.bindValue(':' + k, v); +// } +// } -QueryResult sqlQuery(const SqlQueryAndParams ¶ms) -{ - qf::core::sql::Query q; - q.prepare(params.query, qf::core::Exception::Throw); - bindParams(q, params.params); - q.exec(qf::core::Exception::Throw); - - QueryResult ret; - QSqlRecord rec = q.record(); - for (int i = 0; i < rec.count(); ++i) { - QSqlField fld = rec.field(i); - DbField rfld; - rfld.name = fld.name(); - // rfld.name.replace("__", "."); - ret.fields.push_back(rfld); - } - while(q.next()) { - QueryResult::Row row; - for (int i = 0; i < rec.count(); ++i) { - row.push_back(q.value(i)); - //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); - } - ret.rows.insert(ret.rows.size(), row); - } - return ret; -} +// QueryResult sqlQuery(const SqlQueryAndParams ¶ms) +// { +// qf::core::sql::Query q; +// q.prepare(params.query, qf::core::Exception::Throw); +// bindParams(q, params.params); +// q.exec(qf::core::Exception::Throw); + +// QueryResult ret; +// QSqlRecord rec = q.record(); +// for (int i = 0; i < rec.count(); ++i) { +// QSqlField fld = rec.field(i); +// DbField rfld; +// rfld.name = fld.name(); +// // rfld.name.replace("__", "."); +// ret.fields.push_back(rfld); +// } +// while(q.next()) { +// QueryResult::Row row; +// for (int i = 0; i < rec.count(); ++i) { +// row.push_back(q.value(i)); +// //shvError() << v << v.isNull() << jsv.toVariant() << jsv.toVariant().isNull(); +// } +// ret.rows.insert(ret.rows.size(), row); +// } +// return ret; +// } -ExecResult sqlExec(const SqlQueryAndParams ¶ms) -{ - qf::core::sql::Query q; - q.prepare(params.query, qf::core::Exception::Throw); - bindParams(q, params.params); - q.exec(qf::core::Exception::Throw); - - ExecResult ret; - ret.numRowsAffected = q.numRowsAffected(); - ret.lastInsertId = q.lastInsertId().toInt(); - return ret; -} +// ExecResult sqlExec(const SqlQueryAndParams ¶ms) +// { +// qf::core::sql::Query q; +// q.prepare(params.query, qf::core::Exception::Throw); +// bindParams(q, params.params); +// q.exec(qf::core::Exception::Throw); + +// ExecResult ret; +// ret.numRowsAffected = q.numRowsAffected(); +// ret.lastInsertId = q.lastInsertId().toInt(); +// return ret; +// } -} +// } ExecResult SqlApi::exec(const SqlQueryAndParams ¶ms) { - return sqlExec(params); + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + return qxsql->exec(params.query, params.params); } QueryResult SqlApi::query(const SqlQueryAndParams ¶ms) { - return sqlQuery(params); + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + return qxsql->query(params.query, params.params); } void SqlApi::transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms) { - auto conn = qf::core::sql::Connection::forName(); - Transaction tranaction(conn); - qf::core::sql::Query q(conn); - q.prepare(QString::fromUtf8(query), qf::core::Exception::Throw); - for (const auto ¶m : params) { - for (const auto &[k, v] : param.asMap()) { - bool ok; - QVariant val = shv::coreqt::rpc::rpcValueToQVariant(v, &ok); - if (!ok) { - QF_EXCEPTION(QStringLiteral("Cannot convert SHV type: %1 to QVariant").arg(v.typeName())); - } - q.bindValue(':' + QString::fromStdString(k), val); - } - q.exec(qf::core::Exception::Throw); + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + QVariantList qparams; + for (const auto &p : params) { + qparams << shv::coreqt::rpc::rpcValueToQVariant(p); } - tranaction.commit(); + return qxsql->transaction(QString::fromStdString(query), qparams); } -QueryResult SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) +RpcValue::List SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) { - QStringList qfields; - for (const auto &fn : fields) { - qfields << QString::fromStdString(fn); - } - if (qfields.isEmpty()) { - qfields << "*"; - } - QString sql_query = QStringLiteral("SELECT %1 FROM %2").arg(qfields.join(',')).arg(QString::fromStdString(table)); - if (ids_above.has_value()) { - sql_query += " WHERE id > " + QString::number(ids_above.value()); - } - if (limit.has_value()) { - sql_query += " LIMIT " + QString::number(limit.value()); - } - auto res = sqlQuery(SqlQueryAndParams { .query = sql_query, .params = {}}); - return res; + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + auto records = qxsql->listRecords(QString::fromStdString(table), toQStringList(fields), ids_above, limit); + return toShvRecordList(records); } namespace { std::string to_lower(const std::string &s) @@ -339,109 +233,29 @@ std::string to_lower(const std::string &s) } int64_t SqlApi::create(const std::string &table, const RpcValue::Map &record) { - QStringList fields; - QStringList placeholders; - for (const auto &[k, v] : record) { - Q_UNUSED(v) - auto qk = QString::fromStdString(k); - fields << qk; - placeholders << ':' + qk; - } - QString sql_query = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") - .arg(QString::fromStdString(table)) - .arg(fields.join(',')) - .arg(placeholders.join(',')); - qf::core::sql::Query q; - q.prepare(sql_query, qf::core::Exception::Throw); - for (const auto &[k, v] : record) { - q.bindValue(':' + QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); - } - q.exec(qf::core::Exception::Throw); - auto id = q.lastInsertId().toInt(); - // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - // .table = QString::fromStdString(table), - // .id = id, - // .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), - // .op = qf::core::sql::RecOp::Insert, - // .issuer = {} - // }); - return id; + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + return qxsql->createRecord(QString::fromStdString(table), shv::coreqt::rpc::rpcValueToQVariant(record).toMap(), this); } -std::optional SqlApi::read(const std::string &table, int64_t id, const std::vector &fields) +std::optional SqlApi::read(const std::string &table, int64_t id, const std::vector &fields) { - QStringList qfields; - for (const auto &fn : fields) { - qfields << QString::fromStdString(fn); - } - if (qfields.isEmpty()) { - qfields << "*"; - } - QString sql_query = QStringLiteral("SELECT %1 FROM %2 WHERE id = %3") - .arg(qfields.join(',')) - .arg(QString::fromStdString(table)) - .arg(id) ; - auto res = sqlQuery(SqlQueryAndParams { .query = sql_query, .params = {}}); - if (res.rows.empty()) { - return {}; - } - Record ret; - const auto &row = res.rows.first(); - for (qsizetype i = 0; i < std::ssize(res.fields); ++i) { - ret[res.fields[i].name] = row.value(i); + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + if (auto rec = qxsql->readRecord(QString::fromStdString(table), id, toQStringList(fields)); rec.has_value()) { + return shv::coreqt::rpc::qVariantToRpcValue(rec.value()).asMap(); } - return ret; + return {}; } bool SqlApi::update(const std::string &table, int64_t id, const RpcValue::Map &record) { - QStringList fields; - for (const auto &[k, v] : record) { - Q_UNUSED(v) - auto qk = QString::fromStdString(k); - fields << qk + " = :" + qk; - } - QString sql_query = QStringLiteral("UPDATE %1 SET %2 WHERE id = %3") - .arg(QString::fromStdString(table)) - .arg(fields.join(',')) - .arg(id); - qf::core::sql::Query q; - q.prepare(sql_query, qf::core::Exception::Throw); - for (const auto &[k, v] : record) { - q.bindValue(':' + QString::fromStdString(k), shv::coreqt::rpc::rpcValueToQVariant(v)); - } - q.exec(qf::core::Exception::Throw); - bool updated = q.numRowsAffected() == 1; - if (updated) { - // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - // .table = QString::fromStdString(table), - // .id = id, - // .record = shv::coreqt::rpc::rpcValueToQVariant(normalizeFieldNames(record)).toMap(), - // .op = qf::core::sql::RecOp::Update, - // .issuer = {} - // }); - } - return updated; + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + return qxsql->updateRecord(QString::fromStdString(table), id, shv::coreqt::rpc::rpcValueToQVariant(record).toMap(), this); } bool SqlApi::drop(const std::string &table, int64_t id) { - QString sql_query = QStringLiteral("DELETE FROM %1 WHERE id = %2") - .arg(QString::fromStdString(table)) - .arg(id); - qf::core::sql::Query q; - q.exec(sql_query, qf::core::Exception::Throw); - bool is_drop = q.numRowsAffected() == 1; - if (is_drop) { - // SqlApi::instance()->emitRecChng(qf::core::sql::QxRecChng { - // .table = QString::fromStdString(table), - // .id = id, - // .record = {}, - // .op = qf::core::sql::RecOp::Delete, - // .issuer = {} - // }); - } - return is_drop; + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + return qxsql->deleteRecord(QString::fromStdString(table), id, this); } } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h index d02966a7e..c0d9334b7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h @@ -1,7 +1,7 @@ #pragma once #include -// #include +#include #include #include @@ -11,42 +11,13 @@ namespace qf::core::sql { struct QxRecChng; } namespace Event::services::qx { -struct DbField -{ - QString name; - - //explicit DbField(const QJsonObject &jo = QJsonObject()) : Super(jo) {} - shv::chainpack::RpcValue toRpcValue() const; - // QVariant toVariant() const; - static DbField fromRpcValue(const shv::chainpack::RpcValue &rv); - // static DbField fromVariant(const QVariant &v); -}; - -struct ExecResult -{ - int numRowsAffected = 0; - std::optional lastInsertId = 0; - - shv::chainpack::RpcValue toRpcValue() const; - static ExecResult fromRpcValue(const shv::chainpack::RpcValue &rv); -}; - -struct QueryResult -{ - std::vector fields; - using Row = QVariantList; - QList rows; +using DbField = qf::core::sql::DbField; +using ExecResult = qf::core::sql::ExecResult; +using QueryResult = qf::core::sql::QueryResult; - std::optional columnIndex(const std::string &name) const; - QVariant value(qsizetype row, qsizetype col) const; - QVariant value(qsizetype row, const std::string &name) const; - void setValue(qsizetype row, qsizetype col, const QVariant &val); - void setValue(qsizetype row, const std::string &name, const QVariant &val); - - shv::chainpack::RpcValue toRpcValue() const; - static QueryResult fromRpcValue(const shv::chainpack::RpcValue &rv); - shv::chainpack::RpcValue::List toRecordList() const; -}; +shv::chainpack::RpcValue dbFieldToRpcValue(const DbField &fld); +shv::chainpack::RpcValue execResultToRpcValue(const ExecResult &res); +shv::chainpack::RpcValue queryResultToRpcValue(const QueryResult &res); using Record = QVariantMap; @@ -67,18 +38,14 @@ class SqlApi : public QObject public: explicit SqlApi(QObject *parent = nullptr); - // Q_SIGNAL void recchng(const qf::core::sql::QxRecChng &chng); - // void emitRecChng(const qf::core::sql::QxRecChng &chng); - ExecResult exec(const SqlQueryAndParams ¶ms); QueryResult query(const SqlQueryAndParams ¶ms); void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); - QueryResult list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); + shv::chainpack::RpcValue::List list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit); int64_t create(const std::string &table, const shv::chainpack::RpcValue::Map &record); - std::optional read(const std::string &table, int64_t id, const std::vector &fields); + std::optional read(const std::string &table, int64_t id, const std::vector &fields); bool update(const std::string &table, int64_t id, const shv::chainpack::RpcValue::Map &record); bool drop(const std::string &table, int64_t id); -private: }; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index 9e4b5845f..a495e24b1 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -60,11 +60,11 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin if(shv_path.empty()) { if(method == METH_EXEC) { auto res = m_sqlApi->exec(SqlQueryAndParams::fromRpcValue(params)); - return res.toRpcValue(); + return execResultToRpcValue(res); } if(method == METH_QUERY) { auto res = m_sqlApi->query(SqlQueryAndParams::fromRpcValue(params)); - return res.toRpcValue(); + return queryResultToRpcValue(res); } if(method == METH_TRANSACTION) { auto sql_query = params.asList().valref(0).asString(); @@ -82,7 +82,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin auto ids_above = map.contains("ids_above")? std::optional(map.value("ids_above").toInt64()): std::optional(); auto limit = map.contains("limit")? std::optional(map.value("limit").toInt64()): std::optional(); auto res = m_sqlApi->list(table, fields, ids_above, limit); - return res.toRecordList(); + return res; } if(method == METH_CREATE) { const auto &map = params.asMap(); @@ -101,7 +101,7 @@ RpcValue SqlApiNode::callMethod(const StringViewList &shv_path, const std::strin } auto res = m_sqlApi->read(table, id, fields); if (res.has_value()) { - return shv::coreqt::rpc::qVariantToRpcValue(res.value()); + return res.value(); } return RpcValue(nullptr); } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index 3964ce8de..efa0248b1 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -11,7 +11,7 @@ // #include "../../Competitors/src/competitorwidget.h" #include "../../CardReader/src/cardreaderplugin.h" #include "../../Event/src/eventplugin.h" -#include "../../Event/src/services/qx/qxlateregistrationswidget.h" +#include "../../Event/src/services/qx/qxlateentrieswidget.h" #include #include @@ -142,15 +142,15 @@ void RunsPlugin::onInstalled() } { auto *dw = new qff::DockWidget(nullptr); - dw->setObjectName("qxLateRegistrationsDockWidget"); - dw->setPersistentSettingsId("Runs/qxLateRegistrations"); - dw->setWindowTitle(tr("Late registrations")); - auto *ew = new Event::services::qx::QxLateRegistrationsWidget(); + dw->setObjectName("qxLateEntriesDockWidget"); + dw->setPersistentSettingsId("Runs/qxLateEntries"); + dw->setWindowTitle(tr("Late entries")); + auto *ew = new Event::services::qx::QxLateEntriesWidget(); dw->setWidget(ew); fwk->addDockWidget(Qt::RightDockWidgetArea, dw); dw->hide(); - connect(dw, &qff::DockWidget::visibilityChanged, ew, &Event::services::qx::QxLateRegistrationsWidget::onVisibleChanged); + connect(dw, &qff::DockWidget::visibilityChanged, ew, &Event::services::qx::QxLateEntriesWidget::onVisibleChanged); auto *a = dw->toggleViewAction(); // a->setShortcut(QKeySequence("ctrl+shift+E")); diff --git a/quickevent/app/quickevent/src/appversion.h b/quickevent/app/quickevent/src/appversion.h index d6b84b113..a08b78be1 100644 --- a/quickevent/app/quickevent/src/appversion.h +++ b/quickevent/app/quickevent/src/appversion.h @@ -1,4 +1,4 @@ #pragma once -#define APP_VERSION "3.5.6" +#define APP_VERSION "3.6.0" From 30f6b3a737fff89cdd91ff3ce82ae8ede780587b Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 8 Jun 2026 21:06:36 +0200 Subject: [PATCH 32/83] Fix ofeed client compiler warnings --- .../quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp | 2 +- .../plugins/Event/src/services/ofeed/ofeedclientwidget.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 54d699543..6153547a9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -1373,7 +1373,7 @@ void OFeedClient::markChangelogEntryAsProcessed(int protocolId) variables["processedByType"] = QString("SYSTEM"); variables["processedBySource"] = QString("IT"); - sendGraphQLRequest(mutation, variables, [this, protocolId](QJsonObject data) { + sendGraphQLRequest(mutation, variables, [protocolId](QJsonObject data) { if (data.isEmpty()) { qfWarning() << serviceName().toStdString() + " Failed to mark changelog entry " << protocolId << " as processed"; } else { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclientwidget.h b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclientwidget.h index feef6e8d5..242409451 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclientwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclientwidget.h @@ -40,9 +40,9 @@ class OFeedClientWidget : public qf::gui::framework::DialogWidget QString defaultReceiptEventLink() const; OFeedClient* service(); bool saveSettings(); + bool acceptDialogDone(int result) override; private: Ui::OFeedClientWidget *ui; - bool acceptDialogDone(int result); bool m_isTestConnectionRunning = false; bool m_isImageRefreshRunning = false; QString m_lastAutoReceiptEventLink; From 03ab4d6eb84ae67cbe8430eb8fbd86ff337d0b28 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 9 Jun 2026 11:34:13 +0200 Subject: [PATCH 33/83] Fix create SQL scripts --- libqf/libqfgui/src/framework/dockwidget.h | 4 ++-- quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml | 4 ++-- .../app/quickevent/plugins/Event/qml/sql/def/Field.qml | 2 ++ .../app/quickevent/plugins/Event/sql/create_db_psql.sql | 2 +- .../app/quickevent/plugins/Event/sql/create_db_sqlite.sql | 2 +- .../plugins/Event/src/services/qx/qxlateentrieswidget.cpp | 8 +++++--- .../plugins/Event/src/services/qx/qxlateentrieswidget.h | 2 +- .../plugins/Event/src/services/qx/qxlateentrieswidget.ui | 2 +- 8 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libqf/libqfgui/src/framework/dockwidget.h b/libqf/libqfgui/src/framework/dockwidget.h index 1364ec5ee..bc4067236 100644 --- a/libqf/libqfgui/src/framework/dockwidget.h +++ b/libqf/libqfgui/src/framework/dockwidget.h @@ -22,12 +22,12 @@ class QFGUI_DECL_EXPORT DockWidget : public QDockWidget, public framework::IPers public: explicit DockWidget(const QString &window_title, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); explicit DockWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()) : DockWidget(QString(), parent, flags) {} - ~DockWidget() Q_DECL_OVERRIDE; + ~DockWidget() override; // visibilityChanged() exists already in QDockWidget //Q_SIGNAL void visibleChanged(bool visible); protected: - bool event(QEvent *ev) Q_DECL_OVERRIDE; + bool event(QEvent *ev) override; //void showEvent(QShowEvent *ev) Q_DECL_OVERRIDE; private: void setQmlWidget(QWidget *w); diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index 55222da4a..00bcbb863 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -512,8 +512,8 @@ Schema { Field { name: 'lock_number'; type: Int { } } ] indexes: [ - Index {fields: ['data_type', 'data_id']; unique: false }, - Index {fields: ['status']; unique: false } + Index {fields: ['stage_id', 'data_type', 'data_id']; unique: false }, + Index {fields: ['stage_id', 'status']; unique: false } ] } ] diff --git a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml index 6d43184fe..c3fae0e09 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml @@ -21,6 +21,8 @@ QtObject { def += ' DEFAULT '; if(typeof defaultValue === 'boolean' && driver_name.endsWith("SQLITE")) def += (defaultValue)? 1: 0; + else if(defaultValue === 'CURRENT_TIMESTAMP') + def += defaultValue; else if(typeof defaultValue === 'string') def += "'" + defaultValue + "'"; else diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql index f294be580..6937756b4 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql @@ -298,7 +298,7 @@ CREATE TABLE {{eventId}}.qxchanges ( user_id character varying, status character varying, status_message character varying, - created timestamp with time zone NOT NULL DEFAULT 'CURRENT_TIMESTAMP', + created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, lock_number integer ); CREATE INDEX qxchanges_ix0 ON {{eventId}}.qxchanges (data_type, data_id); diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql index f4f050f6d..cbc337538 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql @@ -325,7 +325,7 @@ CREATE TABLE qxchanges ( user_id character varying, status character varying, status_message character varying, - created timestamp NOT NULL DEFAULT 'CURRENT_TIMESTAMP', + created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, lock_number integer ); CREATE INDEX qxchanges_ix0 ON qxchanges (data_type, data_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index b596faa15..1a25ce21b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -76,17 +76,19 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : m_model->addColumn(COL_ORIG_DATA, tr("Orig data"));//.setToolTip(tr("Locked for drawing")); ui->tableView->setTableModel(m_model); - showMessage({}); + showMessage(tr("QxEvent service is disabled"), true); setEnabled(false); - auto *svc = service(); + auto *svc = qxEventService(); connect(svc, &Service::statusChanged, this, [this](Service::Status new_status){ switch (new_status) { case Service::Status::Unknown: case Service::Status::Stopped: + showMessage(tr("QxEvent service is disabled"), true); setEnabled(false); break; case Service::Status::Running: + showMessage({}); setEnabled(true); reload(); break; @@ -152,7 +154,7 @@ void QxLateEntriesWidget::onVisibleChanged(bool is_visible) } } -QxEventService *QxLateEntriesWidget::service() +QxEventService *QxLateEntriesWidget::qxEventService() { auto *svc = qobject_cast(Event::services::Service::serviceByName(QxEventService::serviceId())); Q_ASSERT(svc); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h index 2caed12b8..5ae69ac66 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h @@ -23,7 +23,7 @@ class QxLateEntriesWidget : public QWidget void onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload); void onVisibleChanged(bool is_visible); private: - QxEventService* service(); + QxEventService* qxEventService(); void reload(); void addQxChangeRow(int sql_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui index 70e933293..30abe1ed9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui @@ -11,7 +11,7 @@ - Form + Late entries From 3fa9d282ed3725b21889311dacf5d7df3a03232a Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 17 Jun 2026 23:12:33 +0200 Subject: [PATCH 34/83] Add LateEntry support and update qxchanges schema Also add recChng signal forwarding to RPC node, check QSqlQuery::prepare and throw on failure, and rename handleQxRecChng to applyQxRecChng across models and widgets --- libqf/libqfcore/src/sql/qxrecchng.cpp | 1 + libqf/libqfcore/src/sql/qxsql.cpp | 8 +- libqf/libqfgui/src/model/tablemodel.cpp | 30 +++- libqf/libqfgui/src/model/tablemodel.h | 2 +- quickevent/app/quickevent/CMakeLists.txt | 2 +- .../CardReader/src/cardreaderwidget.cpp | 2 +- .../plugins/CardReader/src/cardreaderwidget.h | 2 +- .../quickevent/plugins/Event/qml/DbSchema.qml | 14 +- .../plugins/Event/qml/sql/def/Index.qml | 21 ++- .../plugins/Event/qml/sql/def/Table.qml | 20 +-- .../plugins/Event/sql/create_db_psql.sql | 8 +- .../plugins/Event/sql/create_db_sqlite.sql | 8 +- .../plugins/Event/src/eventplugin.cpp | 19 +-- .../plugins/Event/src/eventplugin.h | 21 ++- ...unchangedialog.cpp => lateentrydialog.cpp} | 135 +++++++----------- .../{runchangedialog.h => lateentrydialog.h} | 21 ++- ...{runchangedialog.ui => lateentrydialog.ui} | 33 ++--- .../Event/src/services/qx/qxeventservice.cpp | 109 -------------- .../Event/src/services/qx/qxeventservice.h | 6 - .../src/services/qx/qxlateentrieswidget.cpp | 79 +++------- .../src/services/qx/qxlateentrieswidget.h | 6 +- .../Event/src/services/qx/runchange.cpp | 30 +++- .../plugins/Event/src/services/qx/runchange.h | 24 +++- .../plugins/Event/src/services/qx/sqlapi.cpp | 5 +- .../plugins/Event/src/services/qx/sqlapi.h | 2 + .../Event/src/services/qx/sqlapinode.cpp | 10 ++ .../plugins/Runs/src/runstablemodel.cpp | 2 +- 27 files changed, 258 insertions(+), 362 deletions(-) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{runchangedialog.cpp => lateentrydialog.cpp} (63%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{runchangedialog.h => lateentrydialog.h} (55%) rename quickevent/app/quickevent/plugins/Event/src/services/qx/{runchangedialog.ui => lateentrydialog.ui} (95%) diff --git a/libqf/libqfcore/src/sql/qxrecchng.cpp b/libqf/libqfcore/src/sql/qxrecchng.cpp index fc0ae36b2..b534d9ed5 100644 --- a/libqf/libqfcore/src/sql/qxrecchng.cpp +++ b/libqf/libqfcore/src/sql/qxrecchng.cpp @@ -48,6 +48,7 @@ QString QxRecChng::recopToString(RecOp op) case RecOp::Update: return "Update"; case RecOp::Delete: return "Delete"; } + return QString(); } } diff --git a/libqf/libqfcore/src/sql/qxsql.cpp b/libqf/libqfcore/src/sql/qxsql.cpp index dac711b02..45e55d111 100644 --- a/libqf/libqfcore/src/sql/qxsql.cpp +++ b/libqf/libqfcore/src/sql/qxsql.cpp @@ -157,7 +157,9 @@ QueryResult QxSqlApiImpl::query(const QString &query, const QVariantMap ¶ms) { // qDebug() << query << params; QSqlQuery q(m_db); - q.prepare(query); + if (!q.prepare(query)) { + throw qf::core::Exception(q.lastError().text()); + } for (const auto &[key, val] : params.asKeyValueRange()) { q.bindValue(QStringLiteral(":%1").arg(key), val); } @@ -181,7 +183,9 @@ QueryResult QxSqlApiImpl::query(const QString &query, const QVariantMap ¶ms) ExecResult QxSqlApiImpl::exec(const QString &query, const QVariantMap ¶ms) { QSqlQuery q(m_db); - q.prepare(query); + if (!q.prepare(query)) { + throw qf::core::Exception(q.lastError().text()); + } for (const auto &[key, val] : params.asKeyValueRange()) { q.bindValue(QStringLiteral(":%1").arg(key), val); } diff --git a/libqf/libqfgui/src/model/tablemodel.cpp b/libqf/libqfgui/src/model/tablemodel.cpp index 2fff88940..1eebdbfca 100644 --- a/libqf/libqfgui/src/model/tablemodel.cpp +++ b/libqf/libqfgui/src/model/tablemodel.cpp @@ -672,7 +672,7 @@ QColor TableModel::contrastTextColor(const QColor &background_color) return (qGray(background_color.rgb()) < 128)? QColor(Qt::white) : QColor(Qt::black); } -void TableModel::handleQxRecChng(const core::sql::QxRecChng &recchng, QObject *source) +void TableModel::applyQxRecChng(const core::sql::QxRecChng &recchng, QObject *source) { // qfInfo() << __FUNCTION__ << source; if (source == this) { @@ -685,12 +685,28 @@ void TableModel::handleQxRecChng(const core::sql::QxRecChng &recchng, QObject *s return i; } } + qfMessage() << "cannot find table row with id:" << id; } else { - qfWarning() << "cannot find table column:" << (table_name + ".id"); + // not every change is addressing every table model + qfMessage() << metaObject()->className() << objectName() << "cannot find table column:" << (table_name + ".id"); } return -1; }; - if (recchng.op == qf::core::sql::RecOp::Update) { + if (recchng.op == qf::core::sql::RecOp::Insert) { + if (int row = find_row_by_id(recchng.table, recchng.id); row >= 0) { + // row exists already + return; + } + if (auto fld_ix = table().fields().fieldIndex(recchng.table + ".id"); fld_ix >= 0) { + beginInsertRows({}, 0, 0); + auto row = insertTableRow(0); + tableRowRef(row).setValue(fld_ix, recchng.id); + endInsertRows(); + qfMessage() << "reloading inserted row:" << row << "table:" << recchng.table; + reloadRow(row); + } + } + else if (recchng.op == qf::core::sql::RecOp::Update) { if (int row = find_row_by_id(recchng.table, recchng.id); row >= 0) { for (const auto &[k, v] : recchng.record.asKeyValueRange()) { if (auto col_ix = columnIndexOfTableField(recchng.table + '.' + k); col_ix.has_value()) { @@ -707,12 +723,18 @@ void TableModel::handleQxRecChng(const core::sql::QxRecChng &recchng, QObject *s } } else { // calculated column - qfInfo() << "reloading calculated field, row:" << row << (recchng.table + '.' + k) << "-->" << v; + qfMessage() << "reloading calculated field, row:" << row << (recchng.table + '.' + k) << "-->" << v; reloadRow(row); } } } } + else if (recchng.op == qf::core::sql::RecOp::Delete) { + if (int row = find_row_by_id(recchng.table, recchng.id); row >= 0) { + qfMessage() << "deleteing row:" << row << (recchng.table + ".id") << recchng.id; + removeRowNoOverload(row, !qf::core::Exception::Throw); + } + } } QVariant TableModel::rawValueToEdit(int column_index, const QVariant &val) const diff --git a/libqf/libqfgui/src/model/tablemodel.h b/libqf/libqfgui/src/model/tablemodel.h index fc2c4b805..fded27d00 100644 --- a/libqf/libqfgui/src/model/tablemodel.h +++ b/libqf/libqfgui/src/model/tablemodel.h @@ -209,7 +209,7 @@ class QFGUI_DECL_EXPORT TableModel : public QAbstractTableModel static QColor contrastTextColor(const QColor &background_color); - void handleQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); + void applyQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); protected: virtual void checkColumns(); void createColumnsFromTableFields(); diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index b0cf1f556..1d7ada5a4 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -107,7 +107,7 @@ add_executable(quickevent plugins/Event/src/services/qx/qxeventservice.cpp plugins/Event/src/services/qx/qxeventservice.h plugins/Event/src/services/qx/qxeventservicewidget.cpp plugins/Event/src/services/qx/qxeventservicewidget.h plugins/Event/src/services/qx/qxeventservicewidget.ui plugins/Event/src/services/qx/qxlateentrieswidget.h plugins/Event/src/services/qx/qxlateentrieswidget.cpp plugins/Event/src/services/qx/qxlateentrieswidget.ui - plugins/Event/src/services/qx/runchangedialog.h plugins/Event/src/services/qx/runchangedialog.cpp plugins/Event/src/services/qx/runchangedialog.ui + plugins/Event/src/services/qx/lateentrydialog.h plugins/Event/src/services/qx/lateentrydialog.cpp plugins/Event/src/services/qx/lateentrydialog.ui plugins/Event/src/services/qx/runchange.h plugins/Event/src/services/qx/runchange.cpp plugins/Oris/src/chooseoriseventdialog.cpp diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 2c3db126d..45c6db000 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -522,7 +522,7 @@ void CardReaderWidget::reload() void CardReaderWidget::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source) { if(isVisible()) { - m_cardsModel->handleQxRecChng(recchng, source); + m_cardsModel->applyQxRecChng(recchng, source); } } diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h index 03b7a6aa5..3e2f312b7 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h @@ -68,7 +68,7 @@ class CardReaderWidget : public QFrame Q_SLOT void reload(); private: - void onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); + void onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); void appendLog(NecroLog::Level level, const QString &msg); void processDriverInfo(NecroLog::Level level, const QString &msg); diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index 00bcbb863..df5393e31 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -494,14 +494,13 @@ Schema { fields: [ Field { name: 'id'; type: Serial { primaryKey: true } }, Field { name: 'stage_id'; type: Int { } }, - // Field { name: 'change_id'; type: Int { } }, // not used - Field { name: 'data_id'; type: Int { } }, // not used + // Field { name: 'foreign_table'; type: String { } }, + Field { name: 'foreign_id'; type: Int { } }, Field { name: 'data_type'; type: String { } }, Field { name: 'data'; type: String { } }, Field { name: 'orig_data'; type: String { } comment: 'Store data overriden by change here to enable change rollback.' }, - Field { name: 'source'; type: String { } }, // issuer Field { name: 'user_id'; type: String { } }, Field { name: 'status'; type: String { } }, Field { name: 'status_message'; type: String { } }, @@ -512,8 +511,13 @@ Schema { Field { name: 'lock_number'; type: Int { } } ] indexes: [ - Index {fields: ['stage_id', 'data_type', 'data_id']; unique: false }, - Index {fields: ['stage_id', 'status']; unique: false } + Index {fields: ['stage_id', 'data_type', 'foreign_id']; unique: false }, + Index {fields: ['stage_id', 'status']; unique: false }, + Index {fields: ['stage_id', 'foreign_id'] + where: "status = 'Pending' AND data_type = 'LateEntry' AND foreign_id IS NOT NULL" + comment: 'Only one pending late entry can be present for single runs.id (foreign_id).' + unique: true + } ] } ] diff --git a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Index.qml b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Index.qml index bc72921c5..12986f898 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Index.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Index.qml @@ -9,6 +9,7 @@ QtObject property bool primary: false property bool unique: false property ForeignKeyReference references: null + property string where property string comment function indexName(cnt, table_name) @@ -55,21 +56,29 @@ QtObject else if(primary) { ret += '\tCONSTRAINT ' + indexName(constr_no, options.tableName) + ' PRIMARY KEY (' + fields.join(', ') + ')'; } - else if(unique) { + else if(unique && !where) { ret += '\tCONSTRAINT ' + indexName(constr_no, options.tableName) + ' UNIQUE (' + fields.join(', ') + ')'; } } return ret; } - function createSqlIndexScript(options) + function createSqlIndexScript(index_name, table_name, options) { - var ret = ''; if(fields) { - if(!primary && !unique && !references) { - ret = '(' + fields.join(', ') + ')'; + if (where) { + return 'CREATE ' + + (unique? 'UNIQUE ': ' ') + +'INDEX ' + index_name + + ' ON ' + table_name + ' (' + fields.join(', ') + ')' + + ' WHERE ' + where; + } + else if(!primary && !unique && !references) { + return 'CREATE INDEX ' + index_name + + ' ON ' + table_name + + ' (' + fields.join(', ') + ')'; } } - return ret; + return ''; } } diff --git a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Table.qml b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Table.qml index ab5b750ca..a50ad1766 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Table.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Table.qml @@ -20,8 +20,8 @@ QtObject { var field_defs = []; options.tableName = name; var fieldNames = [] - for(var i=0; i #include #include +#include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include @@ -73,23 +73,6 @@ using qff::getPlugin; namespace Event { -class DbEventPayload : public QVariantMap -{ -private: - typedef QVariantMap Super; - - QF_VARIANTMAP_FIELD(QString, e, setE, ventName) - QF_VARIANTMAP_FIELD(QString, d, setD, omain) - QF_VARIANTMAP_FIELD(int, c, setc, onnectionId) - QF_VARIANTMAP_FIELD(QVariant, d, setD, ata) -public: - DbEventPayload(const QVariantMap &data = QVariantMap()) : QVariantMap(data) {} - - static DbEventPayload fromJson(const QByteArray &json); - - QByteArray toJson() const; -}; - DbEventPayload DbEventPayload::fromJson(const QByteArray &json) { QJsonParseError error; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 50a8e077e..a29badbe4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -26,6 +26,23 @@ namespace Event { static constexpr auto START_LIST_IOFXML3_FILE = "startlist-iof3.xml"; static constexpr auto RESULTS_IOFXML3_FILE = "results-iof3.xml"; +class DbEventPayload : public QVariantMap +{ +private: + typedef QVariantMap Super; + + QF_VARIANTMAP_FIELD(QString, e, setE, ventName) + QF_VARIANTMAP_FIELD(QString, d, setD, omain) + QF_VARIANTMAP_FIELD(int, c, setc, onnectionId) + QF_VARIANTMAP_FIELD(QVariant, d, setD, ata) +public: + DbEventPayload(const QVariantMap &data = QVariantMap()) : QVariantMap(data) {} + + static DbEventPayload fromJson(const QByteArray &json); + + QByteArray toJson() const; +}; + class EventPlugin : public qf::gui::framework::Plugin { Q_OBJECT @@ -60,7 +77,6 @@ class EventPlugin : public qf::gui::framework::Plugin static constexpr auto DBEVENT_PUNCH_RECEIVED = "punchReceived"; static constexpr auto DBEVENT_REGISTRATIONS_IMPORTED = "registrationsImported"; static constexpr auto DBEVENT_STAGE_START_CHANGED = "stageStartChanged"; - static constexpr auto DBEVENT_QX_CHANGE_RECEIVED = "qxChangeReceived"; static constexpr auto DBEVENT_QX_RECCHNG = "qxRecChng"; Q_INVOKABLE void initEventConfig(); @@ -151,8 +167,7 @@ class EventPlugin : public qf::gui::framework::Plugin bool importEventFromFile(const QString &src_file, const QString &dest_event_name); bool convertSqlEvent(const QString &from_event, const QString &to_event); void deleteEvent(const QString &event_name); - QString copyEventSchema(qf::core::sql::Connection &imp_conn, qf::core::sql::Connection &exp_conn, - const QString &dest_schema_name); + QString copyEventSchema(qf::core::sql::Connection &imp_conn, qf::core::sql::Connection &exp_conn, const QString &dest_schema_name); void onServiceDockVisibleChanged(bool on = true); private: diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp similarity index 63% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp rename to quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index e2c50edd5..aedcf62bf 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -1,11 +1,13 @@ -#include "runchangedialog.h" -#include "ui_runchangedialog.h" +#include "lateentrydialog.h" +#include "ui_lateentrydialog.h" #include "qxeventservice.h" #include "runchange.h" #include +#include +#include #include #include @@ -13,15 +15,17 @@ #include #include #include +#include #include +#include namespace Event::services::qx { -RunChangeDialog::RunChangeDialog(int change_id, int run_id, int lock_number, const RunChange &run_change, QWidget *parent) +LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry &late_entry, QWidget *parent) : QDialog(parent) - , ui(new Ui::RunChangeDialog) + , ui(new Ui::LateEntryDialog) , m_changeId(change_id) - , m_runId(run_id) + , m_runId(late_entry.run_id) { ui->setupUi(this); @@ -39,26 +43,43 @@ RunChangeDialog::RunChangeDialog(int change_id, int run_id, int lock_number, con resolveChanges(false); }); - ui->edClassName->setText(run_change.class_name.value_or(QString())); - ui->edNote->setText(run_change.note); + ui->edClassName->setText(late_entry.record.class_name.value_or(QString())); + ui->edNote->setText(late_entry.record.note); - ui->edRunId->setValue(run_id); + ui->edRunId->setValue(m_runId); ui->edChangeId->setValue(change_id); ui->edLockNumber->setValue(lock_number); - ui->grpFirstName->setChecked(run_change.first_name.has_value()); - ui->edFirstName->setText(run_change.first_name.has_value()? run_change.first_name.value(): QString()); + auto update_background = [](QWidget *widget) { + bool is_set = false; + if (auto *le = qobject_cast(widget)) { + is_set = !le->text().isEmpty(); + } + else if (auto *spin_box = qobject_cast(widget)) { + is_set = spin_box->value() > 0; + } + if (is_set) { + widget->setStyleSheet("background: honeydew"); + } + }; - ui->grpLastName->setChecked(run_change.last_name.has_value()); - ui->edLastName->setText(run_change.last_name.has_value()? run_change.last_name.value(): QString()); + ui->grpFirstName->setChecked(late_entry.record.first_name.has_value()); + ui->edFirstName->setText(late_entry.record.first_name.has_value()? late_entry.record.first_name.value(): QString()); + update_background(ui->edFirstName); - ui->grpRegistration->setChecked(run_change.registration.has_value()); - ui->edRegistration->setText(run_change.registration.has_value()? run_change.registration.value(): QString()); + ui->grpLastName->setChecked(late_entry.record.last_name.has_value()); + ui->edLastName->setText(late_entry.record.last_name.has_value()? late_entry.record.last_name.value(): QString()); + update_background(ui->edLastName); - ui->grpSiCard->setChecked(run_change.si_id.has_value()); - ui->edSiCard->setValue(run_change.si_id.has_value()? run_change.si_id.value(): 0); + ui->grpRegistration->setChecked(late_entry.record.registration.has_value()); + ui->edRegistration->setText(late_entry.record.registration.has_value()? late_entry.record.registration.value(): QString()); + update_background(ui->edRegistration); - if (run_id > 0) { + ui->grpSiCard->setChecked(late_entry.record.si_id.has_value()); + ui->edSiCard->setValue(late_entry.record.si_id.has_value()? late_entry.record.si_id.value(): 0); + update_background(ui->edSiCard); + + if (m_runId > 0) { loadOrigValues(); } else { @@ -67,19 +88,19 @@ RunChangeDialog::RunChangeDialog(int change_id, int run_id, int lock_number, con lockChange(); } -RunChangeDialog::~RunChangeDialog() +LateEntryDialog::~LateEntryDialog() { delete ui; } -QxEventService *RunChangeDialog::service() +QxEventService *LateEntryDialog::service() { auto *svc = qobject_cast(Service::serviceByName(QxEventService::serviceId())); Q_ASSERT(svc); return svc; } -void RunChangeDialog::setMessage(const QString &msg, bool error) +void LateEntryDialog::setMessage(const QString &msg, bool error) { if (msg.isEmpty()) { ui->lblError->setStyleSheet({}); @@ -93,7 +114,7 @@ void RunChangeDialog::setMessage(const QString &msg, bool error) ui->lblError->setText(msg); } -void RunChangeDialog::loadOrigValues() +void LateEntryDialog::loadOrigValues() { Q_ASSERT(m_runId > 0); @@ -123,7 +144,7 @@ void RunChangeDialog::loadOrigValues() ui->edSiCardOrig->setValue(m_origValues.si_id); } -void RunChangeDialog::loadClassId() +void LateEntryDialog::loadClassId() { auto class_name = ui->edClassName->text(); if (class_name.isEmpty()) { @@ -140,7 +161,7 @@ void RunChangeDialog::loadClassId() } } -void RunChangeDialog::lockChange() +void LateEntryDialog::lockChange() { // NIY // auto *svc = service(); @@ -200,42 +221,7 @@ void RunChangeDialog::lockChange() // }); } -void RunChangeDialog::resolveChanges(bool is_accepted) -{ - if (is_accepted) { - applyLocalChanges(is_accepted); - } - auto *svc = service(); - auto *nm = svc->networkManager(); - QNetworkRequest request; - auto url = svc->shvBrokerUrl(); - // qfInfo() << "url " << url.toString(); - url.setPath("/api/event/current/changes/resolve-change"); - - QUrlQuery query; - query.addQueryItem("change_id", QString::number(m_changeId)); - query.addQueryItem("lock_number", QString::number(m_lockNumber)); - query.addQueryItem("accepted", is_accepted? "true": "false"); - query.addQueryItem("status_message", ui->edStatusMessage->text()); - url.setQuery(query); - - request.setUrl(url); - request.setRawHeader(QxEventService::QX_API_TOKEN, svc->apiToken().toUtf8()); - auto *reply = nm->get(request); - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - if (reply->error() == QNetworkReply::NetworkError::NoError) { - accept(); - } - else { - QMessageBox::warning(this, - QCoreApplication::applicationName(), - tr("Update change error: %1").arg(reply->errorString())); - } - reply->deleteLater(); - }); -} - -void RunChangeDialog::applyLocalChanges(bool is_accepted) +void LateEntryDialog::resolveChanges(bool is_accepted) { using namespace qf::gui::model; @@ -267,33 +253,12 @@ void RunChangeDialog::applyLocalChanges(bool is_accepted) } } doc.save(); - { - qf::core::sql::Query q; - q.execThrow(QStringLiteral("UPDATE qxchanges SET status='%1' WHERE id=%2") - .arg(is_accepted? "Accepted": "Rejected") - .arg(m_changeId) - ); - } - { - auto dc_str = qf::core::Utils::qvariantToJson(m_origValues.toVariantMap()); - QString qs = "UPDATE qxchanges SET orig_data=:orig_data WHERE id=:id"; - qf::core::sql::Query q; - q.prepare(qs, qf::core::Exception::Throw); - q.bindValue(":orig_data", dc_str); - q.bindValue(":id", m_changeId); - q.exec(qf::core::Exception::Throw); - } -} -bool RunChangeDialog::checkHttpError(QNetworkReply *reply) -{ - if (reply->error() != QNetworkReply::NetworkError::NoError) { - setMessage(tr("Http error: %1\n%2") - .arg(reply->request().url().toString()) - .arg(reply->errorString()), true); - return false; - } - return true; + qf::core::sql::Record rec { + {"status", is_accepted? "Accepted": "Rejected"}, + {"orig_data", qf::core::Utils::qvariantToJson(m_origValues.toVariantMap())}, + }; + qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); } } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h similarity index 55% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h rename to quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index 15a9bf147..d6be39898 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -1,5 +1,5 @@ -#ifndef RUNCHANGEDIALOG_H -#define RUNCHANGEDIALOG_H +#ifndef LATEENTRYDIALOG_H +#define LATEENTRYDIALOG_H #include "runchange.h" @@ -10,19 +10,19 @@ class QNetworkReply; namespace Event::services::qx { namespace Ui { -class RunChangeDialog; +class LateEntryDialog; } -struct RunChange; +struct LateEntryRecord; class QxEventService; -class RunChangeDialog : public QDialog +class LateEntryDialog : public QDialog { Q_OBJECT public: - explicit RunChangeDialog(int change_id, int run_id, int lock_number, const RunChange &run_change, QWidget *parent = nullptr); - ~RunChangeDialog() override; + explicit LateEntryDialog(int change_id, int lock_number, const LateEntry &late_entry, QWidget *parent = nullptr); + ~LateEntryDialog() override; private: QxEventService* service(); @@ -34,11 +34,8 @@ class RunChangeDialog : public QDialog void lockChange(); void resolveChanges(bool is_accepted); - void applyLocalChanges(bool is_accepted); - - bool checkHttpError(QNetworkReply *reply); private: - Ui::RunChangeDialog *ui; + Ui::LateEntryDialog *ui; int m_changeId = 0; int m_runId = 0; int m_competitorId = 0; @@ -51,4 +48,4 @@ class RunChangeDialog : public QDialog } // namespace Event::services::qx -#endif // RUNCHANGEDIALOG_H +#endif // LATEENTRYDIALOG_H diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui similarity index 95% rename from quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.ui rename to quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index c18f157b3..b07ff471c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchangedialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -1,7 +1,7 @@ - Event::services::qx::RunChangeDialog - + Event::services::qx::LateEntryDialog + 0 @@ -13,7 +13,7 @@ Dialog - + @@ -308,6 +308,16 @@ + + + + Message + + + + + + @@ -321,20 +331,6 @@ - - - - - - Message - - - - - - - - @@ -402,7 +398,6 @@ edSiCard edSiCardRent edNote - edStatusMessage chkForce btAccept btReject @@ -413,7 +408,7 @@ btCancel clicked() - Event::services::qx::RunChangeDialog + Event::services::qx::LateEntryDialog reject() diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 6d43c3b4c..999da24c4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -2,7 +2,6 @@ #include "qxeventservicewidget.h" #include "nodes.h" #include "sqlapinode.h" -#include "sqlapi.h" #include "../../eventplugin.h" #include "../../../../Runs/src/runsplugin.h" @@ -103,7 +102,6 @@ void QxEventService::run() { void QxEventService::stop() { m_eventId = 0; - disconnectSSE(); if (m_pollChangesTimer) { m_pollChangesTimer->stop(); } @@ -384,113 +382,6 @@ void QxEventService::httpPostJson(const QString &path, const QString &query, QVa } } -void QxEventService::connectToSSE(int event_id) -{ - Q_UNUSED(event_id); - // auto url = exchangeServerUrl(); - // url.setPath(QStringLiteral("/api/event/%1/run/changes/sse").arg(event_id)); - // QNetworkRequest request(url); - // request.setRawHeader(QByteArray("Accept"), QByteArray("text/event-stream")); - // request.setHeader(QNetworkRequest::UserAgentHeader, "QuickEvent"); - // request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); - // request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); // Events shouldn't be cached - - // qfInfo() << "Connecting to SSE:" << url.toString(); - // m_replySSE = networkManager()->get(request); - // qfInfo() << "Connected"; - // connect(m_replySSE, &QNetworkReply::readyRead, this, [this]() { - // auto data = m_replySSE->readAll(); - // qfInfo() << "DATA:" << data.toStdString(); - // }); - // connect(m_replySSE, &QNetworkReply::finished, this, [this]() { - // qfInfo() << "SSE finished:" << m_replySSE->errorString(); - // }); -} - -void QxEventService::disconnectSSE() -{ - if (m_replySSE) { - qfInfo() << "Disconnecting SSE:" << m_replySSE; - m_replySSE->deleteLater(); - m_replySSE = nullptr; - } -} - -void QxEventService::pollQxChanges() -{ - auto event_plugin = getPlugin(); - if(!getPlugin()->isEventOpen()) { - return; - } - int stage_id = event_plugin->currentStageId(); - try { - int max_change_id = 0; - qf::core::sql::Query q; - q.execThrow("SELECT MAX(change_id) FROM qxchanges WHERE stage_id=" + QString::number(event_plugin->currentStageId())); - if (q.next()) { - max_change_id = q.value(0).toInt(); - } - auto *reply = getQxChangesReply(max_change_id + 1); - connect(reply, &QNetworkReply::finished, this, [reply, stage_id]() { - QString err; - if(reply->error()) { - err = reply->errorString(); - qfWarning() << "Load qxchanges error:" << err; - } - else { - QJsonParseError err; - auto data = reply->readAll(); - auto json = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) { - qfWarning() << "Parse qxchanges error:" << err.errorString(); - } - else { - auto records = json.array().toVariantList(); - qf::core::sql::Query q; - q.prepare("INSERT INTO qxchanges (data_type, data, data_id, source, user_id, status, status_message, stage_id, change_id, created)" - " VALUES (:data_type, :data, :data_id, :source, :user_id, :status, :status_message, :stage_id, :change_id, :created)" - " RETURNING id"); - for (const auto &v : records) { - auto rec = v.toMap(); - auto ba = QJsonDocument::fromVariant(rec.value("data")).toJson(QJsonDocument::Compact); - auto data = QString::fromUtf8(ba); - q.bindValue(":data_type", rec.value("data_type")); - q.bindValue(":data", data); - q.bindValue(":data_id", rec.value("data_id")); - q.bindValue(":source", rec.value("source")); - q.bindValue(":user_id", rec.value("user_id")); - q.bindValue(":status", rec.value("status")); - q.bindValue(":status_message", rec.value("status_message")); - q.bindValue(":stage_id", stage_id); - auto change_id = rec.value("id").toInt(); - Q_ASSERT(change_id > 0); - q.bindValue(":change_id", change_id); - auto created = QDateTime::fromString(rec.value("created").toString(), Qt::ISODate); - qfDebug() << "created:" << created.toString(Qt::ISODate); - q.bindValue(":created", created); - // may fail on prikey violation if more clients are inserting simultaneously - if (q.exec()) { - if (q.next()) { - auto id = q.value(0).toInt(); - qfDebug() << "insert ID:" << id; - getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_QX_CHANGE_RECEIVED, id, true); - } - } - else { - qfInfo() << "sql error:" << q.lastErrorText(); - - } - } - } - } - reply->deleteLater(); - }); - } - catch (const qf::core::Exception &e) { - qfWarning() << "Load qxchanges error:" << e.message(); - } -} - EventInfo QxEventService::eventInfo() const { auto *event_plugin = getPlugin(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index fc5af4120..7c0eb71c2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -79,7 +79,6 @@ class QxEventService : public Service void sendRpcMessage(const shv::chainpack::RpcMessage &rpc_msg); void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); - // void sendRecchgShvSignal(const qf::core::sql::QxRecChng &chng); void subscribeChanges(); private: @@ -92,11 +91,6 @@ class QxEventService : public Service void httpPostJson(const QString &path, const QString &query, QVariantMap json, QObject *context = nullptr, const std::function &call_back = nullptr); - void connectToSSE(int event_id); - void disconnectSSE(); - - void pollQxChanges(); - EventInfo eventInfo() const; private: // shv shv::iotqt::rpc::DeviceConnection *m_rpcConnection = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index 1a25ce21b..edaf69723 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -2,15 +2,18 @@ #include "ui_qxlateentrieswidget.h" #include "qxeventservice.h" -#include "runchangedialog.h" +#include "lateentrydialog.h" #include "runchange.h" #include #include +#include #include #include #include +#include +#include #include #include @@ -23,14 +26,12 @@ using qf::gui::framework::getPlugin; namespace Event::services::qx { constexpr auto COL_ID = "id"; -constexpr auto COL_CHANGE_ID = "change_id"; constexpr auto COL_DATA_TYPE = "data_type"; -constexpr auto COL_DATA_ID = "data_id"; +constexpr auto COL_FOREIGN_ID = "foreign_id"; constexpr auto COL_DATA = "data"; constexpr auto COL_ORIG_DATA = "orig_data"; constexpr auto COL_STATUS = "status"; constexpr auto COL_STATUS_MESSAGE = "status_message"; -constexpr auto COL_SOURCE = "source"; constexpr auto COL_USER_ID = "user_id"; constexpr auto COL_CREATED = "created"; constexpr auto COL_LOCK_NUMBER = "lock_number"; @@ -38,10 +39,6 @@ constexpr auto COL_LOCK_NUMBER = "lock_number"; constexpr auto STATUS_PENDING = "Pending"; constexpr auto STATUS_LOCKED = "Locked"; -constexpr auto DATA_TYPE_RUN_UPDATE_REQUEST = "RunUpdateRequest"; - -constexpr auto SOURCE_WWW = "www"; - QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : QWidget(parent), ui(new Ui::QxLateEntriesWidget) @@ -65,12 +62,10 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : m_model->addColumn(COL_ID).setReadOnly(true).setAlignment(Qt::AlignLeft); m_model->addColumn(COL_STATUS, tr("Status")); m_model->addColumn(COL_DATA_TYPE, tr("Type")); - m_model->addColumn(COL_DATA_ID, tr("Data ID")).setAlignment(Qt::AlignLeft); - m_model->addColumn(COL_SOURCE, tr("Source")); + m_model->addColumn(COL_FOREIGN_ID, tr("Foreign ID")).setAlignment(Qt::AlignLeft); m_model->addColumn(COL_USER_ID, tr("User")); m_model->addColumn(COL_STATUS_MESSAGE, tr("Status message")); m_model->addColumn(COL_CREATED, tr("Created")); - m_model->addColumn(COL_CHANGE_ID, tr("Change ID")); m_model->addColumn(COL_LOCK_NUMBER, tr("Lock")); m_model->addColumn(COL_DATA, tr("Data"));//.setToolTip(tr("Locked for drawing")); m_model->addColumn(COL_ORIG_DATA, tr("Orig data"));//.setToolTip(tr("Locked for drawing")); @@ -95,8 +90,6 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : } }); - connect(getPlugin(), &Event::EventPlugin::dbEventNotify, this, &QxLateEntriesWidget::onDbEventNotify, Qt::QueuedConnection); - { auto *lst = ui->lstType; lst->addItem("All"); @@ -131,6 +124,7 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : reload(); }); + connect(qf::gui::framework::Application::instance()->qxSql(), &qf::core::sql::QxSql::recChng, this, &QxLateEntriesWidget::onQxRecChng, Qt::QueuedConnection); } QxLateEntriesWidget::~QxLateEntriesWidget() @@ -138,15 +132,6 @@ QxLateEntriesWidget::~QxLateEntriesWidget() delete ui; } -void QxLateEntriesWidget::onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload) -{ - Q_UNUSED(connection_id) - if(domain == QLatin1String(Event::EventPlugin::DBEVENT_QX_CHANGE_RECEIVED)) { - int sql_id = payload.toInt(); - addQxChangeRow(sql_id); - } -} - void QxLateEntriesWidget::onVisibleChanged(bool is_visible) { if (is_visible && isEnabled()) { @@ -227,7 +212,7 @@ void QxLateEntriesWidget::reload() m_model->reload(); } -void QxLateEntriesWidget::addQxChangeRow(int sql_id) +void QxLateEntriesWidget::applyQxChange(int sql_id) { qfDebug() << "reloading qxchanges row id:" << sql_id << "col id:" << COL_ID; if(sql_id <= 0) { @@ -252,23 +237,6 @@ void QxLateEntriesWidget::addQxChangeRow(int sql_id) } } - -void QxLateEntriesWidget::applyCurrentChange() -{ - auto row = ui->tableView->currentIndex().row(); - if (row < 0) { - return; - } - auto status = m_model->value(row, COL_STATUS).toString(); - if (status != STATUS_PENDING) { - return; - } - //auto run_id = m_model->value(row, COL_RUN_ID).toInt(); - //int competitor_id = 0; - // int result = getPlugin()->editCompetitor(competitor_id, run_id == 0? Mode::Insert: Mode::Edit); - -} - void QxLateEntriesWidget::onTableCustomContextMenuRequest(const QPoint &pos) { QAction a_neco(tr("Neco"), nullptr); @@ -283,27 +251,24 @@ void QxLateEntriesWidget::onTableCustomContextMenuRequest(const QPoint &pos) void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { auto row = ix.row(); - auto data_type = m_model->value(row, COL_DATA_TYPE).toString(); - if (data_type != DATA_TYPE_RUN_UPDATE_REQUEST) { - return; - } - auto source = m_model->value(row, COL_SOURCE).toString(); - if (source != SOURCE_WWW) { - return; - } - auto change_id = m_model->value(row, COL_CHANGE_ID).toInt(); auto status = m_model->value(row, COL_STATUS).toString(); - auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); - auto data_id = m_model->value(row, COL_DATA_ID).toInt(); - auto data = m_model->value(row, COL_DATA).toString().toUtf8(); - auto change_rec = QJsonDocument::fromJson(data).toVariant().toMap(); - auto run_change = RunChange::fromVariantMap(change_rec.value(DATA_TYPE_RUN_UPDATE_REQUEST).toMap()); if (status == STATUS_PENDING || status == STATUS_LOCKED) { - RunChangeDialog dlg(change_id, data_id, lock_number, run_change, this); - dlg.exec(); - ui->tableView->reloadRow(row); + auto data = m_model->value(row, COL_DATA).toString(); + auto qxdata = QxChangeData::fromJson(data); + if (qxdata.lateEntry.has_value()) { + auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); + auto change_id = m_model->value(row, COL_ID).toInt(); + LateEntryDialog dlg(change_id, lock_number, qxdata.lateEntry.value(), this); + dlg.exec(); + ui->tableView->reloadRow(row); + } } } +void QxLateEntriesWidget::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source) +{ + m_model->applyQxRecChng(recchng, source); +} + } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h index 5ae69ac66..85dd3265e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.h @@ -2,6 +2,7 @@ #include +namespace qf::core::sql { struct QxRecChng; } namespace qf::gui::model { class SqlTableModel; } namespace Event::services::qx { @@ -20,20 +21,19 @@ class QxLateEntriesWidget : public QWidget explicit QxLateEntriesWidget(QWidget *parent = nullptr); ~QxLateEntriesWidget() override; - void onDbEventNotify(const QString &domain, int connection_id, const QVariant &payload); void onVisibleChanged(bool is_visible); private: QxEventService* qxEventService(); void reload(); - void addQxChangeRow(int sql_id); + void applyQxChange(int sql_id); void resizeColumns(); void showMessage(const QString &msg, bool is_error = false); - void applyCurrentChange(); void onTableCustomContextMenuRequest(const QPoint &pos); void onTableDoubleClicked(const QModelIndex &ix); + void onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); private: Ui::QxLateEntriesWidget *ui; qf::gui::model::SqlTableModel *m_model; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp index c9a84e23b..3cd7c04d2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp @@ -11,21 +11,31 @@ namespace Event::services::qx { // return ret; // } -RunChange RunChange::fromVariantMap(const QVariantMap &map) +LateEntryRecord LateEntryRecord::fromVariantMap(const QVariantMap &map) { - RunChange ret; + LateEntryRecord ret; if (auto v = map.value("class_name"); v.isValid()) { ret.class_name = v.toString(); } - if (auto v = map.value("first_name"); v.isValid()) { ret.first_name = v.toString(); } - if (auto v = map.value("last_name"); v.isValid()) { ret.last_name = v.toString(); } + if (auto v = map.value("firstname"); v.isValid()) { ret.first_name = v.toString(); } + if (auto v = map.value("lastname"); v.isValid()) { ret.last_name = v.toString(); } if (auto v = map.value("registration"); v.isValid()) { ret.registration = v.toString(); } - if (auto v = map.value("si_id"); v.isValid()) { ret.si_id = v.toInt(); } + if (auto v = map.value("siid"); v.isValid()) { ret.si_id = v.toInt(); } // if (auto v = map.value("si_id_rent"); v.isValid()) { ret.si_id_rent = v.toBool(); } ret.note = map.value("note").toString(); return ret; } +LateEntry LateEntry::fromVariantMap(const QVariantMap &map) +{ + LateEntry ret; + + ret.record = LateEntryRecord::fromVariantMap(map.value("record").toMap()); + ret.run_id = map.value("run_id").toInt(); + + return ret; +} + QVariantMap OrigRunRecord::toVariantMap() const { QVariantMap ret; @@ -36,6 +46,16 @@ QVariantMap OrigRunRecord::toVariantMap() const return ret; } +QxChangeData QxChangeData::fromJson(const QString &json) +{ + QxChangeData ret; + auto map = QJsonDocument::fromJson(json.toUtf8()).toVariant().toMap(); + if (auto v = map.value(DATA_TYPE_LATE_ENTRY); v.isValid()) { + ret.lateEntry = LateEntry::fromVariantMap(v.toMap()); + } + return ret; +} + } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 83ab57062..1577011d8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -6,7 +6,9 @@ namespace Event::services::qx { -struct RunChange +constexpr auto DATA_TYPE_LATE_ENTRY = "LateEntry"; + +struct LateEntryRecord { std::optional class_name; std::optional first_name; @@ -16,8 +18,24 @@ struct RunChange // std::optional si_id_rent; QString note; - // static RunChange fromJsonString(const QString &json); - static RunChange fromVariantMap(const QVariantMap &map); + // static LateEntryRecord fromJsonString(const QString &json); + static LateEntryRecord fromVariantMap(const QVariantMap &map); +}; + +struct LateEntry +{ + int run_id = 0; + LateEntryRecord record; + + // static LateEntryRecord fromJsonString(const QString &json); + static LateEntry fromVariantMap(const QVariantMap &map); +}; + +struct QxChangeData +{ + std::optional lateEntry; + + static QxChangeData fromJson(const QString &json); }; struct OrigRunRecord diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp index 3e99c1e50..25a68b6fc 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.cpp @@ -96,7 +96,8 @@ RpcValue qxRecChngToRpcValue(const qf::core::sql::QxRecChng &chng) SqlApi::SqlApi(QObject *parent) : QObject{parent} { - // connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, ) + auto *qxsql = qf::gui::framework::Application::instance()->qxSql(); + connect(qxsql, &qf::core::sql::QxSql::recChng, this, &SqlApi::recChng); } // void SqlApi::emitRecChng(const qf::core::sql::QxRecChng &chng) @@ -201,7 +202,7 @@ void SqlApi::transaction(const std::string &query, const shv::chainpack::RpcValu for (const auto &p : params) { qparams << shv::coreqt::rpc::rpcValueToQVariant(p); } - return qxsql->transaction(QString::fromStdString(query), qparams); + qxsql->transaction(QString::fromStdString(query), qparams); } RpcValue::List SqlApi::list(const std::string &table, const std::vector &fields, std::optional ids_above, std::optional limit) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h index c0d9334b7..4e3294683 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapi.h @@ -38,6 +38,8 @@ class SqlApi : public QObject public: explicit SqlApi(QObject *parent = nullptr); + Q_SIGNAL void recChng(const qf::core::sql::QxRecChng &recchng, QObject *source); + ExecResult exec(const SqlQueryAndParams ¶ms); QueryResult query(const SqlQueryAndParams ¶ms); void transaction(const std::string &query, const shv::chainpack::RpcValue::List ¶ms); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp index a495e24b1..063e5d516 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/sqlapinode.cpp @@ -23,6 +23,16 @@ SqlApiNode::SqlApiNode(shv::iotqt::node::ShvNode *parent) : Super("sql", parent) , m_sqlApi(new SqlApi(this)) { + connect(m_sqlApi, &SqlApi::recChng, this, [this](const qf::core::sql::QxRecChng &recchng, QObject *source) { + Q_UNUSED(source); + RpcSignal sig; + sig.setSignal("recchng"); + sig.setShvPath(shvPath().asString()); + sig.setParams(shv::coreqt::rpc::qVariantToRpcValue(recchng.toVariantMap())); + qfInfo() << "emit recchng:" << recchng.table; + emitSendRpcMessage(sig); + }); + } namespace { diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 83391b3ab..bac275c69 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -363,7 +363,7 @@ void RunsTableModel::onDataChanged(const QModelIndex &top_left, const QModelInde void RunsTableModel::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source) { - handleQxRecChng(recchng, source); + applyQxRecChng(recchng, source); } bool RunsTableModel::postRow(int row_no, bool throw_exc) From 9569886f9cad1a7015186a2ce5f92db00d6e7315 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 25 Jun 2026 23:07:46 +0200 Subject: [PATCH 35/83] Remove Force checkbox from LateEntryDialog --- .../plugins/Event/src/services/qx/lateentrydialog.cpp | 4 ---- .../plugins/Event/src/services/qx/lateentrydialog.ui | 10 +--------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index aedcf62bf..3ed2e597a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -32,10 +32,6 @@ LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry ui->btAccept->setDisabled(true); ui->btReject->setDisabled(true); - connect(ui->chkForce, &QCheckBox::checkStateChanged, this, [this]() { - ui->btAccept->setDisabled(!ui->chkForce->isChecked()); - ui->btReject->setDisabled(!ui->chkForce->isChecked()); - }); connect(ui->btAccept, &QPushButton::clicked, this, [this]() { resolveChanges(true); }); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index b07ff471c..2f19b0246 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 569 + 576 @@ -333,13 +333,6 @@ - - - - Force - - - @@ -398,7 +391,6 @@ edSiCard edSiCardRent edNote - chkForce btAccept btReject btCancel From c368b26cfc133cc57301158e58d2ba4f3df5d2ee Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 25 Jun 2026 23:15:27 +0200 Subject: [PATCH 36/83] Use updateRecord API for siId and change highlight --- .../plugins/Event/src/services/qx/lateentrydialog.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 3ed2e597a..1fe8c879d 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -55,7 +55,7 @@ LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry is_set = spin_box->value() > 0; } if (is_set) { - widget->setStyleSheet("background: honeydew"); + widget->setStyleSheet("background: palegreen"); } }; @@ -241,11 +241,10 @@ void LateEntryDialog::resolveChanges(bool is_accepted) doc.setValue("siId", ui->edSiCard->value()); } else { - qf::core::sql::Query q; - q.execThrow(QStringLiteral("UPDATE runs SET siId=%1 WHERE id=%2") - .arg(ui->edSiCard->value()) - .arg(m_runId) - ); + qf::core::sql::Record rec { + { "siId", ui->edSiCard->value() }, + }; + qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", m_runId, rec, this); } } doc.save(); From 2844ee89a61d29688a7a8c3fbcba6c2724a4ffaf Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 25 Jun 2026 23:15:47 +0200 Subject: [PATCH 37/83] Revert "Remove Force checkbox from LateEntryDialog" This reverts commit 9569886f9cad1a7015186a2ce5f92db00d6e7315. --- .../plugins/Event/src/services/qx/lateentrydialog.cpp | 4 ++++ .../plugins/Event/src/services/qx/lateentrydialog.ui | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 1fe8c879d..91ee77d58 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -32,6 +32,10 @@ LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry ui->btAccept->setDisabled(true); ui->btReject->setDisabled(true); + connect(ui->chkForce, &QCheckBox::checkStateChanged, this, [this]() { + ui->btAccept->setDisabled(!ui->chkForce->isChecked()); + ui->btReject->setDisabled(!ui->chkForce->isChecked()); + }); connect(ui->btAccept, &QPushButton::clicked, this, [this]() { resolveChanges(true); }); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index 2f19b0246..b07ff471c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 576 + 569 @@ -333,6 +333,13 @@ + + + + Force + + + @@ -391,6 +398,7 @@ edSiCard edSiCardRent edNote + chkForce btAccept btReject btCancel From b6cdb6175241d5a5062331850abb2b8c87f8e104 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 1 Jul 2026 13:51:33 +0200 Subject: [PATCH 38/83] Refactor LateEntry dialog and model Add foreign_table column to qxchanges and narrow the UNIQUE index WHERE clause to include foreign_table='runs' so pending LateEntry uniqueness applies per run. Refactor LateEntry to use a variant LateEntryId (RunId/ClassId), parse ids from variant maps, normalize keys (firstname/lastname/siid), and introduce LateEntryStatus and helper conversion. Update LateEntryDialog API and UI: accept status, extract run id from the variant id, remove lock-number UI and related "Locked"/"Null" filters, and streamline resolve/close and button enable logic. --- .../quickevent/plugins/Event/qml/DbSchema.qml | 5 +- .../plugins/Event/sql/create_db_psql.sql | 3 +- .../plugins/Event/sql/create_db_sqlite.sql | 3 +- .../Event/src/services/qx/lateentrydialog.cpp | 199 ++++++++++++------ .../Event/src/services/qx/lateentrydialog.h | 22 +- .../Event/src/services/qx/lateentrydialog.ui | 32 +-- .../src/services/qx/qxlateentrieswidget.cpp | 39 ++-- .../src/services/qx/qxlateentrieswidget.ui | 14 -- .../Event/src/services/qx/runchange.cpp | 32 ++- .../plugins/Event/src/services/qx/runchange.h | 28 ++- 10 files changed, 193 insertions(+), 184 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index df5393e31..77f00718c 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -494,7 +494,7 @@ Schema { fields: [ Field { name: 'id'; type: Serial { primaryKey: true } }, Field { name: 'stage_id'; type: Int { } }, - // Field { name: 'foreign_table'; type: String { } }, + Field { name: 'foreign_table'; type: String { } }, Field { name: 'foreign_id'; type: Int { } }, Field { name: 'data_type'; type: String { } }, Field { name: 'data'; type: String { } }, @@ -514,7 +514,8 @@ Schema { Index {fields: ['stage_id', 'data_type', 'foreign_id']; unique: false }, Index {fields: ['stage_id', 'status']; unique: false }, Index {fields: ['stage_id', 'foreign_id'] - where: "status = 'Pending' AND data_type = 'LateEntry' AND foreign_id IS NOT NULL" + // The WHERE clause means the index only contains rows that satisfy where condition + where: "status = 'Pending' AND data_type = 'LateEntry' AND foreign_table='runs' AND foreign_id IS NOT NULL" comment: 'Only one pending late entry can be present for single runs.id (foreign_id).' unique: true } diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql index 08dd346bc..2154be167 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql @@ -290,6 +290,7 @@ CREATE TABLE {{eventId}}.lentcards ( CREATE TABLE {{eventId}}.qxchanges ( id serial PRIMARY KEY, stage_id integer, + foreign_table character varying, foreign_id integer, data_type character varying, data character varying, @@ -302,7 +303,7 @@ CREATE TABLE {{eventId}}.qxchanges ( ); CREATE INDEX qxchanges_ix0 ON {{eventId}}.qxchanges (stage_id, data_type, foreign_id); CREATE INDEX qxchanges_ix1 ON {{eventId}}.qxchanges (stage_id, status); -CREATE UNIQUE INDEX qxchanges_unique2 ON {{eventId}}.qxchanges (stage_id, foreign_id) WHERE status = 'Pending' AND data_type = 'LateEntry' AND foreign_id IS NOT NULL; +CREATE UNIQUE INDEX qxchanges_unique2 ON {{eventId}}.qxchanges (stage_id, foreign_id) WHERE status = 'Pending' AND data_type = 'LateEntry' AND foreign_table='runs' AND foreign_id IS NOT NULL; COMMENT ON COLUMN {{eventId}}.qxchanges.orig_data IS 'Store data overriden by change here to enable change rollback.'; ; ------------------------------------; diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql index 4611adaf7..51aec9f21 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql @@ -317,6 +317,7 @@ CREATE TABLE lentcards ( CREATE TABLE qxchanges ( id integer PRIMARY KEY, stage_id integer, + foreign_table character varying, foreign_id integer, data_type character varying, data character varying, @@ -329,7 +330,7 @@ CREATE TABLE qxchanges ( ); CREATE INDEX qxchanges_ix0 ON qxchanges (stage_id, data_type, foreign_id); CREATE INDEX qxchanges_ix1 ON qxchanges (stage_id, status); -CREATE UNIQUE INDEX qxchanges_unique2 ON qxchanges (stage_id, foreign_id) WHERE status = 'Pending' AND data_type = 'LateEntry' AND foreign_id IS NOT NULL; +CREATE UNIQUE INDEX qxchanges_unique2 ON qxchanges (stage_id, foreign_id) WHERE status = 'Pending' AND data_type = 'LateEntry' AND foreign_table='runs' AND foreign_id IS NOT NULL; -- comments not suported for driver: SQLITE -- COMMENT ON COLUMN qxchanges.orig_data IS 'Store data overriden by change here to enable change rollback.'; ; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 91ee77d58..39e631cfc 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -18,14 +18,35 @@ #include #include #include +#include namespace Event::services::qx { -LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry &late_entry, QWidget *parent) - : QDialog(parent) +namespace { + +LateEntryStatus lateEntryStatusFromString(const QString &status) +{ + if (status.compare(QStringLiteral("Pending"), Qt::CaseInsensitive) == 0) { + return LateEntryStatus::Pending; + } + if (status.compare(QStringLiteral("Accepted"), Qt::CaseInsensitive) == 0) { + return LateEntryStatus::Accepted; + } + if (status.compare(QStringLiteral("Rejected"), Qt::CaseInsensitive) == 0) { + return LateEntryStatus::Rejected; + } + qfWarning() << "Unknown late entry status:" << status; + return LateEntryStatus::Rejected; +} + +} // namespace + +LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, QWidget *parent) + : Super(parent) , ui(new Ui::LateEntryDialog) , m_changeId(change_id) - , m_runId(late_entry.run_id) + , m_lateEntryId(late_entry.id) + , m_status(lateEntryStatusFromString(status)) { ui->setupUi(this); @@ -33,22 +54,20 @@ LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry ui->btReject->setDisabled(true); connect(ui->chkForce, &QCheckBox::checkStateChanged, this, [this]() { - ui->btAccept->setDisabled(!ui->chkForce->isChecked()); - ui->btReject->setDisabled(!ui->chkForce->isChecked()); + updateButtonsEnabled(); }); connect(ui->btAccept, &QPushButton::clicked, this, [this]() { - resolveChanges(true); + resolveChangesAndClose(true); + done(QDialog::Accepted); }); connect(ui->btReject, &QPushButton::clicked, this, [this]() { - resolveChanges(false); + resolveChangesAndClose(false); + done(QDialog::Accepted); }); - ui->edClassName->setText(late_entry.record.class_name.value_or(QString())); - ui->edNote->setText(late_entry.record.note); + ui->edNote->setText(late_entry.note.value_or(QString())); - ui->edRunId->setValue(m_runId); ui->edChangeId->setValue(change_id); - ui->edLockNumber->setValue(lock_number); auto update_background = [](QWidget *widget) { bool is_set = false; @@ -63,27 +82,26 @@ LateEntryDialog::LateEntryDialog(int change_id, int lock_number, const LateEntry } }; - ui->grpFirstName->setChecked(late_entry.record.first_name.has_value()); - ui->edFirstName->setText(late_entry.record.first_name.has_value()? late_entry.record.first_name.value(): QString()); + ui->grpFirstName->setChecked(late_entry.first_name.has_value()); + ui->edFirstName->setText(late_entry.first_name.value_or(QString())); update_background(ui->edFirstName); - ui->grpLastName->setChecked(late_entry.record.last_name.has_value()); - ui->edLastName->setText(late_entry.record.last_name.has_value()? late_entry.record.last_name.value(): QString()); + ui->grpLastName->setChecked(late_entry.last_name.has_value()); + ui->edLastName->setText(late_entry.last_name.value_or(QString())); update_background(ui->edLastName); - ui->grpRegistration->setChecked(late_entry.record.registration.has_value()); - ui->edRegistration->setText(late_entry.record.registration.has_value()? late_entry.record.registration.value(): QString()); + ui->grpRegistration->setChecked(late_entry.registration.has_value()); + ui->edRegistration->setText(late_entry.registration.value_or(QString())); update_background(ui->edRegistration); - ui->grpSiCard->setChecked(late_entry.record.si_id.has_value()); - ui->edSiCard->setValue(late_entry.record.si_id.has_value()? late_entry.record.si_id.value(): 0); + ui->grpSiCard->setChecked(late_entry.si_id.has_value()); + ui->edSiCard->setValue(late_entry.si_id.value_or(0)); update_background(ui->edSiCard); - if (m_runId > 0) { - loadOrigValues(); - } - else { - loadClassId(); + if (auto *run_id = std::get_if(&late_entry.id)) { + auto id = run_id->id; + ui->edRunId->setValue(id); + loadOrigValues(id); } lockChange(); } @@ -114,16 +132,16 @@ void LateEntryDialog::setMessage(const QString &msg, bool error) ui->lblError->setText(msg); } -void LateEntryDialog::loadOrigValues() +void LateEntryDialog::loadOrigValues(int run_id) { - Q_ASSERT(m_runId > 0); + Q_ASSERT(run_id > 0); qf::core::sql::Query q; q.execThrow(QStringLiteral("SELECT classes.name AS class_name, competitors.id AS competitor_id" " FROM runs" " JOIN competitors ON competitors.id=runs.competitorId AND runs.id=%1" " LEFT JOIN classes ON competitors.classId=classes.id") - .arg(m_runId) + .arg(run_id) ); if (q.next()) { ui->edClassName->setText(q.value("class_name").toString()); @@ -144,25 +162,50 @@ void LateEntryDialog::loadOrigValues() ui->edSiCardOrig->setValue(m_origValues.si_id); } -void LateEntryDialog::loadClassId() +// void LateEntryDialog::loadClassId() +// { +// auto class_name = ui->edClassName->text(); +// if (class_name.isEmpty()) { +// return; +// } +// qf::core::sql::Query q; +// q.execThrow(QStringLiteral("SELECT id" +// " FROM classes" +// " WHERE name='%1'") +// .arg(class_name) +// ); +// if (q.next()) { +// m_classId = q.value("id").toInt(); +// } +// } + +void LateEntryDialog::unlockChange() const { - auto class_name = ui->edClassName->text(); - if (class_name.isEmpty()) { - return; - } - qf::core::sql::Query q; - q.execThrow(QStringLiteral("SELECT id" - " FROM classes" - " WHERE name='%1'") - .arg(class_name) - ); - if (q.next()) { - m_classId = q.value("id").toInt(); + if (m_lockNumber > 0 || ui->chkForce->isChecked()) { + qf::core::sql::Query q; + q.execThrow(QStringLiteral("UPDATE qxchanges SET lock_number=NULL WHERE id=%1") + .arg(m_changeId) + ); } } void LateEntryDialog::lockChange() { + auto lock_number = QxEventService::currentConnectionId(); + qf::core::sql::Query q; + q.execThrow(QStringLiteral("UPDATE qxchanges SET lock_number=%1 WHERE id=%2 AND (lock_number IS NULL OR lock_number=%1)") + .arg(lock_number) + .arg(m_changeId) + ); + if (q.numRowsAffected() == 0) { + m_lockNumber = 0; + setMessage(tr("Change is already locked by other user."), true); + } + else { + m_lockNumber = lock_number; + } + updateButtonsEnabled(); + // NIY // auto *svc = service(); // auto *nm = svc->networkManager(); @@ -221,45 +264,69 @@ void LateEntryDialog::lockChange() // }); } -void LateEntryDialog::resolveChanges(bool is_accepted) +void LateEntryDialog::updateButtonsEnabled() +{ + ui->btAccept->setEnabled(m_status == LateEntryStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); + ui->btReject->setEnabled(m_status == LateEntryStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); +} + +void LateEntryDialog::resolveChangesAndClose(bool is_accepted) { using namespace qf::gui::model; - bool is_insert = m_runId == 0; - Competitors::CompetitorDocument doc; - doc.load(m_competitorId, is_insert? DataDocument::ModeInsert: DataDocument::ModeEdit); - if (is_insert) { - doc.setValue("classId", m_classId); - } - if (ui->grpFirstName->isChecked()) { - doc.setValue("firstName", ui->edFirstName->text()); - } - if (ui->grpLastName->isChecked()) { - doc.setValue("lastName", ui->edLastName->text()); - } - if (ui->grpRegistration->isChecked()) { - doc.setValue("registration", ui->edRegistration->text()); - } - if (ui->grpSiCard->isChecked()) { + if (is_accepted) { + bool is_insert = !runId().has_value(); + if (is_insert) { + qfError() << "insert not implemented yet"; + return; + } + Competitors::CompetitorDocument doc; + doc.load(m_competitorId, is_insert? DataDocument::ModeInsert: DataDocument::ModeEdit); if (is_insert) { - doc.setValue("siId", ui->edSiCard->value()); + // doc.setValue("classId", m_classId); } - else { - qf::core::sql::Record rec { - { "siId", ui->edSiCard->value() }, - }; - qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", m_runId, rec, this); + if (ui->grpFirstName->isChecked()) { + doc.setValue("firstName", ui->edFirstName->text()); } + if (ui->grpLastName->isChecked()) { + doc.setValue("lastName", ui->edLastName->text()); + } + if (ui->grpRegistration->isChecked()) { + doc.setValue("registration", ui->edRegistration->text()); + } + if (ui->grpSiCard->isChecked()) { + if (is_insert) { + doc.setValue("siId", ui->edSiCard->value()); + } + else { + qf::core::sql::Record rec { + { "siId", ui->edSiCard->value() }, + }; + qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", runId().value(), rec, this); + } + } + doc.save(); } - doc.save(); qf::core::sql::Record rec { {"status", is_accepted? "Accepted": "Rejected"}, - {"orig_data", qf::core::Utils::qvariantToJson(m_origValues.toVariantMap())}, + {"orig_data", qf::core::Utils::qvariantToJson(is_accepted? m_origValues.toVariantMap(): QVariantMap{})}, }; qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); } -} // namespace Event::services::qx +void LateEntryDialog::done(int result) +{ + unlockChange(); + Super::done(result); +} +std::optional LateEntryDialog::runId() const +{ + if (auto *id = std::get_if(&m_lateEntryId)) { + return id->id; + } + return std::nullopt; +} +} // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index d6be39898..def041690 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -13,34 +13,40 @@ namespace Ui { class LateEntryDialog; } -struct LateEntryRecord; +struct LateEntry; class QxEventService; +enum class LateEntryStatus {Pending, Accepted, Rejected}; + class LateEntryDialog : public QDialog { Q_OBJECT - + using Super = QDialog; public: - explicit LateEntryDialog(int change_id, int lock_number, const LateEntry &late_entry, QWidget *parent = nullptr); + explicit LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, QWidget *parent = nullptr); ~LateEntryDialog() override; + void done(int result) override; private: + std::optional runId() const; QxEventService* service(); void setMessage(const QString &msg, bool error); - void loadOrigValues(); - void loadClassId(); + void loadOrigValues(int run_id); + // void loadClassId(); void lockChange(); + void unlockChange() const; + void updateButtonsEnabled(); - void resolveChanges(bool is_accepted); + void resolveChangesAndClose(bool is_accepted); private: Ui::LateEntryDialog *ui; int m_changeId = 0; - int m_runId = 0; + LateEntryId m_lateEntryId = RunId{}; int m_competitorId = 0; - int m_classId = 0; int m_lockNumber = 0; + LateEntryStatus m_status = LateEntryStatus::Rejected; OrigRunRecord m_origValues; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index b07ff471c..fc234271c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 569 + 576 @@ -101,35 +101,6 @@ - - - - Lock number - - - - - - - - 0 - 0 - - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - - true - - - None - - - 999999999 - - - @@ -382,7 +353,6 @@ edClassName edRunId edChangeId - edLockNumber grpFirstName edFirstNameOrig edFirstName diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index edaf69723..02cc882b2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -36,9 +36,6 @@ constexpr auto COL_USER_ID = "user_id"; constexpr auto COL_CREATED = "created"; constexpr auto COL_LOCK_NUMBER = "lock_number"; -constexpr auto STATUS_PENDING = "Pending"; -constexpr auto STATUS_LOCKED = "Locked"; - QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : QWidget(parent), ui(new Ui::QxLateEntriesWidget) @@ -101,9 +98,7 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : lst->setCurrentIndex(0); connect(lst, &QComboBox::currentIndexChanged, this, &QxLateEntriesWidget::reload); } - connect(ui->chkNull, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); connect(ui->chkPending, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); - connect(ui->chkLocked, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); connect(ui->chkAccepted, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); connect(ui->chkRejected, &QCheckBox::checkStateChanged, this, &QxLateEntriesWidget::reload); @@ -111,12 +106,8 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : QSignalBlocker sb1(ui->lstType); ui->lstType->setCurrentIndex(0); - QSignalBlocker sb2(ui->chkNull); - ui->chkNull->setChecked(true); QSignalBlocker sb3(ui->chkPending); ui->chkPending->setChecked(true); - QSignalBlocker sb4(ui->chkLocked); - ui->chkLocked->setChecked(true); QSignalBlocker sb5(ui->chkAccepted); ui->chkAccepted->setChecked(true); QSignalBlocker sb6(ui->chkRejected); @@ -185,15 +176,9 @@ void QxLateEntriesWidget::reload() .where("stage_id=" + QString::number(stage_id)) .orderBy("id"); QStringList status_cond_list; - if (ui->chkNull->isChecked()) { - status_cond_list << "status IS NULL"; - } if (ui->chkPending->isChecked()) { status_cond_list << "status='Pending'"; } - if (ui->chkLocked->isChecked()) { - status_cond_list << "status LIKE 'Locked%'"; - } if (ui->chkAccepted->isChecked()) { status_cond_list << "status='Accepted'"; } @@ -252,23 +237,25 @@ void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { auto row = ix.row(); auto status = m_model->value(row, COL_STATUS).toString(); - if (status == STATUS_PENDING || status == STATUS_LOCKED) { - auto data = m_model->value(row, COL_DATA).toString(); - auto qxdata = QxChangeData::fromJson(data); - if (qxdata.lateEntry.has_value()) { - auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); - auto change_id = m_model->value(row, COL_ID).toInt(); - LateEntryDialog dlg(change_id, lock_number, qxdata.lateEntry.value(), this); - dlg.exec(); - ui->tableView->reloadRow(row); - } + auto data = m_model->value(row, COL_DATA).toString(); + auto qxdata = QxChangeData::fromJson(data); + if (qxdata.lateEntry.has_value()) { + // auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); + auto change_id = m_model->value(row, COL_ID).toInt(); + LateEntryDialog dlg(change_id, qxdata.lateEntry.value(), status, this); + dlg.exec(); + ui->tableView->reloadRow(row); } } void QxLateEntriesWidget::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source) { + if (recchng.table == "qxchanges" && recchng.record.contains("status")) { + // status affect filter, cannot be solved by applyQxRecChng + m_model->reload(); + return; + } m_model->applyQxRecChng(recchng, source); } } - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui index 30abe1ed9..9ac4e2a67 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.ui @@ -87,13 +87,6 @@ 0 - - - - Locked - - - @@ -108,13 +101,6 @@ - - - - Null - - - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp index 3cd7c04d2..fe2150e97 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp @@ -11,27 +11,23 @@ namespace Event::services::qx { // return ret; // } -LateEntryRecord LateEntryRecord::fromVariantMap(const QVariantMap &map) +LateEntry LateEntry::fromVariantMap(const QVariantMap &map) { - LateEntryRecord ret; + LateEntry ret; - if (auto v = map.value("class_name"); v.isValid()) { ret.class_name = v.toString(); } + auto id_map = map.value("id").toMap(); + if (auto id = id_map.value("RunId").toInt(); id > 0) { + ret.id = RunId{id}; + } + if (auto id = id_map.value("ClassId").toInt(); id > 0) { + ret.id = ClassId{id}; + } if (auto v = map.value("firstname"); v.isValid()) { ret.first_name = v.toString(); } if (auto v = map.value("lastname"); v.isValid()) { ret.last_name = v.toString(); } if (auto v = map.value("registration"); v.isValid()) { ret.registration = v.toString(); } if (auto v = map.value("siid"); v.isValid()) { ret.si_id = v.toInt(); } // if (auto v = map.value("si_id_rent"); v.isValid()) { ret.si_id_rent = v.toBool(); } - ret.note = map.value("note").toString(); - - return ret; -} - -LateEntry LateEntry::fromVariantMap(const QVariantMap &map) -{ - LateEntry ret; - - ret.record = LateEntryRecord::fromVariantMap(map.value("record").toMap()); - ret.run_id = map.value("run_id").toInt(); + if (auto v = map.value("note"); v.isValid()) { ret.note = v.toString(); } return ret; } @@ -39,10 +35,10 @@ LateEntry LateEntry::fromVariantMap(const QVariantMap &map) QVariantMap OrigRunRecord::toVariantMap() const { QVariantMap ret; - ret["first_name"] = first_name; - ret["last_name"] = last_name; + ret["firstname"] = first_name; + ret["lastname"] = last_name; ret["registration"] = registration; - ret["si_id"] = si_id; + ret["siid"] = si_id; return ret; } @@ -57,5 +53,3 @@ QxChangeData QxChangeData::fromJson(const QString &json) } } // namespace Event::services::qx - - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 1577011d8..1020c4a45 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -4,30 +4,29 @@ #include #include +#include +#include + namespace Event::services::qx { constexpr auto DATA_TYPE_LATE_ENTRY = "LateEntry"; -struct LateEntryRecord +struct RunId { int id = 0; }; +struct ClassId { int id = 0; }; + +using LateEntryId = std::variant; + +struct LateEntry { - std::optional class_name; + LateEntryId id = RunId{}; std::optional first_name; std::optional last_name; std::optional registration; std::optional si_id; // std::optional si_id_rent; - QString note; - - // static LateEntryRecord fromJsonString(const QString &json); - static LateEntryRecord fromVariantMap(const QVariantMap &map); -}; + std::optional note; -struct LateEntry -{ - int run_id = 0; - LateEntryRecord record; - - // static LateEntryRecord fromJsonString(const QString &json); + // static LateEntry fromJsonString(const QString &json); static LateEntry fromVariantMap(const QVariantMap &map); }; @@ -92,6 +91,3 @@ struct EventChange // }; } // namespace Event::services::qx - - - From efd64804af9ea85929703e416db07d09bb096ee4 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 4 Jul 2026 00:26:22 +0200 Subject: [PATCH 39/83] Add status message and class handling to late entries Constructor now accepts a status_message; UI adds edStatusMessage and a Send button which calls updateQxChangeMessage to persist the message. Implement loadClassName() and classId() to handle ClassId foreign ids and use the class id for inserts. Rename LateEntryId to LateEntryForeignId and add a foreign_table column in the model. Persist status_message when updating qxchanges and adjust related logic and UI layout. --- .../Event/src/services/qx/lateentrydialog.cpp | 69 +++++++++++-------- .../Event/src/services/qx/lateentrydialog.h | 9 ++- .../Event/src/services/qx/lateentrydialog.ui | 40 +++++++++-- .../src/services/qx/qxlateentrieswidget.cpp | 5 +- .../plugins/Event/src/services/qx/runchange.h | 4 +- 5 files changed, 86 insertions(+), 41 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 39e631cfc..b61a48168 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -41,7 +41,7 @@ LateEntryStatus lateEntryStatusFromString(const QString &status) } // namespace -LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, QWidget *parent) +LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent) : Super(parent) , ui(new Ui::LateEntryDialog) , m_changeId(change_id) @@ -50,6 +50,8 @@ LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, con { ui->setupUi(this); + ui->edStatusMessage->setPlainText(status_message); + ui->btAccept->setDisabled(true); ui->btReject->setDisabled(true); @@ -64,6 +66,7 @@ LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, con resolveChangesAndClose(false); done(QDialog::Accepted); }); + connect(ui->btSendMessage, &QPushButton::clicked, this, &LateEntryDialog::updateQxChangeMessage); ui->edNote->setText(late_entry.note.value_or(QString())); @@ -103,6 +106,10 @@ LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, con ui->edRunId->setValue(id); loadOrigValues(id); } + else if (auto *id = std::get_if(&late_entry.id)) { + auto class_id = id->id; + loadClassName(class_id); + } lockChange(); } @@ -162,30 +169,22 @@ void LateEntryDialog::loadOrigValues(int run_id) ui->edSiCardOrig->setValue(m_origValues.si_id); } -// void LateEntryDialog::loadClassId() -// { -// auto class_name = ui->edClassName->text(); -// if (class_name.isEmpty()) { -// return; -// } -// qf::core::sql::Query q; -// q.execThrow(QStringLiteral("SELECT id" -// " FROM classes" -// " WHERE name='%1'") -// .arg(class_name) -// ); -// if (q.next()) { -// m_classId = q.value("id").toInt(); -// } -// } +void LateEntryDialog::loadClassName(int class_id) +{ + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT name FROM classes WHERE id=%1") + .arg(class_id) ); + if (q.next()) { + ui->edClassName->setText(q.value(0).toString()); + } +} void LateEntryDialog::unlockChange() const { if (m_lockNumber > 0 || ui->chkForce->isChecked()) { qf::core::sql::Query q; q.execThrow(QStringLiteral("UPDATE qxchanges SET lock_number=NULL WHERE id=%1") - .arg(m_changeId) - ); + .arg(m_changeId) ); } } @@ -275,15 +274,12 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) using namespace qf::gui::model; if (is_accepted) { - bool is_insert = !runId().has_value(); - if (is_insert) { - qfError() << "insert not implemented yet"; - return; - } + auto class_id = classId(); + bool is_insert = class_id.has_value(); Competitors::CompetitorDocument doc; doc.load(m_competitorId, is_insert? DataDocument::ModeInsert: DataDocument::ModeEdit); if (is_insert) { - // doc.setValue("classId", m_classId); + doc.setValue("classId", class_id.value()); } if (ui->grpFirstName->isChecked()) { doc.setValue("firstName", ui->edFirstName->text()); @@ -298,11 +294,11 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) if (is_insert) { doc.setValue("siId", ui->edSiCard->value()); } - else { + else if (auto run_id = runId(); run_id.has_value()) { qf::core::sql::Record rec { { "siId", ui->edSiCard->value() }, }; - qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", runId().value(), rec, this); + qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", run_id.value(), rec, this); } } doc.save(); @@ -310,7 +306,16 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) qf::core::sql::Record rec { {"status", is_accepted? "Accepted": "Rejected"}, - {"orig_data", qf::core::Utils::qvariantToJson(is_accepted? m_origValues.toVariantMap(): QVariantMap{})}, + {"status_message", ui->edStatusMessage->toPlainText()}, + {"orig_data", qf::core::Utils::qvariantToJson(is_accepted? m_origValues.toVariantMap(): QVariantMap{})}, + }; + qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); +} + +void LateEntryDialog::updateQxChangeMessage() +{ + qf::core::sql::Record rec { + { "status_message", ui->edStatusMessage->toPlainText() }, }; qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); } @@ -329,4 +334,12 @@ std::optional LateEntryDialog::runId() const return std::nullopt; } +std::optional LateEntryDialog::classId() const +{ + if (auto *id = std::get_if(&m_lateEntryId)) { + return id->id; + } + return std::nullopt; +} + } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index def041690..584b62fd1 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -23,27 +23,30 @@ class LateEntryDialog : public QDialog Q_OBJECT using Super = QDialog; public: - explicit LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, QWidget *parent = nullptr); + explicit LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent = nullptr); ~LateEntryDialog() override; void done(int result) override; private: std::optional runId() const; + std::optional classId() const; QxEventService* service(); void setMessage(const QString &msg, bool error); void loadOrigValues(int run_id); - // void loadClassId(); + void loadClassName(int class_id); void lockChange(); void unlockChange() const; void updateButtonsEnabled(); void resolveChangesAndClose(bool is_accepted); + void updateQxChangeMessage(); + private: Ui::LateEntryDialog *ui; int m_changeId = 0; - LateEntryId m_lateEntryId = RunId{}; + LateEntryForeignId m_lateEntryId = RunId{}; int m_competitorId = 0; int m_lockNumber = 0; LateEntryStatus m_status = LateEntryStatus::Rejected; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index fc234271c..e2b9a4766 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 576 + 586 @@ -280,14 +280,38 @@ - - - Message - - + + + + + Message + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Send + + + + - + @@ -368,6 +392,8 @@ edSiCard edSiCardRent edNote + edStatusMessage + btSendMessage chkForce btAccept btReject diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index 02cc882b2..780c9a28e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -28,6 +28,7 @@ namespace Event::services::qx { constexpr auto COL_ID = "id"; constexpr auto COL_DATA_TYPE = "data_type"; constexpr auto COL_FOREIGN_ID = "foreign_id"; +constexpr auto COL_FOREIGN_TABLE = "foreign_table"; constexpr auto COL_DATA = "data"; constexpr auto COL_ORIG_DATA = "orig_data"; constexpr auto COL_STATUS = "status"; @@ -59,6 +60,7 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : m_model->addColumn(COL_ID).setReadOnly(true).setAlignment(Qt::AlignLeft); m_model->addColumn(COL_STATUS, tr("Status")); m_model->addColumn(COL_DATA_TYPE, tr("Type")); + m_model->addColumn(COL_FOREIGN_TABLE, tr("Foreign table")); m_model->addColumn(COL_FOREIGN_ID, tr("Foreign ID")).setAlignment(Qt::AlignLeft); m_model->addColumn(COL_USER_ID, tr("User")); m_model->addColumn(COL_STATUS_MESSAGE, tr("Status message")); @@ -237,12 +239,13 @@ void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { auto row = ix.row(); auto status = m_model->value(row, COL_STATUS).toString(); + auto status_message = m_model->value(row, COL_STATUS_MESSAGE).toString(); auto data = m_model->value(row, COL_DATA).toString(); auto qxdata = QxChangeData::fromJson(data); if (qxdata.lateEntry.has_value()) { // auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); auto change_id = m_model->value(row, COL_ID).toInt(); - LateEntryDialog dlg(change_id, qxdata.lateEntry.value(), status, this); + LateEntryDialog dlg(change_id, qxdata.lateEntry.value(), status, status_message, this); dlg.exec(); ui->tableView->reloadRow(row); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 1020c4a45..58f0371a7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -14,11 +14,11 @@ constexpr auto DATA_TYPE_LATE_ENTRY = "LateEntry"; struct RunId { int id = 0; }; struct ClassId { int id = 0; }; -using LateEntryId = std::variant; +using LateEntryForeignId = std::variant; struct LateEntry { - LateEntryId id = RunId{}; + LateEntryForeignId id = RunId{}; std::optional first_name; std::optional last_name; std::optional registration; From dbce7f3b9dc82e1a9fc6cfef59d2d571966e15c2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 5 Jul 2026 19:35:40 +0200 Subject: [PATCH 40/83] Move start-time logic to CompetitorDocument Make possibleStartTimesMs a static method on CompetitorDocument and replace the widget-local implementation with a call to it. Add start_time fields to LateEntry/OrigRunRecord and update late-entry dialog (pass stage id, UI tweaks, size, readonly original name). Add isExportDatabase setting and only set RPC device options when enabled. Add RunsWidget::showEditCompetitorDialog helper. --- .../Competitors/src/competitordocument.cpp | 98 +++++++++++++ .../Competitors/src/competitordocument.h | 2 + .../Competitors/src/competitorwidget.cpp | 92 +----------- .../Event/src/services/qx/lateentrydialog.cpp | 131 +++++++++--------- .../Event/src/services/qx/lateentrydialog.h | 4 +- .../Event/src/services/qx/lateentrydialog.ui | 52 ++++++- .../Event/src/services/qx/qxeventservice.cpp | 12 +- .../Event/src/services/qx/qxeventservice.h | 1 + .../src/services/qx/qxeventservicewidget.cpp | 11 +- .../src/services/qx/qxeventservicewidget.h | 4 +- .../src/services/qx/qxeventservicewidget.ui | 73 ++++------ .../src/services/qx/qxlateentrieswidget.cpp | 78 ++++++++--- .../Event/src/services/qx/runchange.cpp | 2 + .../plugins/Event/src/services/qx/runchange.h | 4 +- .../plugins/Runs/src/runswidget.cpp | 12 ++ .../quickevent/plugins/Runs/src/runswidget.h | 1 + 16 files changed, 335 insertions(+), 242 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp index 698f22ebd..cae50bfde 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp @@ -1,5 +1,6 @@ #include "competitordocument.h" +#include #include #include @@ -213,4 +214,101 @@ QVariant CompetitorDocument::siid() const return value(SIID); } +QList CompetitorDocument::possibleStartTimesMs(int run_id) +{ + using namespace qf::core::sql; + + int class_id; + int stage_id; + int start_time; + QString club_abbr; + { + qf::core::sql::QueryBuilder qb; + qb.select2("runs", "competitorId, stageId, startTimeMs") + .select2("competitors", "classId, registration") + .from("runs") + .joinRestricted("runs.competitorId", "competitors.id", "runs.id=" QF_IARG(run_id), qf::core::sql::QueryBuilder::INNER_JOIN) + .where("runs.isRunning"); + Query q; + q.exec(qb.toString(), qf::core::Exception::Throw); + if (q.next()) { + class_id = q.value("classId").toInt(); + stage_id = q.value("stageId").toInt(); + start_time = q.value("startTimeMs").toInt(); + club_abbr = q.value("registration").toString().mid(0, 3).toUpper(); + } + else { + return {}; + } + } + + Classes::ClassDef class_def; + class_def.load(class_id, stage_id, false); + + if (class_def.classInterval == 0) { + return {}; + } + + struct S { + QString club; + int start_time = 0; + + bool operator<(const S &o) const { return start_time < o.start_time; } + }; + QList runs; + { + qf::core::sql::QueryBuilder qb; + qb.select2("runs", "startTimeMs") + .select2("competitors", "registration") + .from("runs") + .joinRestricted("runs.competitorId", "competitors.id", "competitors.classId=" QF_IARG(class_id), qf::core::sql::QueryBuilder::INNER_JOIN) + .where("runs.stageId=" QF_IARG(stage_id)) + .where("runs.isRunning") + .orderBy("runs.startTimeMs"); + //qfInfo() << qb.toString(); + Query q; + q.exec(qb.toString(), qf::core::Exception::Throw); + while (q.next()) { + //auto start_time = q.value("startTimeMs").toInt(); + //if (start_time < class_def.classStartFirst) { + // continue; + //} + runs << S { + .club = q.value("registration").toString().mid(0, 3).toUpper(), + .start_time = q.value("startTimeMs").toInt() + }; + } + std::sort(runs.begin(), runs.end()); + } + QList ret; + auto start_interval_ms = class_def.classInterval * 60 * 1000; + for (auto stime = class_def.classStartFirst; stime <= class_def.classStartLast; stime += class_def.classInterval) { + S r { .club = {}, .start_time = stime }; + auto [lo, up] = std::equal_range(runs.begin(), runs.end(), r); + if (lo == up || stime == start_time) { + // stime does not exist or it is my current start_time, should be inserted before up + // check next club + // qfInfo() << "free stime:" << quickevent::core::og::TimeMs(stime).toString(); + if (up != runs.end()) { + // qfInfo() << "next club:" << up->club; + if (up->club == club_abbr && (up->start_time - stime) <= start_interval_ms) { + // qfInfo() << "same next club:" << club_abbr; + continue; + } + } + // check prev club + if (up != runs.begin()) { + up--; + // qfInfo() << "prev club:" << up->club; + if (up->club == club_abbr && (stime - up->start_time) <= start_interval_ms) { + // qfInfo() << "same prev club:" << club_abbr; + continue; + } + } + ret << stime; + } + } + return ret; +} + diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h index b282d4ebb..8894d63d3 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.h @@ -19,6 +19,8 @@ class CompetitorDocument : public qf::gui::model::SqlDataDocument void setSiid(const QVariant &siid); QVariant siid() const; const QVector& runsIds() const {return m_runsIds;} + + static QList possibleStartTimesMs(int run_id); protected: bool loadData() override; bool saveData() override; diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp index 62c225d4e..a19672881 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp @@ -376,97 +376,7 @@ QString CompetitorWidget::guessClassFromRegistration(const QString ®istration QList CompetitorWidget::possibleStartTimesMs(int run_id) { - int class_id; - int stage_id; - int start_time; - QString club_abbr; - { - qf::core::sql::QueryBuilder qb; - qb.select2("runs", "competitorId, stageId, startTimeMs") - .select2("competitors", "classId, registration") - .from("runs") - .joinRestricted("runs.competitorId", "competitors.id", "runs.id=" QF_IARG(run_id), qf::core::sql::QueryBuilder::INNER_JOIN) - .where("runs.isRunning"); - qfs::Query q; - q.exec(qb.toString(), qf::core::Exception::Throw); - if (q.next()) { - class_id = q.value("classId").toInt(); - stage_id = q.value("stageId").toInt(); - start_time = q.value("startTimeMs").toInt(); - club_abbr = q.value("registration").toString().mid(0, 3).toUpper(); - } - else { - return {}; - } - } - - Classes::ClassDef class_def; - class_def.load(class_id, stage_id, false); - - if (class_def.classInterval == 0) { - return {}; - } - - struct S { - QString club; - int start_time = 0; - - bool operator<(const S &o) const { return start_time < o.start_time; } - }; - QList runs; - { - qf::core::sql::QueryBuilder qb; - qb.select2("runs", "startTimeMs") - .select2("competitors", "registration") - .from("runs") - .joinRestricted("runs.competitorId", "competitors.id", "competitors.classId=" QF_IARG(class_id), qf::core::sql::QueryBuilder::INNER_JOIN) - .where("runs.stageId=" QF_IARG(stage_id)) - .where("runs.isRunning") - .orderBy("runs.startTimeMs"); - //qfInfo() << qb.toString(); - qfs::Query q; - q.exec(qb.toString(), qf::core::Exception::Throw); - while (q.next()) { - //auto start_time = q.value("startTimeMs").toInt(); - //if (start_time < class_def.classStartFirst) { - // continue; - //} - runs << S { - .club = q.value("registration").toString().mid(0, 3).toUpper(), - .start_time = q.value("startTimeMs").toInt() - }; - } - std::sort(runs.begin(), runs.end()); - } - QList ret; - auto start_interval_ms = class_def.classInterval * 60 * 1000; - for (auto stime = class_def.classStartFirst; stime <= class_def.classStartLast; stime += class_def.classInterval) { - S r { .club = {}, .start_time = stime }; - auto [lo, up] = std::equal_range(runs.begin(), runs.end(), r); - if (lo == up || stime == start_time) { - // stime does not exist or it is my current start_time, should be inserted before up - // check next club - // qfInfo() << "free stime:" << quickevent::core::og::TimeMs(stime).toString(); - if (up != runs.end()) { - qfInfo() << "next club:" << up->club; - if (up->club == club_abbr && (up->start_time - stime) <= start_interval_ms) { - // qfInfo() << "same next club:" << club_abbr; - continue; - } - } - // check prev club - if (up != runs.begin()) { - up--; - // qfInfo() << "prev club:" << up->club; - if (up->club == club_abbr && (stime - up->start_time) <= start_interval_ms) { - // qfInfo() << "same prev club:" << club_abbr; - continue; - } - } - ret << stime; - } - } - return ret; + return Competitors::CompetitorDocument::possibleStartTimesMs(run_id); } void CompetitorWidget::onRegistrationSelected(const QVariantMap &values) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index b61a48168..7b9244214 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include #include @@ -20,6 +22,8 @@ #include #include +using namespace quickevent::core::og; + namespace Event::services::qx { namespace { @@ -41,13 +45,16 @@ LateEntryStatus lateEntryStatusFromString(const QString &status) } // namespace -LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent) +LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent) : Super(parent) , ui(new Ui::LateEntryDialog) , m_changeId(change_id) + , m_stageId(stage_id) , m_lateEntryId(late_entry.id) , m_status(lateEntryStatusFromString(status)) { + Q_ASSERT(change_id > 0); + ui->setupUi(this); ui->edStatusMessage->setPlainText(status_message); @@ -101,10 +108,17 @@ LateEntryDialog::LateEntryDialog(int change_id, const LateEntry &late_entry, con ui->edSiCard->setValue(late_entry.si_id.value_or(0)); update_background(ui->edSiCard); + ui->grpStartTime->setChecked(late_entry.start_time_ms.has_value()); + ui->edStartTime->setText(TimeMs(late_entry.start_time_ms.value_or(0)).toString()); + update_background(ui->edStartTime); + + connect(ui->edStartTime, &QLineEdit::textEdited, this, &LateEntryDialog::checkStartTimeIsValid); + if (auto *run_id = std::get_if(&late_entry.id)) { auto id = run_id->id; ui->edRunId->setValue(id); loadOrigValues(id); + checkStartTimeIsValid(); } else if (auto *id = std::get_if(&late_entry.id)) { auto class_id = id->id; @@ -161,11 +175,23 @@ void LateEntryDialog::loadOrigValues(int run_id) m_origValues.first_name = doc.value("firstName").toString(); m_origValues.last_name = doc.value("lastName").toString(); m_origValues.registration = doc.value("registration").toString(); + { + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT startTimeMs" + " FROM runs" + " WHERE id=%1") + .arg(run_id) + ); + if (q.next()) { + m_origValues.start_time_ms = q.value("startTimeMs").toInt(); + } + } m_origValues.si_id = doc.value("siId").toInt(); ui->edFirstNameOrig->setText(m_origValues.first_name); ui->edLastNameOrig->setText(m_origValues.last_name); ui->edRegistrationOrig->setText(m_origValues.registration); + ui->edStartTimeOrig->setText(TimeMs(m_origValues.start_time_ms).toString()); ui->edSiCardOrig->setValue(m_origValues.si_id); } @@ -204,63 +230,6 @@ void LateEntryDialog::lockChange() m_lockNumber = lock_number; } updateButtonsEnabled(); - - // NIY - // auto *svc = service(); - // auto *nm = svc->networkManager(); - - // auto path = QStringLiteral("/api/event/%1/changes").arg(svc->eventId()); - // QUrlQuery query; - // query.addQueryItem("from_id", QString::number(m_changeId)); - // query.addQueryItem("limit", QString::number(1)); - // svc->getHttpJson(path, query, this, [this](auto data, auto error) { - // if (!error.isEmpty()) { - // setMessage(error, true); - // return; - // } - // auto rec = data.toList().value(0).toMap(); - // }); - - - // QNetworkRequest request; - // auto url = svc->exchangeServerUrl(); - // // qfInfo() << "url " << url.toString(); - // url.setPath("/api/event/current/changes/lock-change"); - - // QUrlQuery query; - // query.addQueryItem("change_id", QString::number(m_changeId)); - // auto connection_id = QxClientService::currentConnectionId(); - // query.addQueryItem("lock_number", QString::number(connection_id)); - // url.setQuery(query); - // qfInfo() << "GET " << url.toString(); - - // request.setUrl(url); - // request.setRawHeader(QxClientService::QX_API_TOKEN, svc->apiToken()); - // auto *reply = nm->get(request); - // connect(reply, &QNetworkReply::finished, this, [this, reply, connection_id]() { - // auto data = reply->readAll(); - // if (reply->error() == QNetworkReply::NetworkError::NoError) { - // m_lockNumber = data.toInt(); - // ui->edLockNumber->setValue(m_lockNumber); - // if (m_lockNumber == connection_id) { - // ui->btAccept->setDisabled(false); - // ui->btReject->setDisabled(false); - - // qf::core::sql::Query q; - // q.execThrow(QStringLiteral("UPDATE qxchanges SET lock_number=%1, status='Locked' WHERE id=%2") - // .arg(connection_id) - // .arg(m_changeId) - // ); - // } - // else { - // setMessage(tr("Change is locked already by other client: %1, current client id:.%2").arg(m_lockNumber).arg(connection_id), false); - // } - // } - // else { - // setMessage(tr("Lock change error: %1\n%2").arg(reply->errorString()).arg(QString::fromUtf8(data)), true); - // } - // reply->deleteLater(); - // }); } void LateEntryDialog::updateButtonsEnabled() @@ -294,14 +263,33 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) if (is_insert) { doc.setValue("siId", ui->edSiCard->value()); } - else if (auto run_id = runId(); run_id.has_value()) { - qf::core::sql::Record rec { - { "siId", ui->edSiCard->value() }, - }; - qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", run_id.value(), rec, this); - } } doc.save(); + + qf::core::sql::Record rec; + if (ui->grpSiCard->isChecked()) { + rec["siId"] = ui->edSiCard->value(); + } + if (ui->grpStartTime->isChecked()) { + rec["starttimems"] = TimeMs::fromString(ui->edStartTime->text()).msec(); + } + if (!rec.isEmpty()) { + auto competitor_id = doc.value("id").toInt(); + Q_ASSERT(competitor_id > 0); + int run_id = 0; + { + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT id FROM runs WHERE competitorId=%1 AND stageId=%2") + .arg(competitor_id) + .arg(m_stageId) + ); + if (q.next()) { + run_id = q.value(0).toInt(); + } + } + Q_ASSERT(run_id > 0); + qf::gui::framework::Application::instance()->qxSql()->updateRecord("runs", run_id, rec, this); + } } qf::core::sql::Record rec { @@ -320,6 +308,21 @@ void LateEntryDialog::updateQxChangeMessage() qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); } +void LateEntryDialog::checkStartTimeIsValid() +{ + if (auto run_id = runId(); run_id.has_value()) { + auto stime = TimeMs::fromString(ui->edStartTime->text()); + if (stime.isValid()) { + auto possible_stimes = Competitors::CompetitorDocument::possibleStartTimesMs(run_id.value()); + if (possible_stimes.contains(stime.msec())) { + ui->edStartTime->setStyleSheet({}); + } else { + ui->edStartTime->setStyleSheet("background: red"); + } + } + } +} + void LateEntryDialog::done(int result) { unlockChange(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index 584b62fd1..909cebfd2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -23,7 +23,7 @@ class LateEntryDialog : public QDialog Q_OBJECT using Super = QDialog; public: - explicit LateEntryDialog(int change_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent = nullptr); + explicit LateEntryDialog(int change_id, int stage_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent = nullptr); ~LateEntryDialog() override; void done(int result) override; @@ -43,9 +43,11 @@ class LateEntryDialog : public QDialog void resolveChangesAndClose(bool is_accepted); void updateQxChangeMessage(); + void checkStartTimeIsValid(); private: Ui::LateEntryDialog *ui; int m_changeId = 0; + int m_stageId = 0; LateEntryForeignId m_lateEntryId = RunId{}; int m_competitorId = 0; int m_lockNumber = 0; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index e2b9a4766..73d119d72 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 586 + 668 @@ -113,7 +113,11 @@ - + + + true + + @@ -141,7 +145,11 @@ - + + + true + + @@ -169,7 +177,11 @@ - + + + true + + @@ -261,6 +273,38 @@ + + + + Start time + + + true + + + + + + true + + + + + + + -> + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index c0b4d42d6..fb27d5912 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -83,11 +83,13 @@ void QxEventService::run() { m_rpcConnection = new DeviceConnection("QuickEvent", this); m_rpcConnection->setConnectionString(ss.shvBrokerUrl()); - RpcValue::Map opts; - RpcValue::Map device; - device["deviceId"] = api_token.toStdString(); - opts["device"] = device; - m_rpcConnection->setConnectionOptions(opts); + if (ss.isExportDatabase()) { + RpcValue::Map opts; + RpcValue::Map device; + device["deviceId"] = api_token.toStdString(); + opts["device"] = device; + m_rpcConnection->setConnectionOptions(opts); + } connect(m_rpcConnection, &ClientConnection::brokerConnectedChanged, this, &QxEventService::onBrokerConnectedChanged); connect(m_rpcConnection, &ClientConnection::socketError, this, &QxEventService::onBrokerSocketError); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 7c0eb71c2..0e0ec5509 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -19,6 +19,7 @@ class QxEventServiceSettings : public ServiceSettings using Super = ServiceSettings; QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "tcp://localhost?user=test&password=test") + QF_VARIANTMAP_FIELD2(bool, is, set, ExportDatabase, false) public: QxEventServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index d18cd0e38..e6ba839e5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -30,8 +30,6 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) { setPersistentSettingsId("QxEventServiceWidget"); ui->setupUi(this); - connect(ui->edServerUrl, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); - connect(ui->edApiToken, &QLineEdit::textChanged, this, &QxEventServiceWidget::updateOCheckListPostUrl); setMessage(""); @@ -41,6 +39,7 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) auto current_stage = event_plugin->currentStageId(); auto settings = svc->settings(); ui->edServerUrl->setText(settings.shvBrokerUrl()); + ui->chkExportDatabase->setChecked(settings.isExportDatabase()); ui->edApiToken->setText(svc->apiToken()); ui->edCurrentStage->setValue(current_stage); ui->edEventId->setValue(svc->eventId()); @@ -99,6 +98,7 @@ bool QxEventServiceWidget::saveSettings() if(svc) { auto ss = svc->settings(); ss.setShvBrokerUrl(ui->edServerUrl->text()); + ss.setExportDatabase(ui->chkExportDatabase->isChecked()); svc->setSettings(ss); auto *event_plugin = getPlugin(); @@ -110,13 +110,6 @@ bool QxEventServiceWidget::saveSettings() return true; } -void QxEventServiceWidget::updateOCheckListPostUrl() -{ - auto url = QStringLiteral("%1/api/event/current/oc").arg(ui->edServerUrl->text()); - ui->edOChecklistUrl->setText(url); - ui->edOChecklistUrlHeader->setText(QStringLiteral("qx-api-token=%1").arg(ui->edApiToken->text())); -} - void QxEventServiceWidget::testConnection() { using namespace shv::iotqt::rpc; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h index 19454ad86..7e4b3de21 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h @@ -18,19 +18,19 @@ class QxEventServiceWidget : public qf::gui::framework::DialogWidget public: explicit QxEventServiceWidget(QWidget *parent = nullptr); ~QxEventServiceWidget() override; + + bool acceptDialogDone(int result) override; private: enum class MessageType { Ok, Error, Progress }; void setMessage(const QString &msg = {}, MessageType msg_type = MessageType::Ok); QxEventService* service(); bool saveSettings(); - void updateOCheckListPostUrl(); void testConnection(); void exportEventInfo(); void exportStartList(); void exportRuns(); private: Ui::QxEventServiceWidget *ui; - bool acceptDialogDone(int result) override; }; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui index 5f4a41e1a..590077127 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -16,30 +16,23 @@ - - - - SHV broker url - - - - - - - - + + Fill this url into HTTP POST synchonization method in O-CheckList - API token + Event ID + + + - + Fill this url into HTTP POST synchonization method in O-CheckList @@ -49,7 +42,7 @@ - + false @@ -65,17 +58,14 @@ - - - - Fill this url into HTTP POST synchonization method in O-CheckList - + + - Event ID + SHV broker url - + false @@ -94,37 +84,20 @@ - - + + Fill this url into HTTP POST synchonization method in O-CheckList - OCheckList Url - - - - - - - true + API token - - - - Fill this url into HTTP POST synchonization method in O-CheckList - + + - Header - - - - - - - true + Export database @@ -147,6 +120,9 @@ + + false + Export event info @@ -161,6 +137,9 @@ + + false + Export start list @@ -168,6 +147,9 @@ + + false + Export runs @@ -202,7 +184,6 @@ edServerUrl - edOChecklistUrl diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index 780c9a28e..f6e408ef6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -6,6 +6,7 @@ #include "runchange.h" #include +#include #include #include @@ -17,6 +18,7 @@ #include #include +#include namespace qfm = qf::gui::model; namespace qfs = qf::core::sql; @@ -25,7 +27,25 @@ using qf::gui::framework::getPlugin; namespace Event::services::qx { +namespace { +enum Columns { + col_id = 0, + col_stage_id, + col_data_type, + col_foreign_id, + col_foreign_table, + col_data, + col_orig_data, + col_status, + col_status_message, + col_user_id, + col_created, + col_lock_number, + col_COUNT +}; + constexpr auto COL_ID = "id"; +constexpr auto COL_STAGE_ID = "stage_id"; constexpr auto COL_DATA_TYPE = "data_type"; constexpr auto COL_FOREIGN_ID = "foreign_id"; constexpr auto COL_FOREIGN_TABLE = "foreign_table"; @@ -36,6 +56,7 @@ constexpr auto COL_STATUS_MESSAGE = "status_message"; constexpr auto COL_USER_ID = "user_id"; constexpr auto COL_CREATED = "created"; constexpr auto COL_LOCK_NUMBER = "lock_number"; +} // namespace QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : QWidget(parent), @@ -57,19 +78,24 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : ui->toolbar->setTableView(ui->tableView); m_model = new qfm::SqlTableModel(this); //m->setObjectName("classes.classesModel"); - m_model->addColumn(COL_ID).setReadOnly(true).setAlignment(Qt::AlignLeft); - m_model->addColumn(COL_STATUS, tr("Status")); - m_model->addColumn(COL_DATA_TYPE, tr("Type")); - m_model->addColumn(COL_FOREIGN_TABLE, tr("Foreign table")); - m_model->addColumn(COL_FOREIGN_ID, tr("Foreign ID")).setAlignment(Qt::AlignLeft); - m_model->addColumn(COL_USER_ID, tr("User")); - m_model->addColumn(COL_STATUS_MESSAGE, tr("Status message")); - m_model->addColumn(COL_CREATED, tr("Created")); - m_model->addColumn(COL_LOCK_NUMBER, tr("Lock")); - m_model->addColumn(COL_DATA, tr("Data"));//.setToolTip(tr("Locked for drawing")); - m_model->addColumn(COL_ORIG_DATA, tr("Orig data"));//.setToolTip(tr("Locked for drawing")); + + m_model->clearColumns(col_COUNT); + m_model->setColumn(col_id, qf::gui::model::TableModel::ColumnDefinition(COL_ID).setReadOnly(true).setAlignment(Qt::AlignRight)); + m_model->setColumn(col_stage_id, qf::gui::model::TableModel::ColumnDefinition(COL_STAGE_ID).setReadOnly(true).setAlignment(Qt::AlignRight)); + m_model->setColumn(col_data_type, qf::gui::model::SqlTableModel::ColumnDefinition(COL_DATA_TYPE).setReadOnly(true)); + m_model->setColumn(col_foreign_id, qf::gui::model::SqlTableModel::ColumnDefinition(COL_FOREIGN_ID).setReadOnly(true).setAlignment(Qt::AlignRight)); + m_model->setColumn(col_foreign_table, qf::gui::model::SqlTableModel::ColumnDefinition(COL_FOREIGN_TABLE).setReadOnly(true)); + m_model->setColumn(col_data, qf::gui::model::SqlTableModel::ColumnDefinition(COL_DATA).setReadOnly(true)); + m_model->setColumn(col_orig_data, qf::gui::model::SqlTableModel::ColumnDefinition(COL_ORIG_DATA).setReadOnly(true)); + m_model->setColumn(col_status, qf::gui::model::SqlTableModel::ColumnDefinition(COL_STATUS).setReadOnly(true)); + m_model->setColumn(col_status_message, qf::gui::model::SqlTableModel::ColumnDefinition(COL_STATUS_MESSAGE).setReadOnly(true)); + m_model->setColumn(col_user_id, qf::gui::model::SqlTableModel::ColumnDefinition(COL_USER_ID).setReadOnly(true)); + m_model->setColumn(col_created, qf::gui::model::SqlTableModel::ColumnDefinition(COL_CREATED).setReadOnly(true)); + m_model->setColumn(col_lock_number, qf::gui::model::SqlTableModel::ColumnDefinition(COL_LOCK_NUMBER).setReadOnly(true)); ui->tableView->setTableModel(m_model); + ui->tableView->setColumnHidden(col_stage_id, true); + showMessage(tr("QxEvent service is disabled"), true); setEnabled(false); @@ -226,26 +252,40 @@ void QxLateEntriesWidget::applyQxChange(int sql_id) void QxLateEntriesWidget::onTableCustomContextMenuRequest(const QPoint &pos) { - QAction a_neco(tr("Neco"), nullptr); + QAction a_edit_competitor(tr("Edit competitor"), nullptr); QList lst; - lst << &a_neco; + lst << &a_edit_competitor; QAction *a = QMenu::exec(lst, ui->tableView->viewport()->mapToGlobal(pos)); - if(a == &a_neco) { - //printSelectedCards(); + if(a == &a_edit_competitor) { + if (auto ix = ui->tableView->indexAt(pos); ix.isValid()) { + if (auto t = ix.sibling(ix.row(), col_foreign_table).data().toString(); t == "runs") { + auto run_id = ix.sibling(ix.row(), col_foreign_id).data().toInt(); + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT competitorId FROM runs WHERE id=%1") + .arg(run_id) + ); + if (q.next()) { + auto competitor_id = q.value(0).toInt(); + RunsWidget::showEditCompetitorDialog(competitor_id, this); + return; + } + } + } + QMessageBox::information(this, tr("Edit competitor"), tr("No competitor found for this run.")); } } void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { auto row = ix.row(); - auto status = m_model->value(row, COL_STATUS).toString(); - auto status_message = m_model->value(row, COL_STATUS_MESSAGE).toString(); auto data = m_model->value(row, COL_DATA).toString(); auto qxdata = QxChangeData::fromJson(data); if (qxdata.lateEntry.has_value()) { - // auto lock_number = m_model->value(row, COL_LOCK_NUMBER).toInt(); + auto status = m_model->value(row, COL_STATUS).toString(); + auto status_message = m_model->value(row, COL_STATUS_MESSAGE).toString(); auto change_id = m_model->value(row, COL_ID).toInt(); - LateEntryDialog dlg(change_id, qxdata.lateEntry.value(), status, status_message, this); + auto stage_id = m_model->value(row, COL_STAGE_ID).toInt(); + LateEntryDialog dlg(change_id, stage_id, qxdata.lateEntry.value(), status, status_message, this); dlg.exec(); ui->tableView->reloadRow(row); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp index fe2150e97..b85350c36 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp @@ -25,6 +25,7 @@ LateEntry LateEntry::fromVariantMap(const QVariantMap &map) if (auto v = map.value("firstname"); v.isValid()) { ret.first_name = v.toString(); } if (auto v = map.value("lastname"); v.isValid()) { ret.last_name = v.toString(); } if (auto v = map.value("registration"); v.isValid()) { ret.registration = v.toString(); } + if (auto v = map.value("starttimems"); v.isValid()) { ret.start_time_ms = v.toInt(); } if (auto v = map.value("siid"); v.isValid()) { ret.si_id = v.toInt(); } // if (auto v = map.value("si_id_rent"); v.isValid()) { ret.si_id_rent = v.toBool(); } if (auto v = map.value("note"); v.isValid()) { ret.note = v.toString(); } @@ -39,6 +40,7 @@ QVariantMap OrigRunRecord::toVariantMap() const ret["lastname"] = last_name; ret["registration"] = registration; ret["siid"] = si_id; + ret["starttimems"] = start_time_ms; return ret; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 58f0371a7..62e9e78d4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -23,6 +23,7 @@ struct LateEntry std::optional last_name; std::optional registration; std::optional si_id; + std::optional start_time_ms; // std::optional si_id_rent; std::optional note; @@ -42,7 +43,8 @@ struct OrigRunRecord QString first_name; QString last_name; QString registration; - int si_id; + int start_time_ms = 0; + int si_id = 0; // bool si_id_rent; QVariantMap toVariantMap() const; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 19533c62b..6f60be93f 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -1230,6 +1230,18 @@ void RunsWidget::editCompetitor_helper(const QVariant &id, int mode, int siid) } } +void RunsWidget::showEditCompetitorDialog(int competitor_id, QWidget *parent) +{ + auto *w = new CompetitorWidget(); + w->setWindowTitle(tr("Edit Competitor")); + qfd::Dialog dlg(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, parent); + dlg.setDefaultButton(QDialogButtonBox::Ok); + + dlg.setCentralWidget(w); + w->load(competitor_id, qf::gui::model::DataDocument::ModeEdit); + dlg.exec(); +} + void RunsWidget::updateClassComboBox() { m_cbxClasses->blockSignals(true); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.h b/quickevent/app/quickevent/plugins/Runs/src/runswidget.h index e2efbb970..df6e7fd9b 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.h @@ -51,6 +51,7 @@ class RunsWidget : public QFrame void export_results_stage_csv(); public: + static void showEditCompetitorDialog(int competitor_id, QWidget *parent); void editCompetitor(const QVariant &id, int mode) {editCompetitor_helper(id, mode, 0);} void editCompetitors(int mode); void editCompetitorOnPunch(int siid); From 5febecf146e9877a233445f61bd776cb9421de00 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 7 Jul 2026 00:31:49 +0200 Subject: [PATCH 41/83] Add duplicate checks, SHV UI and misc fixes LateEntryDialog: handle empty start time, add duplicate-registration and duplicate-name checks and call them on init; reset start-time style when group is unchecked. QxEventService: extract eventctl SHV path into method and use it. QxEventServiceWidget/UI: add SHV broker group with default-url radios, only set connection options when exporting DB, add helper to set URL. RunsTableModel: ignore Insert rec changes to avoid applying filtered inserts before they are relevant. --- .../Event/src/services/qx/lateentrydialog.cpp | 46 ++++++- .../Event/src/services/qx/lateentrydialog.h | 2 + .../Event/src/services/qx/qxeventservice.cpp | 7 +- .../Event/src/services/qx/qxeventservice.h | 1 + .../src/services/qx/qxeventservicewidget.cpp | 41 ++++++- .../src/services/qx/qxeventservicewidget.h | 1 + .../src/services/qx/qxeventservicewidget.ui | 116 +++++++++++------- .../plugins/Runs/src/runstablemodel.cpp | 4 + 8 files changed, 169 insertions(+), 49 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 7b9244214..5be8525ef 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -109,7 +109,7 @@ LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &l update_background(ui->edSiCard); ui->grpStartTime->setChecked(late_entry.start_time_ms.has_value()); - ui->edStartTime->setText(TimeMs(late_entry.start_time_ms.value_or(0)).toString()); + ui->edStartTime->setText(late_entry.start_time_ms.has_value()? TimeMs(late_entry.start_time_ms.value()).toString(): QString{}); update_background(ui->edStartTime); connect(ui->edStartTime, &QLineEdit::textEdited, this, &LateEntryDialog::checkStartTimeIsValid); @@ -124,6 +124,8 @@ LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &l auto class_id = id->id; loadClassName(class_id); } + checkDuplicitRegistration(); + checkDuplicitName(); lockChange(); } @@ -308,8 +310,50 @@ void LateEntryDialog::updateQxChangeMessage() qf::gui::framework::Application::instance()->qxSql()->updateRecord("qxchanges", m_changeId, rec, this); } +void LateEntryDialog::checkDuplicitRegistration() +{ + if (!ui->grpRegistration->isChecked() || !classId().has_value()) { + return; + } + auto reg = ui->edRegistration->text().trimmed().toUpper(); + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT firstName, lastName FROM competitors WHERE registration='%1'") + .arg(reg) ); + if (q.next()) { + setMessage(tr("Competitor %1 %2 %3 is registered already.") + .arg(q.value("firstName").toString()) + .arg(q.value("lastName").toString()) + .arg(reg) + , true); + } +} + +void LateEntryDialog::checkDuplicitName() +{ + if (!ui->grpFirstName->isChecked() || !ui->grpLastName->isChecked() || !classId().has_value()) { + return; + } + auto first_name = ui->edFirstName->text().trimmed(); + auto last_name = ui->edLastName->text().trimmed(); + qf::core::sql::Query q; + q.execThrow(QStringLiteral("SELECT registration FROM competitors WHERE firstName='%1' AND lastName='%2'") + .arg(first_name) + .arg(last_name) ); + if (q.next()) { + setMessage(tr("Competitor %1 %2 %3 is registered already.") + .arg(first_name) + .arg(last_name) + .arg(q.value("registration").toString()) + , true); + } +} + void LateEntryDialog::checkStartTimeIsValid() { + if (!ui->grpStartTime->isChecked()) { + ui->edStartTime->setStyleSheet({}); + return; + } if (auto run_id = runId(); run_id.has_value()) { auto stime = TimeMs::fromString(ui->edStartTime->text()); if (stime.isValid()) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index 909cebfd2..82fc59261 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -43,6 +43,8 @@ class LateEntryDialog : public QDialog void resolveChangesAndClose(bool is_accepted); void updateQxChangeMessage(); + void checkDuplicitRegistration(); + void checkDuplicitName(); void checkStartTimeIsValid(); private: Ui::LateEntryDialog *ui; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index fb27d5912..45c65a25c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -470,6 +470,11 @@ int QxEventService::currentConnectionId() return qf::core::sql::Connection::forName().connectionId(); } +const char *QxEventService::eventctlShvPath() const +{ + return "qx/qxeventd/eventctl"; +} + void QxEventService::onBrokerConnectedChanged(bool is_connected) { if(is_connected) { @@ -478,7 +483,7 @@ void QxEventService::onBrokerConnectedChanged(bool is_connected) auto stage_data = event_plugin->stageData(current_stage); auto api_token = stage_data.qxApiToken().toStdString(); auto *rpc_call = shv::iotqt::rpc::RpcCall::create(m_rpcConnection) - ->setShvPath("test/qx/qxeventd/eventctl") + ->setShvPath(eventctlShvPath()) ->setMethod("openEventApiKey") ->setParams(RpcValue(api_token)); connect(rpc_call, &shv::iotqt::rpc::RpcCall::maybeResult, this, [this](const ::shv::chainpack::RpcValue &result, const shv::chainpack::RpcError &error) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index 0e0ec5509..ca1b93e08 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -81,6 +81,7 @@ class QxEventService : public Service void onBrokerSocketError(const QString &err); void onBrokerLoginError(const shv::chainpack::RpcError &err); + const char* eventctlShvPath() const; void subscribeChanges(); private: void loadSettings() override; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index e6ba839e5..63b2ff223 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -47,6 +47,22 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) connect(ui->btExportEventInfo, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportEventInfo); connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportStartList); connect(ui->btExportRuns, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportRuns); + +#ifdef QT_DEBUG + ui->grpShvConnection->setVisible(true); +#else + ui->grpShvConnection->setVisible(false); +#endif + connect(ui->btQxQxOrg, &QAbstractButton::clicked, this, [this](bool checked) { + if (checked) { + setDefaultShvBrokerUrl(false); + } + }); + connect(ui->btLocalhost, &QAbstractButton::clicked, this, [this](bool checked) { + if (checked) { + setDefaultShvBrokerUrl(true); + } + }); } QxEventServiceWidget::~QxEventServiceWidget() @@ -119,11 +135,13 @@ void QxEventServiceWidget::testConnection() auto *rpc = new DeviceConnection("QuickEventTest", this); rpc->setConnectionString(ui->edServerUrl->text()); - RpcValue::Map opts; - RpcValue::Map device; - device["deviceId"] = ui->edApiToken->text().toStdString(); - opts["device"] = device; - rpc->setConnectionOptions(opts); + if (ui->chkExportDatabase->isChecked()) { + RpcValue::Map opts; + RpcValue::Map device; + device["deviceId"] = ui->edApiToken->text().toStdString(); + opts["device"] = device; + rpc->setConnectionOptions(opts); + } connect(rpc, &ClientConnection::brokerConnectedChanged, this, [this, rpc](bool is_connected) { if (is_connected) { @@ -207,5 +225,18 @@ void QxEventServiceWidget::exportRuns() }); } +void QxEventServiceWidget::setDefaultShvBrokerUrl(bool is_local_host) +{ + auto url = QStringLiteral("tcp://%1?user=qe&%2=%3"); + if (is_local_host) { + url = url.arg("localhost"); + } else { + url = url.arg("qxqx.org"); + } + url = url.arg("password"); + url = url.arg("2ddf6394ea6"); + ui->edServerUrl->setText(url); +} + } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h index 7e4b3de21..1bde76efc 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h @@ -29,6 +29,7 @@ class QxEventServiceWidget : public qf::gui::framework::DialogWidget void exportEventInfo(); void exportStartList(); void exportRuns(); + void setDefaultShvBrokerUrl(bool is_local_host); private: Ui::QxEventServiceWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui index 590077127..d61295c58 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -14,36 +14,62 @@ SHV API service + + + + SHV broker connection + + + + + + + 0 + 0 + + + + Url + + + + + + + localhost + + + false + + + + + + + qxqx.org + + + true + + + + + + + + + - - - - Fill this url into HTTP POST synchonization method in O-CheckList - - - Event ID - - - - - - - - - - - - - Fill this url into HTTP POST synchonization method in O-CheckList - + + - Current stage + Export database - - + + false @@ -53,20 +79,29 @@ true - - 1 + + Not loaded + + + 0 - - + + + + Fill this url into HTTP POST synchonization method in O-CheckList + - SHV broker url + Event ID - - + + + + + false @@ -76,11 +111,8 @@ true - - Not loaded - - - 0 + + 1 @@ -94,10 +126,13 @@ - - + + + + Fill this url into HTTP POST synchonization method in O-CheckList + - Export database + Current stage @@ -182,9 +217,6 @@ - - edServerUrl - diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index bac275c69..b6409de8f 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -363,6 +363,10 @@ void RunsTableModel::onDataChanged(const QModelIndex &top_left, const QModelInde void RunsTableModel::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source) { + if (recchng.op == qf::core::sql::RecOp::Insert) { + // inserts might be in filterred out class or stage, this cannot be solved by applyQxRecChng + return; + } applyQxRecChng(recchng, source); } From e12290e992af4c82df183228b01a8b8c021c2f14 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 7 Jul 2026 17:01:44 +0200 Subject: [PATCH 42/83] Delete testing DeviceConnection on dialog accept --- .../plugins/Event/src/services/qx/qxeventservicewidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 63b2ff223..8c87f2f27 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -93,6 +93,8 @@ void QxEventServiceWidget::setMessage(const QString &msg, MessageType msg_type) bool QxEventServiceWidget::acceptDialogDone(int result) { + // delete testing connection if any + delete findChild(); if(result == QDialog::Accepted) { if(!saveSettings()) { return false; From f6f5e83c9df88e6d33ffc5ef708ad9083d6118f6 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 7 Jul 2026 17:13:23 +0200 Subject: [PATCH 43/83] Fix clazy errors --- libqf/libqfgui/src/model/sqltablemodel.cpp | 11 +++++------ .../plugins/Event/src/services/ofeed/ofeedclient.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libqf/libqfgui/src/model/sqltablemodel.cpp b/libqf/libqfgui/src/model/sqltablemodel.cpp index e61a1e0d9..e2d3d25dc 100644 --- a/libqf/libqfgui/src/model/sqltablemodel.cpp +++ b/libqf/libqfgui/src/model/sqltablemodel.cpp @@ -227,15 +227,14 @@ bool SqlTableModel::postRow(int row_no, bool throw_exc) QF_ASSERT(num_rows_affected == 1, tr("numRowsAffected() = %1, should be 1\n%2").arg(num_rows_affected).arg(qs), return false); - auto insert_id = q.lastInsertId(); if(serial_ix >= 0 && !serial_ix_explicitly_set) { - QVariant v = q.lastInsertId(); - qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << v; - if(v.isValid()) { - row_ref.setValue(serial_ix, v); + auto insert_id = q.lastInsertId(); + qfDebug() << "\tsetting serial index:" << serial_ix << "to generated value:" << insert_id; + if(insert_id.isValid()) { + row_ref.setValue(serial_ix, insert_id); row_ref.setDirty(serial_ix, false); if (auto *app = qobject_cast(QApplication::instance()); app) { - app->qxSql()->emitRecInserted(table_id, v.value(), record_to_map(rec), this); + app->qxSql()->emitRecInserted(table_id, insert_id.value(), record_to_map(rec), this); } } else { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 74c1398c6..3fe2f6dec 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -304,7 +304,7 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons auto lst = data.toList(); int run_id = lst.value(0).toInt(); auto dirty_vals = lst.value(1).toMap(); - qfInfo() << serviceName().toStdString() + " DB event RUN CHANGED received, run_id: " << run_id << ", dirty keys: " << dirty_vals.keys().join(", "); + qfInfo() << serviceName().toStdString() + " DB event RUN CHANGED received, run_id: " << run_id << ", dirty keys: " << dirty_vals.keys().join(", "); // clazy:exclude=container-anti-pattern if (!dirty_vals.isEmpty()) { static const QSet relevant_fields = { // Run fields (finishTimeMs and timeMs are covered by DBEVENT_CARD_PROCESSED_AND_ASSIGNED) @@ -319,7 +319,7 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons QStringLiteral("classid"), }; bool has_relevant = false; - for (const auto &key : dirty_vals.keys()) { + for (const auto &[key, _] : dirty_vals.asKeyValueRange()) { if (relevant_fields.contains(key.section('.', -1).toLower())) { has_relevant = true; break; @@ -758,7 +758,7 @@ void OFeedClient::testConnection(const QString &host_url, const QByteArray response_bytes = reply->readAll(); const QString response_text = QString::fromUtf8(response_bytes).trimmed(); - auto callback_error = [&](const QString &msg) { + auto callback_error = [=](const QString &msg) { const QString status_text = http_status > 0 ? QStringLiteral("HTTP %1").arg(http_status) : QStringLiteral("HTTP status unavailable"); const QString full_message = response_text.isEmpty() ? QStringLiteral("%1: %2").arg(status_text, msg) @@ -1522,7 +1522,7 @@ void OFeedClient::processNewRunner(int ofeed_competitor_id) // Save emits db event doc.save(); - auto competitor_id = doc.value("competitors.id"); + // auto competitor_id = doc.value("competitors.id"); unused // Get runs.id for current stage int current_stage = getPlugin()->currentStageId(); @@ -1563,8 +1563,8 @@ void OFeedClient::storeChange(const QJsonObject &change) QString firstname = competitor["firstname"].isString() ? competitor["firstname"].toString() : no_data; QString lastname = competitor["lastname"].isString() ? competitor["lastname"].toString() : no_data; - QJsonDocument change_json_doc(change); - QString change_json = QString::fromUtf8(change_json_doc.toJson(QJsonDocument::Compact)); + // QJsonDocument change_json_doc(change); unused + // QString change_json = QString::fromUtf8(change_json_doc.toJson(QJsonDocument::Compact)); int change_id = change["id"].toInt(); auto created = QDateTime::fromString(change["createdAt"].toString(), Qt::ISODate); From 716d6a85f18415fd12ebbee509e14813f02d180e Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 7 Jul 2026 22:50:10 +0200 Subject: [PATCH 44/83] Delete RPC connection on stop; guard debug connect --- .../quickevent/plugins/Event/src/services/qx/qxeventservice.cpp | 2 ++ quickevent/app/quickevent/src/main.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 45c65a25c..61ec5d71c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -103,6 +103,8 @@ void QxEventService::run() { void QxEventService::stop() { + delete m_rpcConnection; + m_rpcConnection = nullptr; m_eventId = 0; if (m_pollChangesTimer) { m_pollChangesTimer->stop(); diff --git a/quickevent/app/quickevent/src/main.cpp b/quickevent/app/quickevent/src/main.cpp index 742e5efcc..04d873e64 100644 --- a/quickevent/app/quickevent/src/main.cpp +++ b/quickevent/app/quickevent/src/main.cpp @@ -198,6 +198,7 @@ int main(int argc, char *argv[]) main_window.show(); emit main_window.applicationLaunched(); +#ifdef QT_DEBUG QObject::connect(app.qxSql(), &qf::core::sql::QxSql::recChng, &app, [](const qf::core::sql::QxRecChng &recchng) { auto dump_map = [](const QVariantMap &m) { QStringList rows; @@ -211,6 +212,7 @@ int main(int argc, char *argv[]) << "id:" << recchng.id << "record:" << dump_map(recchng.record); }); +#endif int ret = Application::exec(); From 7fadeaf000116da6e4a80642d853820df65d45fe Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Wed, 8 Jul 2026 20:36:52 +0200 Subject: [PATCH 45/83] Support paid late entries and status handling Add 'paid' to LateEntry and parse it from change data. Show paid status in LateEntryDialog (lblPaid) and color rows in the late entries table based on paid/status. Replace local LateEntryStatus with QxChangeStatus and provide qxChangeStatusFromString for unified parsing. Introduce changeEventEntryToStageEntry and m_setIsRunning to update an existing competitor run instead of inserting duplicates. --- .../Event/src/services/qx/lateentrydialog.cpp | 75 +++++++++++-------- .../Event/src/services/qx/lateentrydialog.h | 6 +- .../Event/src/services/qx/lateentrydialog.ui | 23 +++++- .../src/services/qx/qxlateentrieswidget.cpp | 36 ++++++++- .../Event/src/services/qx/runchange.cpp | 18 +++++ .../plugins/Event/src/services/qx/runchange.h | 8 +- 6 files changed, 125 insertions(+), 41 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 5be8525ef..93579c22b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -20,38 +20,20 @@ #include #include #include + #include using namespace quickevent::core::og; namespace Event::services::qx { -namespace { - -LateEntryStatus lateEntryStatusFromString(const QString &status) -{ - if (status.compare(QStringLiteral("Pending"), Qt::CaseInsensitive) == 0) { - return LateEntryStatus::Pending; - } - if (status.compare(QStringLiteral("Accepted"), Qt::CaseInsensitive) == 0) { - return LateEntryStatus::Accepted; - } - if (status.compare(QStringLiteral("Rejected"), Qt::CaseInsensitive) == 0) { - return LateEntryStatus::Rejected; - } - qfWarning() << "Unknown late entry status:" << status; - return LateEntryStatus::Rejected; -} - -} // namespace - LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent) : Super(parent) , ui(new Ui::LateEntryDialog) , m_changeId(change_id) , m_stageId(stage_id) , m_lateEntryId(late_entry.id) - , m_status(lateEntryStatusFromString(status)) + , m_status(qxChangeStatusFromString(status)) { Q_ASSERT(change_id > 0); @@ -124,6 +106,15 @@ LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &l auto class_id = id->id; loadClassName(class_id); } + + if (late_entry.paid.value_or(false)) { + ui->lblPaid->setText(tr("Paid")); + ui->lblPaid->setStyleSheet("background:green;color:white"); + } else { + ui->lblPaid->setText(tr("Not Paid")); + ui->lblPaid->setStyleSheet("background:red;color:white"); + } + checkDuplicitRegistration(); checkDuplicitName(); lockChange(); @@ -236,8 +227,8 @@ void LateEntryDialog::lockChange() void LateEntryDialog::updateButtonsEnabled() { - ui->btAccept->setEnabled(m_status == LateEntryStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); - ui->btReject->setEnabled(m_status == LateEntryStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); + ui->btAccept->setEnabled(m_status == QxChangeStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); + ui->btReject->setEnabled(m_status == QxChangeStatus::Pending && (ui->chkForce->isChecked() || m_lockNumber > 0)); } void LateEntryDialog::resolveChangesAndClose(bool is_accepted) @@ -246,7 +237,7 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) if (is_accepted) { auto class_id = classId(); - bool is_insert = class_id.has_value(); + bool is_insert = class_id.has_value() && !m_setIsRunning; Competitors::CompetitorDocument doc; doc.load(m_competitorId, is_insert? DataDocument::ModeInsert: DataDocument::ModeEdit); if (is_insert) { @@ -275,6 +266,9 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) if (ui->grpStartTime->isChecked()) { rec["starttimems"] = TimeMs::fromString(ui->edStartTime->text()).msec(); } + if (m_setIsRunning) { + rec["isRunning"] = true; + } if (!rec.isEmpty()) { auto competitor_id = doc.value("id").toInt(); Q_ASSERT(competitor_id > 0); @@ -312,42 +306,61 @@ void LateEntryDialog::updateQxChangeMessage() void LateEntryDialog::checkDuplicitRegistration() { - if (!ui->grpRegistration->isChecked() || !classId().has_value()) { + auto class_id = classId(); + if (!ui->grpRegistration->isChecked() || !class_id.has_value()) { return; } auto reg = ui->edRegistration->text().trimmed().toUpper(); qf::core::sql::Query q; - q.execThrow(QStringLiteral("SELECT firstName, lastName FROM competitors WHERE registration='%1'") - .arg(reg) ); + q.execThrow(QStringLiteral("SELECT id, firstName, lastName FROM competitors WHERE registration='%1' AND classId=%2") + .arg(reg).arg(class_id.value()) ); if (q.next()) { - setMessage(tr("Competitor %1 %2 %3 is registered already.") + setMessage(tr("Competitor %1 %2 %3 is registered in this class already, run will be updated.") .arg(q.value("firstName").toString()) .arg(q.value("lastName").toString()) .arg(reg) , true); + auto competitor_id = q.value("id").toInt(); + Q_ASSERT(competitor_id > 0); + changeEventEntryToStageEntry(competitor_id); } } void LateEntryDialog::checkDuplicitName() { - if (!ui->grpFirstName->isChecked() || !ui->grpLastName->isChecked() || !classId().has_value()) { + auto class_id = classId(); + if (!ui->grpFirstName->isChecked() || !ui->grpLastName->isChecked() || !class_id.has_value()) { return; } auto first_name = ui->edFirstName->text().trimmed(); auto last_name = ui->edLastName->text().trimmed(); qf::core::sql::Query q; - q.execThrow(QStringLiteral("SELECT registration FROM competitors WHERE firstName='%1' AND lastName='%2'") + q.execThrow(QStringLiteral("SELECT id, registration FROM competitors WHERE firstName='%1' AND lastName='%2' AND classId=%3") .arg(first_name) - .arg(last_name) ); + .arg(last_name) + .arg(class_id.value())); if (q.next()) { - setMessage(tr("Competitor %1 %2 %3 is registered already.") + setMessage(tr("Competitor %1 %2 %3 is registered in this class already, run will be updated.") .arg(first_name) .arg(last_name) .arg(q.value("registration").toString()) , true); + auto competitor_id = q.value("id").toInt(); + Q_ASSERT(competitor_id > 0); + changeEventEntryToStageEntry(competitor_id); } } +void LateEntryDialog::changeEventEntryToStageEntry(int competitor_id) +{ + m_setIsRunning = true; + m_competitorId = competitor_id; + + ui->grpFirstName->setChecked(false); + ui->grpLastName->setChecked(false); + ui->grpRegistration->setChecked(false); +} + void LateEntryDialog::checkStartTimeIsValid() { if (!ui->grpStartTime->isChecked()) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index 82fc59261..088a2ec39 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -16,8 +16,6 @@ class LateEntryDialog; struct LateEntry; class QxEventService; -enum class LateEntryStatus {Pending, Accepted, Rejected}; - class LateEntryDialog : public QDialog { Q_OBJECT @@ -46,6 +44,7 @@ class LateEntryDialog : public QDialog void checkDuplicitRegistration(); void checkDuplicitName(); void checkStartTimeIsValid(); + void changeEventEntryToStageEntry(int competitor_id); private: Ui::LateEntryDialog *ui; int m_changeId = 0; @@ -53,8 +52,9 @@ class LateEntryDialog : public QDialog LateEntryForeignId m_lateEntryId = RunId{}; int m_competitorId = 0; int m_lockNumber = 0; - LateEntryStatus m_status = LateEntryStatus::Rejected; + QxChangeStatus m_status = QxChangeStatus::Rejected; OrigRunRecord m_origValues; + bool m_setIsRunning = false; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index 73d119d72..809a8a08a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -7,7 +7,7 @@ 0 0 712 - 668 + 696 @@ -370,6 +370,25 @@ + + + + + 0 + 0 + + + + QFrame::Shape::Box + + + Not Paid + + + Qt::AlignmentFlag::AlignCenter + + + @@ -386,7 +405,7 @@ - 40 + 0 20 diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index f6e408ef6..35a6751ee 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -18,6 +18,8 @@ #include #include +#include +#include #include namespace qfm = qf::gui::model; @@ -56,6 +58,36 @@ constexpr auto COL_STATUS_MESSAGE = "status_message"; constexpr auto COL_USER_ID = "user_id"; constexpr auto COL_CREATED = "created"; constexpr auto COL_LOCK_NUMBER = "lock_number"; + +class LateEntriesModel : public qfm::SqlTableModel +{ +public: + using qfm::SqlTableModel::SqlTableModel; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override + { + if (role == Qt::BackgroundRole) { + if (index.column() == col_data) { + auto data = index.data().toString(); + auto qxdata = QxChangeData::fromJson(data); + if (auto le = qxdata.lateEntry; le.has_value()) { + if (le.value().paid.value_or(false)) { + return QColor("lightgreen"); + } + } + } + else if (index.column() == col_status) { + auto status = qxChangeStatusFromString(index.data().toString()); + switch (status) { + case QxChangeStatus::Pending: return {}; + case QxChangeStatus::Accepted: return QColor("lightgreen"); + case QxChangeStatus::Rejected: return QColor("salmon"); + } + } + } + return qfm::SqlTableModel::data(index, role); + } +}; } // namespace QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : @@ -76,7 +108,7 @@ QxLateEntriesWidget::QxLateEntriesWidget(QWidget *parent) : ui->tableView->setDirtyRowsMenuSectionEnabled(false); ui->toolbar->setTableView(ui->tableView); - m_model = new qfm::SqlTableModel(this); + m_model = new LateEntriesModel(this); //m->setObjectName("classes.classesModel"); m_model->clearColumns(col_COUNT); @@ -277,7 +309,7 @@ void QxLateEntriesWidget::onTableCustomContextMenuRequest(const QPoint &pos) void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) { - auto row = ix.row(); + auto row = ui->tableView->toTableModelIndex(ix).row(); auto data = m_model->value(row, COL_DATA).toString(); auto qxdata = QxChangeData::fromJson(data); if (qxdata.lateEntry.has_value()) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp index b85350c36..8e4cdd5c2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.cpp @@ -1,5 +1,7 @@ #include "runchange.h" +#include + #include #include @@ -29,6 +31,7 @@ LateEntry LateEntry::fromVariantMap(const QVariantMap &map) if (auto v = map.value("siid"); v.isValid()) { ret.si_id = v.toInt(); } // if (auto v = map.value("si_id_rent"); v.isValid()) { ret.si_id_rent = v.toBool(); } if (auto v = map.value("note"); v.isValid()) { ret.note = v.toString(); } + if (auto v = map.value("paid"); v.isValid()) { ret.paid = v.toBool(); } return ret; } @@ -54,4 +57,19 @@ QxChangeData QxChangeData::fromJson(const QString &json) return ret; } +QxChangeStatus qxChangeStatusFromString(const QString &status) +{ + if (status.compare(QStringLiteral("Pending"), Qt::CaseInsensitive) == 0) { + return QxChangeStatus::Pending; + } + if (status.compare(QStringLiteral("Accepted"), Qt::CaseInsensitive) == 0) { + return QxChangeStatus::Accepted; + } + if (status.compare(QStringLiteral("Rejected"), Qt::CaseInsensitive) == 0) { + return QxChangeStatus::Rejected; + } + qfWarning() << "Unknown late entry status:" << status; + return QxChangeStatus::Rejected; +} + } // namespace Event::services::qx diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 62e9e78d4..37d576f8d 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -26,6 +26,7 @@ struct LateEntry std::optional start_time_ms; // std::optional si_id_rent; std::optional note; + std::optional paid; // static LateEntry fromJsonString(const QString &json); static LateEntry fromVariantMap(const QVariantMap &map); @@ -57,12 +58,13 @@ enum class DataType { RadioPunch, CardReadout, }; -enum class ChangeStatus { +enum class QxChangeStatus { Pending, - Locked, Accepted, Rejected, }; +QxChangeStatus qxChangeStatusFromString(const QString &status); + struct EventChange { int64_t id; @@ -71,7 +73,7 @@ struct EventChange int64_t data_id; QVariant data; QString user_id; - ChangeStatus status; + QxChangeStatus status; QString status_message; QDateTime created; int64_t lock_number; From 213a87303b1a712eb98a1555dfaff695cc7af4a5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 9 Jul 2026 00:47:36 +0200 Subject: [PATCH 46/83] Disable proxy sorting during batch cell updates, TableView::setValueInSelection --- libqf/libqfgui/src/tableview.cpp | 49 +++++++++++++++----------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/libqf/libqfgui/src/tableview.cpp b/libqf/libqfgui/src/tableview.cpp index 7f935dc21..17e40e82a 100644 --- a/libqf/libqfgui/src/tableview.cpp +++ b/libqf/libqfgui/src/tableview.cpp @@ -633,40 +633,37 @@ void TableView::paste() void TableView::setValueInSelection_helper(const QVariant &new_val) { + auto *sql_m = qobject_cast(tableModel()); + if (!sql_m) { + return; + } QModelIndexList lst = selectedIndexes(); QMap row_selections; foreach(const QModelIndex &ix, lst) { row_selections[ix.row()] << ix; } - QList selected_row_indexes = row_selections.keys(); - if(selected_row_indexes.count() == 1) { - int row_ix = selected_row_indexes.value(0); - foreach(const QModelIndex &ix, row_selections.value(row_ix)) { - model()->setData(ix, new_val); - } - } - else if(selected_row_indexes.count() > 1) { - qfc::sql::Connection conn; - auto *sql_m = qobject_cast(tableModel()); - if(sql_m) { - try { - conn = sql_m->sqlConnection(); - qfc::sql::Transaction transaction(conn); - QF_TIME_SCOPE(QString("Saving %1 rows").arg(selected_row_indexes.count())); - foreach(int row_ix, selected_row_indexes) { - foreach(const QModelIndex &ix, row_selections.value(row_ix)) { - model()->setData(ix, new_val); - } - sql_m->postRow(toTableModelRowNo(row_ix), qf::core::Exception::Throw); - } - transaction.commit(); - } - catch(qfc::Exception &e) { - dialogs::MessageBox::showException(this, e); + auto *proxy_m = qobject_cast(lastProxyModel()); + Q_ASSERT(proxy_m); + auto is_dynamic_sort_filter = proxy_m->dynamicSortFilter(); + proxy_m->setDynamicSortFilter(false); + qfc::sql::Connection conn; + try { + conn = sql_m->sqlConnection(); + qfc::sql::Transaction transaction(conn); + QF_TIME_SCOPE(QString("Saving %1 rows").arg(selected_row_indexes.count())); + for(const auto &[row_ix, row_indexes] : row_selections.asKeyValueRange()) { + for(const auto &ix : row_indexes) { + proxy_m->setData(ix, new_val); } + sql_m->postRow(toTableModelRowNo(row_ix), qf::core::Exception::Throw); } - update(); + transaction.commit(); + } + catch(qfc::Exception &e) { + dialogs::MessageBox::showException(this, e); } + proxy_m->setDynamicSortFilter(is_dynamic_sort_filter); + update(); } void TableView::setValueInSelection() From 2a19e634f17b2cd0e5a872a65816dfe8bc2059f5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 9 Jul 2026 22:45:20 +0200 Subject: [PATCH 47/83] Add Accept and Edit option to LateEntryDialog Emit editCompetitor when user chooses Accept and Edit; save the competitor id after resolving changes; connect the dialog to open the competitor edit dialog from QxLateEntriesWidget. Comment out unused EventChange struct in runchange.h. --- .../Event/src/services/qx/lateentrydialog.cpp | 7 ++++- .../Event/src/services/qx/lateentrydialog.h | 2 ++ .../Event/src/services/qx/lateentrydialog.ui | 7 +++++ .../src/services/qx/qxlateentrieswidget.cpp | 3 ++ .../plugins/Event/src/services/qx/runchange.h | 30 +++++++++---------- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp index 93579c22b..b21873fd7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.cpp @@ -51,6 +51,11 @@ LateEntryDialog::LateEntryDialog(int change_id, int stage_id, const LateEntry &l resolveChangesAndClose(true); done(QDialog::Accepted); }); + connect(ui->btAcceptAndEdit, &QPushButton::clicked, this, [this]() { + resolveChangesAndClose(true); + emit editCompetitor(m_competitorId); + done(QDialog::Accepted); + }); connect(ui->btReject, &QPushButton::clicked, this, [this]() { resolveChangesAndClose(false); done(QDialog::Accepted); @@ -258,7 +263,7 @@ void LateEntryDialog::resolveChangesAndClose(bool is_accepted) } } doc.save(); - + m_competitorId = doc.dataId().toInt(); qf::core::sql::Record rec; if (ui->grpSiCard->isChecked()) { rec["siId"] = ui->edSiCard->value(); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h index 088a2ec39..fee286b76 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.h @@ -24,6 +24,8 @@ class LateEntryDialog : public QDialog explicit LateEntryDialog(int change_id, int stage_id, const LateEntry &late_entry, const QString &status, const QString &status_message, QWidget *parent = nullptr); ~LateEntryDialog() override; + Q_SIGNAL void editCompetitor(int competitor_id); + void done(int result) override; private: std::optional runId() const; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui index 809a8a08a..6e2cee6ef 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/lateentrydialog.ui @@ -432,6 +432,13 @@ + + + + Accept and Edit + + + diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp index 35a6751ee..49b59528e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxlateentrieswidget.cpp @@ -318,6 +318,9 @@ void QxLateEntriesWidget::onTableDoubleClicked(const QModelIndex &ix) auto change_id = m_model->value(row, COL_ID).toInt(); auto stage_id = m_model->value(row, COL_STAGE_ID).toInt(); LateEntryDialog dlg(change_id, stage_id, qxdata.lateEntry.value(), status, status_message, this); + connect(&dlg, &LateEntryDialog::editCompetitor, this, [this](int competitor_id) { + RunsWidget::showEditCompetitorDialog(competitor_id, this); + }, Qt::QueuedConnection); dlg.exec(); ui->tableView->reloadRow(row); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h index 37d576f8d..6fe5aef7a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/runchange.h @@ -65,21 +65,21 @@ enum class QxChangeStatus { }; QxChangeStatus qxChangeStatusFromString(const QString &status); -struct EventChange -{ - int64_t id; - QString source; - DataType data_type; - int64_t data_id; - QVariant data; - QString user_id; - QxChangeStatus status; - QString status_message; - QDateTime created; - int64_t lock_number; - - QVariantMap toVariantMap() const; -}; +// struct EventChange +// { +// int64_t id; +// QString source; +// DataType data_type; +// int64_t data_id; +// QVariant data; +// QString user_id; +// QxChangeStatus status; +// QString status_message; +// QDateTime created; +// int64_t lock_number; + +// QVariantMap toVariantMap() const; +// }; // struct ChangeRecord // { From af629417d5567ffcb9b60857d0e2883611a87d5c Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 10 Jul 2026 12:07:19 +0200 Subject: [PATCH 48/83] Show qx connection params always --- .../Event/src/services/qx/qxeventservicewidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 8c87f2f27..0a3f57225 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -48,11 +48,11 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportStartList); connect(ui->btExportRuns, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportRuns); -#ifdef QT_DEBUG +// #ifdef QT_DEBUG ui->grpShvConnection->setVisible(true); -#else - ui->grpShvConnection->setVisible(false); -#endif +// #else +// ui->grpShvConnection->setVisible(false); +// #endif connect(ui->btQxQxOrg, &QAbstractButton::clicked, this, [this](bool checked) { if (checked) { setDefaultShvBrokerUrl(false); From b901d87b9e83cd13276f46c086f1644cbe112a39 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 10 Jul 2026 14:09:27 +0200 Subject: [PATCH 49/83] Fix runners per courses count --- .../app/quickevent/plugins/Classes/src/editcourseswidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp index 05d6ebe35..98cbc1029 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp @@ -151,7 +151,7 @@ void EditCoursesWidget::updateQuery() .join("courses.id", "classdefs.courseId", qf::core::sql::QueryBuilder::INNER_JOIN) .join("classdefs.classId", "classes.id") .join("classes.id", "competitors.classId") - .joinRestricted("competitors.id", "runs.competitorId", "runs.isRunning") + .joinRestricted("competitors.id", "runs.competitorId", "runs.isRunning AND runs.stageId=" QF_IARG(m_stageId)) .where("classdefs.stageId=" QF_IARG(m_stageId)) .groupBy("courses.id") .orderBy("courses.name"); From 43df156cc809638baaa2b3097cf210e8138efbc5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 10 Jul 2026 14:10:24 +0200 Subject: [PATCH 50/83] Disable db event on card read in sake of QxRecChng --- .../app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 45c6db000..554bc6f9c 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -722,7 +722,7 @@ void CardReaderWidget::processReadCard(const quickevent::core::si::ReadCard &rea if(card_id) { /// receipts printer needs this /// emitDbEvent is using queued invocation - getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_CARD_READ, card_id, true); + // getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_CARD_READ, card_id, true); } } From 02550b5ee5732381e27f50081bc4d34a781df399 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 10 Jul 2026 15:36:56 +0200 Subject: [PATCH 51/83] Fix receipts autoprint --- .../CardReader/src/cardreaderwidget.cpp | 24 +++++++++---------- .../plugins/CardReader/src/cardreaderwidget.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 554bc6f9c..c5e9f37b0 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -476,7 +476,7 @@ void CardReaderWidget::settleDownInPartWidget(::PartWidget *part_widget) a_tools->addActionInto(a); } } - connect(getPlugin(), &Event::EventPlugin::dbEventNotify, this, &CardReaderWidget::onDbEventNotify, Qt::QueuedConnection); + // connect(getPlugin(), &Event::EventPlugin::dbEventNotify, this, &CardReaderWidget::onDbEventNotify, Qt::QueuedConnection); } void CardReaderWidget::reset() @@ -526,16 +526,16 @@ void CardReaderWidget::onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObj } } -void CardReaderWidget::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) -{ - Q_UNUSED(connection_id) - if(domain == QLatin1String(Event::EventPlugin::DBEVENT_CARD_READ)) { - int card_id = data.toInt(); - if(isVisible()) { - updateTableView(card_id); - } - } -} +// void CardReaderWidget::onDbEventNotify(const QString &domain, int connection_id, const QVariant &data) +// { +// Q_UNUSED(connection_id) +// if(domain == QLatin1String(Event::EventPlugin::DBEVENT_CARD_READ)) { +// int card_id = data.toInt(); +// if(isVisible()) { +// updateTableView(card_id); +// } +// } +// } void CardReaderWidget::createActions() { @@ -722,7 +722,7 @@ void CardReaderWidget::processReadCard(const quickevent::core::si::ReadCard &rea if(card_id) { /// receipts printer needs this /// emitDbEvent is using queued invocation - // getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_CARD_READ, card_id, true); + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_CARD_READ, card_id, true); } } diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h index 3e2f312b7..8911758d9 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.h @@ -69,7 +69,7 @@ class CardReaderWidget : public QFrame private: void onQxRecChng(const qf::core::sql::QxRecChng &recchng, QObject *source); - void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); + // void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); void appendLog(NecroLog::Level level, const QString &msg); void processDriverInfo(NecroLog::Level level, const QString &msg); void logDriverRawData(const QByteArray &data); From 11bf6d159c6d2a1c57da8cf99d91ee5bd417ac18 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Tue, 14 Jul 2026 22:36:30 +0200 Subject: [PATCH 52/83] Migrate qxApiToken to EventConfig --- .../quickevent/plugins/Event/qml/DbSchema.qml | 4 +- .../plugins/Event/sql/create_db_psql.sql | 1 - .../plugins/Event/sql/create_db_sqlite.sql | 1 - .../plugins/Event/src/eventconfig.cpp | 13 +++ .../plugins/Event/src/eventconfig.h | 5 + .../Event/src/services/qx/qxeventservice.cpp | 7 +- .../Event/src/services/qx/qxeventservice.h | 3 +- .../src/services/qx/qxeventservicewidget.cpp | 109 +++++------------- .../src/services/qx/qxeventservicewidget.h | 6 +- .../src/services/qx/qxeventservicewidget.ui | 49 +++----- .../app/quickevent/plugins/Event/src/stage.h | 1 - 11 files changed, 70 insertions(+), 129 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index 77f00718c..dff9e5d07 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -40,8 +40,8 @@ Schema { defaultValue: false notNull: true }, - Field { name: 'drawingConfig'; type: String {} }, - Field { name: 'qxApiToken'; type: String {} } + Field { name: 'drawingConfig'; type: String {} } + // Field { name: 'qxApiToken'; type: String {} } ] indexes: [ Index {fields: ['id']; primary: true } diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql index 2154be167..1b5767339 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql @@ -30,7 +30,6 @@ CREATE TABLE {{eventId}}.stages ( startDateTime timestamp with time zone, useAllMaps boolean NOT NULL DEFAULT false, drawingConfig character varying, - qxApiToken character varying, CONSTRAINT stages_pkey PRIMARY KEY (id) ); ; diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql index 51aec9f21..640c65c58 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql @@ -29,7 +29,6 @@ CREATE TABLE stages ( startDateTime timestamp, useAllMaps boolean NOT NULL DEFAULT 0, drawingConfig character varying, - qxApiToken character varying, CONSTRAINT stages_pkey PRIMARY KEY (id) ); ; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 0e3358385..75a583f92 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -275,6 +275,19 @@ QDateTime EventConfig::eventDateTime() const } return dt; } +namespace { +constexpr auto QX_API_TOKEN = "qx.apiToken"; +} +QString EventConfig::qxApiToken() const +{ + return value(QX_API_TOKEN).toString(); +} + +void EventConfig::setQxApiToken(const QString &at) +{ + setValue(QX_API_TOKEN, at); + save(QX_API_TOKEN); +} int EventConfig::dbVersion() const { diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index a4d9c4ea5..d8f48cbaa 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -20,6 +20,7 @@ class EventConfig : public QObject Q_PROPERTY(bool iofXmlRaceNumber READ iofXmlRaceNumber) Q_PROPERTY(QString director READ director) Q_PROPERTY(QString mainReferee READ mainReferee) + Q_PROPERTY(QString qxApiToken READ qxApiToken) //Q_PROPERTY(QString eventName READ eventName) public: enum class Sport {OB = 1, LOB, MTBO, TRAIL}; @@ -72,6 +73,10 @@ class EventConfig : public QObject QString director() const; QString mainReferee() const; QDateTime eventDateTime() const; + + QString qxApiToken() const; + void setQxApiToken(const QString &at); + int dbVersion() const; std::optional maximumCardCheckAdvanceSec() const; bool isOneTenthSecResults() const; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp index 61ec5d71c..305f718cc 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.cpp @@ -284,11 +284,8 @@ int QxEventService::eventId() const QString QxEventService::apiToken() const { - // API token must not be cached to enable service to point - // always to current stage event on qxhttpd auto *event_plugin = getPlugin(); - auto current_stage = event_plugin->currentStageId(); - return event_plugin->stageData(current_stage).qxApiToken(); + return event_plugin->eventConfig()->qxApiToken(); } QUrl QxEventService::shvBrokerUrl() const @@ -483,7 +480,7 @@ void QxEventService::onBrokerConnectedChanged(bool is_connected) auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); auto stage_data = event_plugin->stageData(current_stage); - auto api_token = stage_data.qxApiToken().toStdString(); + auto api_token = event_plugin->eventConfig()->qxApiToken().toStdString(); auto *rpc_call = shv::iotqt::rpc::RpcCall::create(m_rpcConnection) ->setShvPath(eventctlShvPath()) ->setMethod("openEventApiKey") diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h index ca1b93e08..e78831898 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservice.h @@ -18,7 +18,8 @@ class QxEventServiceSettings : public ServiceSettings { using Super = ServiceSettings; - QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "tcp://localhost?user=test&password=test") + QF_VARIANTMAP_FIELD2(QString, s, setS, hvBrokerUrl, "tcp://localhost?user=qe&password=test") + QF_VARIANTMAP_FIELD2(bool, is, set, LocalBroker, false) QF_VARIANTMAP_FIELD2(bool, is, set, ExportDatabase, false) public: QxEventServiceSettings(const QVariantMap &o = QVariantMap()) : Super(o) {} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp index 0a3f57225..4d7fe6171 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.cpp @@ -44,25 +44,10 @@ QxEventServiceWidget::QxEventServiceWidget(QWidget *parent) ui->edCurrentStage->setValue(current_stage); ui->edEventId->setValue(svc->eventId()); connect(ui->btTestConnection, &QAbstractButton::clicked, this, &QxEventServiceWidget::testConnection); - connect(ui->btExportEventInfo, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportEventInfo); - connect(ui->btExportStartList, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportStartList); - connect(ui->btExportRuns, &QAbstractButton::clicked, this, &QxEventServiceWidget::exportRuns); - -// #ifdef QT_DEBUG - ui->grpShvConnection->setVisible(true); -// #else -// ui->grpShvConnection->setVisible(false); -// #endif - connect(ui->btQxQxOrg, &QAbstractButton::clicked, this, [this](bool checked) { - if (checked) { - setDefaultShvBrokerUrl(false); - } - }); - connect(ui->btLocalhost, &QAbstractButton::clicked, this, [this](bool checked) { - if (checked) { - setDefaultShvBrokerUrl(true); - } - }); + + connect(ui->btQxQxOrg, &QRadioButton::toggled, this, &QxEventServiceWidget::setConnectionType); + connect(ui->btLocalhost, &QRadioButton::toggled, this, &QxEventServiceWidget::setConnectionType); + ui->btQxQxOrg->setChecked(!settings.isLocalBroker()); } QxEventServiceWidget::~QxEventServiceWidget() @@ -115,15 +100,17 @@ bool QxEventServiceWidget::saveSettings() auto *svc = service(); if(svc) { auto ss = svc->settings(); - ss.setShvBrokerUrl(ui->edServerUrl->text()); + bool is_localhost = ui->btLocalhost->isChecked(); + if (is_localhost) { + ss.setShvBrokerUrl(ui->edServerUrl->text()); + } + ss.setLocalBroker(is_localhost); ss.setExportDatabase(ui->chkExportDatabase->isChecked()); svc->setSettings(ss); - auto *event_plugin = getPlugin(); - auto current_stage = event_plugin->currentStageId(); - auto stage_data = event_plugin->stageData(current_stage); - stage_data.setQxApiToken(ui->edApiToken->text()); - event_plugin->setStageData(current_stage, stage_data); + auto *event_plugin = getPlugin(); + auto *event_config = event_plugin->eventConfig(); + event_config->setQxApiToken(ui->edApiToken->text()); } return true; } @@ -175,69 +162,29 @@ void QxEventServiceWidget::testConnection() rpc->open(); } -void QxEventServiceWidget::exportEventInfo() -{ - auto *svc = service(); - Q_ASSERT(svc); - auto *reply = svc->postEventInfo(ui->edServerUrl->text(), ui->edApiToken->text()); - connect(reply, &QNetworkReply::finished, this, [this, reply]() { - auto data = reply->readAll(); - if (reply->error() == QNetworkReply::NetworkError::NoError) { - auto doc = QJsonDocument::fromJson(data); - EventInfo event_info(doc.toVariant().toMap()); - ui->edEventId->setValue(event_info.id()); - setMessage(tr("Event info updated OK")); - } - else { - setMessage(tr("Event info update error: %1\n%2").arg(reply->errorString()).arg(QString::fromUtf8(data)), MessageType::Error); - } - reply->deleteLater(); - }); -} - -void QxEventServiceWidget::exportStartList() -{ - auto *svc = service(); - Q_ASSERT(svc); - saveSettings(); - setMessage(tr("Start list export started ..."), MessageType::Progress); - svc->postStartListIofXml3(this, [this](auto err) { - if (err.isEmpty()) { - setMessage(tr("Start list exported Ok")); - } - else { - setMessage(err, MessageType::Error); - } - }); -} - -void QxEventServiceWidget::exportRuns() +void QxEventServiceWidget::setConnectionType() { - auto *svc = service(); - Q_ASSERT(svc); - saveSettings(); - setMessage(tr("Runs export started ..."), MessageType::Progress); - svc->postRuns(this, [this](auto err) { - if (err.isEmpty()) { - setMessage(tr("Runs exported Ok")); - } - else { - setMessage(err, MessageType::Error); - } - }); + bool is_localhost = ui->btLocalhost->isChecked(); + if (is_localhost) { + ui->lblUrl->setVisible(true); + ui->edServerUrl->setVisible(true); + } else { + ui->lblUrl->setVisible(false); + ui->edServerUrl->setVisible(false); + } } -void QxEventServiceWidget::setDefaultShvBrokerUrl(bool is_local_host) +QString QxEventServiceWidget::brokerUrl() const { - auto url = QStringLiteral("tcp://%1?user=qe&%2=%3"); - if (is_local_host) { - url = url.arg("localhost"); - } else { - url = url.arg("qxqx.org"); + bool is_localhost = ui->btLocalhost->isChecked(); + if (is_localhost) { + return ui->edServerUrl->text(); } + auto url = QStringLiteral("tcp://%1?user=qe&%2=%3"); + url = url.arg("qxqx.org"); url = url.arg("password"); url = url.arg("2ddf6394ea6"); - ui->edServerUrl->setText(url); + return url; } } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h index 1bde76efc..0ae762934 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.h @@ -26,10 +26,8 @@ class QxEventServiceWidget : public qf::gui::framework::DialogWidget QxEventService* service(); bool saveSettings(); void testConnection(); - void exportEventInfo(); - void exportStartList(); - void exportRuns(); - void setDefaultShvBrokerUrl(bool is_local_host); + void setConnectionType(); + QString brokerUrl() const; private: Ui::QxEventServiceWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui index d61295c58..b6bc76c50 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxeventservicewidget.ui @@ -21,7 +21,7 @@ - + 0 @@ -39,7 +39,7 @@ localhost - false + true @@ -49,7 +49,7 @@ qxqx.org - true + false @@ -111,8 +111,14 @@ true + + Not defined + - 1 + 0 + + + 0 @@ -139,8 +145,8 @@ - - + + Qt::Orientation::Horizontal @@ -153,40 +159,17 @@ - - - - false - - - Export event info - - - - + Test connection - - - - false - - - Export start list - - - - - - - false - + + - Export runs + Archive event diff --git a/quickevent/app/quickevent/plugins/Event/src/stage.h b/quickevent/app/quickevent/plugins/Event/src/stage.h index f52c79399..ec50622c9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stage.h +++ b/quickevent/app/quickevent/plugins/Event/src/stage.h @@ -16,7 +16,6 @@ class StageData : public QVariantMap QF_VARIANTMAP_KEY_FIELD(bool, useallmaps, is, set, UseAllMaps) QF_VARIANTMAP_KEY_FIELD(QVariantMap, drawingconfig, d, setD, rawingConfig) - QF_VARIANTMAP_KEY_FIELD(QString, qxapitoken, qx, setQx, ApiToken) public: StageData(const QVariantMap &data = QVariantMap()); From 62aecbded63fcb3b45e551faab89ec0a5107a35d Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 17:25:54 +0200 Subject: [PATCH 53/83] Add per-stage start times support for events --- .../plugins/Event/src/eventdialogwidget.cpp | 60 ++++++++++++++++++- .../plugins/Event/src/eventdialogwidget.h | 2 + .../plugins/Event/src/eventdialogwidget.ui | 40 +++++++++++-- .../plugins/Event/src/eventplugin.cpp | 33 ++++++++-- 4 files changed, 124 insertions(+), 11 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 9ed6bc57a..4234698d7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -5,6 +5,10 @@ #include +#include +#include +#include + EventDialogWidget::EventDialogWidget(QWidget *parent) : Super(parent), ui(new Ui::EventDialogWidget) @@ -12,6 +16,13 @@ EventDialogWidget::EventDialogWidget(QWidget *parent) : setPersistentSettingsId("EventDialogWidget"); ui->setupUi(this); + ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + ui->stageStartTimesTable->verticalHeader()->hide(); + connect(ui->ed_stageCount, QOverload::of(&QSpinBox::valueChanged), + this, &EventDialogWidget::updateStageStartTimeEditors); + updateStageStartTimeEditors(ui->ed_stageCount->value()); + connect(ui->ed_iofRace, &QAbstractButton::toggled, ui->frameIofRace, &QWidget::setVisible); ui->frameIofRace->hide(); @@ -60,10 +71,37 @@ void EventDialogWidget::setEventIdEditable(bool b) ui->ed_eventId->setReadOnly(!b); } +void EventDialogWidget::updateStageStartTimeEditors(int stage_count) +{ + QTableWidget *table = ui->stageStartTimesTable; + const int old_count = table->rowCount(); + if(stage_count < old_count) { + table->setRowCount(stage_count); + return; + } + + QDateTime next_start(ui->ed_date->date(), ui->ed_time->time()); + if(old_count > 0) { + if(auto *last_editor = qobject_cast(table->cellWidget(old_count - 1, 1))) + next_start = last_editor->dateTime().addDays(1); + } + + table->setRowCount(stage_count); + for(int row = old_count; row < stage_count; ++row) { + auto *stage_item = new QTableWidgetItem(QString::number(row + 1)); + stage_item->setTextAlignment(Qt::AlignCenter); + table->setItem(row, 0, stage_item); + + auto *editor = new QDateTimeEdit(next_start, table); + editor->setCalendarPopup(true); + editor->setDisplayFormat(QStringLiteral("dd.MM.yyyy HH:mm:ss")); + table->setCellWidget(row, 1, editor); + next_start = next_start.addDays(1); + } +} + void EventDialogWidget::loadParams(const QVariantMap ¶ms) { - ui->ed_stageCount->setValue(params.value("stageCount").toInt()); - //ui->ed_currentStage->setValue(params.value("currentStageId").toInt()); ui->ed_name->setText(params.value("name").toString()); QDate date = params.value("date").toDate(); if(!date.isValid()) @@ -72,6 +110,18 @@ void EventDialogWidget::loadParams(const QVariantMap ¶ms) QTime time = params.value("time").toTime(); if(time.isValid()) ui->ed_time->setTime(time); + + ui->stageStartTimesTable->setRowCount(0); + ui->ed_stageCount->setValue(params.value("stageCount", 1).toInt()); + updateStageStartTimeEditors(ui->ed_stageCount->value()); + const QVariantMap stage_start_times = params.value("stageStartDateTimes").toMap(); + for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { + const QDateTime start_time = stage_start_times.value(QString::number(row + 1)).toDateTime(); + if(start_time.isValid()) { + if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) + editor->setDateTime(start_time); + } + } ui->ed_description->setText(params.value("description").toString()); ui->ed_place->setText(params.value("place").toString()); ui->ed_mainReferee->setText(params.value("mainReferee").toString()); @@ -100,6 +150,12 @@ QVariantMap EventDialogWidget::saveParams() { QVariantMap ret; ret["stageCount"] = ui->ed_stageCount->value(); + QVariantMap stage_start_times; + for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { + if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) + stage_start_times.insert(QString::number(row + 1), editor->dateTime()); + } + ret["stageStartDateTimes"] = stage_start_times; //ret["currentStageId"] = ui->ed_currentStage->value(); ret["name"] = ui->ed_name->text(); ret["date"] = ui->ed_date->date(); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index 35b11dce8..5298cdafa 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -26,6 +26,8 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget static QString disciplineName(int disc_id); static QString sportName(int sport_id); private: + void updateStageStartTimeEditors(int stage_count); + Ui::EventDialogWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui index 5d6f37dda..79096adfa 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui @@ -158,7 +158,7 @@ - + Card check @@ -168,7 +168,7 @@ - + Maximal distance between card CHECK and START time @@ -190,7 +190,7 @@ - + 1/10 sec results @@ -200,7 +200,7 @@ - + @@ -263,6 +263,38 @@ + + + + + 0 + 120 + + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + QAbstractItemView::SelectionMode::NoSelection + + + false + + + 2 + + + + # + + + + + Stage start time + + + + diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 32e500ba3..a19f5fcda 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -940,7 +940,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even bool ok = false; //ConnectionSettings connection_settings; event_config.setValue("event", new_params); - int stage_count = event_params.value("stageCount").toInt(); + int stage_count = new_params.value("stageCount").toInt(); if(stage_count == 0) stage_count = event_config.stageCount(); qfInfo() << "createEvent, stage_count:" << stage_count; @@ -979,17 +979,20 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even if(connection_type == ConnectionType::SqlServer) { stage_table_name = event_id + '.' + stage_table_name; } - QDateTime start_dt = event_config.eventDateTime(); + const QDateTime default_start_dt = event_config.eventDateTime(); + const QVariantMap stage_start_times = new_params.value("stageStartDateTimes").toMap(); // FIXME: handle SQL errors here and below in q.exec() q.prepare("INSERT INTO " + stage_table_name + " (id, startDateTime) VALUES (:id, :startDateTime)"); for(int i=0; isetWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - event_w->loadParams(eventConfig()->value("event").toMap()); + QVariantMap event_params = eventConfig()->value("event").toMap(); + QVariantMap stage_start_times; + qfs::Query stage_query; + if(stage_query.exec("SELECT id, startDateTime FROM stages ORDER BY id")) { + while(stage_query.next()) { + stage_start_times.insert(stage_query.value(0).toString(), + stage_query.value(1).toDateTime().toLocalTime()); + } + } + event_params.insert("stageStartDateTimes", stage_start_times); + event_w->loadParams(event_params); dlg.setCentralWidget(event_w); if(!dlg.exec()) return; - eventConfig()->setValue("event", event_w->saveParams()); + event_params = event_w->saveParams(); + eventConfig()->setValue("event", event_params); eventConfig()->save("event"); + + stage_start_times = event_params.value("stageStartDateTimes").toMap(); + stage_query.prepare("UPDATE stages SET startDateTime=:startDateTime WHERE id=:id"); + for(auto it = stage_start_times.cbegin(); it != stage_start_times.cend(); ++it) { + stage_query.bindValue(":id", it.key().toInt()); + stage_query.bindValue(":startDateTime", it.value().toDateTime()); + stage_query.exec(); + } + clearStageDataCache(); } bool EventPlugin::closeEvent() From 8400492f63dbf9319a89f043ccc5e7e39a06604a Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 17:41:42 +0200 Subject: [PATCH 54/83] Store stage start times in event config --- .../plugins/Event/src/eventdialogwidget.cpp | 16 +++--- .../plugins/Event/src/eventplugin.cpp | 42 +++++++--------- .../plugins/Event/src/stagewidget.cpp | 49 +++++++++---------- .../plugins/Event/src/stagewidget.h | 1 + 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 4234698d7..f93097e26 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -114,9 +114,10 @@ void EventDialogWidget::loadParams(const QVariantMap ¶ms) ui->stageStartTimesTable->setRowCount(0); ui->ed_stageCount->setValue(params.value("stageCount", 1).toInt()); updateStageStartTimeEditors(ui->ed_stageCount->value()); - const QVariantMap stage_start_times = params.value("stageStartDateTimes").toMap(); + const QVariantMap stages = params.value("stage").toMap(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - const QDateTime start_time = stage_start_times.value(QString::number(row + 1)).toDateTime(); + const QVariantMap stage = stages.value(QString::number(row + 1)).toMap(); + const QDateTime start_time = stage.value("startDateTime").toDateTime(); if(start_time.isValid()) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) editor->setDateTime(start_time); @@ -150,12 +151,15 @@ QVariantMap EventDialogWidget::saveParams() { QVariantMap ret; ret["stageCount"] = ui->ed_stageCount->value(); - QVariantMap stage_start_times; + QVariantMap stages; for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) - stage_start_times.insert(QString::number(row + 1), editor->dateTime()); + if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) { + QVariantMap stage; + stage.insert("startDateTime", editor->dateTime()); + stages.insert(QString::number(row + 1), stage); + } } - ret["stageStartDateTimes"] = stage_start_times; + ret["stage"] = stages; //ret["currentStageId"] = ui->ed_currentStage->value(); ret["name"] = ui->ed_name->text(); ret["date"] = ui->ed_date->date(); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index a19f5fcda..3cfae50f3 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -277,9 +278,13 @@ QTime EventPlugin::stageStartTime(int stage_id) QDateTime EventPlugin::stageStartDateTime(int stage_id) { - Event::StageData stage_data = stageData(stage_id); - QDateTime dt = stage_data.startDateTime(); - return dt; + const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(stage_id); + QDateTime dt = eventConfig()->value(config_key).toDateTime(); + if(dt.isValid()) + return dt.toTimeZone(QTimeZone::systemTimeZone()); + + // Events created before stage start times were moved to config keep the value in stages. + return stageData(stage_id).startDateTime(); } int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) @@ -979,16 +984,10 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even if(connection_type == ConnectionType::SqlServer) { stage_table_name = event_id + '.' + stage_table_name; } - const QDateTime default_start_dt = event_config.eventDateTime(); - const QVariantMap stage_start_times = new_params.value("stageStartDateTimes").toMap(); - // FIXME: handle SQL errors here and below in q.exec() - q.prepare("INSERT INTO " + stage_table_name + " (id, startDateTime) VALUES (:id, :startDateTime)"); + // Stage start times are stored in config as event.stage..startDateTime. + q.prepare("INSERT INTO " + stage_table_name + " (id) VALUES (:id)"); for(int i=0; isetEventId(eventName()); event_w->setEventIdEditable(false); QVariantMap event_params = eventConfig()->value("event").toMap(); - QVariantMap stage_start_times; + QVariantMap stages = event_params.value("stage").toMap(); qfs::Query stage_query; if(stage_query.exec("SELECT id, startDateTime FROM stages ORDER BY id")) { while(stage_query.next()) { - stage_start_times.insert(stage_query.value(0).toString(), - stage_query.value(1).toDateTime().toLocalTime()); + const QString stage_id = stage_query.value(0).toString(); + QVariantMap stage = stages.value(stage_id).toMap(); + if(!stage.value("startDateTime").toDateTime().isValid()) { + stage.insert("startDateTime", stage_query.value(1).toDateTime().toLocalTime()); + stages.insert(stage_id, stage); + } } } - event_params.insert("stageStartDateTimes", stage_start_times); + event_params.insert("stage", stages); event_w->loadParams(event_params); dlg.setCentralWidget(event_w); if(!dlg.exec()) @@ -1041,15 +1044,6 @@ void EventPlugin::editEvent() event_params = event_w->saveParams(); eventConfig()->setValue("event", event_params); eventConfig()->save("event"); - - stage_start_times = event_params.value("stageStartDateTimes").toMap(); - stage_query.prepare("UPDATE stages SET startDateTime=:startDateTime WHERE id=:id"); - for(auto it = stage_start_times.cbegin(); it != stage_start_times.cend(); ++it) { - stage_query.bindValue(":id", it.key().toInt()); - stage_query.bindValue(":startDateTime", it.value().toDateTime()); - stage_query.exec(); - } - clearStageDataCache(); } bool EventPlugin::closeEvent() diff --git a/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp index 8156d0142..dcf70c4fd 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp @@ -2,10 +2,15 @@ #include "ui_stagewidget.h" #include "stagedocument.h" +#include "eventconfig.h" +#include "eventplugin.h" + +#include #include using namespace Event; +using qf::gui::framework::getPlugin; StageWidget::StageWidget(QWidget *parent) : Super(parent), @@ -26,20 +31,20 @@ StageWidget::~StageWidget() bool StageWidget::load(const QVariant &id, int mode) { + m_stageId = id.toInt(); bool ok = Super::load(id, mode); if(ok) { - QDateTime dt; - qf::gui::model::DataDocument *doc = dataDocument(); - const auto START_DATE_TIME = QStringLiteral("startDateTime"); - dt = doc->value(START_DATE_TIME).toDateTime().toLocalTime(); - /* - if(!dt.isValid()) { - // try old DB version - QDate d = doc->value(QStringLiteral("startDate")).toDate(); - QTime t = doc->value(QStringLiteral("startTime")).toTime(); - dt = QDateTime(d, t); + const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(m_stageId); + QDateTime dt = getPlugin()->eventConfig()->value(config_key).toDateTime(); + if(dt.isValid()) { + dt = dt.toTimeZone(QTimeZone::systemTimeZone()); + } + else { + // Backward compatibility for events whose start time is still in stages. + qf::gui::model::DataDocument *doc = dataDocument(); + dt = doc->value(QStringLiteral("startDateTime")).toDateTime().toLocalTime(); } - */ + ui->dateEdit->setDate(dt.date()); ui->timeEdit->setTime(dt.time()); } @@ -51,18 +56,12 @@ bool StageWidget::saveData() QDate d = ui->dateEdit->date(); QTime t = ui->timeEdit->time(); QDateTime dt(d, t, QTimeZone::systemTimeZone()); - qf::gui::model::DataDocument *doc = dataDocument(); - const auto START_DATE_TIME = QStringLiteral("startDateTime"); - doc->setValue(START_DATE_TIME, dt); - /* - if(doc->isValidFieldName(START_DATE_TIME)) { - doc->setValue(START_DATE_TIME, dt); - } - else { - // old DB version - doc->setValue(QStringLiteral("startDate"), d); - doc->setValue(QStringLiteral("startTime"), t); - } - */ - return Super::saveData(); + if(!Super::saveData()) + return false; + + EventConfig *config = getPlugin()->eventConfig(); + const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(m_stageId); + config->setValue(config_key, dt); + config->save(config_key); + return true; } diff --git a/quickevent/app/quickevent/plugins/Event/src/stagewidget.h b/quickevent/app/quickevent/plugins/Event/src/stagewidget.h index 1361b80a7..325aca0b3 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stagewidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/stagewidget.h @@ -24,6 +24,7 @@ class StageWidget : public qf::gui::framework::DataDialogWidget protected: bool saveData() Q_DECL_OVERRIDE; private: + int m_stageId = 0; Ui::StageWidget *ui; }; From d0b03c4a5a070863cd3b1e1d2ec242e66b13f220 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 17:53:41 +0200 Subject: [PATCH 55/83] Remove Stage editor support and related files --- quickevent/app/quickevent/CMakeLists.txt | 3 - .../plugins/Event/src/eventplugin.cpp | 88 +++++++++---------- .../plugins/Event/src/eventplugin.h | 2 - .../plugins/Event/src/stagedocument.cpp | 16 ---- .../plugins/Event/src/stagedocument.h | 19 ---- .../plugins/Event/src/stagewidget.cpp | 67 -------------- .../plugins/Event/src/stagewidget.h | 33 ------- .../plugins/Event/src/stagewidget.ui | 70 --------------- 8 files changed, 44 insertions(+), 254 deletions(-) delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagedocument.cpp delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagedocument.h delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagewidget.h delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagewidget.ui diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 5368f5fe7..fcfccef48 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -71,9 +71,6 @@ add_executable(quickevent plugins/Event/src/openeventdialog.cpp plugins/Event/src/openeventdialog.ui plugins/Event/src/stage.cpp - plugins/Event/src/stagedocument.cpp - plugins/Event/src/stagewidget.cpp - plugins/Event/src/stagewidget.ui plugins/Event/src/findregistrationedit.cpp plugins/Event/src/lentcardssettingspage.cpp plugins/Event/src/lentcardssettingspage.ui diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 3cfae50f3..74730403a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -6,8 +6,6 @@ #include "dbschema.h" #include "registrationswidget.h" #include "lentcardssettingspage.h" -#include "stagewidget.h" -#include "stagedocument.h" #include "../../Core/src/widgets/appstatusbar.h" #include "services/serviceswidget.h" @@ -32,6 +30,7 @@ #include #include #include +#include #include #include @@ -301,33 +300,55 @@ int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) StageData EventPlugin::stageData(int stage_id) { if(!m_stageCache.contains(stage_id)) { - StageDocument doc; - doc.load(stage_id); StageData data; - for (const auto &[k, v] : doc.values().asKeyValueRange()) { - auto key = k.toLower(); - if (key == "drawingconfig" && v.userType() == qMetaTypeId()) { - // convert json to variantmap - data[key] = qf::core::Utils::jsonToQVariant(v.toString()); - } - else { - data[key] = v; + qfs::Query q; + q.prepare("SELECT * FROM stages WHERE id=:id"); + q.bindValue(":id", stage_id); + if(q.exec() && q.next()) { + const QSqlRecord record = q.record(); + for(int i = 0; i < record.count(); ++i) { + const QString key = record.fieldName(i).toLower(); + const QVariant value = q.value(i); + if(key == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) + data[key] = qf::core::Utils::jsonToQVariant(value.toString()); + else + data[key] = value; } } - m_stageCache[stage_id] = StageData(data); + m_stageCache[stage_id] = data; } return m_stageCache.value(stage_id); } void EventPlugin::setStageData(int stage_id, const StageData &data) { - StageDocument doc; - doc.load(stage_id); - for (const auto &[k, v] : data.asKeyValueRange()) { - doc.setValue(k, v); - m_stageCache[stage_id][k.toLower()] = v; + static const QMap columns { + {QStringLiteral("useallmaps"), QStringLiteral("useAllMaps")}, + {QStringLiteral("drawingconfig"), QStringLiteral("drawingConfig")}, + {QStringLiteral("qxapitoken"), QStringLiteral("qxApiToken")}, + }; + + QStringList assignments; + QVariantMap values; + for(auto it = columns.cbegin(); it != columns.cend(); ++it) { + if(!data.contains(it.key())) + continue; + assignments.append(it.value() + "=:" + it.key()); + QVariant value = data.value(it.key()); + if(it.key() == QLatin1String("drawingconfig") && value.userType() != qMetaTypeId()) + value = qf::core::Utils::qvariantToJson(value); + values.insert(it.key(), value); } - doc.save(); + if(assignments.isEmpty()) + return; + + qfs::Query q; + q.prepare("UPDATE stages SET " + assignments.join(", ") + " WHERE id=:id"); + q.bindValue(":id", stage_id); + for(auto it = values.cbegin(); it != values.cend(); ++it) + q.bindValue(':' + it.key(), it.value()); + if(q.exec()) + m_stageCache.remove(stage_id); } void EventPlugin::clearStageDataCache() @@ -417,16 +438,8 @@ void EventPlugin::onInstalled() QAction *act_stage = tb->addWidget(m_cbxStage); act_stage->setVisible(false); - - QIcon ico(qf::gui::Style::icon("settings")); - m_actEditStage = new qfw::Action(ico, "Stage settings"); - m_actEditStage->setVisible(false); - connect(m_actEditStage, &QAction::triggered, this, &EventPlugin::editStage); - tb->addAction(m_actEditStage); - - connect(bt_stage, &QPushButton::clicked, this, [this, act_stage](bool checked) { + connect(bt_stage, &QPushButton::clicked, this, [act_stage](bool checked) { act_stage->setVisible(checked); - m_actEditStage->setVisible(checked); }); } fwk->menuBar()->actionForPath("view/toolbar")->addActionInto(tb->toggleViewAction()); @@ -505,20 +518,7 @@ void EventPlugin::saveCurrentStageId(int current_stage) } } -void EventPlugin::editStage() -{ - //qfLogFuncFrame();// << "id:" << id << "mode:" << mode; - int stage_id = currentStageId(); - auto *w = new Event::StageWidget(); - auto *fwk = qf::gui::framework::MainWindow::frameWork(); - qfd::Dialog dlg(QDialogButtonBox::Save | QDialogButtonBox::Cancel, fwk); - dlg.setDefaultButton(QDialogButtonBox::Save); - dlg.setCentralWidget(w); - w->load(stage_id); - if(dlg.exec()) { - emitDbEvent(Event::EventPlugin::DBEVENT_STAGE_START_CHANGED, stage_id, true); - } -} + void EventPlugin::emitDbEvent(const QString &domain, const QVariant &data, bool loopback) { @@ -876,7 +876,7 @@ void EventPlugin::connectToSqlServer() m_actEvent->setEnabled(connect_ok); m_actExport->setEnabled(connect_ok); m_actImport->setEnabled(connect_ok); - m_actEditStage->setEnabled(connect_ok); + if(connect_ok) { closeEvent(); openEvent(conn_w->eventName()); @@ -1180,7 +1180,7 @@ bool EventPlugin::openEvent(const QString &_event_name) setEventName(event_name); //emit reloadDataRequest(); } - m_actEditStage->setEnabled(ok); + m_actOpenEvent->setEnabled(ok || !db_event_names.isEmpty()); m_actEditEvent->setEnabled(ok); m_actExportEvent_qbe->setEnabled(ok); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 50a8e077e..b1dcddbc0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -134,7 +134,6 @@ class EventPlugin : public qf::gui::framework::Plugin void connectToSqlServer(); void loadCurrentStageId(); void saveCurrentStageId(int current_stage); - void editStage(); void onDbEvent(const QString & name, QSqlDriver::NotificationSource source, const QVariant & payload); void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); @@ -165,7 +164,6 @@ class EventPlugin : public qf::gui::framework::Plugin qf::gui::Action *m_actEditEvent = nullptr; qf::gui::Action *m_actExportEvent_qbe = nullptr; qf::gui::Action *m_actImportEvent_qbe = nullptr; - qf::gui::Action *m_actEditStage = nullptr; Event::EventConfig *m_eventConfig = nullptr; bool m_sqlServerConnected = false; QComboBox *m_cbxStage = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/stagedocument.cpp b/quickevent/app/quickevent/plugins/Event/src/stagedocument.cpp deleted file mode 100644 index 45462be9b..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagedocument.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "stagedocument.h" - -#include - -using namespace Event; - -StageDocument::StageDocument(QObject *parent) - : Super(parent) -{ - qf::core::sql::QueryBuilder qb; - qb.select2("stages", "*") - .from("stages") - .where("stages.id={{ID}}"); - setQueryBuilder(qb); -} - diff --git a/quickevent/app/quickevent/plugins/Event/src/stagedocument.h b/quickevent/app/quickevent/plugins/Event/src/stagedocument.h deleted file mode 100644 index 5c2b07992..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagedocument.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef EVENT_STAGEDOCUMENT_H -#define EVENT_STAGEDOCUMENT_H - -#include - -namespace Event { - -class StageDocument : public qf::gui::model::SqlDataDocument -{ - Q_OBJECT -private: - typedef qf::gui::model::SqlDataDocument Super; -public: - StageDocument(QObject *parent = nullptr); -}; - -} - -#endif // EVENT_STAGEDOCUMENT_H diff --git a/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp deleted file mode 100644 index dcf70c4fd..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagewidget.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "stagewidget.h" -#include "ui_stagewidget.h" - -#include "stagedocument.h" -#include "eventconfig.h" -#include "eventplugin.h" - -#include - -#include - -using namespace Event; -using qf::gui::framework::getPlugin; - -StageWidget::StageWidget(QWidget *parent) : - Super(parent), - ui(new Ui::StageWidget) -{ - setPersistentSettingsId("StageWidget"); - ui->setupUi(this); - - setTitle(tr("Stage")); - setWindowTitle(tr("Edit Stage")); - dataController()->setDocument(new StageDocument(this)); -} - -StageWidget::~StageWidget() -{ - delete ui; -} - -bool StageWidget::load(const QVariant &id, int mode) -{ - m_stageId = id.toInt(); - bool ok = Super::load(id, mode); - if(ok) { - const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(m_stageId); - QDateTime dt = getPlugin()->eventConfig()->value(config_key).toDateTime(); - if(dt.isValid()) { - dt = dt.toTimeZone(QTimeZone::systemTimeZone()); - } - else { - // Backward compatibility for events whose start time is still in stages. - qf::gui::model::DataDocument *doc = dataDocument(); - dt = doc->value(QStringLiteral("startDateTime")).toDateTime().toLocalTime(); - } - - ui->dateEdit->setDate(dt.date()); - ui->timeEdit->setTime(dt.time()); - } - return ok; -} - -bool StageWidget::saveData() -{ - QDate d = ui->dateEdit->date(); - QTime t = ui->timeEdit->time(); - QDateTime dt(d, t, QTimeZone::systemTimeZone()); - if(!Super::saveData()) - return false; - - EventConfig *config = getPlugin()->eventConfig(); - const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(m_stageId); - config->setValue(config_key, dt); - config->save(config_key); - return true; -} diff --git a/quickevent/app/quickevent/plugins/Event/src/stagewidget.h b/quickevent/app/quickevent/plugins/Event/src/stagewidget.h deleted file mode 100644 index 325aca0b3..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagewidget.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EVENT_STAGEWIDGET_H -#define EVENT_STAGEWIDGET_H - -#include - -#include - -namespace Event { - -namespace Ui { -class StageWidget; -} - -class StageWidget : public qf::gui::framework::DataDialogWidget -{ - Q_OBJECT -private: - using Super = qf::gui::framework::DataDialogWidget; -public: - explicit StageWidget(QWidget *parent = 0); - ~StageWidget(); - - bool load(const QVariant &id = QVariant(), int mode = qf::gui::model::DataDocument::ModeEdit) Q_DECL_OVERRIDE; -protected: - bool saveData() Q_DECL_OVERRIDE; -private: - int m_stageId = 0; - Ui::StageWidget *ui; -}; - -} - -#endif diff --git a/quickevent/app/quickevent/plugins/Event/src/stagewidget.ui b/quickevent/app/quickevent/plugins/Event/src/stagewidget.ui deleted file mode 100644 index 1b532ce4c..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagewidget.ui +++ /dev/null @@ -1,70 +0,0 @@ - - - Event::StageWidget - - - - 0 - 0 - 413 - 313 - - - - Form - - - - - - &Date - - - dateEdit - - - - - - - dd.MM. yyyy - - - true - - - - - - - &Time - - - timeEdit - - - - - - - H:mm:ss - - - - - - - - qf::gui::TimeEdit - QTimeEdit -
qf/gui/timeedit.h
-
- - qf::gui::DateEdit - QDateEdit -
qf/gui/dateedit.h
-
-
- - -
From 62d1447aab7005925137e4a061538cf41b1b0106 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 22:26:39 +0200 Subject: [PATCH 56/83] Migrate stage config to EventConfig --- .../plugins/Classes/src/drawing/ganttitem.cpp | 11 +-- .../plugins/Event/src/eventdialogwidget.cpp | 17 ++-- .../plugins/Event/src/eventdialogwidget.h | 1 + .../plugins/Event/src/eventplugin.cpp | 90 +++++++++++-------- 4 files changed, 66 insertions(+), 53 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index eb70c0f76..b42ead29e 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -163,15 +163,8 @@ void GanttItem::save(int stage_id) start_slots << sd; } dc.setStartSlots(start_slots); - auto dc_str = qf::core::Utils::qvariantToJson(dc); - - QString qs = "UPDATE stages SET drawingConfig=:drawingConfig WHERE id=:id"; - qfs::Query q(qfs::Connection::forName()); - q.prepare(qs, qf::core::Exception::Throw); - q.bindValue(":drawingConfig", dc_str); - q.bindValue(":id", stage_id); - q.exec(qf::core::Exception::Throw); - getPlugin()->clearStageDataCache(); + stage.setDrawingConfig(dc); + getPlugin()->setStageData(stage_id, stage); } { QString qs = "UPDATE classdefs SET" diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index f93097e26..0917c1b8e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -114,9 +114,9 @@ void EventDialogWidget::loadParams(const QVariantMap ¶ms) ui->stageStartTimesTable->setRowCount(0); ui->ed_stageCount->setValue(params.value("stageCount", 1).toInt()); updateStageStartTimeEditors(ui->ed_stageCount->value()); - const QVariantMap stages = params.value("stage").toMap(); + m_stages = params.value("stage").toMap(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - const QVariantMap stage = stages.value(QString::number(row + 1)).toMap(); + const QVariantMap stage = m_stages.value(QString::number(row + 1)).toMap(); const QDateTime start_time = stage.value("startDateTime").toDateTime(); if(start_time.isValid()) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) @@ -151,12 +151,19 @@ QVariantMap EventDialogWidget::saveParams() { QVariantMap ret; ret["stageCount"] = ui->ed_stageCount->value(); - QVariantMap stages; + QVariantMap stages = m_stages; for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) { - QVariantMap stage; + const QString stage_id = QString::number(row + 1); + QVariantMap stage = stages.value(stage_id).toMap(); stage.insert("startDateTime", editor->dateTime()); - stages.insert(QString::number(row + 1), stage); + if(!stage.contains("useAllMaps")) + stage.insert("useAllMaps", false); + if(!stage.contains("drawingConfig")) + stage.insert("drawingConfig", QStringLiteral("{}")); + if(!stage.contains("qxApiToken")) + stage.insert("qxApiToken", QString()); + stages.insert(stage_id, stage); } } ret["stage"] = stages; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index 5298cdafa..81c86a7a3 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -28,6 +28,7 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget private: void updateStageStartTimeEditors(int stage_count); + QVariantMap m_stages; Ui::EventDialogWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 74730403a..5db455970 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -277,12 +277,6 @@ QTime EventPlugin::stageStartTime(int stage_id) QDateTime EventPlugin::stageStartDateTime(int stage_id) { - const QString config_key = QStringLiteral("event.stage.%1.startDateTime").arg(stage_id); - QDateTime dt = eventConfig()->value(config_key).toDateTime(); - if(dt.isValid()) - return dt.toTimeZone(QTimeZone::systemTimeZone()); - - // Events created before stage start times were moved to config keep the value in stages. return stageData(stage_id).startDateTime(); } @@ -300,19 +294,41 @@ int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) StageData EventPlugin::stageData(int stage_id) { if(!m_stageCache.contains(stage_id)) { + static const QMap config_keys { + {QStringLiteral("startdatetime"), QStringLiteral("startDateTime")}, + {QStringLiteral("useallmaps"), QStringLiteral("useAllMaps")}, + {QStringLiteral("drawingconfig"), QStringLiteral("drawingConfig")}, + {QStringLiteral("qxapitoken"), QStringLiteral("qxApiToken")}, + }; + StageData data; + const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); + const QVariantMap config_data = eventConfig()->value(config_prefix).toMap(); + for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { + if(!config_data.contains(it.value())) + continue; + QVariant value = config_data.value(it.value()); + if(it.key() == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) + value = qf::core::Utils::jsonToQVariant(value.toString()); + data.insert(it.key(), value); + } + + // Fill keys missing from config from the legacy stages table. qfs::Query q; q.prepare("SELECT * FROM stages WHERE id=:id"); q.bindValue(":id", stage_id); if(q.exec() && q.next()) { const QSqlRecord record = q.record(); - for(int i = 0; i < record.count(); ++i) { - const QString key = record.fieldName(i).toLower(); - const QVariant value = q.value(i); - if(key == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) - data[key] = qf::core::Utils::jsonToQVariant(value.toString()); - else - data[key] = value; + for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { + if(data.contains(it.key())) + continue; + const int field_index = record.indexOf(it.value()); + if(field_index < 0) + continue; + QVariant value = q.value(field_index); + if(it.key() == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) + value = qf::core::Utils::jsonToQVariant(value.toString()); + data.insert(it.key(), value); } } m_stageCache[stage_id] = data; @@ -322,33 +338,25 @@ StageData EventPlugin::stageData(int stage_id) void EventPlugin::setStageData(int stage_id, const StageData &data) { - static const QMap columns { + static const QMap config_keys { + {QStringLiteral("startdatetime"), QStringLiteral("startDateTime")}, {QStringLiteral("useallmaps"), QStringLiteral("useAllMaps")}, {QStringLiteral("drawingconfig"), QStringLiteral("drawingConfig")}, {QStringLiteral("qxapitoken"), QStringLiteral("qxApiToken")}, }; - QStringList assignments; - QVariantMap values; - for(auto it = columns.cbegin(); it != columns.cend(); ++it) { + EventConfig *config = eventConfig(); + const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); + for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { if(!data.contains(it.key())) continue; - assignments.append(it.value() + "=:" + it.key()); QVariant value = data.value(it.key()); if(it.key() == QLatin1String("drawingconfig") && value.userType() != qMetaTypeId()) value = qf::core::Utils::qvariantToJson(value); - values.insert(it.key(), value); + config->setValue(config_prefix + '.' + it.value(), value); } - if(assignments.isEmpty()) - return; - - qfs::Query q; - q.prepare("UPDATE stages SET " + assignments.join(", ") + " WHERE id=:id"); - q.bindValue(":id", stage_id); - for(auto it = values.cbegin(); it != values.cend(); ++it) - q.bindValue(':' + it.key(), it.value()); - if(q.exec()) - m_stageCache.remove(stage_id); + config->save(config_prefix); + m_stageCache.remove(stage_id); } void EventPlugin::clearStageDataCache() @@ -1024,16 +1032,20 @@ void EventPlugin::editEvent() event_w->setEventIdEditable(false); QVariantMap event_params = eventConfig()->value("event").toMap(); QVariantMap stages = event_params.value("stage").toMap(); - qfs::Query stage_query; - if(stage_query.exec("SELECT id, startDateTime FROM stages ORDER BY id")) { - while(stage_query.next()) { - const QString stage_id = stage_query.value(0).toString(); - QVariantMap stage = stages.value(stage_id).toMap(); - if(!stage.value("startDateTime").toDateTime().isValid()) { - stage.insert("startDateTime", stage_query.value(1).toDateTime().toLocalTime()); - stages.insert(stage_id, stage); - } - } + const int stage_count = event_params.value("stageCount").toInt(); + for(int stage_id = 1; stage_id <= stage_count; ++stage_id) { + const QString stage_key = QString::number(stage_id); + QVariantMap stage = stages.value(stage_key).toMap(); + const StageData stage_data = stageData(stage_id); + if(!stage.contains("startDateTime") && stage_data.contains("startdatetime")) + stage.insert("startDateTime", stage_data.value("startdatetime")); + if(!stage.contains("useAllMaps") && stage_data.contains("useallmaps")) + stage.insert("useAllMaps", stage_data.value("useallmaps")); + if(!stage.contains("drawingConfig") && stage_data.contains("drawingconfig")) + stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(stage_data.value("drawingconfig"))); + if(!stage.contains("qxApiToken") && stage_data.contains("qxapitoken")) + stage.insert("qxApiToken", stage_data.value("qxapitoken")); + stages.insert(stage_key, stage); } event_params.insert("stage", stages); event_w->loadParams(event_params); From 2fbd6996c8ef812f2a4a3847af3911a2c819ffe5 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 22:52:07 +0200 Subject: [PATCH 57/83] Refactor StageData to typed fields - Replace StageData from QVariantMap with a struct of typed fields startDateTime, useAllMaps, drawingConfig, qxApiToken - Update code to access fields directly - Load defaults from legacy stages table and apply config precedence - Remove the stage.cpp file and simplify stage.h accordingly - Migrate API token flow across qx client components - Normalize startDateTime with system timezone on load/save --- quickevent/app/quickevent/CMakeLists.txt | 1 - .../plugins/Classes/src/classeswidget.cpp | 4 +- .../plugins/Classes/src/drawing/ganttitem.cpp | 6 +- .../Classes/src/drawing/ganttscene.cpp | 2 +- .../plugins/Event/src/eventplugin.cpp | 91 ++++++++----------- .../Event/src/services/qx/qxclientservice.cpp | 2 +- .../src/services/qx/qxclientservicewidget.cpp | 2 +- .../quickevent/plugins/Event/src/stage.cpp | 21 ----- .../app/quickevent/plugins/Event/src/stage.h | 22 ++--- .../plugins/Runs/src/runswidget.cpp | 2 +- 10 files changed, 52 insertions(+), 101 deletions(-) delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stage.cpp diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index fcfccef48..3c1d55f38 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -70,7 +70,6 @@ add_executable(quickevent plugins/Event/src/eventplugin.cpp plugins/Event/src/openeventdialog.cpp plugins/Event/src/openeventdialog.ui - plugins/Event/src/stage.cpp plugins/Event/src/findregistrationedit.cpp plugins/Event/src/lentcardssettingspage.cpp plugins/Event/src/lentcardssettingspage.ui diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index 8fc4af4be..b1a0b4a16 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -157,7 +157,7 @@ ClassesWidget::ClassesWidget(QWidget *parent) : connect(ui->chkUseAllMaps, &QCheckBox::toggled, this, [this](bool checked) { auto evplugin = getPlugin(); auto data = evplugin->stageData(selectedStageId()); - data.setUseAllMaps(checked); + data.useAllMaps = checked; evplugin->setStageData(selectedStageId(), data); }); } @@ -353,7 +353,7 @@ void ClassesWidget::reload() } m_courseItemDelegate->setCourses(courses); } - ui->chkUseAllMaps->setChecked(getPlugin()->stageData(stage_id).isUseAllMaps()); + ui->chkUseAllMaps->setChecked(getPlugin()->stageData(stage_id).useAllMaps); reloadCourseCodes(); } diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index b42ead29e..eaf36dc6c 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -64,7 +64,7 @@ void GanttItem::load(int stage_id) { qfLogFuncFrame(); Event::StageData stage_data = getPlugin()->stageData(stage_id); - DrawingConfig dc(stage_data.drawingConfig()); + DrawingConfig dc(stage_data.drawingConfig); QVariantList start_slot_list = dc.startSlots(); qfs::Query q(qfs::Connection::forName()); @@ -155,7 +155,7 @@ void GanttItem::save(int stage_id) qfLogFuncFrame(); { Event::StageData stage = getPlugin()->stageData(stage_id); - DrawingConfig dc(stage.drawingConfig()); + DrawingConfig dc(stage.drawingConfig); QVariantList start_slots; for (int i = 0; i < startSlotItemCount(); ++i) { StartSlotItem *slot_it = startSlotItemAt(i); @@ -163,7 +163,7 @@ void GanttItem::save(int stage_id) start_slots << sd; } dc.setStartSlots(start_slots); - stage.setDrawingConfig(dc); + stage.drawingConfig = dc; getPlugin()->setStageData(stage_id, stage); } { diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp index 1777644a1..9d607a56f 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp @@ -24,7 +24,7 @@ void GanttScene::load(int stage_id) { clear(); Event::StageData stage_data = getPlugin()->stageData(stage_id); - m_useAllMaps = stage_data.isUseAllMaps(); + m_useAllMaps = stage_data.useAllMaps; m_ganttItem = new GanttItem(); addItem(m_ganttItem); m_ganttItem->load(stage_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 5db455970..0aef6bf33 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -110,6 +110,10 @@ QByteArray DbEventPayload::toJson() const namespace { const auto QBE_EXT = QStringLiteral(".qbe"); +const auto STAGE_START_DATE_TIME_KEY = QStringLiteral("startDateTime"); +const auto STAGE_USE_ALL_MAPS_KEY = QStringLiteral("useAllMaps"); +const auto STAGE_DRAWING_CONFIG_KEY = QStringLiteral("drawingConfig"); +const auto STAGE_QX_API_TOKEN_KEY = QStringLiteral("qxApiToken"); QString singleFileStorageDir() { @@ -277,7 +281,7 @@ QTime EventPlugin::stageStartTime(int stage_id) QDateTime EventPlugin::stageStartDateTime(int stage_id) { - return stageData(stage_id).startDateTime(); + return stageData(stage_id).startDateTime; } int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) @@ -294,43 +298,32 @@ int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) StageData EventPlugin::stageData(int stage_id) { if(!m_stageCache.contains(stage_id)) { - static const QMap config_keys { - {QStringLiteral("startdatetime"), QStringLiteral("startDateTime")}, - {QStringLiteral("useallmaps"), QStringLiteral("useAllMaps")}, - {QStringLiteral("drawingconfig"), QStringLiteral("drawingConfig")}, - {QStringLiteral("qxapitoken"), QStringLiteral("qxApiToken")}, - }; - StageData data; - const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - const QVariantMap config_data = eventConfig()->value(config_prefix).toMap(); - for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { - if(!config_data.contains(it.value())) - continue; - QVariant value = config_data.value(it.value()); - if(it.key() == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) - value = qf::core::Utils::jsonToQVariant(value.toString()); - data.insert(it.key(), value); - } - // Fill keys missing from config from the legacy stages table. + // Load defaults from the legacy stages table. qfs::Query q; q.prepare("SELECT * FROM stages WHERE id=:id"); q.bindValue(":id", stage_id); if(q.exec() && q.next()) { - const QSqlRecord record = q.record(); - for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { - if(data.contains(it.key())) - continue; - const int field_index = record.indexOf(it.value()); - if(field_index < 0) - continue; - QVariant value = q.value(field_index); - if(it.key() == QLatin1String("drawingconfig") && value.userType() == qMetaTypeId()) - value = qf::core::Utils::jsonToQVariant(value.toString()); - data.insert(it.key(), value); - } + data.startDateTime = q.value(STAGE_START_DATE_TIME_KEY).toDateTime(); + data.useAllMaps = q.value(STAGE_USE_ALL_MAPS_KEY).toBool(); + data.drawingConfig = qf::core::Utils::jsonToQVariant(q.value(STAGE_DRAWING_CONFIG_KEY).toString()).toMap(); + data.qxApiToken = q.value(STAGE_QX_API_TOKEN_KEY).toString(); } + + // Config values take precedence over legacy table values. + const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); + const QVariantMap config_data = eventConfig()->value(config_prefix).toMap(); + if(config_data.contains(STAGE_START_DATE_TIME_KEY)) + data.startDateTime = config_data.value(STAGE_START_DATE_TIME_KEY).toDateTime(); + if(config_data.contains(STAGE_USE_ALL_MAPS_KEY)) + data.useAllMaps = config_data.value(STAGE_USE_ALL_MAPS_KEY).toBool(); + if(config_data.contains(STAGE_DRAWING_CONFIG_KEY)) + data.drawingConfig = qf::core::Utils::jsonToQVariant(config_data.value(STAGE_DRAWING_CONFIG_KEY).toString()).toMap(); + if(config_data.contains(STAGE_QX_API_TOKEN_KEY)) + data.qxApiToken = config_data.value(STAGE_QX_API_TOKEN_KEY).toString(); + + data.startDateTime = data.startDateTime.toTimeZone(QTimeZone::systemTimeZone()); m_stageCache[stage_id] = data; } return m_stageCache.value(stage_id); @@ -338,23 +331,12 @@ StageData EventPlugin::stageData(int stage_id) void EventPlugin::setStageData(int stage_id, const StageData &data) { - static const QMap config_keys { - {QStringLiteral("startdatetime"), QStringLiteral("startDateTime")}, - {QStringLiteral("useallmaps"), QStringLiteral("useAllMaps")}, - {QStringLiteral("drawingconfig"), QStringLiteral("drawingConfig")}, - {QStringLiteral("qxapitoken"), QStringLiteral("qxApiToken")}, - }; - EventConfig *config = eventConfig(); const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - for(auto it = config_keys.cbegin(); it != config_keys.cend(); ++it) { - if(!data.contains(it.key())) - continue; - QVariant value = data.value(it.key()); - if(it.key() == QLatin1String("drawingconfig") && value.userType() != qMetaTypeId()) - value = qf::core::Utils::qvariantToJson(value); - config->setValue(config_prefix + '.' + it.value(), value); - } + config->setValue(config_prefix + '.' + STAGE_START_DATE_TIME_KEY, data.startDateTime); + config->setValue(config_prefix + '.' + STAGE_USE_ALL_MAPS_KEY, data.useAllMaps); + config->setValue(config_prefix + '.' + STAGE_DRAWING_CONFIG_KEY, qf::core::Utils::qvariantToJson(data.drawingConfig)); + config->setValue(config_prefix + '.' + STAGE_QX_API_TOKEN_KEY, data.qxApiToken); config->save(config_prefix); m_stageCache.remove(stage_id); } @@ -1037,14 +1019,14 @@ void EventPlugin::editEvent() const QString stage_key = QString::number(stage_id); QVariantMap stage = stages.value(stage_key).toMap(); const StageData stage_data = stageData(stage_id); - if(!stage.contains("startDateTime") && stage_data.contains("startdatetime")) - stage.insert("startDateTime", stage_data.value("startdatetime")); - if(!stage.contains("useAllMaps") && stage_data.contains("useallmaps")) - stage.insert("useAllMaps", stage_data.value("useallmaps")); - if(!stage.contains("drawingConfig") && stage_data.contains("drawingconfig")) - stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(stage_data.value("drawingconfig"))); - if(!stage.contains("qxApiToken") && stage_data.contains("qxapitoken")) - stage.insert("qxApiToken", stage_data.value("qxapitoken")); + if(!stage.contains(STAGE_START_DATE_TIME_KEY) && stage_data.startDateTime.isValid()) + stage.insert(STAGE_START_DATE_TIME_KEY, stage_data.startDateTime); + if(!stage.contains(STAGE_USE_ALL_MAPS_KEY)) + stage.insert(STAGE_USE_ALL_MAPS_KEY, stage_data.useAllMaps); + if(!stage.contains(STAGE_DRAWING_CONFIG_KEY)) + stage.insert(STAGE_DRAWING_CONFIG_KEY, qf::core::Utils::qvariantToJson(stage_data.drawingConfig)); + if(!stage.contains(STAGE_QX_API_TOKEN_KEY)) + stage.insert(STAGE_QX_API_TOKEN_KEY, stage_data.qxApiToken); stages.insert(stage_key, stage); } event_params.insert("stage", stages); @@ -1640,4 +1622,3 @@ const qf::core::utils::Table &EventPlugin::registrationsTable() } } - diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index e80607c83..73d5fa6d2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -275,7 +275,7 @@ QByteArray QxClientService::apiToken() const // always to current stage event on qxhttpd auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - return event_plugin->stageData(current_stage).qxApiToken().toUtf8(); + return event_plugin->stageData(current_stage).qxApiToken.toUtf8(); } QUrl QxClientService::exchangeServerUrl() const diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp index e9a04902e..e84b43d90 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp @@ -98,7 +98,7 @@ bool QxClientServiceWidget::saveSettings() auto current_stage = event_plugin->currentStageId(); auto stage_data = event_plugin->stageData(current_stage); - stage_data.setQxApiToken(ui->edApiToken->text()); + stage_data.qxApiToken = ui->edApiToken->text(); event_plugin->setStageData(current_stage, stage_data); } return true; diff --git a/quickevent/app/quickevent/plugins/Event/src/stage.cpp b/quickevent/app/quickevent/plugins/Event/src/stage.cpp deleted file mode 100644 index 1bd53d5e7..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stage.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "stage.h" - -#include - -using namespace Event; - -StageData::StageData(const QVariantMap &data) - : Super(data) -{ -} - -QDateTime StageData::startDateTime() const -{ - auto dt = value(QStringLiteral("startdatetime")).toDateTime(); - dt = dt.toTimeZone(QTimeZone::systemTimeZone()); - return dt; -} - - - - diff --git a/quickevent/app/quickevent/plugins/Event/src/stage.h b/quickevent/app/quickevent/plugins/Event/src/stage.h index f52c79399..8b0e73d92 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stage.h +++ b/quickevent/app/quickevent/plugins/Event/src/stage.h @@ -1,26 +1,18 @@ #pragma once -#include - +#include +#include #include -#include -#include namespace Event { -class StageData : public QVariantMap +struct StageData { -private: - typedef QVariantMap Super; - - QF_VARIANTMAP_KEY_FIELD(bool, useallmaps, is, set, UseAllMaps) - QF_VARIANTMAP_KEY_FIELD(QVariantMap, drawingconfig, d, setD, rawingConfig) - QF_VARIANTMAP_KEY_FIELD(QString, qxapitoken, qx, setQx, ApiToken) -public: - StageData(const QVariantMap &data = QVariantMap()); - - QDateTime startDateTime() const; + QDateTime startDateTime; + bool useAllMaps = false; + QVariantMap drawingConfig; + QString qxApiToken; }; } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 53793196f..1ec92f1fb 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -694,7 +694,7 @@ void RunsWidget::onDrawClicked() int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); Event::StageData stage_data = getPlugin()->stageData(stage_id); - bool use_all_maps = stage_data.isUseAllMaps(); + bool use_all_maps = stage_data.useAllMaps; qfDebug() << "DrawMethod:" << (int)draw_method << "use_all_maps:" << use_all_maps; QList class_ids; int class_id = m_cbxClasses->currentData().toInt(); From d864026c3a4672aa523d9d5732a4324dbc83b4e2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 23:17:41 +0200 Subject: [PATCH 58/83] Update EventDialog UI and add table height logic --- .../plugins/Event/src/eventdialogwidget.cpp | 17 +- .../plugins/Event/src/eventdialogwidget.h | 1 + .../plugins/Event/src/eventdialogwidget.ui | 260 +++++++++--------- 3 files changed, 144 insertions(+), 134 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 0917c1b8e..2aaa6ccb5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -19,8 +19,7 @@ EventDialogWidget::EventDialogWidget(QWidget *parent) : ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); ui->stageStartTimesTable->verticalHeader()->hide(); - connect(ui->ed_stageCount, QOverload::of(&QSpinBox::valueChanged), - this, &EventDialogWidget::updateStageStartTimeEditors); + connect(ui->ed_stageCount, QOverload::of(&QSpinBox::valueChanged), this, &EventDialogWidget::updateStageStartTimeEditors); updateStageStartTimeEditors(ui->ed_stageCount->value()); connect(ui->ed_iofRace, &QAbstractButton::toggled, ui->frameIofRace, &QWidget::setVisible); @@ -77,6 +76,7 @@ void EventDialogWidget::updateStageStartTimeEditors(int stage_count) const int old_count = table->rowCount(); if(stage_count < old_count) { table->setRowCount(stage_count); + updateStageStartTimesTableHeight(); return; } @@ -98,6 +98,19 @@ void EventDialogWidget::updateStageStartTimeEditors(int stage_count) table->setCellWidget(row, 1, editor); next_start = next_start.addDays(1); } + updateStageStartTimesTableHeight(); +} + +void EventDialogWidget::updateStageStartTimesTableHeight() +{ + QTableWidget *table = ui->stageStartTimesTable; + table->resizeRowsToContents(); + + const int visible_row_count = qMin(table->rowCount(), 5); + int height = table->horizontalHeader()->height() + 2 * table->frameWidth(); + for(int row = 0; row < visible_row_count; ++row) + height += table->rowHeight(row); + table->setFixedHeight(height); } void EventDialogWidget::loadParams(const QVariantMap ¶ms) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index 81c86a7a3..dfc219bfa 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -27,6 +27,7 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget static QString sportName(int sport_id); private: void updateStageStartTimeEditors(int stage_count); + void updateStageStartTimesTableHeight(); QVariantMap m_stages; Ui::EventDialogWidget *ui; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui index 79096adfa..41ada4458 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.ui @@ -6,8 +6,8 @@ 0 0 - 596 - 619 + 590 + 766 @@ -16,19 +16,6 @@ - - - - - - - &Date - - - ed_date - - - @@ -39,27 +26,23 @@ - - - - h:mm:ss + + + + &Date - - + + ed_date - - + + - D&irector + Main r&eferee - ed_director + ed_mainReferee @@ -73,64 +56,82 @@ - - + + - &Place + D&irector - ed_place + ed_director - - + + + + + Disabled + + + + + Enabled + + + - - - - dd.MM.yyyy + + + + Des&cription - - true + + ed_description - - + + - Event ID + Card check - ed_name + ed_handicapLength - - + + - Main r&eferee + 1/10 sec results - ed_mainReferee + ed_handicapLength - - + + + + 1 + + + + + - Discipline + &Handicap length ed_handicapLength - - + + @@ -142,26 +143,39 @@ - - + + - Des&cription + Event ID - ed_description + ed_name + + + - - + + - - + + - Card check + &Place + + + ed_place + + + + + + + Discipline ed_handicapLength @@ -190,40 +204,6 @@ - - - - 1/10 sec results - - - ed_handicapLength - - - - - - - - Disabled - - - - - Enabled - - - - - - - - &Handicap length - - - ed_handicapLength - - - @@ -246,6 +226,43 @@ + + + + Unique event name + + + + + + + + + + h:mm:ss + + + + + + + + + + dd.MM.yyyy + + + true + + + + + + @@ -256,18 +273,17 @@ - - - - 1 - - - - + + + 0 + 0 + + + - 0 + 16777215 120 @@ -277,9 +293,6 @@ QAbstractItemView::SelectionMode::NoSelection - - false - 2 @@ -295,16 +308,6 @@ - - - - - - - Unique event name - - - @@ -331,6 +334,12 @@ + + + 0 + 0 + + @@ -412,19 +421,6 @@ - - - - Qt::Orientation::Vertical - - - - 20 - 0 - - - -
From 50025fb252406e42136e81fdd4d03c5230cb93c7 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 23:24:50 +0200 Subject: [PATCH 59/83] EventConfig is not QObject anymore --- .../plugins/Event/src/eventconfig.cpp | 4 +--- .../plugins/Event/src/eventconfig.h | 19 +++++++++---------- .../plugins/Event/src/eventplugin.cpp | 9 +++++++-- .../plugins/Event/src/eventplugin.h | 1 + 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 0e3358385..70941fcec 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -40,8 +40,7 @@ std::optional EventConfig::disciplineFromInt(int i) return {}; } -EventConfig::EventConfig(QObject *parent) - : QObject(parent) +EventConfig::EventConfig() { } @@ -325,4 +324,3 @@ const QSet &EventConfig::knownKeys() return s; } */ - diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index a4d9c4ea5..33ad967b4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -10,16 +10,15 @@ namespace Event { -class EventConfig : public QObject +class EventConfig { - Q_OBJECT - Q_PROPERTY(int stageCount READ stageCount) - Q_PROPERTY(bool isHandicap READ isHandicap) - Q_PROPERTY(bool isRelays READ isRelays) - Q_PROPERTY(bool isIofRace READ isIofRace) - Q_PROPERTY(bool iofXmlRaceNumber READ iofXmlRaceNumber) - Q_PROPERTY(QString director READ director) - Q_PROPERTY(QString mainReferee READ mainReferee) + // Q_PROPERTY(int stageCount READ stageCount) + // Q_PROPERTY(bool isHandicap READ isHandicap) + // Q_PROPERTY(bool isRelays READ isRelays) + // Q_PROPERTY(bool isIofRace READ isIofRace) + // Q_PROPERTY(bool iofXmlRaceNumber READ iofXmlRaceNumber) + // Q_PROPERTY(QString director READ director) + // Q_PROPERTY(QString mainReferee READ mainReferee) //Q_PROPERTY(QString eventName READ eventName) public: enum class Sport {OB = 1, LOB, MTBO, TRAIL}; @@ -40,7 +39,7 @@ class EventConfig : public QObject }; static std::optional disciplineFromInt(int i); public: - explicit EventConfig(QObject *parent = nullptr); + explicit EventConfig(); public: QVariantMap values() const {return m_data;} QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 0aef6bf33..f348d4afd 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -202,10 +202,15 @@ EventPlugin::EventPlugin(QObject *parent) connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, this, &EventPlugin::onRecChng); } +EventPlugin::~EventPlugin() +{ + QF_SAFE_DELETE(m_eventConfig); +} + void EventPlugin::initEventConfig() { if(m_eventConfig == nullptr) { - m_eventConfig = new Event::EventConfig(this); + m_eventConfig = new Event::EventConfig(); } else { qfWarning() << "Event config exists already!"; @@ -215,7 +220,7 @@ void EventPlugin::initEventConfig() Event::EventConfig *EventPlugin::eventConfig(bool reload) { if(m_eventConfig == nullptr) { - m_eventConfig = new Event::EventConfig(this); + m_eventConfig = new Event::EventConfig(); reload = true; } if(reload) { diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index b1dcddbc0..c7aed3f57 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -41,6 +41,7 @@ class EventPlugin : public qf::gui::framework::Plugin enum class ConnectionType : int {SqlServer = 0, SingleFile}; public: EventPlugin(QObject *parent = nullptr); + ~EventPlugin() override; QF_PROPERTY_BOOL_IMPL(e, E, ventOpen) QF_PROPERTY_IMPL(QString, e, E, ventName) From 0c11da2a1b9aaf953e9d1b345d7ba262b6ab7e46 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 23:36:21 +0200 Subject: [PATCH 60/83] Remove EventConfig knownKeys and unused props --- .../plugins/Event/src/eventconfig.cpp | 18 +----------------- .../quickevent/plugins/Event/src/eventconfig.h | 10 ---------- .../quickevent/plugins/Event/src/eventplugin.h | 2 +- .../Event/src/services/ofeed/ofeedclient.cpp | 2 +- 4 files changed, 3 insertions(+), 29 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 70941fcec..013e1aa9c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -307,20 +307,4 @@ QString EventConfig::orisEventKey() const return value(QStringLiteral("event.orisEventKey")).toString(); } -/* -const QSet &EventConfig::knownKeys() -{ - static QSet s; - if(s.isEmpty()) { - s << "event.stageCount" - << EVENT_NAME - << "event.date" - << "event.description" - << "event.place" - << "event.mainReferee" - << "event.director" - << "event.importId"; - } - return s; -} -*/ + diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index 33ad967b4..53ad87a38 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -12,14 +12,6 @@ namespace Event { class EventConfig { - // Q_PROPERTY(int stageCount READ stageCount) - // Q_PROPERTY(bool isHandicap READ isHandicap) - // Q_PROPERTY(bool isRelays READ isRelays) - // Q_PROPERTY(bool isIofRace READ isIofRace) - // Q_PROPERTY(bool iofXmlRaceNumber READ iofXmlRaceNumber) - // Q_PROPERTY(QString director READ director) - // Q_PROPERTY(QString mainReferee READ mainReferee) - //Q_PROPERTY(QString eventName READ eventName) public: enum class Sport {OB = 1, LOB, MTBO, TRAIL}; enum class Discipline {LongDistance = 1, @@ -66,7 +58,6 @@ class EventConfig bool isIofRace() const; int iofXmlRaceNumber() const; QString eventName() const; - // QString apiKey() const; QString eventPlace() const; QString director() const; QString mainReferee() const; @@ -76,7 +67,6 @@ class EventConfig bool isOneTenthSecResults() const; QString orisEventKey() const; private: - // void checkApiKey(); void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); private: diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index c7aed3f57..72fc42801 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -29,7 +29,7 @@ static constexpr auto RESULTS_IOFXML3_FILE = "results-iof3.xml"; class EventPlugin : public qf::gui::framework::Plugin { Q_OBJECT - Q_PROPERTY(QObject* eventConfig READ eventConfig) + Q_PROPERTY(int currentStageId READ currentStageId NOTIFY currentStageIdChanged) Q_PROPERTY(int stageCount READ stageCount) Q_PROPERTY(QString eventName READ eventName WRITE setEventName NOTIFY eventNameChanged) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 3cc6cb3d7..74c1398c6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -1373,7 +1373,7 @@ void OFeedClient::markChangelogEntryAsProcessed(int protocolId) variables["processedByType"] = QString("SYSTEM"); variables["processedBySource"] = QString("IT"); - sendGraphQLRequest(mutation, variables, [this, protocolId](QJsonObject data) { + sendGraphQLRequest(mutation, variables, [protocolId](QJsonObject data) { if (data.isEmpty()) { qfWarning() << serviceName().toStdString() + " Failed to mark changelog entry " << protocolId << " as processed"; } else { From bddb35f53bc56ebaa7fd297869c6fda0e0f7e69f Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 23:38:40 +0200 Subject: [PATCH 61/83] Add Event action to File menu --- quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index f348d4afd..051ced7a6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -397,7 +397,9 @@ void EventPlugin::onInstalled() a_import->addActionBefore(m_actConnectDb); a_import->addSeparatorBefore(); - m_actEvent = m_actConnectDb->addMenuAfter("file.event", tr("&Event")); + qfw::Action *a_file = fwk->menuBar()->actionForPath("file", false); + Q_ASSERT(a_file); + m_actEvent = a_file->addMenuAfter("event", tr("&Event")); m_actEvent->setEnabled(false); m_actEvent->addActionInto(m_actCreateEvent); From 36a69cc2c2fee28c5899d339f4598918a2cf23c4 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Thu, 16 Jul 2026 23:54:01 +0200 Subject: [PATCH 62/83] Add Set Current Stage button and stage chooser --- .../plugins/Core/src/widgets/appstatusbar.cpp | 11 ++++---- .../plugins/Core/src/widgets/appstatusbar.h | 4 ++- .../plugins/Event/src/eventplugin.cpp | 25 +++++++++++++++++++ .../plugins/Event/src/eventplugin.h | 2 ++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp index 7d605b9ba..dd1dc6a9b 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp @@ -1,6 +1,7 @@ #include "appstatusbar.h" #include +#include #include namespace Core { @@ -16,10 +17,10 @@ AppStatusBar::AppStatusBar(QWidget *parent) m_lblEvent->setFrameShadow(QFrame::Plain); addPermanentWidget(m_lblEvent); - m_lblStage = new QLabel(this); - m_lblStage->setFrameShape(QFrame::Panel); - m_lblStage->setFrameShadow(QFrame::Plain); - addPermanentWidget(m_lblStage); + m_btStage = new QPushButton(this); + m_btStage->setToolTip(tr("Set current stage")); + connect(m_btStage, &QPushButton::clicked, this, &AppStatusBar::stageClicked); + addPermanentWidget(m_btStage); m_progress = new QProgressBar(this); m_progress->setMinimumWidth(200); @@ -46,7 +47,7 @@ void AppStatusBar::setEventName(const QString &event_name) void AppStatusBar::setStageNo(int stage_no) { m_stageNo = stage_no; - m_lblStage->setText(tr("E%1").arg(m_stageNo)); + m_btStage->setText(tr("E%1").arg(m_stageNo)); } void AppStatusBar::showProgress(const QString &msg, int completed, int total) diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h index 869dc0b70..5a38d6f66 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h @@ -6,6 +6,7 @@ class QLabel; class QProgressBar; +class QPushButton; namespace Core { @@ -28,13 +29,14 @@ class AppStatusBar : public qf::gui::StatusBar int stageNo() const {return m_stageNo;} Q_SLOT void setStageNo(int stage_no); Q_SIGNAL void stageNoChanged(); + Q_SIGNAL void stageClicked(); void showProgress(const QString &msg, int completed, int total) Q_DECL_OVERRIDE; private: QLabel *m_lblMessage; QProgressBar *m_progress; QLabel *m_lblEvent; - QLabel *m_lblStage; + QPushButton *m_btStage; QString m_eventName; int m_stageNo = 0; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 051ced7a6..99f32ed5a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -376,6 +376,11 @@ void EventPlugin::onInstalled() this->m_actEditEvent->setEnabled(!event_name.isEmpty()); }); + m_actSetCurrentStage = new qfw::Action(tr("Set current &stage")); + m_actSetCurrentStage->setEnabled(false); + connect(m_actSetCurrentStage, &QAction::triggered, this, &EventPlugin::setCurrentStage); + connect(this, &EventPlugin::eventOpenChanged, m_actSetCurrentStage, &QAction::setEnabled); + m_actExportEvent_qbe = new qfw::Action(tr("Event (*.qbe)")); m_actExportEvent_qbe->setEnabled(false); connect(m_actExportEvent_qbe, &QAction::triggered, this, &EventPlugin::exportEvent_qbe); @@ -386,6 +391,7 @@ void EventPlugin::onInstalled() if(auto *sb = qobject_cast(fwk->statusBar())) { connect(this, &EventPlugin::eventNameChanged, sb, &Core::AppStatusBar::setEventName); connect(this, &EventPlugin::currentStageIdChanged, sb, &Core::AppStatusBar::setStageNo); + connect(sb, &Core::AppStatusBar::stageClicked, this, &EventPlugin::setCurrentStage); } connect(this, &EventPlugin::eventNameChanged, this, &EventPlugin::updateWindowTitle); connect(this, &EventPlugin::currentStageIdChanged, this, &EventPlugin::updateWindowTitle); @@ -405,6 +411,8 @@ void EventPlugin::onInstalled() m_actEvent->addActionInto(m_actCreateEvent); m_actEvent->addActionInto(m_actOpenEvent); m_actEvent->addActionInto(m_actEditEvent); + m_actEvent->addActionInto(m_actSetCurrentStage); + m_actSetCurrentStage->addSeparatorBefore(); m_actImport = fwk->menuBar()->actionForPath("file/import"); m_actImport->addActionInto(m_actImportEvent_qbe); @@ -515,7 +523,24 @@ void EventPlugin::saveCurrentStageId(int current_stage) } } +void EventPlugin::setCurrentStage() +{ + QStringList stages; + for(int stage_id = 1; stage_id <= stageCount(); ++stage_id) + stages.append(QStringLiteral("E%1").arg(stage_id)); + if(stages.isEmpty()) + return; + QInputDialog dialog(qff::MainWindow::frameWork()); + dialog.setWindowTitle(tr("Set current stage")); + dialog.setLabelText(tr("Stage:")); + dialog.setComboBoxItems(stages); + dialog.setComboBoxEditable(false); + dialog.setOption(QInputDialog::UseListViewForComboBoxItems); + dialog.setTextValue(stages.value(currentStageId() - 1, stages.first())); + if(dialog.exec() == QDialog::Accepted) + setCurrentStageId(stages.indexOf(dialog.textValue()) + 1); +} void EventPlugin::emitDbEvent(const QString &domain, const QVariant &data, bool loopback) { diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 72fc42801..e26ac7a2d 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -135,6 +135,7 @@ class EventPlugin : public qf::gui::framework::Plugin void connectToSqlServer(); void loadCurrentStageId(); void saveCurrentStageId(int current_stage); + void setCurrentStage(); void onDbEvent(const QString & name, QSqlDriver::NotificationSource source, const QVariant & payload); void onDbEventNotify(const QString &domain, int connection_id, const QVariant &data); @@ -163,6 +164,7 @@ class EventPlugin : public qf::gui::framework::Plugin qf::gui::Action *m_actCreateEvent = nullptr; qf::gui::Action *m_actOpenEvent = nullptr; qf::gui::Action *m_actEditEvent = nullptr; + qf::gui::Action *m_actSetCurrentStage = nullptr; qf::gui::Action *m_actExportEvent_qbe = nullptr; qf::gui::Action *m_actImportEvent_qbe = nullptr; Event::EventConfig *m_eventConfig = nullptr; From 0b0349a18c5ebd4f4bfd41bd83efe1712d0d409f Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 00:05:05 +0200 Subject: [PATCH 63/83] Rename stage button to current stage - Rename m_btStage to m_btCurrentStage in AppStatusBar - Update all references to the new field - Set lime background on the current stage button - Update setStageNo to use the new button - Remove UseListViewForComboBoxItems option from EventPlugin dialog --- .../plugins/Core/src/widgets/appstatusbar.cpp | 11 ++++++----- .../plugins/Core/src/widgets/appstatusbar.h | 3 +-- .../app/quickevent/plugins/Event/src/eventplugin.cpp | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp index dd1dc6a9b..d64f5b955 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp @@ -17,10 +17,11 @@ AppStatusBar::AppStatusBar(QWidget *parent) m_lblEvent->setFrameShadow(QFrame::Plain); addPermanentWidget(m_lblEvent); - m_btStage = new QPushButton(this); - m_btStage->setToolTip(tr("Set current stage")); - connect(m_btStage, &QPushButton::clicked, this, &AppStatusBar::stageClicked); - addPermanentWidget(m_btStage); + m_btCurrentStage = new QPushButton(this); + m_btCurrentStage->setToolTip(tr("Set current stage")); + m_btCurrentStage->setStyleSheet("background: lime;"); + connect(m_btCurrentStage, &QPushButton::clicked, this, &AppStatusBar::stageClicked); + addPermanentWidget(m_btCurrentStage); m_progress = new QProgressBar(this); m_progress->setMinimumWidth(200); @@ -47,7 +48,7 @@ void AppStatusBar::setEventName(const QString &event_name) void AppStatusBar::setStageNo(int stage_no) { m_stageNo = stage_no; - m_btStage->setText(tr("E%1").arg(m_stageNo)); + m_btCurrentStage->setText(tr("E%1").arg(m_stageNo)); } void AppStatusBar::showProgress(const QString &msg, int completed, int total) diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h index 5a38d6f66..cd8f4734e 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h @@ -36,11 +36,10 @@ class AppStatusBar : public qf::gui::StatusBar QLabel *m_lblMessage; QProgressBar *m_progress; QLabel *m_lblEvent; - QPushButton *m_btStage; + QPushButton *m_btCurrentStage; QString m_eventName; int m_stageNo = 0; }; } - diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 99f32ed5a..ff0214233 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -536,7 +536,6 @@ void EventPlugin::setCurrentStage() dialog.setLabelText(tr("Stage:")); dialog.setComboBoxItems(stages); dialog.setComboBoxEditable(false); - dialog.setOption(QInputDialog::UseListViewForComboBoxItems); dialog.setTextValue(stages.value(currentStageId() - 1, stages.first())); if(dialog.exec() == QDialog::Accepted) setCurrentStageId(stages.indexOf(dialog.textValue()) + 1); From 6637629f4350307fb526554d42abdafc137496bc Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 00:16:40 +0200 Subject: [PATCH 64/83] Remove stage QComboBox and use tool button --- .../plugins/Event/src/eventplugin.cpp | 32 ++++--------------- .../plugins/Event/src/eventplugin.h | 2 -- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index ff0214233..ff9e0d811 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -425,27 +424,19 @@ void EventPlugin::onInstalled() qfw::ToolBar *tb = fwk->toolBar("Event", true); tb->setObjectName("EventToolbar"); tb->setWindowTitle(tr("Event")); + if(auto *part_switch = fwk->findChild(QStringLiteral("partSwitch"))) + fwk->insertToolBar(part_switch, tb); { auto *bt_stage = new QToolButton(); - //bt_stage->setFlat(true); bt_stage->setAutoRaise(true); - bt_stage->setCheckable(true); + bt_stage->setEnabled(false); + bt_stage->setToolTip(tr("Set current stage")); tb->addWidget(bt_stage); - m_cbxStage = new QComboBox(); - connect(m_cbxStage, &QComboBox::activated, this, [this](int ix) { - setCurrentStageId(ix + 1); - }); - connect(this, &EventPlugin::currentStageIdChanged, bt_stage, [this, bt_stage](int stage_id) { - QSignalBlocker b(m_cbxStage); - m_cbxStage->setCurrentIndex(stage_id - 1); + connect(bt_stage, &QToolButton::clicked, this, &EventPlugin::setCurrentStage); + connect(this, &EventPlugin::eventOpenChanged, bt_stage, &QToolButton::setEnabled); + connect(this, &EventPlugin::currentStageIdChanged, bt_stage, [bt_stage](int stage_id) { bt_stage->setText(tr("Current stage E%1").arg(stage_id)); }); - QAction *act_stage = tb->addWidget(m_cbxStage); - act_stage->setVisible(false); - - connect(bt_stage, &QPushButton::clicked, this, [act_stage](bool checked) { - act_stage->setVisible(checked); - }); } fwk->menuBar()->actionForPath("view/toolbar")->addActionInto(tb->toggleViewAction()); @@ -742,15 +733,6 @@ void EventPlugin::onEventOpened() if(!isEventOpen()) return; qfLogFuncFrame() << "stage count:" << stageCount(); - { - QSignalBlocker b(m_cbxStage); - m_cbxStage->clear(); - int stage_cnt = stageCount(); - for (int i = 0; i < stage_cnt; ++i) { - m_cbxStage->addItem("E" + QString::number(i + 1), i + 1); - } - m_cbxStage->setCurrentIndex(-1); - } loadCurrentStageId(); } diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index e26ac7a2d..108350d8e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -17,7 +17,6 @@ namespace qf::gui { class Action; } namespace qf::gui::framework { class DockWidget; } namespace qf::gui::model { class SqlTableModel; } -class QComboBox; class DbSchema; namespace Event { @@ -169,7 +168,6 @@ class EventPlugin : public qf::gui::framework::Plugin qf::gui::Action *m_actImportEvent_qbe = nullptr; Event::EventConfig *m_eventConfig = nullptr; bool m_sqlServerConnected = false; - QComboBox *m_cbxStage = nullptr; int m_currentStageId = 0; QMap m_stageCache; QMap m_classNameCache; From a8ae55baea1de09142130d2a4cbea59fbf7915a2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 00:32:35 +0200 Subject: [PATCH 65/83] Fix linter issues - Use defaulted EventConfig constructor and remove empty ctor - Iterate dirty_vals with asKeyValueRange to access keys safely - Disable a verbose DB event log line in OFeedClient - Capture http_status and response_text in callback_error lambda - Comment out competitor_id retrieval and JSON change logging in OFeed --- .../app/quickevent/plugins/Event/src/eventconfig.cpp | 4 ---- .../app/quickevent/plugins/Event/src/eventconfig.h | 2 +- .../plugins/Event/src/services/ofeed/ofeedclient.cpp | 12 ++++++------ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 013e1aa9c..1e363dad3 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -40,10 +40,6 @@ std::optional EventConfig::disciplineFromInt(int i) return {}; } -EventConfig::EventConfig() -{ -} - QVariant EventConfig::value(const QStringList &path, const QVariant &default_value) const { //QF_ASSERT(knownKeys().contains(key), "Key " + key + " is not known key!", return QVariant()); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index 53ad87a38..f9371ed07 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -31,7 +31,7 @@ class EventConfig }; static std::optional disciplineFromInt(int i); public: - explicit EventConfig(); + explicit EventConfig() = default; public: QVariantMap values() const {return m_data;} QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 74c1398c6..f7650c86c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -304,7 +304,7 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons auto lst = data.toList(); int run_id = lst.value(0).toInt(); auto dirty_vals = lst.value(1).toMap(); - qfInfo() << serviceName().toStdString() + " DB event RUN CHANGED received, run_id: " << run_id << ", dirty keys: " << dirty_vals.keys().join(", "); + // qfInfo() << serviceName().toStdString() << "DB event RUN CHANGED received, run_id: " << run_id << ", dirty keys: " << dirty_vals.keys().join(", "); if (!dirty_vals.isEmpty()) { static const QSet relevant_fields = { // Run fields (finishTimeMs and timeMs are covered by DBEVENT_CARD_PROCESSED_AND_ASSIGNED) @@ -319,7 +319,7 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons QStringLiteral("classid"), }; bool has_relevant = false; - for (const auto &key : dirty_vals.keys()) { + for (const auto &[key, _] : dirty_vals.asKeyValueRange()) { if (relevant_fields.contains(key.section('.', -1).toLower())) { has_relevant = true; break; @@ -758,7 +758,7 @@ void OFeedClient::testConnection(const QString &host_url, const QByteArray response_bytes = reply->readAll(); const QString response_text = QString::fromUtf8(response_bytes).trimmed(); - auto callback_error = [&](const QString &msg) { + auto callback_error = [http_status, response_text, callback](const QString &msg) { const QString status_text = http_status > 0 ? QStringLiteral("HTTP %1").arg(http_status) : QStringLiteral("HTTP status unavailable"); const QString full_message = response_text.isEmpty() ? QStringLiteral("%1: %2").arg(status_text, msg) @@ -1522,7 +1522,7 @@ void OFeedClient::processNewRunner(int ofeed_competitor_id) // Save emits db event doc.save(); - auto competitor_id = doc.value("competitors.id"); + // auto competitor_id = doc.value("competitors.id"); // Get runs.id for current stage int current_stage = getPlugin()->currentStageId(); @@ -1563,8 +1563,8 @@ void OFeedClient::storeChange(const QJsonObject &change) QString firstname = competitor["firstname"].isString() ? competitor["firstname"].toString() : no_data; QString lastname = competitor["lastname"].isString() ? competitor["lastname"].toString() : no_data; - QJsonDocument change_json_doc(change); - QString change_json = QString::fromUtf8(change_json_doc.toJson(QJsonDocument::Compact)); + // QJsonDocument change_json_doc(change); + // QString change_json = QString::fromUtf8(change_json_doc.toJson(QJsonDocument::Compact)); int change_id = change["id"].toInt(); auto created = QDateTime::fromString(change["createdAt"].toString(), Qt::ISODate); From 4bab2acaa3576e6161b2854c1c69f865e005a5ea Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 00:48:43 +0200 Subject: [PATCH 66/83] Refactor event config to use EventConfigData --- .../plugins/Event/src/eventdialogwidget.cpp | 191 ++++++++++++------ .../plugins/Event/src/eventdialogwidget.h | 44 +++- .../plugins/Event/src/eventplugin.cpp | 33 +-- 3 files changed, 175 insertions(+), 93 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 2aaa6ccb5..b5ad9a409 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -4,11 +4,86 @@ #include "eventconfig.h" #include +#include #include #include #include +Event::EventConfigData Event::EventConfigData::fromVariantMap(const QVariantMap &values) +{ + EventConfigData data; + data.stageCount = values.value("stageCount", 1).toInt(); + const QVariantMap stages = values.value("stage").toMap(); + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + const int stage_id = it.key().toInt(); + if(stage_id <= 0) + continue; + const QVariantMap stage_values = it.value().toMap(); + StageData stage; + stage.startDateTime = stage_values.value("startDateTime").toDateTime(); + stage.useAllMaps = stage_values.value("useAllMaps").toBool(); + const QVariant drawing_config = stage_values.value("drawingConfig"); + stage.drawingConfig = drawing_config.userType() == qMetaTypeId() + ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() + : drawing_config.toMap(); + stage.qxApiToken = stage_values.value("qxApiToken").toString(); + data.stages.insert(stage_id, stage); + } + data.name = values.value("name").toString(); + data.date = values.value("date").toDate(); + data.time = values.value("time").toTime(); + data.description = values.value("description").toString(); + data.place = values.value("place").toString(); + data.mainReferee = values.value("mainReferee").toString(); + data.director = values.value("director").toString(); + data.handicapLength = values.value("handicapLength").toInt(); + data.sportId = values.value("sportId").toInt(); + data.disciplineId = values.value("disciplineId").toInt(); + data.importId = values.value("importId").toInt(); + data.orisEventKey = values.value("orisEventKey").toString(); + data.cardCheckTimeSec = values.value("cardChechCheckTimeSec").toInt(); + data.oneTenthSecResults = values.value("oneTenthSecResults").toInt(); + data.iofRace = values.value("iofRace").toBool(); + data.iofXmlRaceNumber = values.value("iofXmlRaceNumber").toInt(); + data.currentStageId = values.value("currentStageId", 1).toInt(); + return data; +} + +QVariantMap Event::EventConfigData::toVariantMap() const +{ + QVariantMap values; + values.insert("stageCount", stageCount); + QVariantMap stage_values; + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + QVariantMap stage; + stage.insert("startDateTime", it.value().startDateTime); + stage.insert("useAllMaps", it.value().useAllMaps); + stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); + stage.insert("qxApiToken", it.value().qxApiToken); + stage_values.insert(QString::number(it.key()), stage); + } + values.insert("stage", stage_values); + values.insert("name", name); + values.insert("date", date); + values.insert("time", time); + values.insert("description", description); + values.insert("place", place); + values.insert("mainReferee", mainReferee); + values.insert("director", director); + values.insert("handicapLength", handicapLength); + values.insert("sportId", sportId); + values.insert("disciplineId", disciplineId); + values.insert("importId", importId); + values.insert("orisEventKey", orisEventKey); + values.insert("cardChechCheckTimeSec", cardCheckTimeSec); + values.insert("oneTenthSecResults", oneTenthSecResults); + values.insert("iofRace", iofRace); + values.insert("iofXmlRaceNumber", iofXmlRaceNumber); + values.insert("currentStageId", currentStageId); + return values; +} + EventDialogWidget::EventDialogWidget(QWidget *parent) : Super(parent), ui(new Ui::EventDialogWidget) @@ -113,91 +188,75 @@ void EventDialogWidget::updateStageStartTimesTableHeight() table->setFixedHeight(height); } -void EventDialogWidget::loadParams(const QVariantMap ¶ms) +void EventDialogWidget::loadParams(const Event::EventConfigData ¶ms) { - ui->ed_name->setText(params.value("name").toString()); - QDate date = params.value("date").toDate(); - if(!date.isValid()) - date = QDate::currentDate(); - ui->ed_date->setDate(date); - QTime time = params.value("time").toTime(); - if(time.isValid()) - ui->ed_time->setTime(time); + m_data = params; + ui->ed_name->setText(params.name); + ui->ed_date->setDate(params.date.isValid() ? params.date : QDate::currentDate()); + if(params.time.isValid()) + ui->ed_time->setTime(params.time); ui->stageStartTimesTable->setRowCount(0); - ui->ed_stageCount->setValue(params.value("stageCount", 1).toInt()); + ui->ed_stageCount->setValue(params.stageCount); updateStageStartTimeEditors(ui->ed_stageCount->value()); - m_stages = params.value("stage").toMap(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - const QVariantMap stage = m_stages.value(QString::number(row + 1)).toMap(); - const QDateTime start_time = stage.value("startDateTime").toDateTime(); + const QDateTime start_time = params.stages.value(row + 1).startDateTime; if(start_time.isValid()) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) editor->setDateTime(start_time); } } - ui->ed_description->setText(params.value("description").toString()); - ui->ed_place->setText(params.value("place").toString()); - ui->ed_mainReferee->setText(params.value("mainReferee").toString()); - ui->ed_director->setText(params.value("director").toString()); - ui->ed_handicapLength->setValue(params.value("handicapLength").toInt()); - if (auto ix = ui->cbxSportId->findData(params.value("sportId").toInt()); ix < 0) { + ui->ed_description->setText(params.description); + ui->ed_place->setText(params.place); + ui->ed_mainReferee->setText(params.mainReferee); + ui->ed_director->setText(params.director); + ui->ed_handicapLength->setValue(params.handicapLength); + if(auto ix = ui->cbxSportId->findData(params.sportId); ix < 0) ui->cbxSportId->setCurrentIndex(0); - } else { + else ui->cbxSportId->setCurrentIndex(ix); - } - if (auto ix = ui->cbxDisciplineId->findData(params.value("disciplineId").toInt()); ix < 0) { + if(auto ix = ui->cbxDisciplineId->findData(params.disciplineId); ix < 0) ui->cbxDisciplineId->setCurrentIndex(0); - } else { + else ui->cbxDisciplineId->setCurrentIndex(ix); - } - ui->ed_orisImportId->setText(params.value("importId").toString()); - ui->ed_orisRace->setChecked(!ui->ed_orisImportId->text().isEmpty()); - ui->ed_orisEventKey->setText(params.value("orisEventKey").toString()); - ui->ed_cardChecCheckTimeSec->setValue(params.value("cardChechCheckTimeSec").toInt()); - ui->ed_oneTenthSecResults->setCurrentIndex(params.value("oneTenthSecResults").toInt()); - ui->ed_iofRace->setChecked(params.value("iofRace").toInt() != 0); - ui->ed_xmlRaceNumber->setValue(params.value("iofXmlRaceNumber").toInt()); + ui->ed_orisImportId->setText(params.importId > 0 ? QString::number(params.importId) : QString()); + ui->ed_orisRace->setChecked(params.importId > 0); + ui->ed_orisEventKey->setText(params.orisEventKey); + ui->ed_cardChecCheckTimeSec->setValue(params.cardCheckTimeSec); + ui->ed_oneTenthSecResults->setCurrentIndex(params.oneTenthSecResults); + ui->ed_iofRace->setChecked(params.iofRace); + ui->ed_xmlRaceNumber->setValue(params.iofXmlRaceNumber); } -QVariantMap EventDialogWidget::saveParams() +Event::EventConfigData EventDialogWidget::saveParams() { - QVariantMap ret; - ret["stageCount"] = ui->ed_stageCount->value(); - QVariantMap stages = m_stages; + Event::EventConfigData data = m_data; + data.stageCount = ui->ed_stageCount->value(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) { - const QString stage_id = QString::number(row + 1); - QVariantMap stage = stages.value(stage_id).toMap(); - stage.insert("startDateTime", editor->dateTime()); - if(!stage.contains("useAllMaps")) - stage.insert("useAllMaps", false); - if(!stage.contains("drawingConfig")) - stage.insert("drawingConfig", QStringLiteral("{}")); - if(!stage.contains("qxApiToken")) - stage.insert("qxApiToken", QString()); - stages.insert(stage_id, stage); - } + if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) + data.stages[row + 1].startDateTime = editor->dateTime(); } - ret["stage"] = stages; - //ret["currentStageId"] = ui->ed_currentStage->value(); - ret["name"] = ui->ed_name->text(); - ret["date"] = ui->ed_date->date(); - ret["time"] = ui->ed_time->time(); - ret["description"] = ui->ed_description->text(); - ret["place"] = ui->ed_place->text(); - ret["mainReferee"] = ui->ed_mainReferee->text(); - ret["director"] = ui->ed_director->text(); - ret["handicapLength"] = ui->ed_handicapLength->value(); - ret["sportId"] = ui->cbxSportId->currentData().isNull() ? static_cast(Event::EventConfig::Sport::OB) : ui->cbxSportId->currentData().toInt(); - ret["disciplineId"] = (ui->cbxDisciplineId->currentIndex() <= 0) ? static_cast(Event::EventConfig::Discipline::LongDistance) : ui->cbxDisciplineId->currentData(); - ret["importId"] = ui->ed_orisImportId->text().toInt(); - ret["orisEventKey"] = ui->ed_orisEventKey->text(); - ret["cardChechCheckTimeSec"] = ui->ed_cardChecCheckTimeSec->value(); - ret["oneTenthSecResults"] = ui->ed_oneTenthSecResults->currentIndex(); - ret["iofRace"] = (int)ui->ed_iofRace->isChecked(); - ret["iofXmlRaceNumber"] = ui->ed_xmlRaceNumber->value(); - return ret; + data.name = ui->ed_name->text(); + data.date = ui->ed_date->date(); + data.time = ui->ed_time->time(); + data.description = ui->ed_description->text(); + data.place = ui->ed_place->text(); + data.mainReferee = ui->ed_mainReferee->text(); + data.director = ui->ed_director->text(); + data.handicapLength = ui->ed_handicapLength->value(); + data.sportId = ui->cbxSportId->currentData().isNull() + ? static_cast(Event::EventConfig::Sport::OB) + : ui->cbxSportId->currentData().toInt(); + data.disciplineId = ui->cbxDisciplineId->currentIndex() <= 0 + ? static_cast(Event::EventConfig::Discipline::LongDistance) + : ui->cbxDisciplineId->currentData().toInt(); + data.importId = ui->ed_orisImportId->text().toInt(); + data.orisEventKey = ui->ed_orisEventKey->text(); + data.cardCheckTimeSec = ui->ed_cardChecCheckTimeSec->value(); + data.oneTenthSecResults = ui->ed_oneTenthSecResults->currentIndex(); + data.iofRace = ui->ed_iofRace->isChecked(); + data.iofXmlRaceNumber = ui->ed_xmlRaceNumber->value(); + return data; } QString EventDialogWidget::disciplineName(int disc_id) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index dfc219bfa..12474af9d 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -1,8 +1,46 @@ #ifndef EVENTDIALOGWIDGET_H #define EVENTDIALOGWIDGET_H +#include "stage.h" + #include +#include +#include +#include +#include +#include + +namespace Event { + +struct EventConfigData +{ + static EventConfigData fromVariantMap(const QVariantMap &values); + QVariantMap toVariantMap() const; + + int stageCount = 1; + QMap stages; + QString name; + QDate date; + QTime time; + QString description; + QString place; + QString mainReferee; + QString director; + int handicapLength = 0; + int sportId = 0; + int disciplineId = 0; + int importId = 0; + QString orisEventKey; + int cardCheckTimeSec = 0; + int oneTenthSecResults = 0; + bool iofRace = false; + int iofXmlRaceNumber = 0; + int currentStageId = 1; +}; + +} + namespace Ui { class EventDialogWidget; } @@ -20,8 +58,8 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget QString eventId() const; void setEventIdEditable(bool b); - void loadParams(const QVariantMap ¶ms); - QVariantMap saveParams(); + void loadParams(const Event::EventConfigData ¶ms); + Event::EventConfigData saveParams(); static QString disciplineName(int disc_id); static QString sportName(int sport_id); @@ -29,7 +67,7 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget void updateStageStartTimeEditors(int stage_count); void updateStageStartTimesTableHeight(); - QVariantMap m_stages; + Event::EventConfigData m_data; Ui::EventDialogWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index ff9e0d811..5e0bdd15b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -917,7 +917,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even else existing_event_ids = existingSqlEventNames(); QString event_id = event_name; - QVariantMap new_params = event_params; + EventConfigData new_params = EventConfigData::fromVariantMap(event_params); do { qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -947,8 +947,8 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even Event::EventConfig event_config; bool ok = false; //ConnectionSettings connection_settings; - event_config.setValue("event", new_params); - int stage_count = new_params.value("stageCount").toInt(); + event_config.setValue("event", new_params.toVariantMap()); + int stage_count = new_params.stageCount; if(stage_count == 0) stage_count = event_config.stageCount(); qfInfo() << "createEvent, stage_count:" << stage_count; @@ -1025,31 +1025,16 @@ void EventPlugin::editEvent() event_w->setWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - QVariantMap event_params = eventConfig()->value("event").toMap(); - QVariantMap stages = event_params.value("stage").toMap(); - const int stage_count = event_params.value("stageCount").toInt(); - for(int stage_id = 1; stage_id <= stage_count; ++stage_id) { - const QString stage_key = QString::number(stage_id); - QVariantMap stage = stages.value(stage_key).toMap(); - const StageData stage_data = stageData(stage_id); - if(!stage.contains(STAGE_START_DATE_TIME_KEY) && stage_data.startDateTime.isValid()) - stage.insert(STAGE_START_DATE_TIME_KEY, stage_data.startDateTime); - if(!stage.contains(STAGE_USE_ALL_MAPS_KEY)) - stage.insert(STAGE_USE_ALL_MAPS_KEY, stage_data.useAllMaps); - if(!stage.contains(STAGE_DRAWING_CONFIG_KEY)) - stage.insert(STAGE_DRAWING_CONFIG_KEY, qf::core::Utils::qvariantToJson(stage_data.drawingConfig)); - if(!stage.contains(STAGE_QX_API_TOKEN_KEY)) - stage.insert(STAGE_QX_API_TOKEN_KEY, stage_data.qxApiToken); - stages.insert(stage_key, stage); - } - event_params.insert("stage", stages); - event_w->loadParams(event_params); + EventConfigData event_data = EventConfigData::fromVariantMap(eventConfig()->value("event").toMap()); + for(int stage_id = 1; stage_id <= event_data.stageCount; ++stage_id) + event_data.stages.insert(stage_id, stageData(stage_id)); + event_w->loadParams(event_data); dlg.setCentralWidget(event_w); if(!dlg.exec()) return; - event_params = event_w->saveParams(); - eventConfig()->setValue("event", event_params); + event_data = event_w->saveParams(); + eventConfig()->setValue("event", event_data.toVariantMap()); eventConfig()->save("event"); } From 4cfe7908135b199f17b30c382a76dbd0d0212072 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 00:53:42 +0200 Subject: [PATCH 67/83] Extract EventConfigData to its own file --- quickevent/app/quickevent/CMakeLists.txt | 1 + .../plugins/Event/src/eventconfigdata.cpp | 77 +++++++++++++++++++ .../plugins/Event/src/eventconfigdata.h | 39 ++++++++++ .../plugins/Event/src/eventdialogwidget.cpp | 73 ------------------ .../plugins/Event/src/eventdialogwidget.h | 38 +-------- 5 files changed, 118 insertions(+), 110 deletions(-) create mode 100644 quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 3c1d55f38..58387cedd 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -65,6 +65,7 @@ add_executable(quickevent plugins/Event/src/connectionsettings.cpp plugins/Event/src/dbschema.cpp plugins/Event/src/eventconfig.cpp + plugins/Event/src/eventconfigdata.cpp plugins/Event/src/eventdialogwidget.cpp plugins/Event/src/eventdialogwidget.ui plugins/Event/src/eventplugin.cpp diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp new file mode 100644 index 000000000..27668a228 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp @@ -0,0 +1,77 @@ +#include "eventconfigdata.h" + +#include + +Event::EventConfigData Event::EventConfigData::fromVariantMap(const QVariantMap &values) +{ + EventConfigData data; + data.stageCount = values.value("stageCount", 1).toInt(); + const QVariantMap stages = values.value("stage").toMap(); + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + const int stage_id = it.key().toInt(); + if(stage_id <= 0) + continue; + const QVariantMap stage_values = it.value().toMap(); + StageData stage; + stage.startDateTime = stage_values.value("startDateTime").toDateTime(); + stage.useAllMaps = stage_values.value("useAllMaps").toBool(); + const QVariant drawing_config = stage_values.value("drawingConfig"); + stage.drawingConfig = drawing_config.userType() == qMetaTypeId() + ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() + : drawing_config.toMap(); + stage.qxApiToken = stage_values.value("qxApiToken").toString(); + data.stages.insert(stage_id, stage); + } + data.name = values.value("name").toString(); + data.date = values.value("date").toDate(); + data.time = values.value("time").toTime(); + data.description = values.value("description").toString(); + data.place = values.value("place").toString(); + data.mainReferee = values.value("mainReferee").toString(); + data.director = values.value("director").toString(); + data.handicapLength = values.value("handicapLength").toInt(); + data.sportId = values.value("sportId").toInt(); + data.disciplineId = values.value("disciplineId").toInt(); + data.importId = values.value("importId").toInt(); + data.orisEventKey = values.value("orisEventKey").toString(); + data.cardCheckTimeSec = values.value("cardChechCheckTimeSec").toInt(); + data.oneTenthSecResults = values.value("oneTenthSecResults").toInt(); + data.iofRace = values.value("iofRace").toBool(); + data.iofXmlRaceNumber = values.value("iofXmlRaceNumber").toInt(); + data.currentStageId = values.value("currentStageId", 1).toInt(); + return data; +} + +QVariantMap Event::EventConfigData::toVariantMap() const +{ + QVariantMap values; + values.insert("stageCount", stageCount); + QVariantMap stage_values; + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + QVariantMap stage; + stage.insert("startDateTime", it.value().startDateTime); + stage.insert("useAllMaps", it.value().useAllMaps); + stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); + stage.insert("qxApiToken", it.value().qxApiToken); + stage_values.insert(QString::number(it.key()), stage); + } + values.insert("stage", stage_values); + values.insert("name", name); + values.insert("date", date); + values.insert("time", time); + values.insert("description", description); + values.insert("place", place); + values.insert("mainReferee", mainReferee); + values.insert("director", director); + values.insert("handicapLength", handicapLength); + values.insert("sportId", sportId); + values.insert("disciplineId", disciplineId); + values.insert("importId", importId); + values.insert("orisEventKey", orisEventKey); + values.insert("cardChechCheckTimeSec", cardCheckTimeSec); + values.insert("oneTenthSecResults", oneTenthSecResults); + values.insert("iofRace", iofRace); + values.insert("iofXmlRaceNumber", iofXmlRaceNumber); + values.insert("currentStageId", currentStageId); + return values; +} diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h new file mode 100644 index 000000000..9a93af7a2 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h @@ -0,0 +1,39 @@ +#pragma once + +#include "stage.h" + +#include +#include +#include +#include +#include + +namespace Event { + +struct EventConfigData +{ + static EventConfigData fromVariantMap(const QVariantMap &values); + QVariantMap toVariantMap() const; + + int stageCount = 1; + QMap stages; + QString name; + QDate date; + QTime time; + QString description; + QString place; + QString mainReferee; + QString director; + int handicapLength = 0; + int sportId = 0; + int disciplineId = 0; + int importId = 0; + QString orisEventKey; + int cardCheckTimeSec = 0; + int oneTenthSecResults = 0; + bool iofRace = false; + int iofXmlRaceNumber = 0; + int currentStageId = 1; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index b5ad9a409..54c0ccb56 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -4,85 +4,12 @@ #include "eventconfig.h" #include -#include #include #include #include -Event::EventConfigData Event::EventConfigData::fromVariantMap(const QVariantMap &values) -{ - EventConfigData data; - data.stageCount = values.value("stageCount", 1).toInt(); - const QVariantMap stages = values.value("stage").toMap(); - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { - const int stage_id = it.key().toInt(); - if(stage_id <= 0) - continue; - const QVariantMap stage_values = it.value().toMap(); - StageData stage; - stage.startDateTime = stage_values.value("startDateTime").toDateTime(); - stage.useAllMaps = stage_values.value("useAllMaps").toBool(); - const QVariant drawing_config = stage_values.value("drawingConfig"); - stage.drawingConfig = drawing_config.userType() == qMetaTypeId() - ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() - : drawing_config.toMap(); - stage.qxApiToken = stage_values.value("qxApiToken").toString(); - data.stages.insert(stage_id, stage); - } - data.name = values.value("name").toString(); - data.date = values.value("date").toDate(); - data.time = values.value("time").toTime(); - data.description = values.value("description").toString(); - data.place = values.value("place").toString(); - data.mainReferee = values.value("mainReferee").toString(); - data.director = values.value("director").toString(); - data.handicapLength = values.value("handicapLength").toInt(); - data.sportId = values.value("sportId").toInt(); - data.disciplineId = values.value("disciplineId").toInt(); - data.importId = values.value("importId").toInt(); - data.orisEventKey = values.value("orisEventKey").toString(); - data.cardCheckTimeSec = values.value("cardChechCheckTimeSec").toInt(); - data.oneTenthSecResults = values.value("oneTenthSecResults").toInt(); - data.iofRace = values.value("iofRace").toBool(); - data.iofXmlRaceNumber = values.value("iofXmlRaceNumber").toInt(); - data.currentStageId = values.value("currentStageId", 1).toInt(); - return data; -} -QVariantMap Event::EventConfigData::toVariantMap() const -{ - QVariantMap values; - values.insert("stageCount", stageCount); - QVariantMap stage_values; - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { - QVariantMap stage; - stage.insert("startDateTime", it.value().startDateTime); - stage.insert("useAllMaps", it.value().useAllMaps); - stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); - stage.insert("qxApiToken", it.value().qxApiToken); - stage_values.insert(QString::number(it.key()), stage); - } - values.insert("stage", stage_values); - values.insert("name", name); - values.insert("date", date); - values.insert("time", time); - values.insert("description", description); - values.insert("place", place); - values.insert("mainReferee", mainReferee); - values.insert("director", director); - values.insert("handicapLength", handicapLength); - values.insert("sportId", sportId); - values.insert("disciplineId", disciplineId); - values.insert("importId", importId); - values.insert("orisEventKey", orisEventKey); - values.insert("cardChechCheckTimeSec", cardCheckTimeSec); - values.insert("oneTenthSecResults", oneTenthSecResults); - values.insert("iofRace", iofRace); - values.insert("iofXmlRaceNumber", iofXmlRaceNumber); - values.insert("currentStageId", currentStageId); - return values; -} EventDialogWidget::EventDialogWidget(QWidget *parent) : Super(parent), diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index 12474af9d..583fc018a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -1,46 +1,10 @@ #ifndef EVENTDIALOGWIDGET_H #define EVENTDIALOGWIDGET_H -#include "stage.h" +#include "eventconfigdata.h" #include -#include -#include -#include -#include -#include - -namespace Event { - -struct EventConfigData -{ - static EventConfigData fromVariantMap(const QVariantMap &values); - QVariantMap toVariantMap() const; - - int stageCount = 1; - QMap stages; - QString name; - QDate date; - QTime time; - QString description; - QString place; - QString mainReferee; - QString director; - int handicapLength = 0; - int sportId = 0; - int disciplineId = 0; - int importId = 0; - QString orisEventKey; - int cardCheckTimeSec = 0; - int oneTenthSecResults = 0; - bool iofRace = false; - int iofXmlRaceNumber = 0; - int currentStageId = 1; -}; - -} - namespace Ui { class EventDialogWidget; } From e03a4c32b49abbe05f63eecc2321e2b8d188d1c1 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 01:19:27 +0200 Subject: [PATCH 68/83] Migrate EventConfig to AppDbConfig --- quickevent/app/quickevent/CMakeLists.txt | 5 +- .../plugins/CardReader/src/cardchecker.cpp | 2 +- .../CardReader/src/cardreaderplugin.cpp | 4 +- .../CardReader/src/cardreaderwidget.cpp | 2 +- .../plugins/Classes/src/classesplugin.cpp | 2 +- .../plugins/Classes/src/classeswidget.cpp | 8 +- .../plugins/Classes/src/editcourseswidget.cpp | 4 +- .../Competitors/src/competitorwidget.cpp | 10 +- .../plugins/Event/src/appdbconfig.cpp | 312 +++++++++++++++ .../plugins/Event/src/appdbconfig.h | 79 ++++ .../plugins/Event/src/eventconfig.cpp | 369 ++++-------------- .../plugins/Event/src/eventconfig.h | 97 ++--- .../plugins/Event/src/eventconfigdata.cpp | 77 ---- .../plugins/Event/src/eventconfigdata.h | 39 -- .../plugins/Event/src/eventdialogwidget.cpp | 20 +- .../plugins/Event/src/eventdialogwidget.h | 8 +- .../plugins/Event/src/eventplugin.cpp | 32 +- .../plugins/Event/src/eventplugin.h | 8 +- .../plugins/Event/src/openeventdialog.cpp | 2 +- .../plugins/Event/src/services/emmaclient.cpp | 10 +- .../Event/src/services/ofeed/ofeedclient.cpp | 66 ++-- .../Event/src/services/oresultsclient.cpp | 16 +- .../punchingtest/punchingtestservice.cpp | 2 +- .../Event/src/services/qx/qxclientservice.cpp | 6 +- .../Event/src/{stage.h => stagedata.h} | 0 .../plugins/Oris/src/orisimporter.cpp | 16 +- .../plugins/Oris/src/xmlimporter.cpp | 12 +- .../plugins/Receipts/src/receiptsplugin.cpp | 16 +- .../Receipts/src/receiptssettingspage.cpp | 6 +- .../plugins/Receipts/src/receiptswidget.cpp | 2 +- .../plugins/Relays/src/relaysplugin.cpp | 10 +- .../plugins/Relays/src/relayswidget.cpp | 2 +- .../awards/results_stage_awards-hsh.qml | 4 +- .../plugins/Runs/src/runsplugin.cpp | 46 +-- .../Runs/src/runstableitemdelegate.cpp | 4 +- .../plugins/Runs/src/runstablemodel.cpp | 4 +- .../plugins/Runs/src/runstablewidget.cpp | 4 +- .../plugins/Runs/src/runswidget.cpp | 22 +- .../Runs/src/services/resultsexporter.cpp | 6 +- 39 files changed, 671 insertions(+), 663 deletions(-) create mode 100644 quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/appdbconfig.h delete mode 100644 quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp delete mode 100644 quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h rename quickevent/app/quickevent/plugins/Event/src/{stage.h => stagedata.h} (100%) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 58387cedd..8ffb1f5d1 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -60,12 +60,13 @@ add_executable(quickevent plugins/Core/src/widgets/settingsdialog.cpp plugins/Core/src/widgets/settingsdialog.ui + plugins/Event/src/stagedata.h plugins/Event/src/connectdbdialogwidget.cpp plugins/Event/src/connectdbdialogwidget.ui plugins/Event/src/connectionsettings.cpp plugins/Event/src/dbschema.cpp - plugins/Event/src/eventconfig.cpp - plugins/Event/src/eventconfigdata.cpp + plugins/Event/src/appdbconfig.cpp plugins/Event/src/appdbconfig.h + plugins/Event/src/eventconfig.cpp plugins/Event/src/eventconfig.h plugins/Event/src/eventdialogwidget.cpp plugins/Event/src/eventdialogwidget.ui plugins/Event/src/eventplugin.cpp diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp index bbdf0d63b..e03a7a665 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp @@ -82,7 +82,7 @@ int CardChecker::startTimeSec(int run_id) std::optional CardChecker::maximumCardCheckAdvanceSec() { - return getPlugin()->eventConfig()->maximumCardCheckAdvanceSec(); + return getPlugin()->appDbConfig()->maximumCardCheckAdvanceSec(); } quickevent::core::CourseDef CardChecker::courseCodesForRunId(int run_id) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp index 11148b97a..e357ccf63 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp @@ -115,7 +115,7 @@ int CardReaderPlugin::findRunId(int si_id, int si_finish_time, QString *err_msg) *err_msg = QString(); int si_finish_time_msec = getPlugin()->msecToStageStartAM(si_finish_time); qf::core::sql::Query q; - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(is_relays) { q.exec("SELECT id, leg, startTimeMs, finishTimeMs FROM runs WHERE siId=" QF_IARG(si_id) " AND isRunning" @@ -551,7 +551,7 @@ void CardReaderPlugin::setStartTime(int relay_id, int leg, int start_time) { bool CardReaderPlugin::processCardToRunAssignment(int card_id, int run_id) { qfLogFuncFrame(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(is_relays) { qf::core::sql::Query q; q.execThrow("SELECT relayId, leg, startTimeMs FROM runs WHERE id=" + QString::number(run_id)); diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 45ec6ea0d..44a07f59e 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -488,7 +488,7 @@ void CardReaderWidget::reset() void CardReaderWidget::reload() { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); //QString driver_name = m_cardsModel->sqlConnection().driverName(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp index 148b738c4..d21993ff0 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp @@ -93,7 +93,7 @@ void ClassesPlugin::createCourses(int stage_id, const QList &co { qfLogFuncFrame(); try { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); qf::core::sql::Transaction transaction(qf::core::sql::Connection::forName()); qf::core::sql::Query q; if (delete_current) diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index b1a0b4a16..5fe2dd7a1 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -405,7 +405,7 @@ static QString normalize_course_name(const QString &course_name) void ClassesWidget::import_ocad_txt() { - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -493,7 +493,7 @@ void ClassesWidget::import_ocad_v8() lines << QString::fromUtf8(ba).trimmed(); } try { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QMap defined_courses_map; for(const auto &line : lines) { // [classname];coursename;[relay.leg];lenght_km;climb;S1;dist_1;code_1[;dist_n;code_n];dist_finish;F1 @@ -586,7 +586,7 @@ static QString dump_element(const QDomElement &el) void ClassesWidget::import_ocad_iofxml_2() { - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -735,7 +735,7 @@ void ClassesWidget::import_ocad_iofxml_3() coursedef.addClass(class_name); } } - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { QDomNodeList ndlst = xdoc.elementsByTagName(QStringLiteral("TeamCourseAssignment")); QMap relay_courses; for (int i = 0; i < ndlst.count(); ++i) { diff --git a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp index 05d6ebe35..bda7861bc 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp @@ -94,7 +94,7 @@ EditCoursesWidget::EditCoursesWidget(int stage_id, QWidget *parent) QHeaderView *hh = ui->tblCourses->horizontalHeader(); hh->setSectionHidden(CoursesTableModel::Col_runCount, true); - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { ui->cbRunnersCount->setVisible(false); } else { connect (ui->cbRunnersCount,&QCheckBox::clicked,this,&EditCoursesWidget::updateQuery); @@ -135,7 +135,7 @@ void EditCoursesWidget::updateQuery() qfs::QueryBuilder qb; - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { qb.select2("courses", "*") .select("0 AS run_count") .select(code_list_query + "AS code_list") diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp index 854300cf1..b593dca31 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp @@ -155,7 +155,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : ui(new Ui::CompetitorWidget) { qfLogFuncFrame(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); setPersistentSettingsId("CompetitorWidget"); ui->setupUi(this); @@ -205,7 +205,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : connect(ui->tblRuns, &qfw::TableView::editCellRequest, this, [this](QModelIndex index) { auto col = index.column(); if(col == CompetitorRunsModel::col_runs_startTimeMs) { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if (!is_relays) { saveData(); auto row = ui->tblRuns->tableRow(); @@ -477,7 +477,7 @@ void CompetitorWidget::onRegistrationSelected(const QVariantMap &values) qfDebug() << "\t" << s << "->" << values.value(s); doc->setValue(s, values.value(s)); } - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(!is_relays) { // if no class is set, guess class from registration if(ui->cbxClass->currentText().isEmpty()) { @@ -517,7 +517,7 @@ void CompetitorWidget::save() bool CompetitorWidget::saveData() { try { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); auto *doc = qobject_cast(dataController()->document()); if(!is_relays && doc->value(QStringLiteral("classId")).toInt() == 0) { qf::gui::dialogs::MessageBox::showWarning(this, tr("Class should be entered.")); @@ -537,7 +537,7 @@ bool CompetitorWidget::acceptDialogDone(int result) { if (result == QDialog::Accepted) { auto *doc = qobject_cast(dataController()->document()); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if (doc->mode() != Competitors::CompetitorDocument::ModeDelete) { if (doc->value("classId").toInt() == 0 && !is_relays) { QMessageBox::information(this, tr("Competitor form check"), tr("Class must be set.")); diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp new file mode 100644 index 000000000..f418e473b --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -0,0 +1,312 @@ +#include "appdbconfig.h" +#include "eventplugin.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace Event; + +namespace { +const auto EVENT_NAME = QStringLiteral("event.name"); +} + +std::optional AppDbConfig::disciplineFromInt(int i) +{ + switch (static_cast(i)) { + case Discipline::LongDistance: return Discipline::LongDistance; + case Discipline::ShortDistance: return Discipline::ShortDistance; + case Discipline::Sprint: return Discipline::Sprint; + case Discipline::Relays: return Discipline::Relays; + case Discipline::Teams: return Discipline::Teams; + case Discipline::NightRace: return Discipline::NightRace; + case Discipline::SprintRelays: return Discipline::SprintRelays; + case Discipline::UltralongDistance: return Discipline::UltralongDistance; + case Discipline::FreeOrder: return Discipline::FreeOrder; + case Discipline::KnocOutSprint: return Discipline::KnocOutSprint; + case Discipline::TempO: return Discipline::TempO; + case Discipline::MultiStages: return Discipline::MultiStages; + case Discipline::MassStart: return Discipline::MassStart; + case Discipline::Indoor: return Discipline::Indoor; + } + return {}; +} + +QVariant AppDbConfig::value(const QStringList &path, const QVariant &default_value) const +{ + //QF_ASSERT(knownKeys().contains(key), "Key " + key + " is not known key!", return QVariant()); + QVariant ret = default_value; + if(!path.isEmpty()) { + QVariantMap m = m_data; + for (int i = 0; i < path.count() - 1; ++i) { + const QString &key = path[i]; + m = m.value(key).toMap(); + } + ret = m.value(path.last(), default_value); + } + return ret; +} + +void AppDbConfig::setValue(const QStringList &path, const QVariant &val) +{ + QF_ASSERT(!path.isEmpty(), "Empty path!", return); + m_data = setValue_helper(m_data, path, val); +} + +void AppDbConfig::load() +{ + using namespace qf::core::sql; + Connection conn = Connection::forName(); + + // Check connection existence / validity + Q_ASSERT(conn.isOpen()); + // if(!conn.isOpen()) { + // qfWarning() << "EventConfig::load(): database connection is not open:" + // << conn.errorString(); + // return; + // } + + Query q(conn); + QueryBuilder qb; + qb.select("ckey, cvalue, ctype").from("config").orderBy("ckey"); + if(q.exec(qb.toString(), qf::core::Exception::Throw)) { + while(q.next()) { + QString key = q.value(0).toString(); + /* + if(!knownKeys().contains(key)) { + qfWarning() << "Config key" << key << "is not known to the QuickEvent config system"; + } + */ + QVariant val = q.value(1); + QString type = q.value(2).toString(); + QVariant v = qf::core::Utils::retypeStringValue(val.toString(), type); + setValue(key, v); + } + } + // checkApiKey(); +} + +void AppDbConfig::save(const QString &path_to_save) +{ + QVariantMap m; + save_helper(m, QString(), m_data); + using namespace qf::core::sql; + Connection conn = Connection::forName(); + + try { + Query q_up(conn); + q_up.prepare("UPDATE config SET cvalue=:val WHERE ckey=:key", qf::core::Exception::Throw); + Query q_ins(conn); + q_ins.prepare("INSERT INTO config (ckey, cvalue, ctype) VALUES (:key, :val, :type)", qf::core::Exception::Throw); + QMapIterator it(m); + while(it.hasNext()) { + it.next(); + QString key = it.key(); + if(!path_to_save.isEmpty()) { + if(!key.startsWith(path_to_save)) + continue; + if(key.length() > path_to_save.length() && key[path_to_save.length()] != '.') + continue; + } + QVariant val = it.value(); + QString val_str; + if(val.typeId() == qMetaTypeId()) + val_str = val.toDate().toString(Qt::ISODate); + else if(val.typeId() == qMetaTypeId()) + val_str = val.toTime().toString(Qt::ISODate); + else if(val.typeId() == qMetaTypeId()) + val_str = val.toDateTime().toString(Qt::ISODate); + else + val_str = val.toString(); + q_up.bindValue(":key", key); + q_up.bindValue(":val", val_str); + q_up.exec(qf::core::Exception::Throw); + if(q_up.numRowsAffected() < 1) { + QString type = val.typeName(); + q_ins.bindValue(":key", key); + q_ins.bindValue(":type", type); + q_ins.bindValue(":val", val_str); + q_ins.exec(qf::core::Exception::Throw); + } + } + } + catch(const qf::core::Exception &e) { + qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); + qf::gui::dialogs::MessageBox::showException(fwk, e); + } + +} + +void AppDbConfig::save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val) +{ + if(val.typeId() == qMetaTypeId()) { + QVariantMap m = val.toMap(); + QMapIterator it(m); + while(it.hasNext()) { + it.next(); + QString cp = it.key(); + if(!current_path.isEmpty()) + cp = current_path + '.' + cp; + save_helper(ret, cp, it.value()); + } + } + else { + ret[current_path] = val; + } +} + +QVariantMap AppDbConfig::setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val) +{ + QVariantMap ret; + QF_ASSERT(!path.isEmpty(), "Empty path!", return ret); + if(path.count() == 1) { + ret = m; + ret[path.first()] = val; + } + else { + QStringList p = path; + QString key = p.takeFirst(); + ret = m; + ret[key] = setValue_helper(m.value(key).toMap(), p, val); + } + return ret; +} + +int AppDbConfig::stageCount() const +{ + return value(QStringLiteral("event.stageCount")).toInt(); +} + +int AppDbConfig::currentStageId() const +{ + int ret = value(QStringLiteral("event.currentStageId")).toInt(); + if(ret == 0) + ret = 1; + return ret; +} + +int AppDbConfig::sportId() const +{ + return value(QStringLiteral("event.sportId")).toInt(); +} + +AppDbConfig::Discipline AppDbConfig::discipline() const +{ + auto di = value(QStringLiteral("event.disciplineId")).toInt(); + return disciplineFromInt(di).value_or(Discipline::LongDistance); +} + +int AppDbConfig::importId() const +{ + return value(QStringLiteral("event.importId")).toInt(); +} + +int AppDbConfig::handicapLength() const +{ + return value(QStringLiteral("event.handicapLength")).toInt(); +} + +QString AppDbConfig::eventName() const +{ + return value(QStringLiteral("event.name")).toString(); +} + +// namespace { +// auto const API_KEY_CONFIG_PATH = QStringLiteral("event.apiKey"); +// } +// QString EventConfig::apiKey() const +// { +// return value(API_KEY_CONFIG_PATH).toString(); +// } + +// void AppDbConfig::checkApiKey() +// { +// if (apiKey().isEmpty()) { +// auto api_key = EventPlugin::createApiKey(10); +// setValue(API_KEY_CONFIG_PATH, api_key); +// save(API_KEY_CONFIG_PATH); +// } +// } + +QString AppDbConfig::eventPlace() const +{ + return value(QStringLiteral("event.place")).toString(); +} + +QString AppDbConfig::director() const +{ + return value(QStringLiteral("event.director")).toString(); +} + +QString AppDbConfig::mainReferee() const +{ + return value(QStringLiteral("event.mainReferee")).toString(); +} + +QDateTime AppDbConfig::eventDateTime() const +{ + QDateTime dt; + QVariant v = value(QStringLiteral("event.dateTime")); + if(v.isValid()) { + dt = v.toDateTime(); + } + else { + QVariant v = value(QStringLiteral("event.date")); + dt.setDate(v.toDate()); + v = value(QStringLiteral("event.time")); + QTime tm = v.toTime(); + if(tm.isValid()) + dt.setTime(tm); + else + dt = dt.addSecs(10 * 60 * 60); // start at 10:00 if not specified + } + return dt; +} + +int AppDbConfig::dbVersion() const +{ + return value(QStringLiteral("db.version")).toInt(); +} + +std::optional AppDbConfig::maximumCardCheckAdvanceSec() const +{ + if(auto sec = value(QStringLiteral("event.cardChechCheckTimeSec")).toInt(); sec > 0) + return sec; + return {}; +} + +bool AppDbConfig::isOneTenthSecResults() const +{ + return static_cast(value(QStringLiteral("oneTenthSecResults")).toInt()); +} + +bool AppDbConfig::isIofRace() const +{ + return value(QStringLiteral("event.iofRace")).toInt() != 0; +} + +int AppDbConfig::iofXmlRaceNumber() const +{ + return value(QStringLiteral("event.iofXmlRaceNumber")).toInt(); +} + +QString AppDbConfig::orisEventKey() const +{ + return value(QStringLiteral("event.orisEventKey")).toString(); +} + +EventConfig AppDbConfig::eventConfig() const +{ + return EventConfig::fromVariantMap(value(QStringLiteral("event")).toMap()); +} + + + diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h new file mode 100644 index 000000000..e68587fd1 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -0,0 +1,79 @@ +#pragma once + +#include "eventconfig.h" + +#include +#include +#include +#include + +#include + +namespace Event { + +class AppDbConfig +{ +public: + enum class Sport {OB = 1, LOB, MTBO, TRAIL}; + enum class Discipline {LongDistance = 1, + ShortDistance = 2, + Sprint = 3, + UltralongDistance = 4, + Relays = 5, + Teams = 6, + FreeOrder = 7, + NightRace = 9, + TempO = 11, + MultiStages = 13, + MassStart = 14, + SprintRelays = 15, + KnocOutSprint = 16, + Indoor = 19, + }; + static std::optional disciplineFromInt(int i); +public: + explicit AppDbConfig() = default; +public: + QVariantMap values() const {return m_data;} + QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; + QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { + return value(path.split('.'), default_value); + } + void setValue(const QStringList &path, const QVariant &val); + void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} + void load(); + void save(const QString &path_to_save = QString()); + + int stageCount() const; + int currentStageId() const; + int sportId() const; + Discipline discipline() const; + int importId() const; + int handicapLength() const; + bool isHandicap() const {return handicapLength() > 0;} + bool isRelays() const { + return discipline() == Discipline::Relays + || discipline() == Discipline::Teams + || discipline() == Discipline::SprintRelays; + } + bool isIofRace() const; + int iofXmlRaceNumber() const; + QString eventName() const; + QString eventPlace() const; + QString director() const; + QString mainReferee() const; + QDateTime eventDateTime() const; + int dbVersion() const; + std::optional maximumCardCheckAdvanceSec() const; + bool isOneTenthSecResults() const; + QString orisEventKey() const; + EventConfig eventConfig() const; +private: + void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); + QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); +private: + QVariantMap m_data; +}; + +} + diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 1e363dad3..683383a88 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -1,306 +1,77 @@ #include "eventconfig.h" -#include "eventplugin.h" -#include #include -#include -#include -#include -#include -#include -#include - -#include - -using namespace Event; - -namespace { -const auto EVENT_NAME = QStringLiteral("event.name"); -} - -std::optional EventConfig::disciplineFromInt(int i) -{ - switch (static_cast(i)) { - case Discipline::LongDistance: return Discipline::LongDistance; - case Discipline::ShortDistance: return Discipline::ShortDistance; - case Discipline::Sprint: return Discipline::Sprint; - case Discipline::Relays: return Discipline::Relays; - case Discipline::Teams: return Discipline::Teams; - case Discipline::NightRace: return Discipline::NightRace; - case Discipline::SprintRelays: return Discipline::SprintRelays; - case Discipline::UltralongDistance: return Discipline::UltralongDistance; - case Discipline::FreeOrder: return Discipline::FreeOrder; - case Discipline::KnocOutSprint: return Discipline::KnocOutSprint; - case Discipline::TempO: return Discipline::TempO; - case Discipline::MultiStages: return Discipline::MultiStages; - case Discipline::MassStart: return Discipline::MassStart; - case Discipline::Indoor: return Discipline::Indoor; - } - return {}; -} - -QVariant EventConfig::value(const QStringList &path, const QVariant &default_value) const -{ - //QF_ASSERT(knownKeys().contains(key), "Key " + key + " is not known key!", return QVariant()); - QVariant ret = default_value; - if(!path.isEmpty()) { - QVariantMap m = m_data; - for (int i = 0; i < path.count() - 1; ++i) { - const QString &key = path[i]; - m = m.value(key).toMap(); - } - ret = m.value(path.last(), default_value); - } - return ret; -} - -void EventConfig::setValue(const QStringList &path, const QVariant &val) -{ - QF_ASSERT(!path.isEmpty(), "Empty path!", return); - m_data = setValue_helper(m_data, path, val); -} - -void EventConfig::load() -{ - using namespace qf::core::sql; - Connection conn = Connection::forName(); - - // Check connection existence / validity - Q_ASSERT(conn.isOpen()); - // if(!conn.isOpen()) { - // qfWarning() << "EventConfig::load(): database connection is not open:" - // << conn.errorString(); - // return; - // } - - Query q(conn); - QueryBuilder qb; - qb.select("ckey, cvalue, ctype").from("config").orderBy("ckey"); - if(q.exec(qb.toString(), qf::core::Exception::Throw)) { - while(q.next()) { - QString key = q.value(0).toString(); - /* - if(!knownKeys().contains(key)) { - qfWarning() << "Config key" << key << "is not known to the QuickEvent config system"; - } - */ - QVariant val = q.value(1); - QString type = q.value(2).toString(); - QVariant v = qf::core::Utils::retypeStringValue(val.toString(), type); - setValue(key, v); - } - } - // checkApiKey(); -} - -void EventConfig::save(const QString &path_to_save) -{ - QVariantMap m; - save_helper(m, QString(), m_data); - using namespace qf::core::sql; - Connection conn = Connection::forName(); - - try { - Query q_up(conn); - q_up.prepare("UPDATE config SET cvalue=:val WHERE ckey=:key", qf::core::Exception::Throw); - Query q_ins(conn); - q_ins.prepare("INSERT INTO config (ckey, cvalue, ctype) VALUES (:key, :val, :type)", qf::core::Exception::Throw); - QMapIterator it(m); - while(it.hasNext()) { - it.next(); - QString key = it.key(); - if(!path_to_save.isEmpty()) { - if(!key.startsWith(path_to_save)) - continue; - if(key.length() > path_to_save.length() && key[path_to_save.length()] != '.') - continue; - } - QVariant val = it.value(); - QString val_str; - if(val.typeId() == qMetaTypeId()) - val_str = val.toDate().toString(Qt::ISODate); - else if(val.typeId() == qMetaTypeId()) - val_str = val.toTime().toString(Qt::ISODate); - else if(val.typeId() == qMetaTypeId()) - val_str = val.toDateTime().toString(Qt::ISODate); - else - val_str = val.toString(); - q_up.bindValue(":key", key); - q_up.bindValue(":val", val_str); - q_up.exec(qf::core::Exception::Throw); - if(q_up.numRowsAffected() < 1) { - QString type = val.typeName(); - q_ins.bindValue(":key", key); - q_ins.bindValue(":type", type); - q_ins.bindValue(":val", val_str); - q_ins.exec(qf::core::Exception::Throw); - } - } - } - catch(const qf::core::Exception &e) { - qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); - qf::gui::dialogs::MessageBox::showException(fwk, e); - } - -} - -void EventConfig::save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val) -{ - if(val.typeId() == qMetaTypeId()) { - QVariantMap m = val.toMap(); - QMapIterator it(m); - while(it.hasNext()) { - it.next(); - QString cp = it.key(); - if(!current_path.isEmpty()) - cp = current_path + '.' + cp; - save_helper(ret, cp, it.value()); - } - } - else { - ret[current_path] = val; - } -} - -QVariantMap EventConfig::setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val) -{ - QVariantMap ret; - QF_ASSERT(!path.isEmpty(), "Empty path!", return ret); - if(path.count() == 1) { - ret = m; - ret[path.first()] = val; - } - else { - QStringList p = path; - QString key = p.takeFirst(); - ret = m; - ret[key] = setValue_helper(m.value(key).toMap(), p, val); - } - return ret; -} - -int EventConfig::stageCount() const -{ - return value(QStringLiteral("event.stageCount")).toInt(); -} - -int EventConfig::currentStageId() const -{ - int ret = value(QStringLiteral("event.currentStageId")).toInt(); - if(ret == 0) - ret = 1; - return ret; -} - -int EventConfig::sportId() const -{ - return value(QStringLiteral("event.sportId")).toInt(); -} - -EventConfig::Discipline EventConfig::discipline() const -{ - auto di = value(QStringLiteral("event.disciplineId")).toInt(); - return disciplineFromInt(di).value_or(Discipline::LongDistance); -} - -int EventConfig::importId() const -{ - return value(QStringLiteral("event.importId")).toInt(); -} - -int EventConfig::handicapLength() const -{ - return value(QStringLiteral("event.handicapLength")).toInt(); -} - -QString EventConfig::eventName() const -{ - return value(QStringLiteral("event.name")).toString(); -} - -// namespace { -// auto const API_KEY_CONFIG_PATH = QStringLiteral("event.apiKey"); -// } -// QString EventConfig::apiKey() const -// { -// return value(API_KEY_CONFIG_PATH).toString(); -// } - -// void EventConfig::checkApiKey() -// { -// if (apiKey().isEmpty()) { -// auto api_key = EventPlugin::createApiKey(10); -// setValue(API_KEY_CONFIG_PATH, api_key); -// save(API_KEY_CONFIG_PATH); -// } -// } - -QString EventConfig::eventPlace() const -{ - return value(QStringLiteral("event.place")).toString(); -} - -QString EventConfig::director() const -{ - return value(QStringLiteral("event.director")).toString(); -} - -QString EventConfig::mainReferee() const -{ - return value(QStringLiteral("event.mainReferee")).toString(); -} - -QDateTime EventConfig::eventDateTime() const -{ - QDateTime dt; - QVariant v = value(QStringLiteral("event.dateTime")); - if(v.isValid()) { - dt = v.toDateTime(); +Event::EventConfig Event::EventConfig::fromVariantMap(const QVariantMap &values) +{ + EventConfig data; + data.stageCount = values.value("stageCount", 1).toInt(); + const QVariantMap stages = values.value("stage").toMap(); + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + const int stage_id = it.key().toInt(); + if(stage_id <= 0) + continue; + const QVariantMap stage_values = it.value().toMap(); + StageData stage; + stage.startDateTime = stage_values.value("startDateTime").toDateTime(); + stage.useAllMaps = stage_values.value("useAllMaps").toBool(); + const QVariant drawing_config = stage_values.value("drawingConfig"); + stage.drawingConfig = drawing_config.userType() == qMetaTypeId() + ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() + : drawing_config.toMap(); + stage.qxApiToken = stage_values.value("qxApiToken").toString(); + data.stages.insert(stage_id, stage); } - else { - QVariant v = value(QStringLiteral("event.date")); - dt.setDate(v.toDate()); - v = value(QStringLiteral("event.time")); - QTime tm = v.toTime(); - if(tm.isValid()) - dt.setTime(tm); - else - dt = dt.addSecs(10 * 60 * 60); // start at 10:00 if not specified + data.name = values.value("name").toString(); + data.date = values.value("date").toDate(); + data.time = values.value("time").toTime(); + data.description = values.value("description").toString(); + data.place = values.value("place").toString(); + data.mainReferee = values.value("mainReferee").toString(); + data.director = values.value("director").toString(); + data.handicapLength = values.value("handicapLength").toInt(); + data.sportId = values.value("sportId").toInt(); + data.disciplineId = values.value("disciplineId").toInt(); + data.importId = values.value("importId").toInt(); + data.orisEventKey = values.value("orisEventKey").toString(); + data.cardCheckTimeSec = values.value("cardChechCheckTimeSec").toInt(); + data.oneTenthSecResults = values.value("oneTenthSecResults").toInt(); + data.iofRace = values.value("iofRace").toBool(); + data.iofXmlRaceNumber = values.value("iofXmlRaceNumber").toInt(); + data.currentStageId = values.value("currentStageId", 1).toInt(); + return data; +} + +QVariantMap Event::EventConfig::toVariantMap() const +{ + QVariantMap values; + values.insert("stageCount", stageCount); + QVariantMap stage_values; + for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + QVariantMap stage; + stage.insert("startDateTime", it.value().startDateTime); + stage.insert("useAllMaps", it.value().useAllMaps); + stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); + stage.insert("qxApiToken", it.value().qxApiToken); + stage_values.insert(QString::number(it.key()), stage); } - return dt; -} - -int EventConfig::dbVersion() const -{ - return value(QStringLiteral("db.version")).toInt(); -} - -std::optional EventConfig::maximumCardCheckAdvanceSec() const -{ - if(auto sec = value(QStringLiteral("event.cardChechCheckTimeSec")).toInt(); sec > 0) - return sec; - return {}; -} - -bool EventConfig::isOneTenthSecResults() const -{ - return static_cast(value(QStringLiteral("oneTenthSecResults")).toInt()); + values.insert("stage", stage_values); + values.insert("name", name); + values.insert("date", date); + values.insert("time", time); + values.insert("description", description); + values.insert("place", place); + values.insert("mainReferee", mainReferee); + values.insert("director", director); + values.insert("handicapLength", handicapLength); + values.insert("sportId", sportId); + values.insert("disciplineId", disciplineId); + values.insert("importId", importId); + values.insert("orisEventKey", orisEventKey); + values.insert("cardChechCheckTimeSec", cardCheckTimeSec); + values.insert("oneTenthSecResults", oneTenthSecResults); + values.insert("iofRace", iofRace); + values.insert("iofXmlRaceNumber", iofXmlRaceNumber); + values.insert("currentStageId", currentStageId); + return values; } - -bool EventConfig::isIofRace() const -{ - return value(QStringLiteral("event.iofRace")).toInt() != 0; -} - -int EventConfig::iofXmlRaceNumber() const -{ - return value(QStringLiteral("event.iofXmlRaceNumber")).toInt(); -} - -QString EventConfig::orisEventKey() const -{ - return value(QStringLiteral("event.orisEventKey")).toString(); -} - - diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index f9371ed07..83edd2735 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -1,78 +1,39 @@ -#ifndef EVENTCONFIG_H -#define EVENTCONFIG_H +#pragma once -#include -#include -#include -#include +#include "stagedata.h" -#include +#include +#include +#include +#include +#include namespace Event { -class EventConfig +struct EventConfig { -public: - enum class Sport {OB = 1, LOB, MTBO, TRAIL}; - enum class Discipline {LongDistance = 1, - ShortDistance = 2, - Sprint = 3, - UltralongDistance = 4, - Relays = 5, - Teams = 6, - FreeOrder = 7, - NightRace = 9, - TempO = 11, - MultiStages = 13, - MassStart = 14, - SprintRelays = 15, - KnocOutSprint = 16, - Indoor = 19, - }; - static std::optional disciplineFromInt(int i); -public: - explicit EventConfig() = default; -public: - QVariantMap values() const {return m_data;} - QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; - QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { - return value(path.split('.'), default_value); - } - void setValue(const QStringList &path, const QVariant &val); - void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} - void load(); - void save(const QString &path_to_save = QString()); + static EventConfig fromVariantMap(const QVariantMap &values); + QVariantMap toVariantMap() const; - int stageCount() const; - int currentStageId() const; - int sportId() const; - Discipline discipline() const; - int importId() const; - int handicapLength() const; - bool isHandicap() const {return handicapLength() > 0;} - bool isRelays() const { - return discipline() == Discipline::Relays - || discipline() == Discipline::Teams - || discipline() == Discipline::SprintRelays; - } - bool isIofRace() const; - int iofXmlRaceNumber() const; - QString eventName() const; - QString eventPlace() const; - QString director() const; - QString mainReferee() const; - QDateTime eventDateTime() const; - int dbVersion() const; - std::optional maximumCardCheckAdvanceSec() const; - bool isOneTenthSecResults() const; - QString orisEventKey() const; -private: - void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); - QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); -private: - QVariantMap m_data; + int stageCount = 1; + QMap stages; + QString name; + QDate date; + QTime time; + QString description; + QString place; + QString mainReferee; + QString director; + int handicapLength = 0; + int sportId = 0; + int disciplineId = 0; + int importId = 0; + QString orisEventKey; + int cardCheckTimeSec = 0; + int oneTenthSecResults = 0; + bool iofRace = false; + int iofXmlRaceNumber = 0; + int currentStageId = 1; }; } - -#endif // EVENTCONFIG_H diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp deleted file mode 100644 index 27668a228..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "eventconfigdata.h" - -#include - -Event::EventConfigData Event::EventConfigData::fromVariantMap(const QVariantMap &values) -{ - EventConfigData data; - data.stageCount = values.value("stageCount", 1).toInt(); - const QVariantMap stages = values.value("stage").toMap(); - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { - const int stage_id = it.key().toInt(); - if(stage_id <= 0) - continue; - const QVariantMap stage_values = it.value().toMap(); - StageData stage; - stage.startDateTime = stage_values.value("startDateTime").toDateTime(); - stage.useAllMaps = stage_values.value("useAllMaps").toBool(); - const QVariant drawing_config = stage_values.value("drawingConfig"); - stage.drawingConfig = drawing_config.userType() == qMetaTypeId() - ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() - : drawing_config.toMap(); - stage.qxApiToken = stage_values.value("qxApiToken").toString(); - data.stages.insert(stage_id, stage); - } - data.name = values.value("name").toString(); - data.date = values.value("date").toDate(); - data.time = values.value("time").toTime(); - data.description = values.value("description").toString(); - data.place = values.value("place").toString(); - data.mainReferee = values.value("mainReferee").toString(); - data.director = values.value("director").toString(); - data.handicapLength = values.value("handicapLength").toInt(); - data.sportId = values.value("sportId").toInt(); - data.disciplineId = values.value("disciplineId").toInt(); - data.importId = values.value("importId").toInt(); - data.orisEventKey = values.value("orisEventKey").toString(); - data.cardCheckTimeSec = values.value("cardChechCheckTimeSec").toInt(); - data.oneTenthSecResults = values.value("oneTenthSecResults").toInt(); - data.iofRace = values.value("iofRace").toBool(); - data.iofXmlRaceNumber = values.value("iofXmlRaceNumber").toInt(); - data.currentStageId = values.value("currentStageId", 1).toInt(); - return data; -} - -QVariantMap Event::EventConfigData::toVariantMap() const -{ - QVariantMap values; - values.insert("stageCount", stageCount); - QVariantMap stage_values; - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { - QVariantMap stage; - stage.insert("startDateTime", it.value().startDateTime); - stage.insert("useAllMaps", it.value().useAllMaps); - stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); - stage.insert("qxApiToken", it.value().qxApiToken); - stage_values.insert(QString::number(it.key()), stage); - } - values.insert("stage", stage_values); - values.insert("name", name); - values.insert("date", date); - values.insert("time", time); - values.insert("description", description); - values.insert("place", place); - values.insert("mainReferee", mainReferee); - values.insert("director", director); - values.insert("handicapLength", handicapLength); - values.insert("sportId", sportId); - values.insert("disciplineId", disciplineId); - values.insert("importId", importId); - values.insert("orisEventKey", orisEventKey); - values.insert("cardChechCheckTimeSec", cardCheckTimeSec); - values.insert("oneTenthSecResults", oneTenthSecResults); - values.insert("iofRace", iofRace); - values.insert("iofXmlRaceNumber", iofXmlRaceNumber); - values.insert("currentStageId", currentStageId); - return values; -} diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h b/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h deleted file mode 100644 index 9a93af7a2..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfigdata.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "stage.h" - -#include -#include -#include -#include -#include - -namespace Event { - -struct EventConfigData -{ - static EventConfigData fromVariantMap(const QVariantMap &values); - QVariantMap toVariantMap() const; - - int stageCount = 1; - QMap stages; - QString name; - QDate date; - QTime time; - QString description; - QString place; - QString mainReferee; - QString director; - int handicapLength = 0; - int sportId = 0; - int disciplineId = 0; - int importId = 0; - QString orisEventKey; - int cardCheckTimeSec = 0; - int oneTenthSecResults = 0; - bool iofRace = false; - int iofXmlRaceNumber = 0; - int currentStageId = 1; -}; - -} diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 54c0ccb56..e77837923 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -1,7 +1,7 @@ #include "eventdialogwidget.h" #include "ui_eventdialogwidget.h" -#include "eventconfig.h" +#include "appdbconfig.h" #include @@ -30,11 +30,11 @@ EventDialogWidget::EventDialogWidget(QWidget *parent) : connect(ui->ed_orisRace, &QAbstractButton::toggled, ui->frameOrisRace, &QWidget::setVisible); ui->frameOrisRace->hide(); - using S = Event::EventConfig::Sport; + using S = Event::AppDbConfig::Sport; for (S sport : {S::OB, S::LOB, S::MTBO, S::TRAIL}) ui->cbxSportId->addItem(sportName(static_cast(sport)), static_cast(sport)); - using D = Event::EventConfig::Discipline; + using D = Event::AppDbConfig::Discipline; for (D disc : {D::LongDistance, D::ShortDistance, D::UltralongDistance, D::Sprint, D::Relays, D::Teams, D::FreeOrder, D::NightRace, D::SprintRelays, D::KnocOutSprint, D::TempO, D::MultiStages, D::Indoor, D::MassStart}) { @@ -115,7 +115,7 @@ void EventDialogWidget::updateStageStartTimesTableHeight() table->setFixedHeight(height); } -void EventDialogWidget::loadParams(const Event::EventConfigData ¶ms) +void EventDialogWidget::loadParams(const Event::EventConfig ¶ms) { m_data = params; ui->ed_name->setText(params.name); @@ -155,9 +155,9 @@ void EventDialogWidget::loadParams(const Event::EventConfigData ¶ms) ui->ed_xmlRaceNumber->setValue(params.iofXmlRaceNumber); } -Event::EventConfigData EventDialogWidget::saveParams() +Event::EventConfig EventDialogWidget::saveParams() { - Event::EventConfigData data = m_data; + Event::EventConfig data = m_data; data.stageCount = ui->ed_stageCount->value(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) @@ -172,10 +172,10 @@ Event::EventConfigData EventDialogWidget::saveParams() data.director = ui->ed_director->text(); data.handicapLength = ui->ed_handicapLength->value(); data.sportId = ui->cbxSportId->currentData().isNull() - ? static_cast(Event::EventConfig::Sport::OB) + ? static_cast(Event::AppDbConfig::Sport::OB) : ui->cbxSportId->currentData().toInt(); data.disciplineId = ui->cbxDisciplineId->currentIndex() <= 0 - ? static_cast(Event::EventConfig::Discipline::LongDistance) + ? static_cast(Event::AppDbConfig::Discipline::LongDistance) : ui->cbxDisciplineId->currentData().toInt(); data.importId = ui->ed_orisImportId->text().toInt(); data.orisEventKey = ui->ed_orisEventKey->text(); @@ -188,7 +188,7 @@ Event::EventConfigData EventDialogWidget::saveParams() QString EventDialogWidget::disciplineName(int disc_id) { - using D = Event::EventConfig::Discipline; + using D = Event::AppDbConfig::Discipline; switch (static_cast(disc_id)) { case D::LongDistance: return tr("Long distance"); case D::ShortDistance: return tr("Middle distance"); @@ -210,7 +210,7 @@ QString EventDialogWidget::disciplineName(int disc_id) QString EventDialogWidget::sportName(int sport_id) { - using S = Event::EventConfig::Sport; + using S = Event::AppDbConfig::Sport; switch (static_cast(sport_id)) { case S::OB: return QStringLiteral("OB"); case S::LOB: return QStringLiteral("LOB"); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index 583fc018a..d8f9527b0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -1,7 +1,7 @@ #ifndef EVENTDIALOGWIDGET_H #define EVENTDIALOGWIDGET_H -#include "eventconfigdata.h" +#include "eventconfig.h" #include @@ -22,8 +22,8 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget QString eventId() const; void setEventIdEditable(bool b); - void loadParams(const Event::EventConfigData ¶ms); - Event::EventConfigData saveParams(); + void loadParams(const Event::EventConfig ¶ms); + Event::EventConfig saveParams(); static QString disciplineName(int disc_id); static QString sportName(int sport_id); @@ -31,7 +31,7 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget void updateStageStartTimeEditors(int stage_count); void updateStageStartTimesTableHeight(); - Event::EventConfigData m_data; + Event::EventConfig m_data; Ui::EventDialogWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 5e0bdd15b..66803ad35 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -209,17 +209,17 @@ EventPlugin::~EventPlugin() void EventPlugin::initEventConfig() { if(m_eventConfig == nullptr) { - m_eventConfig = new Event::EventConfig(); + m_eventConfig = new Event::AppDbConfig(); } else { qfWarning() << "Event config exists already!"; } } -Event::EventConfig *EventPlugin::eventConfig(bool reload) +Event::AppDbConfig *EventPlugin::appDbConfig(bool reload) { if(m_eventConfig == nullptr) { - m_eventConfig = new Event::EventConfig(); + m_eventConfig = new Event::AppDbConfig(); reload = true; } if(reload) { @@ -233,7 +233,7 @@ int EventPlugin::stageCount() { if(eventName().isEmpty()) return 0; - return eventConfig()->stageCount(); + return appDbConfig()->stageCount(); } void EventPlugin::setCurrentStageId(int stage_id) @@ -317,7 +317,7 @@ StageData EventPlugin::stageData(int stage_id) // Config values take precedence over legacy table values. const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - const QVariantMap config_data = eventConfig()->value(config_prefix).toMap(); + const QVariantMap config_data = appDbConfig()->value(config_prefix).toMap(); if(config_data.contains(STAGE_START_DATE_TIME_KEY)) data.startDateTime = config_data.value(STAGE_START_DATE_TIME_KEY).toDateTime(); if(config_data.contains(STAGE_USE_ALL_MAPS_KEY)) @@ -335,7 +335,7 @@ StageData EventPlugin::stageData(int stage_id) void EventPlugin::setStageData(int stage_id, const StageData &data) { - EventConfig *config = eventConfig(); + AppDbConfig *config = appDbConfig(); const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); config->setValue(config_prefix + '.' + STAGE_START_DATE_TIME_KEY, data.startDateTime); config->setValue(config_prefix + '.' + STAGE_USE_ALL_MAPS_KEY, data.useAllMaps); @@ -501,16 +501,16 @@ void EventPlugin::loadCurrentStageId() { int stage_id = 1; if(!eventName().isEmpty()) { - stage_id = eventConfig()->currentStageId(); + stage_id = appDbConfig()->currentStageId(); } setCurrentStageId(stage_id); } void EventPlugin::saveCurrentStageId(int current_stage) { - if(current_stage != eventConfig()->currentStageId()) { - eventConfig()->setValue("event.currentStageId", current_stage); - eventConfig()->save("event"); + if(current_stage != appDbConfig()->currentStageId()) { + appDbConfig()->setValue("event.currentStageId", current_stage); + appDbConfig()->save("event"); } } @@ -917,7 +917,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even else existing_event_ids = existingSqlEventNames(); QString event_id = event_name; - EventConfigData new_params = EventConfigData::fromVariantMap(event_params); + EventConfig new_params = EventConfig::fromVariantMap(event_params); do { qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -944,7 +944,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even closeEvent(); - Event::EventConfig event_config; + Event::AppDbConfig event_config; bool ok = false; //ConnectionSettings connection_settings; event_config.setValue("event", new_params.toVariantMap()); @@ -1025,7 +1025,7 @@ void EventPlugin::editEvent() event_w->setWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - EventConfigData event_data = EventConfigData::fromVariantMap(eventConfig()->value("event").toMap()); + EventConfig event_data = EventConfig::fromVariantMap(appDbConfig()->value("event").toMap()); for(int stage_id = 1; stage_id <= event_data.stageCount; ++stage_id) event_data.stages.insert(stage_id, stageData(stage_id)); event_w->loadParams(event_data); @@ -1034,8 +1034,8 @@ void EventPlugin::editEvent() return; event_data = event_w->saveParams(); - eventConfig()->setValue("event", event_data.toVariantMap()); - eventConfig()->save("event"); + appDbConfig()->setValue("event", event_data.toVariantMap()); + appDbConfig()->save("event"); } bool EventPlugin::closeEvent() @@ -1154,7 +1154,7 @@ bool EventPlugin::openEvent(const QString &_event_name) } } if(ok) { - EventConfig *evc = eventConfig(true); + AppDbConfig *evc = appDbConfig(true); if(evc->dbVersion() < dbVersion()) { qfd::MessageBox::showError(fwk, tr("Event data version (%1) is too low, minimal version is (%2).\nUse: File --> Import --> Event (*.qbe) to convert event to current version.") .arg(qf::core::Utils::intToVersionString(evc->dbVersion())) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 108350d8e..f2e5e6db4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -1,8 +1,8 @@ #ifndef EVENTPLUGIN_H #define EVENTPLUGIN_H -#include "eventconfig.h" -#include "stage.h" +#include "appdbconfig.h" +#include "stagedata.h" #include @@ -64,7 +64,7 @@ class EventPlugin : public qf::gui::framework::Plugin static constexpr auto DBEVENT_QX_RECCHNG = "qxRecChng"; Q_INVOKABLE void initEventConfig(); - Event::EventConfig* eventConfig(bool reload = false); + Event::AppDbConfig* appDbConfig(bool reload = false); int stageCount(); Q_SLOT void setCurrentStageId(int stage_id); @@ -166,7 +166,7 @@ class EventPlugin : public qf::gui::framework::Plugin qf::gui::Action *m_actSetCurrentStage = nullptr; qf::gui::Action *m_actExportEvent_qbe = nullptr; qf::gui::Action *m_actImportEvent_qbe = nullptr; - Event::EventConfig *m_eventConfig = nullptr; + Event::AppDbConfig *m_eventConfig = nullptr; bool m_sqlServerConnected = false; int m_currentStageId = 0; QMap m_stageCache; diff --git a/quickevent/app/quickevent/plugins/Event/src/openeventdialog.cpp b/quickevent/app/quickevent/plugins/Event/src/openeventdialog.cpp index fa363e2f0..67e10264a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/openeventdialog.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/openeventdialog.cpp @@ -1,6 +1,6 @@ #include "openeventdialog.h" #include "ui_openeventdialog.h" -#include "eventconfig.h" +#include "appdbconfig.h" #include "eventdialogwidget.h" #include diff --git a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp index 308cba100..195b373ae 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp @@ -90,7 +90,7 @@ void EmmaClient::exportRadioCodesRacomTxt() QTextStream ts_codes(&f_splitcodes); int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if (is_relays) { qfs::QueryBuilder qb_classes; @@ -193,7 +193,7 @@ void EmmaClient::exportResultsIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".results.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -213,7 +213,7 @@ void EmmaClient::exportStartListIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".startlist.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() @@ -405,7 +405,7 @@ void EmmaClient::exportStartListRacomTxt() const QTextStream ts(&f); ts.setGenerateByteOrderMark(true); // BOM - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; qb.select2("runs", "startTimeMs, siId, competitorId, isrunning, leg, finishTimeMs") @@ -526,7 +526,7 @@ void EmmaClient::exportStartListRacomCsv() const #else ts.setCodec("UTF-8"); #endif - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); int current_stage = getPlugin()->currentStageId(); const QString separator(";"); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index f7650c86c..8d9b78bee 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -164,7 +164,7 @@ void OFeedClient::exportResultsIofXml3() m_resultsExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -184,7 +184,7 @@ void OFeedClient::exportStartListIofXml3(std::function on_success) m_startListExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() @@ -341,26 +341,26 @@ QString OFeedClient::hostUrl() const { int current_stage = getPlugin()->currentStageId(); QString key = serviceName().toLower() + ".hostUrl.E" + QString::number(current_stage); - return normalized_base_host_url(getPlugin()->eventConfig()->value(key, k_default_host_url).toString()); + return normalized_base_host_url(getPlugin()->appDbConfig()->value(key, k_default_host_url).toString()); } QString OFeedClient::eventId() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->eventConfig()->value(serviceName().toLower() + ".eventId.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->value(serviceName().toLower() + ".eventId.E" + QString::number(current_stage)).toString(); } QString OFeedClient::eventPassword() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->eventConfig()->value(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->value(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage)).toString(); } QString OFeedClient::changelogOrigin() const { int current_stage = getPlugin()->currentStageId(); QString key = serviceName().toLower() + ".changelogOrigin.E" + QString::number(current_stage); - return getPlugin()->eventConfig()->value(key, "START").toString(); + return getPlugin()->appDbConfig()->value(key, "START").toString(); } bool OFeedClient::isInsertFromOFeed = false; @@ -370,14 +370,14 @@ QDateTime OFeedClient::lastChangelogCall() { QString key = serviceName().toLower() + ".lastChangelogCall.E" + QString::number(current_stage); // Retrieve the stored value from the configuration - QVariant value = getPlugin()->eventConfig()->value(key); + QVariant value = getPlugin()->appDbConfig()->value(key); // Check if the value exists if (!value.isValid() || value.toString().isEmpty()) { // No valid value exists, set the initial value QDateTime initialValue = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch (1970-01-01T00:00:00Z) - getPlugin()->eventConfig()->setValue(key, initialValue.toString(Qt::ISODate)); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(key, initialValue.toString(Qt::ISODate)); + getPlugin()->appDbConfig()->save(serviceName().toLower()); // qDebug() << "No lastChangelogCall found. Setting initial value to:" << initialValue.toString(Qt::ISODate); return initialValue; } @@ -389,8 +389,8 @@ QDateTime OFeedClient::lastChangelogCall() { if (!lastChangelog.isValid()) { // If invalid, set the default value QDateTime initialValue = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch - getPlugin()->eventConfig()->setValue(key, initialValue.toString(Qt::ISODate)); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(key, initialValue.toString(Qt::ISODate)); + getPlugin()->appDbConfig()->save(serviceName().toLower()); // qDebug() << "Invalid lastChangelogCall found. Setting initial value to:" << initialValue.toString(Qt::ISODate); return initialValue; } @@ -402,14 +402,14 @@ bool OFeedClient::runXmlValidation() { int current_stage = getPlugin()->currentStageId(); QString key = serviceName().toLower() + ".runXmlValidation.E" + QString::number(current_stage); - return getPlugin()->eventConfig()->value(key, "true").toBool(); + return getPlugin()->appDbConfig()->value(key, "true").toBool(); } bool OFeedClient::runChangesProcessing () { int current_stage = getPlugin()->currentStageId(); QString key = serviceName().toLower() + ".runChangesProcessing.E" + QString::number(current_stage); - return getPlugin()->eventConfig()->value(key, "false").toBool(); + return getPlugin()->appDbConfig()->value(key, "false").toBool(); }; QString OFeedClient::receiptConfigKey(const QString &suffix) const @@ -420,12 +420,12 @@ QString OFeedClient::receiptConfigKey(const QString &suffix) const QVariant OFeedClient::receiptConfigValue(const QString &suffix, const QVariant &default_value) const { - return getPlugin()->eventConfig()->value(receiptConfigKey(suffix), default_value); + return getPlugin()->appDbConfig()->value(receiptConfigKey(suffix), default_value); } void OFeedClient::setReceiptConfigValue(const QString &suffix, const QVariant &value) { - auto *event_config = getPlugin()->eventConfig(); + auto *event_config = getPlugin()->appDbConfig(); event_config->setValue(receiptConfigKey(suffix), value); event_config->save(k_event_config_prefix); } @@ -532,7 +532,7 @@ QString OFeedClient::cachedEventImageFormat() const void OFeedClient::setCachedEventImage(const QByteArray &raw_data, const QString &format) { - auto *event_config = getPlugin()->eventConfig(); + auto *event_config = getPlugin()->appDbConfig(); event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageDataBase64")), QString::fromLatin1(raw_data.toBase64())); event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageFormat")), format.toLower()); event_config->save(k_event_config_prefix); @@ -540,7 +540,7 @@ void OFeedClient::setCachedEventImage(const QByteArray &raw_data, const QString void OFeedClient::clearCachedEventImage() { - auto *event_config = getPlugin()->eventConfig(); + auto *event_config = getPlugin()->appDbConfig(); event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageDataBase64")), QString()); event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageFormat")), QString()); event_config->save(k_event_config_prefix); @@ -661,64 +661,64 @@ void OFeedClient::refreshEventImageCache(std::function()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".hostUrl.E" + QString::number(current_stage), hostUrl); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".hostUrl.E" + QString::number(current_stage), hostUrl); + getPlugin()->appDbConfig()->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setEventId(QString eventId) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".eventId.E" + QString::number(current_stage), eventId); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".eventId.E" + QString::number(current_stage), eventId); + getPlugin()->appDbConfig()->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setEventPassword(QString eventPassword) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage), eventPassword); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage), eventPassword); + getPlugin()->appDbConfig()->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setChangelogOrigin(QString changelogOrigin) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".changelogOrigin.E" + QString::number(current_stage), changelogOrigin); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".changelogOrigin.E" + QString::number(current_stage), changelogOrigin); + getPlugin()->appDbConfig()->save(serviceName().toLower()); } void OFeedClient::setLastChangelogCall(QDateTime lastChangelogCall) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".lastChangelogCall.E" + QString::number(current_stage), lastChangelogCall); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".lastChangelogCall.E" + QString::number(current_stage), lastChangelogCall); + getPlugin()->appDbConfig()->save(serviceName().toLower()); } void OFeedClient::setRunXmlValidation(bool runXmlValidation) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".runXmlValidation.E" + QString::number(current_stage), runXmlValidation); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".runXmlValidation.E" + QString::number(current_stage), runXmlValidation); + getPlugin()->appDbConfig()->save(serviceName().toLower()); } void OFeedClient::setRunChangesProcessing(bool runChangesProcessing) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue(serviceName().toLower() + ".runChangesProcessing.E" + QString::number(current_stage), runChangesProcessing); - getPlugin()->eventConfig()->save(serviceName().toLower()); + getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".runChangesProcessing.E" + QString::number(current_stage), runChangesProcessing); + getPlugin()->appDbConfig()->save(serviceName().toLower()); } bool OFeedClient::introTourShowed() const { - return getPlugin()->eventConfig()->value( + return getPlugin()->appDbConfig()->value( serviceName().toLower() + QStringLiteral(".introTourShowed"), false).toBool(); } void OFeedClient::setIntroTourShowed(bool shown) { - auto *event_config = getPlugin()->eventConfig(); + auto *event_config = getPlugin()->appDbConfig(); event_config->setValue(serviceName().toLower() + QStringLiteral(".introTourShowed"), shown); event_config->save(serviceName().toLower()); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index 61c99f7fb..263348ff2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -60,7 +60,7 @@ void OResultsClient::stop() { void OResultsClient::exportResultsIofXml3() { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -72,7 +72,7 @@ void OResultsClient::exportResultsIofXml3() void OResultsClient::exportStartListIofXml3(std::function on_success) { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() @@ -169,27 +169,27 @@ void OResultsClient::onDbEventNotify(const QString &domain, int connection_id, c QString OResultsClient::apiKey() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->eventConfig()->value("oresults.apiKey.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->value("oresults.apiKey.E" + QString::number(current_stage)).toString(); } void OResultsClient::setApiKey(QString apiKey) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue("oresults.apiKey.E" + QString::number(current_stage), apiKey); - getPlugin()->eventConfig()->save("oresults"); + getPlugin()->appDbConfig()->setValue("oresults.apiKey.E" + QString::number(current_stage), apiKey); + getPlugin()->appDbConfig()->save("oresults"); } QString OResultsClient::eventName() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->eventConfig()->value("oresults.eventName.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->value("oresults.eventName.E" + QString::number(current_stage)).toString(); } void OResultsClient::setEventName(const QString &name) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->eventConfig()->setValue("oresults.eventName.E" + QString::number(current_stage), name); - getPlugin()->eventConfig()->save("oresults"); + getPlugin()->appDbConfig()->setValue("oresults.eventName.E" + QString::number(current_stage), name); + getPlugin()->appDbConfig()->save("oresults"); } void OResultsClient::sendCompetitorChange(QString xml) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp index 0f228fec4..657a67f12 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp @@ -139,7 +139,7 @@ void PunchingTestService::onTimerTick() // When enabled: 1/badCheckRate chance the runner checked too early (triggers bad-check). // When disabled: natural 1–2 minute window, no bad-check possible. int check_offset_sec; - if (auto cfg = event_plugin->eventConfig()->maximumCardCheckAdvanceSec(); cfg.has_value()) { + if (auto cfg = event_plugin->appDbConfig()->maximumCardCheckAdvanceSec(); cfg.has_value()) { int max_sec = cfg.value(); if (rng.bounded(static_cast(ss.badCheckRate())) == 0) { // Bad check: checked too early — [max+1, max*3] seconds before start diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index 73d5fa6d2..20da55eb2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -201,7 +201,7 @@ void QxClientService::postStartListIofXml3(QObject *context, std::function(); int current_stage = ep->currentStageId(); - bool is_relays = ep->eventConfig()->isRelays(); + bool is_relays = ep->appDbConfig()->isRelays(); if (!is_relays) { auto xml = getPlugin()->startListStageIofXml30(current_stage, quickevent::gui::ReportOptionsDialog::VacantsOption::OnlyRunners); uploadSpecFile(SpecFile::StartListIofXml3, xml.toUtf8(), context, call_back); @@ -212,7 +212,7 @@ void QxClientService::postRuns(QObject *context, std::function c { auto *ep = getPlugin(); int current_stage = ep->currentStageId(); - bool is_relays = ep->eventConfig()->isRelays(); + bool is_relays = ep->appDbConfig()->isRelays(); if (!is_relays) { auto runs = getPlugin()->qxExportRunsCsvJson(current_stage); auto json = qf::core::Utils::qvariantToJsonUtf8(runs, false); @@ -483,7 +483,7 @@ void QxClientService::pollQxChanges() EventInfo QxClientService::eventInfo() const { auto *event_plugin = getPlugin(); - auto *event_config = event_plugin->eventConfig(); + auto *event_config = event_plugin->appDbConfig(); EventInfo ei; ei.set_stage(event_plugin->currentStageId()); ei.set_stage_count(event_plugin->stageCount()); diff --git a/quickevent/app/quickevent/plugins/Event/src/stage.h b/quickevent/app/quickevent/plugins/Event/src/stagedata.h similarity index 100% rename from quickevent/app/quickevent/plugins/Event/src/stage.h rename to quickevent/app/quickevent/plugins/Event/src/stagedata.h diff --git a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp index f17a5a91e..89df0df9e 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp @@ -140,7 +140,7 @@ void OrisImporter::syncCurrentEventEntries(std::function success_callba { qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); //if(!qf::gui::dialogs::MessageBox::askYesNo(fwk, tr("All runners entries imported from Oris will be synchronized, manual changes will be lost!"))) - int oris_id = getPlugin()->eventConfig()->importId(); + int oris_id = getPlugin()->appDbConfig()->importId(); if(oris_id == 0) { qf::gui::dialogs::MessageBox::showError(fwk, tr("Cannot find Oris import ID.")); return; @@ -348,11 +348,11 @@ void OrisImporter::importEvent(int event_id, std::function success_call stage_count = 1; int sport_id = data.value(QStringLiteral("Sport")).toObject().value(QStringLiteral("ID")).toString().toInt(); int di = data.value(QStringLiteral("Discipline")).toObject().value(QStringLiteral("ID")).toString().toInt(); - auto discipline_id_opt = Event::EventConfig::disciplineFromInt(di);//.value_or(Event::EventConfig::Discipline::Classic); + auto discipline_id_opt = Event::AppDbConfig::disciplineFromInt(di);//.value_or(Event::EventConfig::Discipline::Classic); if (!discipline_id_opt.has_value()) { qfError() << "OrisImporter: Unknown discipline ID:" << di; } - auto discipline = discipline_id_opt.value_or(Event::EventConfig::Discipline::LongDistance); + auto discipline = discipline_id_opt.value_or(Event::AppDbConfig::Discipline::LongDistance); qfInfo() << "pocet etap:" << stage_count << "sport id:" << sport_id << "discipline id:" << di; QVariantMap ecfg; ecfg["stageCount"] = stage_count; @@ -369,7 +369,7 @@ void OrisImporter::importEvent(int event_id, std::function success_call if(!getPlugin()->createEvent(QString(), ecfg)) return; - bool is_relay = getPlugin()->eventConfig()->isRelays(); + bool is_relay = getPlugin()->appDbConfig()->isRelays(); //QString event_name = getPlugin()->eventName(); qfLogScope("importEvent"); qf::core::sql::Transaction transaction; @@ -467,7 +467,7 @@ const char KEY_ORIG_RUNS[] = "origRuns"; void OrisImporter::syncEventEntries(int event_id, std::function success_callback) { - if(getPlugin()->eventConfig()->isRelays()) { + if(getPlugin()->appDbConfig()->isRelays()) { syncRelaysEntries(event_id, success_callback); return; } @@ -769,7 +769,7 @@ void OrisImporter::syncEventEntries(int event_id, std::function success void OrisImporter::importRegistrations(std::function success_callback) { - int sport_id = getPlugin()->eventConfig()->sportId(); + int sport_id = getPlugin()->appDbConfig()->sportId(); int year = QDate::currentDate().addMonths(-2).year(); bool ok; @@ -898,7 +898,7 @@ void OrisImporter::getAndImportClub(const QString &club, const QString &key) void OrisImporter::importMissingOneTimeClubs() { auto *fwk = qf::gui::framework::MainWindow::frameWork(); - auto event_key = getPlugin()->eventConfig()->orisEventKey(); + auto event_key = getPlugin()->appDbConfig()->orisEventKey(); if (event_key.isEmpty()) { QMessageBox::warning(fwk,tr("Warning"),tr("For import one-time clubs, you need to fill ORIS Event Key in File->Event->Edit event")); return; @@ -925,7 +925,7 @@ void OrisImporter::importMissingOneTimeClubs() } } - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { // also from relays table q.exec("SELECT id, club FROM relays ORDER BY id", qf::core::Exception::Throw); while(q.next()) { diff --git a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp index 7f0181aea..ffd6c3e67 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp @@ -185,7 +185,7 @@ bool XmlImporter::importEntries(QXmlStreamReader &reader, const XmlCreators crea } } - Event::EventConfig *event_config = getPlugin()->eventConfig(); + Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); int selected_race = event_config->iofXmlRaceNumber(); // if entries has more races in (defined in Event), selected race // load from XML & insert to db int items_processed = 0; @@ -476,7 +476,7 @@ bool XmlImporter::importStartlist(QXmlStreamReader &reader, const XmlCreators cr bool XmlImporter::importClasses(QXmlStreamReader &reader, const XmlCreators creator) { // load data from XML - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); qf::core::sql::Transaction transaction; int items_processed = 0; while(reader.readNextStartElement()) { @@ -752,7 +752,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato QString race_name; int event_id = -1; QMap races; - auto discipline = Event::EventConfig::Discipline::LongDistance; + auto discipline = Event::AppDbConfig::Discipline::LongDistance; while(reader.readNextStartElement()) { if(reader.name().toString() == "Event") { @@ -764,9 +764,9 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato else if (reader.name().toString() == "Form") { auto form = reader.readElementText(); if (form == "Relay") - discipline = Event::EventConfig::Discipline::Relays; + discipline = Event::AppDbConfig::Discipline::Relays; else if (form == "Team") - discipline = Event::EventConfig::Discipline::Teams; + discipline = Event::AppDbConfig::Discipline::Teams; } else if (reader.name().toString() == "Race") { SRace race; @@ -814,7 +814,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato ecfg["place"] = QString(); ecfg["mainReferee"] = QString(); ecfg["director"] = QString(); - ecfg["sportId"] = static_cast(Event::EventConfig::Sport::OB); + ecfg["sportId"] = static_cast(Event::AppDbConfig::Sport::OB); ecfg["disciplineId"] = static_cast(discipline); ecfg["importId"] = event_id; ecfg["time"] = event_race.datetime.time(); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index d8546c457..bea63ec6c 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -63,7 +63,7 @@ QString eventConfigKey(const QString &suffix) QString configuredReceiptEventLinkUrl() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptEventLinkUrl"))).toString().trimmed(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptEventLinkUrl"))).toString().trimmed(); } QString defaultReceiptQrCodeCaption() @@ -73,7 +73,7 @@ QString defaultReceiptQrCodeCaption() QString configuredReceiptQrCodeCaption() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), defaultReceiptQrCodeCaption()).toString().trimmed(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), defaultReceiptQrCodeCaption()).toString().trimmed(); } QString receiptLinkWithCompetitorClass(const QString &base_url, const QString &class_name) @@ -100,28 +100,28 @@ QString receiptLinkWithCompetitorClass(const QString &base_url, const QString &c bool printReceiptImageEnabled() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventImage")), false).toBool(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventImage")), false).toBool(); } bool printReceiptQrCodeEnabled() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool(); } QString configuredReceiptImageBase64() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptImageDataBase64"))).toString(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageDataBase64"))).toString(); } QString configuredReceiptImageFormat() { - return getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptImageFormat")), QStringLiteral("png")).toString().trimmed().toLower(); + return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageFormat")), QStringLiteral("png")).toString().trimmed().toLower(); } int configuredReceiptImageHeightMm() { bool ok = false; - int image_height_mm = getPlugin()->eventConfig()->value(eventConfigKey(QStringLiteral("receiptImageHeightMm")), 18).toInt(&ok); + int image_height_mm = getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageHeightMm")), 18).toInt(&ok); if(!ok) return 18; if(image_height_mm < 10) @@ -403,7 +403,7 @@ QVariantMap ReceiptsPlugin::receiptTablesData(int card_id) { qfLogFuncFrame() << card_id; QF_TIME_SCOPE("receiptTablesData()"); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QVariantMap ret; quickevent::core::si::ReadCard read_card = getPlugin()->readCard(card_id); quickevent::core::si::CheckedCard checked_card = getPlugin()->checkCard(read_card); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp index 57300219f..d300c782e 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp @@ -389,7 +389,7 @@ void ReceiptsSettingsPage::load() } auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->eventConfig(); + auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); m_stageId = qMax(event_config->currentStageId(), 1); ui->chkPrintReceiptQrCode->setChecked(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool()); @@ -427,7 +427,7 @@ void ReceiptsSettingsPage::save() auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->eventConfig(); + auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); event_config->setValue(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), ui->chkPrintReceiptQrCode->isChecked()); event_config->setValue(eventConfigKey(QStringLiteral("receiptEventLinkUrl")), ui->edReceiptQrCodeBaseUrl->text().trimmed()); @@ -445,7 +445,7 @@ QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->eventConfig(); + auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); const int stage_id = qMax(m_stageId, 1); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp index 79bad5063..2ec1a7eb1 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp @@ -117,7 +117,7 @@ void ReceiptsWidget::reset() void ReceiptsWidget::reload() { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); int current_stage = currentStageId(); qfs::QueryBuilder qb; qb.select2("cards", "id, siId, printerConnectionId") diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index a34241215..61b23b4e2 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -80,7 +80,7 @@ void RelaysPlugin::onInstalled() return; auto *ep = getPlugin(); bool event_open = ep->isEventOpen(); - auto *cfg = event_open ? ep->eventConfig() : nullptr; + auto *cfg = event_open ? ep->appDbConfig() : nullptr; bool is_relays = cfg && cfg->isRelays(); scw->setPartVisible(featureId(), is_relays); if(event_open && !is_relays && m_partWidget && m_partWidget->isActive()) @@ -188,7 +188,7 @@ qf::core::utils::TreeTable RelaysPlugin::nLegsResultsTable(const QString &where_ { qfLogFuncFrame() << "leg cnt:" << leg_count; qf::core::utils::TreeTable tt; - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); tt.appendColumn("className", QMetaType(QMetaType::QString)); qfs::QueryBuilder qb; @@ -513,7 +513,7 @@ QVariant RelaysPlugin::startListByClassesTableData(const QString &class_filter, //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; @@ -579,7 +579,7 @@ QString RelaysPlugin::resultsIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - Event::EventConfig *event_config = getPlugin()->eventConfig(); + Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); bool is_iof_race = event_config->isIofRace(); //auto tt_classes = getPlugin()->nLegsResultsTable("classes.name='D105'", 999, 999999, false); auto tt_classes = getPlugin()->nLegsResultsTable(QString(), 999, 999999, false); @@ -863,7 +863,7 @@ QString RelaysPlugin::startListIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - Event::EventConfig *event_config = getPlugin()->eventConfig(); + Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); bool is_iof_race = event_config->isIofRace(); qf::core::utils::TreeTable tt_classes = startListByClassesTableData(QString(), false); QVariantList start_list{ diff --git a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp index f128fb23e..13d9d3981 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp @@ -392,7 +392,7 @@ QVariant RelaysWidget::startListByClubsTableData(bool with_vacants) //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-hsh.qml b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-hsh.qml index 33e45d9fe..e6a85f9d8 100644 --- a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-hsh.qml +++ b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-hsh.qml @@ -127,7 +127,7 @@ Report { halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold //text: root.eventConfig.event.mainReferee - text: root.eventConfig.mainReferee() + text: root.eventConfig.mainReferee } Para { width: "%" @@ -152,7 +152,7 @@ Report { width: "%" halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold - text: root.eventConfig.director() + text: root.eventConfig.director } Para { width: "%" diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index b5e3ccbe7..c9fc790e5 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -168,7 +168,7 @@ int RunsPlugin::courseForRun(int run_id) { // TODO: implementation should be dependend on event type and exposed to QML // see: CardCheck pattern - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(is_relays) { return courseForRun_Relays(run_id); } @@ -758,7 +758,7 @@ qf::core::utils::TreeTable RunsPlugin::stageResultsTable(int stage_id, const QSt model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { @@ -959,7 +959,7 @@ QString RunsPlugin::resultsIofXml30Stage(int stage_id) { QDateTime stage_start_date_time = getPlugin()->stageStartDateTime(stage_id);//.toTimeSpec(Qt::OffsetFromUTC); qf::core::utils::TreeTable tt1 = stageResultsTable(stage_id, QString(), 0, false, true); - Event::EventConfig *event_config = getPlugin()->eventConfig(); + Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); bool is_iof_race = event_config->isIofRace(); int iof_xml_race_number = event_config->iofXmlRaceNumber(); @@ -1178,7 +1178,7 @@ void RunsPlugin::writeCSOSHeader(QTextStream &ts) const auto *evp = getPlugin(); int stage_id = selectedStageId(); QDateTime start_dt = evp->stageStartDateTime(stage_id); - Event::EventConfig *ec = evp->eventConfig(); + Event::AppDbConfig *ec = evp->appDbConfig(); static constexpr int HWIDTH = -19; ts << make_width("Kod zavodu", HWIDTH) << ": " << ec->importId() << "\r\n"; ts << make_width("Nazev zavodu", HWIDTH) << ": " << ec->eventName() << "\r\n"; @@ -1294,7 +1294,7 @@ bool RunsPlugin::exportResultsCsosOverall(int stage_count, const QString &file_n qf::core::sql::QueryBuilder RunsPlugin::runsQuery(int stage_id, int class_id, bool show_offrace) { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); qfs::QueryBuilder qb; qb.select2("runs", "*") .select2("classes", "name") @@ -1428,7 +1428,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesTable(const QString &wher m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("courses.numberOfControls", QMetaType(QMetaType::Int)); tt.appendColumn("courses.startNumber", QMetaType(QMetaType::Int)); @@ -1564,7 +1564,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsTable(const quickevent::gui m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -1633,7 +1633,7 @@ qf::core::utils::TreeTable RunsPlugin::startListStartersTable(const QString &whe qf::core::utils::TreeTable tt; tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("competitors.registration", QMetaType(QMetaType::QString)); @@ -1658,7 +1658,7 @@ qf::core::utils::TreeTable RunsPlugin::startListStartersTable(const QString &whe for(int j=0; j()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); QVector start00_epoch_sec; for(int stage_id = 1; stage_id <= stages_count; stage_id++) { @@ -1781,7 +1781,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsNStagesTable(const int stag m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", sel_stage_id); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -2046,7 +2046,7 @@ void RunsPlugin::report_resultsAwards() return; QVariantMap props; - props["eventConfig"] = QVariant::fromValue(getPlugin()->eventConfig()); + props["eventConfig"] = getPlugin()->appDbConfig()->eventConfig().toVariantMap(); auto tt = stageResultsTable(opts.value("stageId").toInt(), QString(), opts.value("numPlaces").toInt()); qf::gui::reports::ReportViewWidget::showReport(fwk , findReportFile(rep_path) @@ -2070,7 +2070,7 @@ void RunsPlugin::report_resultsNStages() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); @@ -2097,7 +2097,7 @@ void RunsPlugin::report_resultsNStagesSpeaker() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); @@ -2122,7 +2122,7 @@ void RunsPlugin::report_nStagesAwards() return; QVariantMap props; - props["eventConfig"] = QVariant::fromValue(getPlugin()->eventConfig()); + props["eventConfig"] = getPlugin()->appDbConfig()->eventConfig().toVariantMap(); auto tt = nstagesResultsTable(QString(), opts.value("stageId").toInt(), opts.value("numPlaces").toInt()); qf::gui::reports::ReportViewWidget::showReport(fwk , findReportFile(rep_path) @@ -2473,7 +2473,7 @@ void RunsPlugin::export_resultsHtmlNStages() qff::MainWindow *fwk = qff::MainWindow::frameWork(); auto tt1 = nstagesResultsTable(sql_where_expr, stage_id, num_places, exclude_disq); - tt1.setValue("event", getPlugin()->eventConfig()->value("event")); + tt1.setValue("event", getPlugin()->appDbConfig()->value("event")); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QString file_dir = QDir::tempPath() + "/quickevent/overall-e" + QString::number(stage_id); @@ -2738,7 +2738,7 @@ QString RunsPlugin::getClubAbbrFromName(QString name) QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::ReportOptionsDialog::VacantsOption vacants_option) { QDateTime start00 = getPlugin()->stageStartDateTime(stage_id); - Event::EventConfig *event_config = getPlugin()->eventConfig(); + Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); //console.debug("print_vacants", print_vacants); auto tt1 = startListClassesTable("", vacants_option, quickevent::gui::ReportOptionsDialog::StartTimeFormat::RelativeToClassStart); bool is_iof_race = event_config->isIofRace(); @@ -2814,9 +2814,9 @@ QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::Report for(int j=0; j()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); m_classDef.load(m_highlightedClassId, m_stageId, is_relays); //qfInfo() << "interval:" << m_classInterval << "first:" << m_classStartFirst << "last:" << m_classStartLast; } @@ -50,7 +50,7 @@ void RunsTableItemDelegate::paintBackground(QPainter *painter, const QStyleOptio auto *tm = qobject_cast(v->tableModel()); if(!(m && tm)) return; - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(m_highlightedClassId > 0) { if(is_relays) { // check that start time in classes is the same diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 858272e09..dca0591aa 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -62,7 +62,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const //qfInfo() << flgs; } if(index.column() == col_course_id) { - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { flgs &= ~Qt::ItemIsEditable; } } @@ -72,7 +72,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const QVariant RunsTableModel::data(const QModelIndex &index, int role) const { if(index.column() == col_course_id && role == Qt::DisplayRole) { - if (getPlugin()->eventConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->isRelays()) { auto start_number = value(index.row(), "startNumber").toInt(); auto leg = value(index.row(), "runs.leg").toInt(); return QStringLiteral("%1.%2").arg(start_number).arg(leg); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index c40d4b517..2fc27fa80 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -58,7 +58,7 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : ui->tblRuns->setItemDelegate(m_runsTableItemDelegate); auto *event_plugin = getPlugin(); connect(event_plugin, &EventPlugin::eventOpenChanged, this, [this, event_plugin](bool is_open) { - if (is_open && !event_plugin->eventConfig()->isRelays() && !m_courseItemDelegate) { + if (is_open && !event_plugin->appDbConfig()->isRelays() && !m_courseItemDelegate) { m_courseItemDelegate = new CourseItemDelegate(ui->tblRuns); m_courseItemDelegate->setNullText(tr("Implicit")); ui->tblRuns->setItemDelegateForColumn(RunsTableModel::col_course_id, m_courseItemDelegate); @@ -173,7 +173,7 @@ void RunsTableWidget::reload(int stage_id, int class_id, bool show_offrace, cons ui->lblClassStart->setText(class_start_time_min >= 0? QString::number(class_start_time_min): "---"); ui->lblClassInterval->setText(class_start_interval_min >= 0? QString::number(class_start_interval_min): "---"); } - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if (!is_relays && m_courseItemDelegate) { m_courseItemDelegate->setCourses(definedCourses()); } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 1ec92f1fb..c54a841cf 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -73,7 +73,7 @@ RunsWidget::RunsWidget(QWidget *parent) : ui->cbxDrawMethod->clear(); if(!getPlugin()->isEventOpen()) return; - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(is_relays) { ui->cbxDrawMethod->addItem(tr("Relays first leg"), static_cast(DrawMethod::RelaysFirstLeg)); } @@ -119,7 +119,7 @@ void RunsWidget::reset() } /// Note: You should use QAction::setVisible() to change the visibility of the widget. /// Using QWidget::setVisible(), QWidget::show() and QWidget::hide() does not work. - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); m_toolbarActionLabelLeg->setVisible(is_relays); m_toolbarActionComboLeg->setVisible(is_relays); //qfWarning() << "is relays:" << is_relays << "legs visible:" << m_cbxLeg->isVisible(); @@ -131,7 +131,7 @@ void RunsWidget::reset() void RunsWidget::reload() { qfLogFuncFrame(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); int stage_id = is_relays? m_cbxLeg->currentData().toInt(): selectedStageId(); int class_id = m_cbxClasses->currentData().toInt(); ui->wRunsTableWidget->reload(stage_id, class_id, m_chkShowOffRace->isChecked()); @@ -425,7 +425,7 @@ void RunsWidget::settleDownInPartWidget(::PartWidget *part_widget) auto updateMenuEnabled = [part_widget]() { auto *ep = getPlugin(); - auto *cfg = ep->isEventOpen() ? ep->eventConfig() : nullptr; + auto *cfg = ep->isEventOpen() ? ep->appDbConfig() : nullptr; bool enabled = !(cfg && cfg->isRelays()); for(const char *path : {"print", "import", "export"}) { if(auto *a = part_widget->menuBar()->actionForPath(path)) { @@ -508,7 +508,7 @@ QList RunsWidget::runsForClass(int stage_id, int class_id, const QString &e QList RunsWidget::competitorsForClass(int stage_id, int class_id, const QString &extra_where_condition, const QString &order_by) { qfLogFuncFrame() << "stage:" << stage_id << "class:" << class_id; - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QList ret; qf::core::sql::QueryBuilder qb; qb.select2("runs", "id, competitorId") @@ -690,7 +690,7 @@ void RunsWidget::saveLockedForDrawing(int class_id, int stage_id, bool is_locked void RunsWidget::onDrawClicked() { qfLogFuncFrame(); - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); Event::StageData stage_data = getPlugin()->stageData(stage_id); @@ -724,7 +724,7 @@ void RunsWidget::onDrawClicked() try { qf::core::sql::Transaction transaction; for(int class_id : class_ids) { - int handicap_length_ms = getPlugin()->eventConfig()->handicapLength() * 60 * 1000; + int handicap_length_ms = getPlugin()->appDbConfig()->handicapLength() * 60 * 1000; QVector handicap_times; qf::core::sql::QueryBuilder qb; qb.select2("classdefs", "startTimeMin, startIntervalMin, vacantsBefore, vacantEvery, vacantsAfter, mapCount") @@ -772,7 +772,7 @@ void RunsWidget::onDrawClicked() runners_draw_ids = group1 + group2 + group3; } else if(draw_method == DrawMethod::Handicap) { - int stage_count = getPlugin()->eventConfig()->stageCount(); + int stage_count = getPlugin()->appDbConfig()->stageCount(); qf::core::utils::Table results = getPlugin()->nstagesClassResultsTable(stage_count - 1, class_id); QMap competitor_to_run; for(const auto &cc : competitorsForClass(stage_count, class_id)) @@ -1057,7 +1057,7 @@ void RunsWidget::export_results_stage_csv() if(fn.isEmpty()) return; - bool is_iof_race = getPlugin()->eventConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); QFileInfo fi(fn); exp.setOutDir(fi.absolutePath()); @@ -1140,7 +1140,7 @@ void RunsWidget::report_competitorsStatistics() m.setQueryBuilder(qb); m.reload(); qfu::TreeTable tt = m.toTreeTable(); - tt.setValue("event", getPlugin()->eventConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->value("event")); for (int stage_id = 1; stage_id <= stage_cnt; ++stage_id) { QString prefix = "e" + QString::number(stage_id) + "_"; QString col_runs_count = prefix + "runCount"; @@ -1210,7 +1210,7 @@ void RunsWidget::editCompetitor_helper(const QVariant &id, int mode, int siid) QF_ASSERT(doc != nullptr, "Document is null!", return); if(mode == qfm::DataDocument::ModeInsert) { if(siid == 0) { - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); if(!is_relays) { int class_id = m_cbxClasses->currentData().toInt(); if(class_id > 0) diff --git a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp index 5f006eac1..82def3a67 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp @@ -73,7 +73,7 @@ bool ResultsExporter::exportResults() const if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::IofXml3)) { int current_stage = getPlugin()->currentStageId(); QString file_name = ss.exportDir() + "/" + getPlugin()->eventName() + "." + Event::RESULTS_IOFXML3_FILE; - bool is_relays = getPlugin()->eventConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -94,7 +94,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSVMulti)) { - bool is_iof_race = getPlugin()->eventConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) @@ -106,7 +106,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSV)) { - bool is_iof_race = getPlugin()->eventConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) From 7ae2467fd2a009eb85c2080369868d82a4693e9e Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 10:40:01 +0200 Subject: [PATCH 69/83] Switch to EventConfig for isRelays --- .../CardReader/src/cardreaderplugin.cpp | 4 +- .../CardReader/src/cardreaderwidget.cpp | 2 +- .../plugins/Classes/src/classesplugin.cpp | 2 +- .../plugins/Classes/src/classeswidget.cpp | 8 +- .../plugins/Classes/src/editcourseswidget.cpp | 4 +- .../Competitors/src/competitorwidget.cpp | 10 +- .../plugins/Event/src/appdbconfig.cpp | 116 +----------------- .../plugins/Event/src/appdbconfig.h | 54 +++----- .../plugins/Event/src/eventconfig.cpp | 34 ++++- .../plugins/Event/src/eventconfig.h | 19 +++ .../plugins/Event/src/eventdialogwidget.cpp | 12 +- .../plugins/Event/src/eventplugin.cpp | 10 +- .../plugins/Event/src/services/emmaclient.cpp | 10 +- .../Event/src/services/ofeed/ofeedclient.cpp | 4 +- .../Event/src/services/oresultsclient.cpp | 4 +- .../Event/src/services/qx/qxclientservice.cpp | 10 +- .../plugins/Oris/src/orisimporter.cpp | 19 ++- .../plugins/Oris/src/xmlimporter.cpp | 14 +-- .../plugins/Receipts/src/receiptsplugin.cpp | 2 +- .../Receipts/src/receiptssettingspage.cpp | 4 +- .../plugins/Receipts/src/receiptswidget.cpp | 2 +- .../plugins/Relays/src/relaysplugin.cpp | 14 +-- .../plugins/Runs/src/runsplugin.cpp | 43 ++++--- .../Runs/src/runstableitemdelegate.cpp | 4 +- .../plugins/Runs/src/runstablemodel.cpp | 4 +- .../plugins/Runs/src/runstablewidget.cpp | 4 +- .../plugins/Runs/src/runswidget.cpp | 20 +-- .../Runs/src/services/resultsexporter.cpp | 6 +- 28 files changed, 173 insertions(+), 266 deletions(-) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp index e357ccf63..684ff258c 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp @@ -115,7 +115,7 @@ int CardReaderPlugin::findRunId(int si_id, int si_finish_time, QString *err_msg) *err_msg = QString(); int si_finish_time_msec = getPlugin()->msecToStageStartAM(si_finish_time); qf::core::sql::Query q; - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(is_relays) { q.exec("SELECT id, leg, startTimeMs, finishTimeMs FROM runs WHERE siId=" QF_IARG(si_id) " AND isRunning" @@ -551,7 +551,7 @@ void CardReaderPlugin::setStartTime(int relay_id, int leg, int start_time) { bool CardReaderPlugin::processCardToRunAssignment(int card_id, int run_id) { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(is_relays) { qf::core::sql::Query q; q.execThrow("SELECT relayId, leg, startTimeMs FROM runs WHERE id=" + QString::number(run_id)); diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index 44a07f59e..a894ef549 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -488,7 +488,7 @@ void CardReaderWidget::reset() void CardReaderWidget::reload() { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); //QString driver_name = m_cardsModel->sqlConnection().driverName(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp index d21993ff0..3ea47c97e 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp @@ -93,7 +93,7 @@ void ClassesPlugin::createCourses(int stage_id, const QList &co { qfLogFuncFrame(); try { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); qf::core::sql::Transaction transaction(qf::core::sql::Connection::forName()); qf::core::sql::Query q; if (delete_current) diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index 5fe2dd7a1..6eacf9ba7 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -405,7 +405,7 @@ static QString normalize_course_name(const QString &course_name) void ClassesWidget::import_ocad_txt() { - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -493,7 +493,7 @@ void ClassesWidget::import_ocad_v8() lines << QString::fromUtf8(ba).trimmed(); } try { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QMap defined_courses_map; for(const auto &line : lines) { // [classname];coursename;[relay.leg];lenght_km;climb;S1;dist_1;code_1[;dist_n;code_n];dist_finish;F1 @@ -586,7 +586,7 @@ static QString dump_element(const QDomElement &el) void ClassesWidget::import_ocad_iofxml_2() { - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -735,7 +735,7 @@ void ClassesWidget::import_ocad_iofxml_3() coursedef.addClass(class_name); } } - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { QDomNodeList ndlst = xdoc.elementsByTagName(QStringLiteral("TeamCourseAssignment")); QMap relay_courses; for (int i = 0; i < ndlst.count(); ++i) { diff --git a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp index bda7861bc..9de417d7d 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp @@ -94,7 +94,7 @@ EditCoursesWidget::EditCoursesWidget(int stage_id, QWidget *parent) QHeaderView *hh = ui->tblCourses->horizontalHeader(); hh->setSectionHidden(CoursesTableModel::Col_runCount, true); - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { ui->cbRunnersCount->setVisible(false); } else { connect (ui->cbRunnersCount,&QCheckBox::clicked,this,&EditCoursesWidget::updateQuery); @@ -135,7 +135,7 @@ void EditCoursesWidget::updateQuery() qfs::QueryBuilder qb; - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { qb.select2("courses", "*") .select("0 AS run_count") .select(code_list_query + "AS code_list") diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp index b593dca31..085c276f6 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp @@ -155,7 +155,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : ui(new Ui::CompetitorWidget) { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); setPersistentSettingsId("CompetitorWidget"); ui->setupUi(this); @@ -205,7 +205,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : connect(ui->tblRuns, &qfw::TableView::editCellRequest, this, [this](QModelIndex index) { auto col = index.column(); if(col == CompetitorRunsModel::col_runs_startTimeMs) { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if (!is_relays) { saveData(); auto row = ui->tblRuns->tableRow(); @@ -477,7 +477,7 @@ void CompetitorWidget::onRegistrationSelected(const QVariantMap &values) qfDebug() << "\t" << s << "->" << values.value(s); doc->setValue(s, values.value(s)); } - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(!is_relays) { // if no class is set, guess class from registration if(ui->cbxClass->currentText().isEmpty()) { @@ -517,7 +517,7 @@ void CompetitorWidget::save() bool CompetitorWidget::saveData() { try { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); auto *doc = qobject_cast(dataController()->document()); if(!is_relays && doc->value(QStringLiteral("classId")).toInt() == 0) { qf::gui::dialogs::MessageBox::showWarning(this, tr("Class should be entered.")); @@ -537,7 +537,7 @@ bool CompetitorWidget::acceptDialogDone(int result) { if (result == QDialog::Accepted) { auto *doc = qobject_cast(dataController()->document()); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if (doc->mode() != Competitors::CompetitorDocument::ModeDelete) { if (doc->value("classId").toInt() == 0 && !is_relays) { QMessageBox::information(this, tr("Competitor form check"), tr("Class must be set.")); diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index f418e473b..4db9fca69 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -19,27 +19,6 @@ namespace { const auto EVENT_NAME = QStringLiteral("event.name"); } -std::optional AppDbConfig::disciplineFromInt(int i) -{ - switch (static_cast(i)) { - case Discipline::LongDistance: return Discipline::LongDistance; - case Discipline::ShortDistance: return Discipline::ShortDistance; - case Discipline::Sprint: return Discipline::Sprint; - case Discipline::Relays: return Discipline::Relays; - case Discipline::Teams: return Discipline::Teams; - case Discipline::NightRace: return Discipline::NightRace; - case Discipline::SprintRelays: return Discipline::SprintRelays; - case Discipline::UltralongDistance: return Discipline::UltralongDistance; - case Discipline::FreeOrder: return Discipline::FreeOrder; - case Discipline::KnocOutSprint: return Discipline::KnocOutSprint; - case Discipline::TempO: return Discipline::TempO; - case Discipline::MultiStages: return Discipline::MultiStages; - case Discipline::MassStart: return Discipline::MassStart; - case Discipline::Indoor: return Discipline::Indoor; - } - return {}; -} - QVariant AppDbConfig::value(const QStringList &path, const QVariant &default_value) const { //QF_ASSERT(knownKeys().contains(key), "Key " + key + " is not known key!", return QVariant()); @@ -180,44 +159,7 @@ QVariantMap AppDbConfig::setValue_helper(const QVariantMap &m, const QStringList return ret; } -int AppDbConfig::stageCount() const -{ - return value(QStringLiteral("event.stageCount")).toInt(); -} - -int AppDbConfig::currentStageId() const -{ - int ret = value(QStringLiteral("event.currentStageId")).toInt(); - if(ret == 0) - ret = 1; - return ret; -} -int AppDbConfig::sportId() const -{ - return value(QStringLiteral("event.sportId")).toInt(); -} - -AppDbConfig::Discipline AppDbConfig::discipline() const -{ - auto di = value(QStringLiteral("event.disciplineId")).toInt(); - return disciplineFromInt(di).value_or(Discipline::LongDistance); -} - -int AppDbConfig::importId() const -{ - return value(QStringLiteral("event.importId")).toInt(); -} - -int AppDbConfig::handicapLength() const -{ - return value(QStringLiteral("event.handicapLength")).toInt(); -} - -QString AppDbConfig::eventName() const -{ - return value(QStringLiteral("event.name")).toString(); -} // namespace { // auto const API_KEY_CONFIG_PATH = QStringLiteral("event.apiKey"); @@ -236,40 +178,7 @@ QString AppDbConfig::eventName() const // } // } -QString AppDbConfig::eventPlace() const -{ - return value(QStringLiteral("event.place")).toString(); -} -QString AppDbConfig::director() const -{ - return value(QStringLiteral("event.director")).toString(); -} - -QString AppDbConfig::mainReferee() const -{ - return value(QStringLiteral("event.mainReferee")).toString(); -} - -QDateTime AppDbConfig::eventDateTime() const -{ - QDateTime dt; - QVariant v = value(QStringLiteral("event.dateTime")); - if(v.isValid()) { - dt = v.toDateTime(); - } - else { - QVariant v = value(QStringLiteral("event.date")); - dt.setDate(v.toDate()); - v = value(QStringLiteral("event.time")); - QTime tm = v.toTime(); - if(tm.isValid()) - dt.setTime(tm); - else - dt = dt.addSecs(10 * 60 * 60); // start at 10:00 if not specified - } - return dt; -} int AppDbConfig::dbVersion() const { @@ -278,35 +187,12 @@ int AppDbConfig::dbVersion() const std::optional AppDbConfig::maximumCardCheckAdvanceSec() const { - if(auto sec = value(QStringLiteral("event.cardChechCheckTimeSec")).toInt(); sec > 0) + if(auto sec = eventConfig().cardCheckTimeSec; sec > 0) return sec; return {}; } -bool AppDbConfig::isOneTenthSecResults() const -{ - return static_cast(value(QStringLiteral("oneTenthSecResults")).toInt()); -} - -bool AppDbConfig::isIofRace() const -{ - return value(QStringLiteral("event.iofRace")).toInt() != 0; -} - -int AppDbConfig::iofXmlRaceNumber() const -{ - return value(QStringLiteral("event.iofXmlRaceNumber")).toInt(); -} - -QString AppDbConfig::orisEventKey() const -{ - return value(QStringLiteral("event.orisEventKey")).toString(); -} - EventConfig AppDbConfig::eventConfig() const { return EventConfig::fromVariantMap(value(QStringLiteral("event")).toMap()); } - - - diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index e68587fd1..19f33564d 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -8,29 +8,22 @@ #include #include +#include namespace Event { +struct QxConfig +{ + QString apiToken; +}; + +struct OResultsConfig +{ + QMap apiKeys; +}; + class AppDbConfig { -public: - enum class Sport {OB = 1, LOB, MTBO, TRAIL}; - enum class Discipline {LongDistance = 1, - ShortDistance = 2, - Sprint = 3, - UltralongDistance = 4, - Relays = 5, - Teams = 6, - FreeOrder = 7, - NightRace = 9, - TempO = 11, - MultiStages = 13, - MassStart = 14, - SprintRelays = 15, - KnocOutSprint = 16, - Indoor = 19, - }; - static std::optional disciplineFromInt(int i); public: explicit AppDbConfig() = default; public: @@ -44,29 +37,11 @@ class AppDbConfig void load(); void save(const QString &path_to_save = QString()); - int stageCount() const; - int currentStageId() const; - int sportId() const; - Discipline discipline() const; - int importId() const; - int handicapLength() const; - bool isHandicap() const {return handicapLength() > 0;} - bool isRelays() const { - return discipline() == Discipline::Relays - || discipline() == Discipline::Teams - || discipline() == Discipline::SprintRelays; - } - bool isIofRace() const; - int iofXmlRaceNumber() const; - QString eventName() const; - QString eventPlace() const; - QString director() const; - QString mainReferee() const; - QDateTime eventDateTime() const; + bool isHandicap() const {return eventConfig().handicapLength > 0;} + + int dbVersion() const; std::optional maximumCardCheckAdvanceSec() const; - bool isOneTenthSecResults() const; - QString orisEventKey() const; EventConfig eventConfig() const; private: void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); @@ -76,4 +51,3 @@ class AppDbConfig }; } - diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 683383a88..1b615c51b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -2,7 +2,30 @@ #include -Event::EventConfig Event::EventConfig::fromVariantMap(const QVariantMap &values) +namespace Event { + +std::optional EventConfig::disciplineFromInt(int i) +{ + switch (static_cast(i)) { + case Discipline::LongDistance: return Discipline::LongDistance; + case Discipline::ShortDistance: return Discipline::ShortDistance; + case Discipline::Sprint: return Discipline::Sprint; + case Discipline::Relays: return Discipline::Relays; + case Discipline::Teams: return Discipline::Teams; + case Discipline::NightRace: return Discipline::NightRace; + case Discipline::SprintRelays: return Discipline::SprintRelays; + case Discipline::UltralongDistance: return Discipline::UltralongDistance; + case Discipline::FreeOrder: return Discipline::FreeOrder; + case Discipline::KnocOutSprint: return Discipline::KnocOutSprint; + case Discipline::TempO: return Discipline::TempO; + case Discipline::MultiStages: return Discipline::MultiStages; + case Discipline::MassStart: return Discipline::MassStart; + case Discipline::Indoor: return Discipline::Indoor; + } + return {}; +} + +EventConfig EventConfig::fromVariantMap(const QVariantMap &values) { EventConfig data; data.stageCount = values.value("stageCount", 1).toInt(); @@ -42,7 +65,12 @@ Event::EventConfig Event::EventConfig::fromVariantMap(const QVariantMap &values) return data; } -QVariantMap Event::EventConfig::toVariantMap() const +bool EventConfig::isRelays() const +{ + return disciplineId == 5 || disciplineId == 6 || disciplineId == 15; +} + +QVariantMap EventConfig::toVariantMap() const { QVariantMap values; values.insert("stageCount", stageCount); @@ -75,3 +103,5 @@ QVariantMap Event::EventConfig::toVariantMap() const values.insert("currentStageId", currentStageId); return values; } + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index 83edd2735..a8bf089ba 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -12,8 +12,27 @@ namespace Event { struct EventConfig { + enum class Sport {OB = 1, LOB, MTBO, TRAIL}; + enum class Discipline {LongDistance = 1, + ShortDistance = 2, + Sprint = 3, + UltralongDistance = 4, + Relays = 5, + Teams = 6, + FreeOrder = 7, + NightRace = 9, + TempO = 11, + MultiStages = 13, + MassStart = 14, + SprintRelays = 15, + KnocOutSprint = 16, + Indoor = 19, + }; + static std::optional disciplineFromInt(int i); + static EventConfig fromVariantMap(const QVariantMap &values); QVariantMap toVariantMap() const; + bool isRelays() const; int stageCount = 1; QMap stages; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index e77837923..4d67deacb 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -30,11 +30,11 @@ EventDialogWidget::EventDialogWidget(QWidget *parent) : connect(ui->ed_orisRace, &QAbstractButton::toggled, ui->frameOrisRace, &QWidget::setVisible); ui->frameOrisRace->hide(); - using S = Event::AppDbConfig::Sport; + using S = Event::EventConfig::Sport; for (S sport : {S::OB, S::LOB, S::MTBO, S::TRAIL}) ui->cbxSportId->addItem(sportName(static_cast(sport)), static_cast(sport)); - using D = Event::AppDbConfig::Discipline; + using D = Event::EventConfig::Discipline; for (D disc : {D::LongDistance, D::ShortDistance, D::UltralongDistance, D::Sprint, D::Relays, D::Teams, D::FreeOrder, D::NightRace, D::SprintRelays, D::KnocOutSprint, D::TempO, D::MultiStages, D::Indoor, D::MassStart}) { @@ -172,10 +172,10 @@ Event::EventConfig EventDialogWidget::saveParams() data.director = ui->ed_director->text(); data.handicapLength = ui->ed_handicapLength->value(); data.sportId = ui->cbxSportId->currentData().isNull() - ? static_cast(Event::AppDbConfig::Sport::OB) + ? static_cast(Event::EventConfig::Sport::OB) : ui->cbxSportId->currentData().toInt(); data.disciplineId = ui->cbxDisciplineId->currentIndex() <= 0 - ? static_cast(Event::AppDbConfig::Discipline::LongDistance) + ? static_cast(Event::EventConfig::Discipline::LongDistance) : ui->cbxDisciplineId->currentData().toInt(); data.importId = ui->ed_orisImportId->text().toInt(); data.orisEventKey = ui->ed_orisEventKey->text(); @@ -188,7 +188,7 @@ Event::EventConfig EventDialogWidget::saveParams() QString EventDialogWidget::disciplineName(int disc_id) { - using D = Event::AppDbConfig::Discipline; + using D = Event::EventConfig::Discipline; switch (static_cast(disc_id)) { case D::LongDistance: return tr("Long distance"); case D::ShortDistance: return tr("Middle distance"); @@ -210,7 +210,7 @@ QString EventDialogWidget::disciplineName(int disc_id) QString EventDialogWidget::sportName(int sport_id) { - using S = Event::AppDbConfig::Sport; + using S = Event::EventConfig::Sport; switch (static_cast(sport_id)) { case S::OB: return QStringLiteral("OB"); case S::LOB: return QStringLiteral("LOB"); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 66803ad35..54a9af78f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -233,7 +233,7 @@ int EventPlugin::stageCount() { if(eventName().isEmpty()) return 0; - return appDbConfig()->stageCount(); + return appDbConfig()->eventConfig().stageCount; } void EventPlugin::setCurrentStageId(int stage_id) @@ -501,14 +501,14 @@ void EventPlugin::loadCurrentStageId() { int stage_id = 1; if(!eventName().isEmpty()) { - stage_id = appDbConfig()->currentStageId(); + stage_id = appDbConfig()->eventConfig().currentStageId; } setCurrentStageId(stage_id); } void EventPlugin::saveCurrentStageId(int current_stage) { - if(current_stage != appDbConfig()->currentStageId()) { + if(current_stage != appDbConfig()->eventConfig().currentStageId) { appDbConfig()->setValue("event.currentStageId", current_stage); appDbConfig()->save("event"); } @@ -590,7 +590,7 @@ QString EventPlugin::classNameById(int class_id) QString EventPlugin::shvApiEventId() const { - return eventName() + "-" + QString::number(m_eventConfig->importId()); + return eventName() + "-" + QString::number(m_eventConfig->eventConfig().importId); } QString EventPlugin::createApiKey(int length) @@ -950,7 +950,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even event_config.setValue("event", new_params.toVariantMap()); int stage_count = new_params.stageCount; if(stage_count == 0) - stage_count = event_config.stageCount(); + stage_count = event_config.eventConfig().stageCount; qfInfo() << "createEvent, stage_count:" << stage_count; QF_ASSERT(stage_count > 0, "Stage count have to be greater than 0", return false); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp index 195b373ae..299781a49 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp @@ -90,7 +90,7 @@ void EmmaClient::exportRadioCodesRacomTxt() QTextStream ts_codes(&f_splitcodes); int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if (is_relays) { qfs::QueryBuilder qb_classes; @@ -193,7 +193,7 @@ void EmmaClient::exportResultsIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".results.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -213,7 +213,7 @@ void EmmaClient::exportStartListIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".startlist.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() @@ -405,7 +405,7 @@ void EmmaClient::exportStartListRacomTxt() const QTextStream ts(&f); ts.setGenerateByteOrderMark(true); // BOM - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; qb.select2("runs", "startTimeMs, siId, competitorId, isrunning, leg, finishTimeMs") @@ -526,7 +526,7 @@ void EmmaClient::exportStartListRacomCsv() const #else ts.setCodec("UTF-8"); #endif - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int current_stage = getPlugin()->currentStageId(); const QString separator(";"); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 8d9b78bee..104344df9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -164,7 +164,7 @@ void OFeedClient::exportResultsIofXml3() m_resultsExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -184,7 +184,7 @@ void OFeedClient::exportStartListIofXml3(std::function on_success) m_startListExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index 263348ff2..e11f705f0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -60,7 +60,7 @@ void OResultsClient::stop() { void OResultsClient::exportResultsIofXml3() { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -72,7 +72,7 @@ void OResultsClient::exportResultsIofXml3() void OResultsClient::exportStartListIofXml3(std::function on_success) { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index 20da55eb2..cff9a3c0f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -201,7 +201,7 @@ void QxClientService::postStartListIofXml3(QObject *context, std::function(); int current_stage = ep->currentStageId(); - bool is_relays = ep->appDbConfig()->isRelays(); + bool is_relays = ep->appDbConfig()->eventConfig().isRelays(); if (!is_relays) { auto xml = getPlugin()->startListStageIofXml30(current_stage, quickevent::gui::ReportOptionsDialog::VacantsOption::OnlyRunners); uploadSpecFile(SpecFile::StartListIofXml3, xml.toUtf8(), context, call_back); @@ -212,7 +212,7 @@ void QxClientService::postRuns(QObject *context, std::function c { auto *ep = getPlugin(); int current_stage = ep->currentStageId(); - bool is_relays = ep->appDbConfig()->isRelays(); + bool is_relays = ep->appDbConfig()->eventConfig().isRelays(); if (!is_relays) { auto runs = getPlugin()->qxExportRunsCsvJson(current_stage); auto json = qf::core::Utils::qvariantToJsonUtf8(runs, false); @@ -483,12 +483,12 @@ void QxClientService::pollQxChanges() EventInfo QxClientService::eventInfo() const { auto *event_plugin = getPlugin(); - auto *event_config = event_plugin->appDbConfig(); + const auto event_config = event_plugin->appDbConfig()->eventConfig(); EventInfo ei; ei.set_stage(event_plugin->currentStageId()); ei.set_stage_count(event_plugin->stageCount()); - ei.set_name(event_config->eventName()); - ei.set_place(event_config->eventPlace()); + ei.set_name(event_config.name); + ei.set_place(event_config.place); ei.set_start_time(event_plugin->stageStartDateTime(event_plugin->currentStageId()).toString(Qt::ISODate)); qf::core::sql::Query q; diff --git a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp index 89df0df9e..cff49f1d9 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp @@ -1,4 +1,5 @@ #include "chooseoriseventdialog.h" +#include "plugins/Event/src/eventconfig.h" #include "orisimporter.h" #include @@ -140,7 +141,7 @@ void OrisImporter::syncCurrentEventEntries(std::function success_callba { qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); //if(!qf::gui::dialogs::MessageBox::askYesNo(fwk, tr("All runners entries imported from Oris will be synchronized, manual changes will be lost!"))) - int oris_id = getPlugin()->appDbConfig()->importId(); + int oris_id = getPlugin()->appDbConfig()->eventConfig().importId; if(oris_id == 0) { qf::gui::dialogs::MessageBox::showError(fwk, tr("Cannot find Oris import ID.")); return; @@ -348,11 +349,11 @@ void OrisImporter::importEvent(int event_id, std::function success_call stage_count = 1; int sport_id = data.value(QStringLiteral("Sport")).toObject().value(QStringLiteral("ID")).toString().toInt(); int di = data.value(QStringLiteral("Discipline")).toObject().value(QStringLiteral("ID")).toString().toInt(); - auto discipline_id_opt = Event::AppDbConfig::disciplineFromInt(di);//.value_or(Event::EventConfig::Discipline::Classic); + auto discipline_id_opt = Event::EventConfig::disciplineFromInt(di);//.value_or(Event::EventConfig::Discipline::Classic); if (!discipline_id_opt.has_value()) { qfError() << "OrisImporter: Unknown discipline ID:" << di; } - auto discipline = discipline_id_opt.value_or(Event::AppDbConfig::Discipline::LongDistance); + auto discipline = discipline_id_opt.value_or(Event::EventConfig::Discipline::LongDistance); qfInfo() << "pocet etap:" << stage_count << "sport id:" << sport_id << "discipline id:" << di; QVariantMap ecfg; ecfg["stageCount"] = stage_count; @@ -369,7 +370,7 @@ void OrisImporter::importEvent(int event_id, std::function success_call if(!getPlugin()->createEvent(QString(), ecfg)) return; - bool is_relay = getPlugin()->appDbConfig()->isRelays(); + bool is_relay = getPlugin()->appDbConfig()->eventConfig().isRelays(); //QString event_name = getPlugin()->eventName(); qfLogScope("importEvent"); qf::core::sql::Transaction transaction; @@ -467,7 +468,7 @@ const char KEY_ORIG_RUNS[] = "origRuns"; void OrisImporter::syncEventEntries(int event_id, std::function success_callback) { - if(getPlugin()->appDbConfig()->isRelays()) { + if(getPlugin()->appDbConfig()->eventConfig().isRelays()) { syncRelaysEntries(event_id, success_callback); return; } @@ -769,7 +770,7 @@ void OrisImporter::syncEventEntries(int event_id, std::function success void OrisImporter::importRegistrations(std::function success_callback) { - int sport_id = getPlugin()->appDbConfig()->sportId(); + int sport_id = getPlugin()->appDbConfig()->eventConfig().sportId; int year = QDate::currentDate().addMonths(-2).year(); bool ok; @@ -898,7 +899,7 @@ void OrisImporter::getAndImportClub(const QString &club, const QString &key) void OrisImporter::importMissingOneTimeClubs() { auto *fwk = qf::gui::framework::MainWindow::frameWork(); - auto event_key = getPlugin()->appDbConfig()->orisEventKey(); + auto event_key = getPlugin()->appDbConfig()->eventConfig().orisEventKey; if (event_key.isEmpty()) { QMessageBox::warning(fwk,tr("Warning"),tr("For import one-time clubs, you need to fill ORIS Event Key in File->Event->Edit event")); return; @@ -925,7 +926,7 @@ void OrisImporter::importMissingOneTimeClubs() } } - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { // also from relays table q.exec("SELECT id, club FROM relays ORDER BY id", qf::core::Exception::Throw); while(q.next()) { @@ -959,5 +960,3 @@ void OrisImporter::importMissingOneTimeClubs() qf::gui::dialogs::MessageBox::showException(fwk, e); } } - - diff --git a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp index ffd6c3e67..8b96e4455 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp @@ -185,8 +185,8 @@ bool XmlImporter::importEntries(QXmlStreamReader &reader, const XmlCreators crea } } - Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); - int selected_race = event_config->iofXmlRaceNumber(); // if entries has more races in (defined in Event), selected race + const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + int selected_race = event_config.iofXmlRaceNumber; // if entries has more races in (defined in Event), selected race // load from XML & insert to db int items_processed = 0; int relays_processed = 0; @@ -476,7 +476,7 @@ bool XmlImporter::importStartlist(QXmlStreamReader &reader, const XmlCreators cr bool XmlImporter::importClasses(QXmlStreamReader &reader, const XmlCreators creator) { // load data from XML - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); qf::core::sql::Transaction transaction; int items_processed = 0; while(reader.readNextStartElement()) { @@ -752,7 +752,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato QString race_name; int event_id = -1; QMap races; - auto discipline = Event::AppDbConfig::Discipline::LongDistance; + auto discipline = Event::EventConfig::Discipline::LongDistance; while(reader.readNextStartElement()) { if(reader.name().toString() == "Event") { @@ -764,9 +764,9 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato else if (reader.name().toString() == "Form") { auto form = reader.readElementText(); if (form == "Relay") - discipline = Event::AppDbConfig::Discipline::Relays; + discipline = Event::EventConfig::Discipline::Relays; else if (form == "Team") - discipline = Event::AppDbConfig::Discipline::Teams; + discipline = Event::EventConfig::Discipline::Teams; } else if (reader.name().toString() == "Race") { SRace race; @@ -814,7 +814,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato ecfg["place"] = QString(); ecfg["mainReferee"] = QString(); ecfg["director"] = QString(); - ecfg["sportId"] = static_cast(Event::AppDbConfig::Sport::OB); + ecfg["sportId"] = static_cast(Event::EventConfig::Sport::OB); ecfg["disciplineId"] = static_cast(discipline); ecfg["importId"] = event_id; ecfg["time"] = event_race.datetime.time(); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index bea63ec6c..d9616ca87 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -403,7 +403,7 @@ QVariantMap ReceiptsPlugin::receiptTablesData(int card_id) { qfLogFuncFrame() << card_id; QF_TIME_SCOPE("receiptTablesData()"); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QVariantMap ret; quickevent::core::si::ReadCard read_card = getPlugin()->readCard(card_id); quickevent::core::si::CheckedCard checked_card = getPlugin()->checkCard(read_card); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp index d300c782e..03945fde0 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp @@ -391,7 +391,7 @@ void ReceiptsSettingsPage::load() Q_ASSERT(event_plugin); auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); - m_stageId = qMax(event_config->currentStageId(), 1); + m_stageId = qMax(event_config->eventConfig().currentStageId, 1); ui->chkPrintReceiptQrCode->setChecked(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool()); ui->edReceiptQrCodeBaseUrl->setText(event_config->value(eventConfigKey(QStringLiteral("receiptEventLinkUrl"))).toString().trimmed()); ui->edReceiptQrCodeCaption->setText(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), defaultReceiptQrCodeCaption()).toString().trimmed()); @@ -514,7 +514,7 @@ QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const int stage_start_time_ms = event_plugin->stageStartMsec(stage_id); if(stage_start_time_ms <= 0) { - QTime tm = event_config->eventDateTime().time(); + QTime tm = event_config->eventConfig().time; stage_start_time_ms = tm.isValid() ? tm.msecsSinceStartOfDay() : (10 * 60 * 60 * 1000); } diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp index 2ec1a7eb1..22eecda98 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp @@ -117,7 +117,7 @@ void ReceiptsWidget::reset() void ReceiptsWidget::reload() { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int current_stage = currentStageId(); qfs::QueryBuilder qb; qb.select2("cards", "id, siId, printerConnectionId") diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index 61b23b4e2..ae4d7c104 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -26,6 +26,7 @@ #include #include +#include #include @@ -81,7 +82,7 @@ void RelaysPlugin::onInstalled() auto *ep = getPlugin(); bool event_open = ep->isEventOpen(); auto *cfg = event_open ? ep->appDbConfig() : nullptr; - bool is_relays = cfg && cfg->isRelays(); + bool is_relays = cfg && cfg->eventConfig().isRelays(); scw->setPartVisible(featureId(), is_relays); if(event_open && !is_relays && m_partWidget && m_partWidget->isActive()) scw->setActivePart(QStringLiteral("Runs"), true); @@ -248,8 +249,7 @@ qf::core::utils::TreeTable RelaysPlugin::nLegsClassResultsTable(int class_id, in qfError() << "Leg count not defined for class id:" << class_id; return qf::core::utils::TreeTable(); } - if(leg_count > max_leg) - leg_count = max_leg; + leg_count = std::min(leg_count, max_leg); QList relays; //QStringList relay_ids; @@ -579,8 +579,8 @@ QString RelaysPlugin::resultsIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); - bool is_iof_race = event_config->isIofRace(); + const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + bool is_iof_race = event_config.iofRace; //auto tt_classes = getPlugin()->nLegsResultsTable("classes.name='D105'", 999, 999999, false); auto tt_classes = getPlugin()->nLegsResultsTable(QString(), 999, 999999, false); QVariantList result_list{ @@ -863,8 +863,8 @@ QString RelaysPlugin::startListIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); - bool is_iof_race = event_config->isIofRace(); + const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + bool is_iof_race = event_config.iofRace; qf::core::utils::TreeTable tt_classes = startListByClassesTableData(QString(), false); QVariantList start_list{ "StartList", diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index c9fc790e5..89dc63992 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -43,6 +43,7 @@ #include #include +#include #include namespace qff = qf::gui::framework; @@ -168,7 +169,7 @@ int RunsPlugin::courseForRun(int run_id) { // TODO: implementation should be dependend on event type and exposed to QML // see: CardCheck pattern - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(is_relays) { return courseForRun_Relays(run_id); } @@ -959,9 +960,9 @@ QString RunsPlugin::resultsIofXml30Stage(int stage_id) { QDateTime stage_start_date_time = getPlugin()->stageStartDateTime(stage_id);//.toTimeSpec(Qt::OffsetFromUTC); qf::core::utils::TreeTable tt1 = stageResultsTable(stage_id, QString(), 0, false, true); - Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); - bool is_iof_race = event_config->isIofRace(); - int iof_xml_race_number = event_config->iofXmlRaceNumber(); + const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + bool is_iof_race = event_config.iofRace; + int iof_xml_race_number = event_config.iofXmlRaceNumber; QVariantList result_list{ "ResultList", @@ -1009,7 +1010,7 @@ QString RunsPlugin::resultsIofXml30Stage(int stage_id) event_lst.insert(event_lst.count(), QVariantList{"Race", QVariantList{"RaceNumber", iof_xml_race_number}, - QVariantList{"Name", event_config->eventName()} + QVariantList{"Name", event_config.name} } ); } @@ -1178,17 +1179,17 @@ void RunsPlugin::writeCSOSHeader(QTextStream &ts) const auto *evp = getPlugin(); int stage_id = selectedStageId(); QDateTime start_dt = evp->stageStartDateTime(stage_id); - Event::AppDbConfig *ec = evp->appDbConfig(); + const auto ec = evp->appDbConfig()->eventConfig(); static constexpr int HWIDTH = -19; - ts << make_width("Kod zavodu", HWIDTH) << ": " << ec->importId() << "\r\n"; - ts << make_width("Nazev zavodu", HWIDTH) << ": " << ec->eventName() << "\r\n"; + ts << make_width("Kod zavodu", HWIDTH) << ": " << ec.importId << "\r\n"; + ts << make_width("Nazev zavodu", HWIDTH) << ": " << ec.name << "\r\n"; ts << make_width("Zarazeni do soutezi", HWIDTH) << ": " << "" << "\r\n"; ts << make_width("Datum konani", HWIDTH) << ": " << start_dt.toString(Qt::ISODate) << "\r\n"; - ts << make_width("Misto konani", HWIDTH) << ": " << ec->eventPlace() << "\r\n"; + ts << make_width("Misto konani", HWIDTH) << ": " << ec.place << "\r\n"; ts << make_width("Poradatel", HWIDTH) << ": " << "" << "\r\n"; ts << make_width("Mapa", HWIDTH) << ": " << "" << "\r\n"; - ts << make_width("Reditel zavodu", HWIDTH) << ": " << ec->director() << "\r\n"; - ts << make_width("Hlavni rozhodci", HWIDTH) << ": " << ec->mainReferee() << "\r\n"; + ts << make_width("Reditel zavodu", HWIDTH) << ": " << ec.director << "\r\n"; + ts << make_width("Hlavni rozhodci", HWIDTH) << ": " << ec.mainReferee << "\r\n"; ts << make_width("Stavitel trati", HWIDTH) << ": " << "" << "\r\n"; ts << make_width("JURY", HWIDTH) << ": " << "" << "\r\n"; ts << make_width("Protokol", HWIDTH) << ": " << "\r\n"; @@ -1294,7 +1295,7 @@ bool RunsPlugin::exportResultsCsosOverall(int stage_count, const QString &file_n qf::core::sql::QueryBuilder RunsPlugin::runsQuery(int stage_id, int class_id, bool show_offrace) { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); qfs::QueryBuilder qb; qb.select2("runs", "*") .select2("classes", "name") @@ -1527,9 +1528,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesTable(const QString &wher int mapCount = tt_row.value(QStringLiteral("mapCount")).toInt(); int cnt = tt2.rowCount(); int total_vacants = mapCount - cnt; - if (total_vacants < 0) { - total_vacants = 0; - } + total_vacants = std::max(total_vacants, 0); for (int k = 0; k < total_vacants; ++k) { int ix = tt2.appendRow(); qf::core::utils::TreeTableRow tt2_row = tt2.row(ix); @@ -2738,11 +2737,11 @@ QString RunsPlugin::getClubAbbrFromName(QString name) QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::ReportOptionsDialog::VacantsOption vacants_option) { QDateTime start00 = getPlugin()->stageStartDateTime(stage_id); - Event::AppDbConfig *event_config = getPlugin()->appDbConfig(); + const auto event_config = getPlugin()->appDbConfig()->eventConfig(); //console.debug("print_vacants", print_vacants); auto tt1 = startListClassesTable("", vacants_option, quickevent::gui::ReportOptionsDialog::StartTimeFormat::RelativeToClassStart); - bool is_iof_race = event_config->isIofRace(); - int iof_xml_race_number = event_config->iofXmlRaceNumber(); + bool is_iof_race = event_config.iofRace; + int iof_xml_race_number = event_config.iofXmlRaceNumber; QVariantList xml_root{"StartList" , QVariantMap { @@ -2756,7 +2755,7 @@ QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::Report QVariantMap event = tt1.value("event").toMap(); QVariantList xml_event{"Event"}; append_list(xml_event, QVariantList{"Id", QVariantMap{{"type", "ORIS"}}, event.value("importId")}); - append_list(xml_event, QVariantList{"Name", event_config->eventName()}); + append_list(xml_event, QVariantList{"Name", event_config.name}); append_list(xml_event, QVariantList{"StartTime", QVariantList{"Date", start00.date().toString(Qt::ISODate)}, @@ -2786,11 +2785,11 @@ QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::Report } ); - if (iof_xml_race_number != 0) { - append_list(xml_event, + if(iof_xml_race_number != 0) { + xml_event.insert(xml_event.count(), QVariantList{"Race", QVariantList{"RaceNumber", iof_xml_race_number}, - QVariantList{"Name", event_config->eventName()} + QVariantList{"Name", event_config.name} } ); } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp index 86ec6fcbd..79a5a090f 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp @@ -33,7 +33,7 @@ void RunsTableItemDelegate::setHighlightedClassId(int class_id, int stage_id) void RunsTableItemDelegate::reloadHighlightedClassId() { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); m_classDef.load(m_highlightedClassId, m_stageId, is_relays); //qfInfo() << "interval:" << m_classInterval << "first:" << m_classStartFirst << "last:" << m_classStartLast; } @@ -50,7 +50,7 @@ void RunsTableItemDelegate::paintBackground(QPainter *painter, const QStyleOptio auto *tm = qobject_cast(v->tableModel()); if(!(m && tm)) return; - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(m_highlightedClassId > 0) { if(is_relays) { // check that start time in classes is the same diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index dca0591aa..0b1beadca 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -62,7 +62,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const //qfInfo() << flgs; } if(index.column() == col_course_id) { - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { flgs &= ~Qt::ItemIsEditable; } } @@ -72,7 +72,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const QVariant RunsTableModel::data(const QModelIndex &index, int role) const { if(index.column() == col_course_id && role == Qt::DisplayRole) { - if (getPlugin()->appDbConfig()->isRelays()) { + if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { auto start_number = value(index.row(), "startNumber").toInt(); auto leg = value(index.row(), "runs.leg").toInt(); return QStringLiteral("%1.%2").arg(start_number).arg(leg); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 2fc27fa80..ccd1940f0 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -58,7 +58,7 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : ui->tblRuns->setItemDelegate(m_runsTableItemDelegate); auto *event_plugin = getPlugin(); connect(event_plugin, &EventPlugin::eventOpenChanged, this, [this, event_plugin](bool is_open) { - if (is_open && !event_plugin->appDbConfig()->isRelays() && !m_courseItemDelegate) { + if (is_open && !event_plugin->appDbConfig()->eventConfig().isRelays() && !m_courseItemDelegate) { m_courseItemDelegate = new CourseItemDelegate(ui->tblRuns); m_courseItemDelegate->setNullText(tr("Implicit")); ui->tblRuns->setItemDelegateForColumn(RunsTableModel::col_course_id, m_courseItemDelegate); @@ -173,7 +173,7 @@ void RunsTableWidget::reload(int stage_id, int class_id, bool show_offrace, cons ui->lblClassStart->setText(class_start_time_min >= 0? QString::number(class_start_time_min): "---"); ui->lblClassInterval->setText(class_start_interval_min >= 0? QString::number(class_start_interval_min): "---"); } - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if (!is_relays && m_courseItemDelegate) { m_courseItemDelegate->setCourses(definedCourses()); } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index c54a841cf..e8859ab9e 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -73,7 +73,7 @@ RunsWidget::RunsWidget(QWidget *parent) : ui->cbxDrawMethod->clear(); if(!getPlugin()->isEventOpen()) return; - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(is_relays) { ui->cbxDrawMethod->addItem(tr("Relays first leg"), static_cast(DrawMethod::RelaysFirstLeg)); } @@ -119,7 +119,7 @@ void RunsWidget::reset() } /// Note: You should use QAction::setVisible() to change the visibility of the widget. /// Using QWidget::setVisible(), QWidget::show() and QWidget::hide() does not work. - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); m_toolbarActionLabelLeg->setVisible(is_relays); m_toolbarActionComboLeg->setVisible(is_relays); //qfWarning() << "is relays:" << is_relays << "legs visible:" << m_cbxLeg->isVisible(); @@ -131,7 +131,7 @@ void RunsWidget::reset() void RunsWidget::reload() { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int stage_id = is_relays? m_cbxLeg->currentData().toInt(): selectedStageId(); int class_id = m_cbxClasses->currentData().toInt(); ui->wRunsTableWidget->reload(stage_id, class_id, m_chkShowOffRace->isChecked()); @@ -426,7 +426,7 @@ void RunsWidget::settleDownInPartWidget(::PartWidget *part_widget) auto updateMenuEnabled = [part_widget]() { auto *ep = getPlugin(); auto *cfg = ep->isEventOpen() ? ep->appDbConfig() : nullptr; - bool enabled = !(cfg && cfg->isRelays()); + bool enabled = !(cfg && cfg->eventConfig().isRelays()); for(const char *path : {"print", "import", "export"}) { if(auto *a = part_widget->menuBar()->actionForPath(path)) { a->setEnabled(enabled); @@ -508,7 +508,7 @@ QList RunsWidget::runsForClass(int stage_id, int class_id, const QString &e QList RunsWidget::competitorsForClass(int stage_id, int class_id, const QString &extra_where_condition, const QString &order_by) { qfLogFuncFrame() << "stage:" << stage_id << "class:" << class_id; - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QList ret; qf::core::sql::QueryBuilder qb; qb.select2("runs", "id, competitorId") @@ -690,7 +690,7 @@ void RunsWidget::saveLockedForDrawing(int class_id, int stage_id, bool is_locked void RunsWidget::onDrawClicked() { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); Event::StageData stage_data = getPlugin()->stageData(stage_id); @@ -724,7 +724,7 @@ void RunsWidget::onDrawClicked() try { qf::core::sql::Transaction transaction; for(int class_id : class_ids) { - int handicap_length_ms = getPlugin()->appDbConfig()->handicapLength() * 60 * 1000; + int handicap_length_ms = getPlugin()->appDbConfig()->eventConfig().handicapLength * 60 * 1000; QVector handicap_times; qf::core::sql::QueryBuilder qb; qb.select2("classdefs", "startTimeMin, startIntervalMin, vacantsBefore, vacantEvery, vacantsAfter, mapCount") @@ -772,7 +772,7 @@ void RunsWidget::onDrawClicked() runners_draw_ids = group1 + group2 + group3; } else if(draw_method == DrawMethod::Handicap) { - int stage_count = getPlugin()->appDbConfig()->stageCount(); + int stage_count = getPlugin()->appDbConfig()->eventConfig().stageCount; qf::core::utils::Table results = getPlugin()->nstagesClassResultsTable(stage_count - 1, class_id); QMap competitor_to_run; for(const auto &cc : competitorsForClass(stage_count, class_id)) @@ -1057,7 +1057,7 @@ void RunsWidget::export_results_stage_csv() if(fn.isEmpty()) return; - bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); QFileInfo fi(fn); exp.setOutDir(fi.absolutePath()); @@ -1210,7 +1210,7 @@ void RunsWidget::editCompetitor_helper(const QVariant &id, int mode, int siid) QF_ASSERT(doc != nullptr, "Document is null!", return); if(mode == qfm::DataDocument::ModeInsert) { if(siid == 0) { - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); if(!is_relays) { int class_id = m_cbxClasses->currentData().toInt(); if(class_id > 0) diff --git a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp index 82def3a67..26c94bb7f 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp @@ -73,7 +73,7 @@ bool ResultsExporter::exportResults() const if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::IofXml3)) { int current_stage = getPlugin()->currentStageId(); QString file_name = ss.exportDir() + "/" + getPlugin()->eventName() + "." + Event::RESULTS_IOFXML3_FILE; - bool is_relays = getPlugin()->appDbConfig()->isRelays(); + bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -94,7 +94,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSVMulti)) { - bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) @@ -106,7 +106,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSV)) { - bool is_iof_race = getPlugin()->appDbConfig()->isIofRace(); + bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) From e86ea9f92c911586fad41f276c6585b41dc4e750 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 10:55:49 +0200 Subject: [PATCH 70/83] Add receipts and OFeed config support --- .../plugins/Event/src/appdbconfig.cpp | 65 +++++++++++++++++++ .../plugins/Event/src/appdbconfig.h | 6 ++ .../plugins/Event/src/ofeedconfig.h | 21 ++++++ .../plugins/Event/src/receiptsconfig.h | 18 +++++ 4 files changed, 110 insertions(+) create mode 100644 quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h create mode 100644 quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 4db9fca69..6d4b16eba 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -196,3 +196,68 @@ EventConfig AppDbConfig::eventConfig() const { return EventConfig::fromVariantMap(value(QStringLiteral("event")).toMap()); } + +ReceiptsConfig AppDbConfig::receiptsConfig(int stage_id) const +{ + const QString e = QStringLiteral(".E") + QString::number(stage_id); + ReceiptsConfig cfg; + cfg.printQrCode = value(QStringLiteral("event.receiptPrintEventQrCode") + e, false).toBool(); + cfg.linkUrl = value(QStringLiteral("event.receiptEventLinkUrl") + e).toString().trimmed(); + const QString caption = value(QStringLiteral("event.receiptPrintEventQrCodeCaption") + e).toString().trimmed(); + cfg.qrCodeCaption = caption.isEmpty() ? QStringLiteral("Live Results") : caption; + cfg.printImage = value(QStringLiteral("event.receiptPrintEventImage") + e, false).toBool(); + const int h = value(QStringLiteral("event.receiptImageHeightMm") + e, 18).toInt(); + cfg.imageHeightMm = (h < 10) ? 10 : (h > 60) ? 60 : h; + cfg.imageBase64 = value(QStringLiteral("event.receiptImageDataBase64") + e).toString(); + const QString fmt = value(QStringLiteral("event.receiptImageFormat") + e).toString().trimmed().toLower(); + cfg.imageFormat = fmt.isEmpty() ? QStringLiteral("png") : fmt; + return cfg; +} + +void AppDbConfig::setReceiptsConfig(int stage_id, const ReceiptsConfig &cfg) +{ + const QString e = QStringLiteral(".E") + QString::number(stage_id); + setValue(QStringLiteral("event.receiptPrintEventQrCode") + e, cfg.printQrCode); + setValue(QStringLiteral("event.receiptEventLinkUrl") + e, cfg.linkUrl); + setValue(QStringLiteral("event.receiptPrintEventQrCodeCaption") + e, cfg.qrCodeCaption); + setValue(QStringLiteral("event.receiptPrintEventImage") + e, cfg.printImage); + setValue(QStringLiteral("event.receiptImageHeightMm") + e, cfg.imageHeightMm); + setValue(QStringLiteral("event.receiptImageDataBase64") + e, cfg.imageBase64); + setValue(QStringLiteral("event.receiptImageFormat") + e, cfg.imageFormat); +} + +OFeedConfig AppDbConfig::ofeedConfig(int stage_id) const +{ + const QString prefix = QStringLiteral("ofeed."); + const QString e = QStringLiteral(".E") + QString::number(stage_id); + OFeedConfig cfg; + const QString default_host = QStringLiteral("https://api.orienteerfeed.com"); + cfg.hostUrl = value(prefix + QStringLiteral("hostUrl") + e, default_host).toString(); + cfg.eventId = value(prefix + QStringLiteral("eventId") + e).toString(); + cfg.eventPassword = value(prefix + QStringLiteral("eventPassword") + e).toString(); + const QString origin = value(prefix + QStringLiteral("changelogOrigin") + e).toString(); + cfg.changelogOrigin = origin.isEmpty() ? QStringLiteral("START") : origin; + const QString lcc = value(prefix + QStringLiteral("lastChangelogCall") + e).toString(); + cfg.lastChangelogCall = lcc.isEmpty() ? QDateTime::fromSecsSinceEpoch(0) + : QDateTime::fromString(lcc, Qt::ISODate); + if (!cfg.lastChangelogCall.isValid()) + cfg.lastChangelogCall = QDateTime::fromSecsSinceEpoch(0); + cfg.runXmlValidation = value(prefix + QStringLiteral("runXmlValidation") + e, true).toBool(); + cfg.runChangesProcessing = value(prefix + QStringLiteral("runChangesProcessing") + e, false).toBool(); + cfg.introTourShowed = value(prefix + QStringLiteral("introTourShowed"), false).toBool(); + return cfg; +} + +void AppDbConfig::setOfeedConfig(int stage_id, const OFeedConfig &cfg) +{ + const QString prefix = QStringLiteral("ofeed."); + const QString e = QStringLiteral(".E") + QString::number(stage_id); + setValue(prefix + QStringLiteral("hostUrl") + e, cfg.hostUrl); + setValue(prefix + QStringLiteral("eventId") + e, cfg.eventId); + setValue(prefix + QStringLiteral("eventPassword") + e, cfg.eventPassword); + setValue(prefix + QStringLiteral("changelogOrigin") + e, cfg.changelogOrigin); + setValue(prefix + QStringLiteral("lastChangelogCall") + e, cfg.lastChangelogCall.toString(Qt::ISODate)); + setValue(prefix + QStringLiteral("runXmlValidation") + e, cfg.runXmlValidation); + setValue(prefix + QStringLiteral("runChangesProcessing") + e, cfg.runChangesProcessing); + setValue(prefix + QStringLiteral("introTourShowed"), cfg.introTourShowed); +} diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index 19f33564d..e3c30b0d0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -1,6 +1,8 @@ #pragma once #include "eventconfig.h" +#include "receiptsconfig.h" +#include "ofeedconfig.h" #include #include @@ -43,6 +45,10 @@ class AppDbConfig int dbVersion() const; std::optional maximumCardCheckAdvanceSec() const; EventConfig eventConfig() const; + ReceiptsConfig receiptsConfig(int stage_id) const; + void setReceiptsConfig(int stage_id, const ReceiptsConfig &config); + OFeedConfig ofeedConfig(int stage_id) const; + void setOfeedConfig(int stage_id, const OFeedConfig &config); private: void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); diff --git a/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h b/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h new file mode 100644 index 000000000..8b22a5c3d --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace Event { + +struct OFeedConfig +{ + QString hostUrl; // Default "https://api.orienteerfeed.com" applied by AppDbConfig::ofeedConfig() + QString eventId; + QString eventPassword; + QString changelogOrigin; // Default "START" applied by AppDbConfig::ofeedConfig() + QDateTime lastChangelogCall; // Default QDateTime::fromSecsSinceEpoch(0) applied by AppDbConfig::ofeedConfig() + bool runXmlValidation = true; + bool runChangesProcessing = false; + // Non-stage-specific field, stored as ofeed.introTourShowed + bool introTourShowed = false; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h b/quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h new file mode 100644 index 000000000..a9d4e48e5 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace Event { + +struct ReceiptsConfig +{ + bool printQrCode = false; + QString linkUrl; + QString qrCodeCaption; // Default "Live Results" applied by AppDbConfig::receiptsConfig() + bool printImage = false; + int imageHeightMm = 18; // Clamped to [10, 60] + QString imageBase64; + QString imageFormat; // Default "png" applied by AppDbConfig::receiptsConfig() +}; + +} From 79ef02d49ad7af28f0e9b4ab833ee72c87581dfe Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 19:03:28 +0200 Subject: [PATCH 71/83] Switch to per-stage OFeed config in Event --- .../plugins/Event/src/appdbconfig.h | 10 +- .../plugins/Event/src/eventplugin.cpp | 2 +- .../Event/src/services/ofeed/ofeedclient.cpp | 109 +++++++++--------- .../Event/src/services/ofeed/ofeedclient.h | 6 +- 4 files changed, 62 insertions(+), 65 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index e3c30b0d0..a0677014b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -29,11 +29,6 @@ class AppDbConfig public: explicit AppDbConfig() = default; public: - QVariantMap values() const {return m_data;} - QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; - QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { - return value(path.split('.'), default_value); - } void setValue(const QStringList &path, const QVariant &val); void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} void load(); @@ -50,6 +45,11 @@ class AppDbConfig OFeedConfig ofeedConfig(int stage_id) const; void setOfeedConfig(int stage_id, const OFeedConfig &config); private: + QVariantMap values() const {return m_data;} + QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; + QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { + return value(path.split('.'), default_value); + } void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); private: diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 54a9af78f..e02e201ef 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -1025,7 +1025,7 @@ void EventPlugin::editEvent() event_w->setWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - EventConfig event_data = EventConfig::fromVariantMap(appDbConfig()->value("event").toMap()); + auto event_data = appDbConfig()->eventConfig(); for(int stage_id = 1; stage_id <= event_data.stageCount; ++stage_id) event_data.stages.insert(stage_id, stageData(stage_id)); event_w->loadParams(event_data); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 104344df9..673f16684 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -340,114 +340,111 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons QString OFeedClient::hostUrl() const { int current_stage = getPlugin()->currentStageId(); - QString key = serviceName().toLower() + ".hostUrl.E" + QString::number(current_stage); - return normalized_base_host_url(getPlugin()->appDbConfig()->value(key, k_default_host_url).toString()); + OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + return normalized_base_host_url(cfg.hostUrl); } QString OFeedClient::eventId() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->value(serviceName().toLower() + ".eventId.E" + QString::number(current_stage)).toString(); + OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + return cfg.eventId; } QString OFeedClient::eventPassword() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->value(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage)).toString(); + OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + return cfg.eventPassword; } QString OFeedClient::changelogOrigin() const { int current_stage = getPlugin()->currentStageId(); - QString key = serviceName().toLower() + ".changelogOrigin.E" + QString::number(current_stage); - return getPlugin()->appDbConfig()->value(key, "START").toString(); + OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + return cfg.changelogOrigin; } bool OFeedClient::isInsertFromOFeed = false; QDateTime OFeedClient::lastChangelogCall() { int current_stage = getPlugin()->currentStageId(); - QString key = serviceName().toLower() + ".lastChangelogCall.E" + QString::number(current_stage); - + auto config = getPlugin()->appDbConfig()->ofeedConfig(current_stage); // Retrieve the stored value from the configuration - QVariant value = getPlugin()->appDbConfig()->value(key); + auto last_call = config.lastChangelogCall; // Check if the value exists - if (!value.isValid() || value.toString().isEmpty()) { + if (!last_call.isValid() || last_call.toString().isEmpty()) { // No valid value exists, set the initial value - QDateTime initialValue = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch (1970-01-01T00:00:00Z) - getPlugin()->appDbConfig()->setValue(key, initialValue.toString(Qt::ISODate)); - getPlugin()->appDbConfig()->save(serviceName().toLower()); - // qDebug() << "No lastChangelogCall found. Setting initial value to:" << initialValue.toString(Qt::ISODate); - return initialValue; - } - - // Convert the stored string to QDateTime - QDateTime lastChangelog = QDateTime::fromString(value.toString(), Qt::ISODate); - - // Check if the conversion was successful - if (!lastChangelog.isValid()) { - // If invalid, set the default value - QDateTime initialValue = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch - getPlugin()->appDbConfig()->setValue(key, initialValue.toString(Qt::ISODate)); - getPlugin()->appDbConfig()->save(serviceName().toLower()); - // qDebug() << "Invalid lastChangelogCall found. Setting initial value to:" << initialValue.toString(Qt::ISODate); - return initialValue; + config.lastChangelogCall = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch (1970-01-01T00:00:00Z) + getPlugin()->appDbConfig()->setOfeedConfig(current_stage, config); + // qDebug() << "No lastChangelogCall found. Setting initial value to:" << config.lastChangelogCall.toString(Qt::ISODate); } - - return lastChangelog; + return config.lastChangelogCall; } bool OFeedClient::runXmlValidation() { - int current_stage = getPlugin()->currentStageId(); - QString key = serviceName().toLower() + ".runXmlValidation.E" + QString::number(current_stage); - return getPlugin()->appDbConfig()->value(key, "true").toBool(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->ofeedConfig(current_stage).runXmlValidation; } bool OFeedClient::runChangesProcessing () { - int current_stage = getPlugin()->currentStageId(); - QString key = serviceName().toLower() + ".runChangesProcessing.E" + QString::number(current_stage); - return getPlugin()->appDbConfig()->value(key, "false").toBool(); -}; - -QString OFeedClient::receiptConfigKey(const QString &suffix) const -{ - const int current_stage = getPlugin()->currentStageId(); - return stageConfigKey(k_event_config_prefix, suffix, current_stage); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->ofeedConfig(current_stage).runChangesProcessing; } -QVariant OFeedClient::receiptConfigValue(const QString &suffix, const QVariant &default_value) const -{ - return getPlugin()->appDbConfig()->value(receiptConfigKey(suffix), default_value); -} +// QString OFeedClient::receiptConfigKey(const QString &suffix) const +// { +// const int current_stage = getPlugin()->currentStageId(); +// return stageConfigKey(k_event_config_prefix, suffix, current_stage); +// } -void OFeedClient::setReceiptConfigValue(const QString &suffix, const QVariant &value) -{ - auto *event_config = getPlugin()->appDbConfig(); - event_config->setValue(receiptConfigKey(suffix), value); - event_config->save(k_event_config_prefix); -} +// QVariant OFeedClient::receiptConfigValue(const QString &suffix, const QVariant &default_value) const +// { +// return getPlugin()->appDbConfig()->value(receiptConfigKey(suffix), default_value); +// } + +// void OFeedClient::setReceiptConfigValue(const QString &suffix, const QVariant &value) +// { +// auto *event_config = getPlugin()->appDbConfig(); +// event_config->setValue(receiptConfigKey(suffix), value); +// event_config->save(k_event_config_prefix); +// } bool OFeedClient::printEventImageOnReceipt() const { - return receiptConfigValue(QStringLiteral("receiptPrintEventImage"), false).toBool(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).printImage; } void OFeedClient::setPrintEventImageOnReceipt(bool on) { - setReceiptConfigValue(QStringLiteral("receiptPrintEventImage"), on); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto print_config = config->receiptsConfig(current_stage); + print_config.printImage = on; + config->setReceiptsConfig(current_stage, print_config); } bool OFeedClient::printEventQrCodeOnReceipt() const { - return receiptConfigValue(QStringLiteral("receiptPrintEventQrCode"), false).toBool(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).printQrCode; } void OFeedClient::setPrintEventQrCodeOnReceipt(bool on) { - setReceiptConfigValue(QStringLiteral("receiptPrintEventQrCode"), on); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto print_config = config->receiptsConfig(current_stage); + print_config.printQrCode = on; + config->setReceiptsConfig(current_stage, print_config); } int OFeedClient::receiptImageHeightMm() const diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h index 4a0d036b9..2c4500d1c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h @@ -108,9 +108,9 @@ class OFeedClient : public Service void onExportTimerTimeOut(); void init(); void ensureEventImageCachedAtStartup(); - QString receiptConfigKey(const QString &suffix) const; - QVariant receiptConfigValue(const QString &suffix, const QVariant &default_value = QVariant()) const; - void setReceiptConfigValue(const QString &suffix, const QVariant &value); + // QString receiptConfigKey(const QString &suffix) const; + // QVariant receiptConfigValue(const QString &suffix, const QVariant &default_value = QVariant()) const; + // void setReceiptConfigValue(const QString &suffix, const QVariant &value); void setCachedEventImage(const QByteArray &raw_data, const QString &format); void clearCachedEventImage(); void checkCredentials(); From 7b7f9eb00689b57f50f9f9d33f069a461fa87121 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 19:29:31 +0200 Subject: [PATCH 72/83] Introduce structured Event and OResults config --- .../plugins/Event/src/appdbconfig.cpp | 21 +++ .../plugins/Event/src/appdbconfig.h | 12 +- .../plugins/Event/src/eventplugin.cpp | 39 ++--- .../Event/src/services/ofeed/ofeedclient.cpp | 148 ++++++++++++------ .../Event/src/services/oresultsclient.cpp | 18 ++- .../plugins/Receipts/src/receiptsplugin.cpp | 26 ++- .../Receipts/src/receiptssettingspage.cpp | 36 ++--- .../plugins/Relays/src/relaysplugin.cpp | 4 +- .../plugins/Relays/src/relayswidget.cpp | 2 +- .../plugins/Runs/src/runsplugin.cpp | 22 +-- .../plugins/Runs/src/runswidget.cpp | 2 +- 11 files changed, 200 insertions(+), 130 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 6d4b16eba..d0eb030b5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -197,6 +197,27 @@ EventConfig AppDbConfig::eventConfig() const return EventConfig::fromVariantMap(value(QStringLiteral("event")).toMap()); } +void AppDbConfig::setEventConfig(const EventConfig &config) +{ + setValue(QStringLiteral("event"), config.toVariantMap()); +} + +OResultsConfig AppDbConfig::oresultsConfig(int stage_id) const +{ + const QString e = QStringLiteral(".E") + QString::number(stage_id); + OResultsConfig cfg; + cfg.apiKey = value(QStringLiteral("oresults.apiKey") + e).toString(); + cfg.eventName = value(QStringLiteral("oresults.eventName") + e).toString(); + return cfg; +} + +void AppDbConfig::setOresultsConfig(int stage_id, const OResultsConfig &cfg) +{ + const QString e = QStringLiteral(".E") + QString::number(stage_id); + setValue(QStringLiteral("oresults.apiKey") + e, cfg.apiKey); + setValue(QStringLiteral("oresults.eventName") + e, cfg.eventName); +} + ReceiptsConfig AppDbConfig::receiptsConfig(int stage_id) const { const QString e = QStringLiteral(".E") + QString::number(stage_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index a0677014b..a20caaeba 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -21,7 +21,8 @@ struct QxConfig struct OResultsConfig { - QMap apiKeys; + QString apiKey; + QString eventName; }; class AppDbConfig @@ -29,8 +30,6 @@ class AppDbConfig public: explicit AppDbConfig() = default; public: - void setValue(const QStringList &path, const QVariant &val); - void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} void load(); void save(const QString &path_to_save = QString()); @@ -40,12 +39,17 @@ class AppDbConfig int dbVersion() const; std::optional maximumCardCheckAdvanceSec() const; EventConfig eventConfig() const; + void setEventConfig(const EventConfig &config); + OResultsConfig oresultsConfig(int stage_id) const; + void setOresultsConfig(int stage_id, const OResultsConfig &config); ReceiptsConfig receiptsConfig(int stage_id) const; void setReceiptsConfig(int stage_id, const ReceiptsConfig &config); OFeedConfig ofeedConfig(int stage_id) const; void setOfeedConfig(int stage_id, const OFeedConfig &config); private: - QVariantMap values() const {return m_data;} + void setValue(const QStringList &path, const QVariant &val); + void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} + QVariantMap values() const {return m_data;} QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { return value(path.split('.'), default_value); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index e02e201ef..7daa2b035 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -316,16 +316,16 @@ StageData EventPlugin::stageData(int stage_id) } // Config values take precedence over legacy table values. - const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - const QVariantMap config_data = appDbConfig()->value(config_prefix).toMap(); - if(config_data.contains(STAGE_START_DATE_TIME_KEY)) - data.startDateTime = config_data.value(STAGE_START_DATE_TIME_KEY).toDateTime(); - if(config_data.contains(STAGE_USE_ALL_MAPS_KEY)) - data.useAllMaps = config_data.value(STAGE_USE_ALL_MAPS_KEY).toBool(); - if(config_data.contains(STAGE_DRAWING_CONFIG_KEY)) - data.drawingConfig = qf::core::Utils::jsonToQVariant(config_data.value(STAGE_DRAWING_CONFIG_KEY).toString()).toMap(); - if(config_data.contains(STAGE_QX_API_TOKEN_KEY)) - data.qxApiToken = config_data.value(STAGE_QX_API_TOKEN_KEY).toString(); + // Default values: startDateTime=invalid, useAllMaps=false, drawingConfig=empty, qxApiToken=empty + const StageData cfg_stage = appDbConfig()->eventConfig().stages.value(stage_id); + if (cfg_stage.startDateTime.isValid()) + data.startDateTime = cfg_stage.startDateTime; + if (cfg_stage.useAllMaps) + data.useAllMaps = cfg_stage.useAllMaps; + if (!cfg_stage.drawingConfig.isEmpty()) + data.drawingConfig = cfg_stage.drawingConfig; + if (!cfg_stage.qxApiToken.isEmpty()) + data.qxApiToken = cfg_stage.qxApiToken; data.startDateTime = data.startDateTime.toTimeZone(QTimeZone::systemTimeZone()); m_stageCache[stage_id] = data; @@ -336,12 +336,11 @@ StageData EventPlugin::stageData(int stage_id) void EventPlugin::setStageData(int stage_id, const StageData &data) { AppDbConfig *config = appDbConfig(); - const QString config_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - config->setValue(config_prefix + '.' + STAGE_START_DATE_TIME_KEY, data.startDateTime); - config->setValue(config_prefix + '.' + STAGE_USE_ALL_MAPS_KEY, data.useAllMaps); - config->setValue(config_prefix + '.' + STAGE_DRAWING_CONFIG_KEY, qf::core::Utils::qvariantToJson(data.drawingConfig)); - config->setValue(config_prefix + '.' + STAGE_QX_API_TOKEN_KEY, data.qxApiToken); - config->save(config_prefix); + auto event_cfg = config->eventConfig(); + event_cfg.stages.insert(stage_id, data); + config->setEventConfig(event_cfg); + const QString save_prefix = QStringLiteral("event.stage.%1").arg(stage_id); + config->save(save_prefix); m_stageCache.remove(stage_id); } @@ -509,7 +508,9 @@ void EventPlugin::loadCurrentStageId() void EventPlugin::saveCurrentStageId(int current_stage) { if(current_stage != appDbConfig()->eventConfig().currentStageId) { - appDbConfig()->setValue("event.currentStageId", current_stage); + auto event_cfg = appDbConfig()->eventConfig(); + event_cfg.currentStageId = current_stage; + appDbConfig()->setEventConfig(event_cfg); appDbConfig()->save("event"); } } @@ -947,7 +948,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even Event::AppDbConfig event_config; bool ok = false; //ConnectionSettings connection_settings; - event_config.setValue("event", new_params.toVariantMap()); + event_config.setEventConfig(new_params); int stage_count = new_params.stageCount; if(stage_count == 0) stage_count = event_config.eventConfig().stageCount; @@ -1034,7 +1035,7 @@ void EventPlugin::editEvent() return; event_data = event_w->saveParams(); - appDbConfig()->setValue("event", event_data.toVariantMap()); + appDbConfig()->setEventConfig(event_data); appDbConfig()->save("event"); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 673f16684..1641d22a5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -449,15 +449,9 @@ void OFeedClient::setPrintEventQrCodeOnReceipt(bool on) int OFeedClient::receiptImageHeightMm() const { - bool ok = false; - int height_mm = receiptConfigValue(QStringLiteral("receiptImageHeightMm"), 18).toInt(&ok); - if(!ok) - return 18; - if(height_mm < 10) - return 10; - if(height_mm > 60) - return 60; - return height_mm; + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).imageHeightMm; } void OFeedClient::setReceiptImageHeightMm(int height_mm) @@ -466,12 +460,19 @@ void OFeedClient::setReceiptImageHeightMm(int height_mm) height_mm = 10; else if(height_mm > 60) height_mm = 60; - setReceiptConfigValue(QStringLiteral("receiptImageHeightMm"), height_mm); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto rc = config->receiptsConfig(current_stage); + rc.imageHeightMm = height_mm; + config->setReceiptsConfig(current_stage, rc); + config->save(QStringLiteral("event")); } QString OFeedClient::receiptEventLinkUrl() const { - const QString custom_url = receiptConfigValue(QStringLiteral("receiptEventLinkUrl")).toString().trimmed(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + const QString custom_url = config->receiptsConfig(current_stage).linkUrl; if(!custom_url.isEmpty()) return custom_url; return defaultReceiptEventLinkUrl(); @@ -493,12 +494,19 @@ QString OFeedClient::defaultReceiptEventLinkUrl() const void OFeedClient::setReceiptEventLinkUrl(QString link_url) { link_url = link_url.trimmed(); - setReceiptConfigValue(QStringLiteral("receiptEventLinkUrl"), link_url); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto rc = config->receiptsConfig(current_stage); + rc.linkUrl = link_url; + config->setReceiptsConfig(current_stage, rc); + config->save(QStringLiteral("event")); } QString OFeedClient::receiptEventQrCodeCaption() const { - return receiptConfigValue(QStringLiteral("receiptPrintEventQrCodeCaption"), defaultReceiptEventQrCodeCaption()).toString().trimmed(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).qrCodeCaption; } QString OFeedClient::defaultReceiptEventQrCodeCaption() const @@ -509,7 +517,12 @@ QString OFeedClient::defaultReceiptEventQrCodeCaption() const void OFeedClient::setReceiptEventQrCodeCaption(QString caption) { caption = caption.trimmed(); - setReceiptConfigValue(QStringLiteral("receiptPrintEventQrCodeCaption"), caption); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto rc = config->receiptsConfig(current_stage); + rc.qrCodeCaption = caption; + config->setReceiptsConfig(current_stage, rc); + config->save(QStringLiteral("event")); } bool OFeedClient::hasCachedEventImage() const @@ -519,28 +532,38 @@ bool OFeedClient::hasCachedEventImage() const QString OFeedClient::cachedEventImageBase64() const { - return receiptConfigValue(QStringLiteral("receiptImageDataBase64")).toString(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).imageBase64; } QString OFeedClient::cachedEventImageFormat() const { - return receiptConfigValue(QStringLiteral("receiptImageFormat"), QStringLiteral("png")).toString().toLower(); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + return config->receiptsConfig(current_stage).imageFormat; } void OFeedClient::setCachedEventImage(const QByteArray &raw_data, const QString &format) { - auto *event_config = getPlugin()->appDbConfig(); - event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageDataBase64")), QString::fromLatin1(raw_data.toBase64())); - event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageFormat")), format.toLower()); - event_config->save(k_event_config_prefix); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto rc = config->receiptsConfig(current_stage); + rc.imageBase64 = QString::fromLatin1(raw_data.toBase64()); + rc.imageFormat = format.toLower(); + config->setReceiptsConfig(current_stage, rc); + config->save(QStringLiteral("event")); } void OFeedClient::clearCachedEventImage() { - auto *event_config = getPlugin()->appDbConfig(); - event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageDataBase64")), QString()); - event_config->setValue(receiptConfigKey(QStringLiteral("receiptImageFormat")), QString()); - event_config->save(k_event_config_prefix); + auto *config = getPlugin()->appDbConfig(); + auto current_stage = config->eventConfig().currentStageId; + auto rc = config->receiptsConfig(current_stage); + rc.imageBase64.clear(); + rc.imageFormat.clear(); + config->setReceiptsConfig(current_stage, rc); + config->save(QStringLiteral("event")); } void OFeedClient::ensureEventImageCachedAtStartup() @@ -657,67 +680,92 @@ void OFeedClient::refreshEventImageCache(std::function()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".hostUrl.E" + QString::number(current_stage), hostUrl); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.hostUrl = hostUrl; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setEventId(QString eventId) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".eventId.E" + QString::number(current_stage), eventId); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.eventId = eventId; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setEventPassword(QString eventPassword) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".eventPassword.E" + QString::number(current_stage), eventPassword); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.eventPassword = eventPassword; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } void OFeedClient::setChangelogOrigin(QString changelogOrigin) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".changelogOrigin.E" + QString::number(current_stage), changelogOrigin); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.changelogOrigin = changelogOrigin; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); } void OFeedClient::setLastChangelogCall(QDateTime lastChangelogCall) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".lastChangelogCall.E" + QString::number(current_stage), lastChangelogCall); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.lastChangelogCall = lastChangelogCall; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); } void OFeedClient::setRunXmlValidation(bool runXmlValidation) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".runXmlValidation.E" + QString::number(current_stage), runXmlValidation); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.runXmlValidation = runXmlValidation; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); } void OFeedClient::setRunChangesProcessing(bool runChangesProcessing) { - int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue(serviceName().toLower() + ".runChangesProcessing.E" + QString::number(current_stage), runChangesProcessing); - getPlugin()->appDbConfig()->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.runChangesProcessing = runChangesProcessing; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); } bool OFeedClient::introTourShowed() const { - return getPlugin()->appDbConfig()->value( - serviceName().toLower() + QStringLiteral(".introTourShowed"), false).toBool(); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + return config->ofeedConfig(current_stage).introTourShowed; } void OFeedClient::setIntroTourShowed(bool shown) { - auto *event_config = getPlugin()->appDbConfig(); - event_config->setValue(serviceName().toLower() + QStringLiteral(".introTourShowed"), shown); - event_config->save(serviceName().toLower()); + auto *config = getPlugin()->appDbConfig(); + const int current_stage = getPlugin()->currentStageId(); + auto cfg = config->ofeedConfig(current_stage); + cfg.introTourShowed = shown; + config->setOfeedConfig(current_stage, cfg); + config->save(serviceName().toLower()); } void OFeedClient::testConnection(const QString &host_url, diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index e11f705f0..0d8473393 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -169,27 +169,33 @@ void OResultsClient::onDbEventNotify(const QString &domain, int connection_id, c QString OResultsClient::apiKey() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->value("oresults.apiKey.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->oresultsConfig(current_stage).apiKey; } void OResultsClient::setApiKey(QString apiKey) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue("oresults.apiKey.E" + QString::number(current_stage), apiKey); - getPlugin()->appDbConfig()->save("oresults"); + auto *db = getPlugin()->appDbConfig(); + auto cfg = db->oresultsConfig(current_stage); + cfg.apiKey = apiKey; + db->setOresultsConfig(current_stage, cfg); + db->save("oresults"); } QString OResultsClient::eventName() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->value("oresults.eventName.E" + QString::number(current_stage)).toString(); + return getPlugin()->appDbConfig()->oresultsConfig(current_stage).eventName; } void OResultsClient::setEventName(const QString &name) { int current_stage = getPlugin()->currentStageId(); - getPlugin()->appDbConfig()->setValue("oresults.eventName.E" + QString::number(current_stage), name); - getPlugin()->appDbConfig()->save("oresults"); + auto *db = getPlugin()->appDbConfig(); + auto cfg = db->oresultsConfig(current_stage); + cfg.eventName = name; + db->setOresultsConfig(current_stage, cfg); + db->save("oresults"); } void OResultsClient::sendCompetitorChange(QString xml) { diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index d9616ca87..2c11e61a2 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -55,15 +55,15 @@ using CardReader::CardReaderPlugin; namespace Receipts { namespace { -QString eventConfigKey(const QString &suffix) +Event::ReceiptsConfig currentReceiptsConfig() { const int current_stage = qMax(getPlugin()->currentStageId(), 1); - return QStringLiteral("event.") + suffix + QStringLiteral(".E") + QString::number(current_stage); + return getPlugin()->appDbConfig()->receiptsConfig(current_stage); } QString configuredReceiptEventLinkUrl() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptEventLinkUrl"))).toString().trimmed(); + return currentReceiptsConfig().linkUrl; } QString defaultReceiptQrCodeCaption() @@ -73,7 +73,7 @@ QString defaultReceiptQrCodeCaption() QString configuredReceiptQrCodeCaption() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), defaultReceiptQrCodeCaption()).toString().trimmed(); + return currentReceiptsConfig().qrCodeCaption; } QString receiptLinkWithCompetitorClass(const QString &base_url, const QString &class_name) @@ -100,35 +100,27 @@ QString receiptLinkWithCompetitorClass(const QString &base_url, const QString &c bool printReceiptImageEnabled() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventImage")), false).toBool(); + return currentReceiptsConfig().printImage; } bool printReceiptQrCodeEnabled() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool(); + return currentReceiptsConfig().printQrCode; } QString configuredReceiptImageBase64() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageDataBase64"))).toString(); + return currentReceiptsConfig().imageBase64; } QString configuredReceiptImageFormat() { - return getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageFormat")), QStringLiteral("png")).toString().trimmed().toLower(); + return currentReceiptsConfig().imageFormat; } int configuredReceiptImageHeightMm() { - bool ok = false; - int image_height_mm = getPlugin()->appDbConfig()->value(eventConfigKey(QStringLiteral("receiptImageHeightMm")), 18).toInt(&ok); - if(!ok) - return 18; - if(image_height_mm < 10) - return 10; - if(image_height_mm > 60) - return 60; - return image_height_mm; + return currentReceiptsConfig().imageHeightMm; } QString receiptImageCacheDirPath() diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp index 03945fde0..90d2ccfa1 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp @@ -392,18 +392,14 @@ void ReceiptsSettingsPage::load() auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); m_stageId = qMax(event_config->eventConfig().currentStageId, 1); - ui->chkPrintReceiptQrCode->setChecked(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), false).toBool()); - ui->edReceiptQrCodeBaseUrl->setText(event_config->value(eventConfigKey(QStringLiteral("receiptEventLinkUrl"))).toString().trimmed()); - ui->edReceiptQrCodeCaption->setText(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), defaultReceiptQrCodeCaption()).toString().trimmed()); - ui->chkPrintReceiptImage->setChecked(event_config->value(eventConfigKey(QStringLiteral("receiptPrintEventImage")), false).toBool()); - int image_height_mm = event_config->value(eventConfigKey(QStringLiteral("receiptImageHeightMm")), 18).toInt(); - if(image_height_mm < 10) - image_height_mm = 10; - else if(image_height_mm > 60) - image_height_mm = 60; - ui->edReceiptImageHeight->setValue(image_height_mm); - m_receiptImageBase64 = event_config->value(eventConfigKey(QStringLiteral("receiptImageDataBase64"))).toString(); - m_receiptImageFormat = event_config->value(eventConfigKey(QStringLiteral("receiptImageFormat"))).toString().trimmed().toLower(); + const auto rc = event_config->receiptsConfig(m_stageId); + ui->chkPrintReceiptQrCode->setChecked(rc.printQrCode); + ui->edReceiptQrCodeBaseUrl->setText(rc.linkUrl); + ui->edReceiptQrCodeCaption->setText(rc.qrCodeCaption); + ui->chkPrintReceiptImage->setChecked(rc.printImage); + ui->edReceiptImageHeight->setValue(rc.imageHeightMm); + m_receiptImageBase64 = rc.imageBase64; + m_receiptImageFormat = rc.imageFormat; if(m_receiptImageBase64.isEmpty()) { m_receiptImageFormat.clear(); ui->edReceiptImageFile->clear(); @@ -429,13 +425,15 @@ void ReceiptsSettingsPage::save() Q_ASSERT(event_plugin); auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); - event_config->setValue(eventConfigKey(QStringLiteral("receiptPrintEventQrCode")), ui->chkPrintReceiptQrCode->isChecked()); - event_config->setValue(eventConfigKey(QStringLiteral("receiptEventLinkUrl")), ui->edReceiptQrCodeBaseUrl->text().trimmed()); - event_config->setValue(eventConfigKey(QStringLiteral("receiptPrintEventQrCodeCaption")), ui->edReceiptQrCodeCaption->text().trimmed()); - event_config->setValue(eventConfigKey(QStringLiteral("receiptPrintEventImage")), ui->chkPrintReceiptImage->isChecked()); - event_config->setValue(eventConfigKey(QStringLiteral("receiptImageHeightMm")), ui->edReceiptImageHeight->value()); - event_config->setValue(eventConfigKey(QStringLiteral("receiptImageDataBase64")), m_receiptImageBase64); - event_config->setValue(eventConfigKey(QStringLiteral("receiptImageFormat")), m_receiptImageFormat); + Event::ReceiptsConfig rc; + rc.printQrCode = ui->chkPrintReceiptQrCode->isChecked(); + rc.linkUrl = ui->edReceiptQrCodeBaseUrl->text().trimmed(); + rc.qrCodeCaption = ui->edReceiptQrCodeCaption->text().trimmed(); + rc.printImage = ui->chkPrintReceiptImage->isChecked(); + rc.imageHeightMm = ui->edReceiptImageHeight->value(); + rc.imageBase64 = m_receiptImageBase64; + rc.imageFormat = m_receiptImageFormat; + event_config->setReceiptsConfig(m_stageId, rc); event_config->save(QStringLiteral("event")); } diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index ae4d7c104..d9831f55c 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -189,7 +189,7 @@ qf::core::utils::TreeTable RelaysPlugin::nLegsResultsTable(const QString &where_ { qfLogFuncFrame() << "leg cnt:" << leg_count; qf::core::utils::TreeTable tt; - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); tt.appendColumn("className", QMetaType(QMetaType::QString)); qfs::QueryBuilder qb; @@ -513,7 +513,7 @@ QVariant RelaysPlugin::startListByClassesTableData(const QString &class_filter, //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp index 13d9d3981..3d540b08a 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp @@ -392,7 +392,7 @@ QVariant RelaysWidget::startListByClubsTableData(bool with_vacants) //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index 89dc63992..3827fbb82 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -759,7 +759,7 @@ qf::core::utils::TreeTable RunsPlugin::stageResultsTable(int stage_id, const QSt model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { @@ -1429,7 +1429,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesTable(const QString &wher m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("courses.numberOfControls", QMetaType(QMetaType::Int)); tt.appendColumn("courses.startNumber", QMetaType(QMetaType::Int)); @@ -1563,7 +1563,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsTable(const quickevent::gui m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -1632,7 +1632,7 @@ qf::core::utils::TreeTable RunsPlugin::startListStartersTable(const QString &whe qf::core::utils::TreeTable tt; tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("competitors.registration", QMetaType(QMetaType::QString)); @@ -1732,7 +1732,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesNStagesTable(const int st m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", sel_stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); QVector start00_epoch_sec; for(int stage_id = 1; stage_id <= stages_count; stage_id++) { @@ -1780,7 +1780,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsNStagesTable(const int stag m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", sel_stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -2069,13 +2069,13 @@ void RunsPlugin::report_resultsNStages() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); props["options"] = opts; qf::gui::reports::ReportViewWidget::showReport(fwk - , findReportFile("results_nstages.qml") + , findReportFile("results_nstages.qml") , tt.toVariant() , tr("Results after %n stage(s)", "", dlg.stagesCount()) , "printResultsNStages" @@ -2096,13 +2096,13 @@ void RunsPlugin::report_resultsNStagesSpeaker() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); props["options"] = opts; qf::gui::reports::ReportViewWidget::showReport(fwk - , findReportFile("results_nstagesSpeaker.qml") + , findReportFile("results_nstagesSpeaker.qml") , tt.toVariant() , tr("Results after %n stage(s)", "", dlg.stagesCount()) , "printResultsNStagesWide" @@ -2472,7 +2472,7 @@ void RunsPlugin::export_resultsHtmlNStages() qff::MainWindow *fwk = qff::MainWindow::frameWork(); auto tt1 = nstagesResultsTable(sql_where_expr, stage_id, num_places, exclude_disq); - tt1.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt1.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QString file_dir = QDir::tempPath() + "/quickevent/overall-e" + QString::number(stage_id); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index e8859ab9e..d2178a9ee 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -1140,7 +1140,7 @@ void RunsWidget::report_competitorsStatistics() m.setQueryBuilder(qb); m.reload(); qfu::TreeTable tt = m.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->value("event")); + tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); for (int stage_id = 1; stage_id <= stage_cnt; ++stage_id) { QString prefix = "e" + QString::number(stage_id) + "_"; QString col_runs_count = prefix + "runCount"; From 02df126ceed68d162c811c7b2316f0d0426238c3 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 17 Jul 2026 19:38:35 +0200 Subject: [PATCH 73/83] Use EventConfig for stage data access Move stage data getters/setters into EventConfig and persist changes via AppDbConfig (setEventConfig + save("event")). Update callers to use appDbConfig()->eventConfig().stageData(...) / setStageData(...). Remove EventPlugin's stage cache and its legacy stageData/setStageData/clearStageDataCache implementations and adjust related code. Add EventConfig::stageData and setStageData methods. --- .../plugins/Classes/src/classeswidget.cpp | 10 ++- .../plugins/Classes/src/drawing/ganttitem.cpp | 10 ++- .../Classes/src/drawing/ganttscene.cpp | 2 +- .../plugins/Event/src/eventconfig.cpp | 10 +++ .../plugins/Event/src/eventconfig.h | 2 + .../plugins/Event/src/eventplugin.cpp | 66 +------------------ .../plugins/Event/src/eventplugin.h | 5 +- .../Event/src/services/ofeed/ofeedclient.cpp | 4 -- .../Event/src/services/qx/qxclientservice.cpp | 2 +- .../src/services/qx/qxclientservicewidget.cpp | 8 ++- .../plugins/Receipts/src/receiptsplugin.cpp | 4 -- .../plugins/Runs/src/runswidget.cpp | 2 +- 12 files changed, 39 insertions(+), 86 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index 6eacf9ba7..ca90e0c13 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -156,9 +156,13 @@ ClassesWidget::ClassesWidget(QWidget *parent) : connect(ui->tblClasses, &qf::gui::TableView::currentRowChanged, this, &ClassesWidget::reloadCourseCodes); connect(ui->chkUseAllMaps, &QCheckBox::toggled, this, [this](bool checked) { auto evplugin = getPlugin(); - auto data = evplugin->stageData(selectedStageId()); + auto *config = evplugin->appDbConfig(); + auto event_config = config->eventConfig(); + auto data = event_config.stageData(selectedStageId()); data.useAllMaps = checked; - evplugin->setStageData(selectedStageId(), data); + event_config.setStageData(selectedStageId(), data); + config->setEventConfig(event_config); + config->save(QStringLiteral("event")); }); } @@ -353,7 +357,7 @@ void ClassesWidget::reload() } m_courseItemDelegate->setCourses(courses); } - ui->chkUseAllMaps->setChecked(getPlugin()->stageData(stage_id).useAllMaps); + ui->chkUseAllMaps->setChecked(getPlugin()->appDbConfig()->eventConfig().stageData(stage_id).useAllMaps); reloadCourseCodes(); } diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index eaf36dc6c..15d437068 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -63,7 +63,7 @@ StartSlotItem *GanttItem::addStartSlotItem() void GanttItem::load(int stage_id) { qfLogFuncFrame(); - Event::StageData stage_data = getPlugin()->stageData(stage_id); + Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); DrawingConfig dc(stage_data.drawingConfig); QVariantList start_slot_list = dc.startSlots(); @@ -154,7 +154,9 @@ void GanttItem::save(int stage_id) { qfLogFuncFrame(); { - Event::StageData stage = getPlugin()->stageData(stage_id); + auto *config = getPlugin()->appDbConfig(); + auto event_config = config->eventConfig(); + Event::StageData stage = event_config.stageData(stage_id); DrawingConfig dc(stage.drawingConfig); QVariantList start_slots; for (int i = 0; i < startSlotItemCount(); ++i) { @@ -164,7 +166,9 @@ void GanttItem::save(int stage_id) } dc.setStartSlots(start_slots); stage.drawingConfig = dc; - getPlugin()->setStageData(stage_id, stage); + event_config.setStageData(stage_id, stage); + config->setEventConfig(event_config); + config->save(QStringLiteral("event")); } { QString qs = "UPDATE classdefs SET" diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp index 9d607a56f..8e3e56595 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp @@ -23,7 +23,7 @@ GanttScene::GanttScene(QObject * parent) void GanttScene::load(int stage_id) { clear(); - Event::StageData stage_data = getPlugin()->stageData(stage_id); + Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); m_useAllMaps = stage_data.useAllMaps; m_ganttItem = new GanttItem(); addItem(m_ganttItem); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 1b615c51b..9acdc6e67 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -70,6 +70,16 @@ bool EventConfig::isRelays() const return disciplineId == 5 || disciplineId == 6 || disciplineId == 15; } +StageData EventConfig::stageData(int stage_id) const +{ + return stages.value(stage_id); +} + +void EventConfig::setStageData(int stage_id, const StageData &data) +{ + stages.insert(stage_id, data); +} + QVariantMap EventConfig::toVariantMap() const { QVariantMap values; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index a8bf089ba..1f6267dca 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -33,6 +33,8 @@ struct EventConfig static EventConfig fromVariantMap(const QVariantMap &values); QVariantMap toVariantMap() const; bool isRelays() const; + StageData stageData(int stage_id) const; + void setStageData(int stage_id, const StageData &data); int stageCount = 1; QMap stages; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 7daa2b035..608c216b9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -43,7 +43,6 @@ #include #include -#include #include #include #include @@ -109,10 +108,7 @@ QByteArray DbEventPayload::toJson() const namespace { const auto QBE_EXT = QStringLiteral(".qbe"); -const auto STAGE_START_DATE_TIME_KEY = QStringLiteral("startDateTime"); -const auto STAGE_USE_ALL_MAPS_KEY = QStringLiteral("useAllMaps"); -const auto STAGE_DRAWING_CONFIG_KEY = QStringLiteral("drawingConfig"); -const auto STAGE_QX_API_TOKEN_KEY = QStringLiteral("qxApiToken"); + QString singleFileStorageDir() { @@ -285,7 +281,7 @@ QTime EventPlugin::stageStartTime(int stage_id) QDateTime EventPlugin::stageStartDateTime(int stage_id) { - return stageData(stage_id).startDateTime; + return appDbConfig()->eventConfig().stageData(stage_id).startDateTime; } int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) @@ -299,56 +295,7 @@ int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) return time_msec; } -StageData EventPlugin::stageData(int stage_id) -{ - if(!m_stageCache.contains(stage_id)) { - StageData data; - - // Load defaults from the legacy stages table. - qfs::Query q; - q.prepare("SELECT * FROM stages WHERE id=:id"); - q.bindValue(":id", stage_id); - if(q.exec() && q.next()) { - data.startDateTime = q.value(STAGE_START_DATE_TIME_KEY).toDateTime(); - data.useAllMaps = q.value(STAGE_USE_ALL_MAPS_KEY).toBool(); - data.drawingConfig = qf::core::Utils::jsonToQVariant(q.value(STAGE_DRAWING_CONFIG_KEY).toString()).toMap(); - data.qxApiToken = q.value(STAGE_QX_API_TOKEN_KEY).toString(); - } - - // Config values take precedence over legacy table values. - // Default values: startDateTime=invalid, useAllMaps=false, drawingConfig=empty, qxApiToken=empty - const StageData cfg_stage = appDbConfig()->eventConfig().stages.value(stage_id); - if (cfg_stage.startDateTime.isValid()) - data.startDateTime = cfg_stage.startDateTime; - if (cfg_stage.useAllMaps) - data.useAllMaps = cfg_stage.useAllMaps; - if (!cfg_stage.drawingConfig.isEmpty()) - data.drawingConfig = cfg_stage.drawingConfig; - if (!cfg_stage.qxApiToken.isEmpty()) - data.qxApiToken = cfg_stage.qxApiToken; - - data.startDateTime = data.startDateTime.toTimeZone(QTimeZone::systemTimeZone()); - m_stageCache[stage_id] = data; - } - return m_stageCache.value(stage_id); -} - -void EventPlugin::setStageData(int stage_id, const StageData &data) -{ - AppDbConfig *config = appDbConfig(); - auto event_cfg = config->eventConfig(); - event_cfg.stages.insert(stage_id, data); - config->setEventConfig(event_cfg); - const QString save_prefix = QStringLiteral("event.stage.%1").arg(stage_id); - config->save(save_prefix); - m_stageCache.remove(stage_id); -} -void EventPlugin::clearStageDataCache() -{ - qfInfo() << "stages data cache cleared"; - m_stageCache.clear(); -} void EventPlugin::onInstalled() { @@ -1027,8 +974,6 @@ void EventPlugin::editEvent() event_w->setEventId(eventName()); event_w->setEventIdEditable(false); auto event_data = appDbConfig()->eventConfig(); - for(int stage_id = 1; stage_id <= event_data.stageCount; ++stage_id) - event_data.stages.insert(stage_id, stageData(stage_id)); event_w->loadParams(event_data); dlg.setCentralWidget(event_w); if(!dlg.exec()) @@ -1042,7 +987,6 @@ void EventPlugin::editEvent() bool EventPlugin::closeEvent() { qfLogFuncFrame(); - clearStageDataCache(); m_classNameCache.clear(); setEventName(QString()); QF_SAFE_DELETE(m_eventConfig) @@ -1553,11 +1497,7 @@ void EventPlugin::onDbEventNotify(const QString &domain, int connection_id, cons { Q_UNUSED(connection_id) qfLogFuncFrame() << "domain:" << domain << "payload:" << data; - if(domain == QLatin1String(Event::EventPlugin::DBEVENT_STAGE_START_CHANGED)) { - //int stage_id = data.toInt(); - clearStageDataCache(); - } - else if(domain == QLatin1String(Event::EventPlugin::DBEVENT_REGISTRATIONS_IMPORTED)) { + if(domain == QLatin1String(Event::EventPlugin::DBEVENT_REGISTRATIONS_IMPORTED)) { reloadRegistrationsModel(); } } diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index f2e5e6db4..93f0f3eab 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -80,9 +80,7 @@ class EventPlugin : public qf::gui::framework::Plugin //Q_INVOKABLE int currentStageStartMsec(); int msecToStageStartAM(int si_am_time_sec, int msec = 0, int stage_id = 0); - StageData stageData(int stage_id); - void setStageData(int stage_id, const StageData &data); - Q_SLOT void clearStageDataCache(); + Q_SLOT bool createEvent(const QString &event_name = QString(), const QVariantMap &event_params = QVariantMap()); Q_SLOT void editEvent(); @@ -169,7 +167,6 @@ class EventPlugin : public qf::gui::framework::Plugin Event::AppDbConfig *m_eventConfig = nullptr; bool m_sqlServerConnected = false; int m_currentStageId = 0; - QMap m_stageCache; QMap m_classNameCache; qf::gui::framework::DockWidget *m_servicesDockWidget = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 1641d22a5..937f18f16 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -109,10 +109,6 @@ namespace Event::services { return base_url.toString(); } - QString stageConfigKey(const QString &prefix, const QString &suffix, int stage) - { - return prefix + QLatin1Char('.') + suffix + QStringLiteral(".E") + QString::number(stage); - } } OFeedClient::OFeedClient(QObject *parent) diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index cff9a3c0f..f603b94b1 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -275,7 +275,7 @@ QByteArray QxClientService::apiToken() const // always to current stage event on qxhttpd auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - return event_plugin->stageData(current_stage).qxApiToken.toUtf8(); + return event_plugin->appDbConfig()->eventConfig().stageData(current_stage).qxApiToken.toUtf8(); } QUrl QxClientService::exchangeServerUrl() const diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp index e84b43d90..41de67c59 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp @@ -97,9 +97,13 @@ bool QxClientServiceWidget::saveSettings() auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - auto stage_data = event_plugin->stageData(current_stage); + auto *config = event_plugin->appDbConfig(); + auto event_config = config->eventConfig(); + auto stage_data = event_config.stageData(current_stage); stage_data.qxApiToken = ui->edApiToken->text(); - event_plugin->setStageData(current_stage, stage_data); + event_config.setStageData(current_stage, stage_data); + config->setEventConfig(event_config); + config->save(QStringLiteral("event")); } return true; } diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index 2c11e61a2..32c158973 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -66,10 +66,6 @@ QString configuredReceiptEventLinkUrl() return currentReceiptsConfig().linkUrl; } -QString defaultReceiptQrCodeCaption() -{ - return QStringLiteral("Live Results"); -} QString configuredReceiptQrCodeCaption() { diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index d2178a9ee..1669d130b 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -693,7 +693,7 @@ void RunsWidget::onDrawClicked() bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); - Event::StageData stage_data = getPlugin()->stageData(stage_id); + Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); bool use_all_maps = stage_data.useAllMaps; qfDebug() << "DrawMethod:" << (int)draw_method << "use_all_maps:" << use_all_maps; QList class_ids; From b40be3c8bfd219860d890fb630de25051fddea90 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 18 Jul 2026 01:12:16 +0200 Subject: [PATCH 74/83] Refactor Event config and AppDbConfig APIs --- quickevent/app/quickevent/CMakeLists.txt | 4 + .../plugins/CardReader/src/cardchecker.cpp | 2 +- .../plugins/Classes/src/classeswidget.cpp | 14 +- .../plugins/Classes/src/drawing/ganttitem.cpp | 6 - .../Classes/src/drawing/ganttscene.cpp | 2 +- .../plugins/Event/src/appdbconfig.cpp | 320 +++++++----------- .../plugins/Event/src/appdbconfig.h | 74 ++-- .../plugins/Event/src/eventconfig.cpp | 31 +- .../plugins/Event/src/eventconfig.h | 13 +- .../plugins/Event/src/eventdialogwidget.cpp | 2 +- .../plugins/Event/src/eventplugin.cpp | 73 ++-- .../plugins/Event/src/eventplugin.h | 14 +- .../plugins/Event/src/ofeedconfig.h | 21 -- .../Event/src/services/ofeed/ofeedclient.cpp | 13 - .../Event/src/services/ofeed/ofeedclient.h | 6 +- .../Event/src/services/ofeed/ofeedconfig.cpp | 40 +++ .../Event/src/services/ofeed/ofeedconfig.h | 25 ++ .../Event/src/services/oresultsclient.cpp | 12 +- .../Event/src/services/oresultsconfig.cpp | 21 ++ .../Event/src/services/oresultsconfig.h | 17 + .../punchingtest/punchingtestservice.cpp | 2 +- .../Event/src/services/qx/qxclientservice.cpp | 2 +- .../src/services/qx/qxclientservicewidget.cpp | 2 - .../plugins/Oris/src/orisimporter.cpp | 24 +- .../plugins/Oris/src/xmlimporter.cpp | 30 +- .../plugins/Receipts/src/receiptsconfig.cpp | 37 ++ .../{Event => Receipts}/src/receiptsconfig.h | 6 +- .../plugins/Receipts/src/receiptsplugin.cpp | 2 +- .../Receipts/src/receiptssettingspage.cpp | 3 +- .../plugins/Relays/src/relaysplugin.cpp | 8 +- .../plugins/Runs/src/runsplugin.cpp | 6 +- .../plugins/Runs/src/runswidget.cpp | 2 +- 32 files changed, 430 insertions(+), 404 deletions(-) delete mode 100644 quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.h create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.h create mode 100644 quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp rename quickevent/app/quickevent/plugins/{Event => Receipts}/src/receiptsconfig.h (73%) diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index 8ffb1f5d1..e07ac08da 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -83,7 +83,10 @@ add_executable(quickevent plugins/Event/src/services/oresultsclient.cpp plugins/Event/src/services/oresultsclientwidget.cpp plugins/Event/src/services/oresultsclientwidget.ui + plugins/Event/src/services/oresultsconfig.cpp plugins/Event/src/services/oresultsconfig.h + plugins/Event/src/services/ofeed/ofeedclient.cpp + plugins/Event/src/services/ofeed/ofeedconfig.cpp plugins/Event/src/services/ofeed/ofeedconfig.h plugins/Event/src/services/ofeed/ofeedclientwidget.cpp plugins/Event/src/services/ofeed/ofeedclientwidget.ui plugins/Event/src/services/ofeed/ofeedwelcomedialog.h @@ -118,6 +121,7 @@ add_executable(quickevent plugins/Oris/src/txtimporter.cpp plugins/Oris/src/xmlimporter.cpp + plugins/Receipts/src/receiptsconfig.cpp plugins/Receipts/src/receiptsconfig.h plugins/Receipts/src/receiptsplugin.cpp plugins/Receipts/src/receiptsprinter.cpp plugins/Receipts/src/receiptsprinteroptions.cpp diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp index e03a7a665..9a47d0e5e 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp @@ -82,7 +82,7 @@ int CardChecker::startTimeSec(int run_id) std::optional CardChecker::maximumCardCheckAdvanceSec() { - return getPlugin()->appDbConfig()->maximumCardCheckAdvanceSec(); + return getPlugin()->appDbConfig()->eventConfig().maximumCardCheckAdvanceSec(); } quickevent::core::CourseDef CardChecker::courseCodesForRunId(int run_id) diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index ca90e0c13..d47cf5047 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -50,6 +50,8 @@ using qf::gui::framework::getPlugin; using Event::EventPlugin; using Classes::ClassesPlugin; +namespace { + class CourseCodesTableModel : public qfm::SqlTableModel { Q_OBJECT @@ -98,6 +100,7 @@ class CourseCodesTableModel : public qfm::SqlTableModel return Super::data(index, role); } }; +} ClassesWidget::ClassesWidget(QWidget *parent) : Super(parent), @@ -162,7 +165,6 @@ ClassesWidget::ClassesWidget(QWidget *parent) : data.useAllMaps = checked; event_config.setStageData(selectedStageId(), data); config->setEventConfig(event_config); - config->save(QStringLiteral("event")); }); } @@ -396,7 +398,8 @@ void ClassesWidget::importCourses(const QList &course_defs, con reload(); } -static QString normalize_course_name(const QString &course_name) +namespace { +QString normalize_course_name(const QString &course_name) { QString ret = qf::core::Collator::toAscii7(QLocale::Czech, course_name, false); ret.replace(' ', QString()); @@ -406,6 +409,7 @@ static QString normalize_course_name(const QString &course_name) ret.replace('-', '+'); return ret; } +} void ClassesWidget::import_ocad_txt() { @@ -572,7 +576,8 @@ void ClassesWidget::import_ocad_v8() } } -static QString element_text(const QDomElement &parent, const QString &tag_name) +namespace { +QString element_text(const QDomElement &parent, const QString &tag_name) { QDomElement el = parent.firstChildElement(tag_name); if(el.isNull()) @@ -580,13 +585,14 @@ static QString element_text(const QDomElement &parent, const QString &tag_name) return el.text(); } -static QString dump_element(const QDomElement &el) +QString dump_element(const QDomElement &el) { QString ret; QTextStream s(&ret); el.save(s, QDomNode::EncodingFromDocument); return ret; } +} void ClassesWidget::import_ocad_iofxml_2() { diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index 15d437068..566392053 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -168,7 +168,6 @@ void GanttItem::save(int stage_id) stage.drawingConfig = dc; event_config.setStageData(stage_id, stage); config->setEventConfig(event_config); - config->save(QStringLiteral("event")); } { QString qs = "UPDATE classdefs SET" @@ -301,8 +300,3 @@ void GanttItem::moveStartSlotItem(int from_slot_ix, int to_slot_ix) checkClassClash(); } } - - - - - diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp index 8e3e56595..e17be0920 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp @@ -23,7 +23,7 @@ GanttScene::GanttScene(QObject * parent) void GanttScene::load(int stage_id) { clear(); - Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); m_useAllMaps = stage_data.useAllMaps; m_ganttItem = new GanttItem(); addItem(m_ganttItem); diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index d0eb030b5..acd44cb79 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -1,6 +1,9 @@ #include "appdbconfig.h" + #include "eventplugin.h" +#include "eventconfig.h" +#include #include #include #include @@ -16,269 +19,172 @@ using namespace Event; namespace { -const auto EVENT_NAME = QStringLiteral("event.name"); + +constexpr auto EVENT = "event"; +constexpr auto RECEIPTS = "receipts"; +constexpr auto OFEED = "ofeed"; +constexpr auto ORESULTS = "oresults"; +constexpr auto QX = "qx"; + } -QVariant AppDbConfig::value(const QStringList &path, const QVariant &default_value) const +QxConfig QxConfig::fromVariantMap(const QVariantMap &map) { - //QF_ASSERT(knownKeys().contains(key), "Key " + key + " is not known key!", return QVariant()); - QVariant ret = default_value; - if(!path.isEmpty()) { - QVariantMap m = m_data; - for (int i = 0; i < path.count() - 1; ++i) { - const QString &key = path[i]; - m = m.value(key).toMap(); - } - ret = m.value(path.last(), default_value); - } + QxConfig ret; + ret.apiToken = map.value("apiToken").toString(); return ret; } -void AppDbConfig::setValue(const QStringList &path, const QVariant &val) +QVariantMap QxConfig::toVariantMap() const { - QF_ASSERT(!path.isEmpty(), "Empty path!", return); - m_data = setValue_helper(m_data, path, val); + QVariantMap ret; + ret["apiToken"] = apiToken; + return ret; } void AppDbConfig::load() { using namespace qf::core::sql; Connection conn = Connection::forName(); - - // Check connection existence / validity Q_ASSERT(conn.isOpen()); - // if(!conn.isOpen()) { - // qfWarning() << "EventConfig::load(): database connection is not open:" - // << conn.errorString(); - // return; - // } + + QVariantMap config; + const auto set_group_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { + auto m = config.value(group).toMap(); + m[path.mid(1).join('.')] = value; + config[group] = m; + }; + const auto set_gropu_stage_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { + auto stage = path.value(1); + auto m1 = config.value(group).toMap(); + auto m2 = m1.value(stage).toMap(); + m2[path.mid(2).join('.')] = value; + m1[stage] = m2; + config[group] = m1; + }; Query q(conn); QueryBuilder qb; - qb.select("ckey, cvalue, ctype").from("config").orderBy("ckey"); + qb.select("ckey, cvalue, ctype").from("config"); if(q.exec(qb.toString(), qf::core::Exception::Throw)) { while(q.next()) { QString key = q.value(0).toString(); - /* - if(!knownKeys().contains(key)) { - qfWarning() << "Config key" << key << "is not known to the QuickEvent config system"; - } - */ QVariant val = q.value(1); QString type = q.value(2).toString(); QVariant v = qf::core::Utils::retypeStringValue(val.toString(), type); - setValue(key, v); - } - } - // checkApiKey(); -} - -void AppDbConfig::save(const QString &path_to_save) -{ - QVariantMap m; - save_helper(m, QString(), m_data); - using namespace qf::core::sql; - Connection conn = Connection::forName(); - - try { - Query q_up(conn); - q_up.prepare("UPDATE config SET cvalue=:val WHERE ckey=:key", qf::core::Exception::Throw); - Query q_ins(conn); - q_ins.prepare("INSERT INTO config (ckey, cvalue, ctype) VALUES (:key, :val, :type)", qf::core::Exception::Throw); - QMapIterator it(m); - while(it.hasNext()) { - it.next(); - QString key = it.key(); - if(!path_to_save.isEmpty()) { - if(!key.startsWith(path_to_save)) - continue; - if(key.length() > path_to_save.length() && key[path_to_save.length()] != '.') - continue; - } - QVariant val = it.value(); - QString val_str; - if(val.typeId() == qMetaTypeId()) - val_str = val.toDate().toString(Qt::ISODate); - else if(val.typeId() == qMetaTypeId()) - val_str = val.toTime().toString(Qt::ISODate); - else if(val.typeId() == qMetaTypeId()) - val_str = val.toDateTime().toString(Qt::ISODate); - else - val_str = val.toString(); - q_up.bindValue(":key", key); - q_up.bindValue(":val", val_str); - q_up.exec(qf::core::Exception::Throw); - if(q_up.numRowsAffected() < 1) { - QString type = val.typeName(); - q_ins.bindValue(":key", key); - q_ins.bindValue(":type", type); - q_ins.bindValue(":val", val_str); - q_ins.exec(qf::core::Exception::Throw); + auto path = key.split('.'); + const auto group = path.value(0); + if (group == EVENT || group == QX) { + set_group_value(group, path, v); + } else if (group == RECEIPTS || group == ORESULTS || group == OFEED) { + set_gropu_stage_value(group, path, v); + } else { + config[key] = v; } + } } - catch(const qf::core::Exception &e) { - qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); - qf::gui::dialogs::MessageBox::showException(fwk, e); - } + m_dbVersion = config.value("db.version", 0).toInt(); + Q_ASSERT(m_dbVersion > 0); -} + m_qxConfig = QxConfig::fromVariantMap(config.value(QX).toMap()); + m_eventConfig = EventConfig::fromVariantMap(config.value(EVENT).toMap()); -void AppDbConfig::save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val) -{ - if(val.typeId() == qMetaTypeId()) { - QVariantMap m = val.toMap(); - QMapIterator it(m); - while(it.hasNext()) { - it.next(); - QString cp = it.key(); - if(!current_path.isEmpty()) - cp = current_path + '.' + cp; - save_helper(ret, cp, it.value()); + const auto load_stage_config = [&config](const QString &group, auto &target, auto fromVariantMap) { + for ( const auto &[stage, val] : config.value(group).toMap().asKeyValueRange()) { + target[stage.toInt()] = fromVariantMap(val.toMap()); } - } - else { - ret[current_path] = val; - } + }; + load_stage_config(RECEIPTS, m_receiptsConfig, Receipts::ReceiptsConfig::fromVariantMap); + load_stage_config(ORESULTS, m_oresultsConfig, services::OResultsConfig::fromVariantMap); + load_stage_config(OFEED, m_ofeedConfig, services::OFeedConfig::fromVariantMap); } -QVariantMap AppDbConfig::setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val) +void AppDbConfig::save(const QString &prefix, int stage_id, const QVariantMap &data) { - QVariantMap ret; - QF_ASSERT(!path.isEmpty(), "Empty path!", return ret); - if(path.count() == 1) { - ret = m; - ret[path.first()] = val; - } - else { - QStringList p = path; - QString key = p.takeFirst(); - ret = m; - ret[key] = setValue_helper(m.value(key).toMap(), p, val); - } - return ret; + save(prefix + "." + QString::number(stage_id), data); } - - -// namespace { -// auto const API_KEY_CONFIG_PATH = QStringLiteral("event.apiKey"); -// } -// QString EventConfig::apiKey() const -// { -// return value(API_KEY_CONFIG_PATH).toString(); -// } - -// void AppDbConfig::checkApiKey() -// { -// if (apiKey().isEmpty()) { -// auto api_key = EventPlugin::createApiKey(10); -// setValue(API_KEY_CONFIG_PATH, api_key); -// save(API_KEY_CONFIG_PATH); -// } -// } - - - -int AppDbConfig::dbVersion() const +void AppDbConfig::save(const QString &prefix, const QVariantMap &data) { - return value(QStringLiteral("db.version")).toInt(); -} - -std::optional AppDbConfig::maximumCardCheckAdvanceSec() const -{ - if(auto sec = eventConfig().cardCheckTimeSec; sec > 0) - return sec; - return {}; -} + using namespace qf::core::sql; + Connection conn = Connection::forName(); -EventConfig AppDbConfig::eventConfig() const -{ - return EventConfig::fromVariantMap(value(QStringLiteral("event")).toMap()); + Query q_up(conn); + q_up.prepare("UPDATE config SET cvalue=:val WHERE ckey=:key", qf::core::Exception::Throw); + Query q_ins(conn); + q_ins.prepare("INSERT INTO config (ckey, cvalue, ctype) VALUES (:key, :val, :type)", qf::core::Exception::Throw); + for (const auto &[key, val] : data.asKeyValueRange()) { + QString val_str; + if(val.typeId() == qMetaTypeId()) + val_str = val.toDate().toString(Qt::ISODate); + else if(val.typeId() == qMetaTypeId()) + val_str = val.toTime().toString(Qt::ISODate); + else if(val.typeId() == qMetaTypeId()) + val_str = val.toDateTime().toString(Qt::ISODate); + else + val_str = val.toString(); + auto full_key = prefix.isEmpty() ? key : prefix + "." + key; + q_up.bindValue(":key", full_key); + q_up.bindValue(":val", val_str); + q_up.exec(qf::core::Exception::Throw); + if(q_up.numRowsAffected() < 1) { + QString type = val.typeName(); + q_ins.bindValue(":key", full_key); + q_ins.bindValue(":type", type); + q_ins.bindValue(":val", val_str); + q_ins.exec(qf::core::Exception::Throw); + } + } } void AppDbConfig::setEventConfig(const EventConfig &config) { - setValue(QStringLiteral("event"), config.toVariantMap()); + m_eventConfig = config; + save(EVENT, config.toVariantMap()); } -OResultsConfig AppDbConfig::oresultsConfig(int stage_id) const +const services::OResultsConfig& AppDbConfig::oresultsConfig(int stage_id) const { - const QString e = QStringLiteral(".E") + QString::number(stage_id); - OResultsConfig cfg; - cfg.apiKey = value(QStringLiteral("oresults.apiKey") + e).toString(); - cfg.eventName = value(QStringLiteral("oresults.eventName") + e).toString(); - return cfg; + if (m_oresultsConfig.contains(stage_id)) { + return m_oresultsConfig.at(stage_id); + } + static services::OResultsConfig defaultCfg; + return defaultCfg; } -void AppDbConfig::setOresultsConfig(int stage_id, const OResultsConfig &cfg) +void AppDbConfig::setOresultsConfig(int stage_id, const services::OResultsConfig &cfg) { - const QString e = QStringLiteral(".E") + QString::number(stage_id); - setValue(QStringLiteral("oresults.apiKey") + e, cfg.apiKey); - setValue(QStringLiteral("oresults.eventName") + e, cfg.eventName); + m_oresultsConfig[stage_id] = cfg; + save(ORESULTS, stage_id, cfg.toVariantMap()); } -ReceiptsConfig AppDbConfig::receiptsConfig(int stage_id) const +const Receipts::ReceiptsConfig& AppDbConfig::receiptsConfig(int stage_id) const { - const QString e = QStringLiteral(".E") + QString::number(stage_id); - ReceiptsConfig cfg; - cfg.printQrCode = value(QStringLiteral("event.receiptPrintEventQrCode") + e, false).toBool(); - cfg.linkUrl = value(QStringLiteral("event.receiptEventLinkUrl") + e).toString().trimmed(); - const QString caption = value(QStringLiteral("event.receiptPrintEventQrCodeCaption") + e).toString().trimmed(); - cfg.qrCodeCaption = caption.isEmpty() ? QStringLiteral("Live Results") : caption; - cfg.printImage = value(QStringLiteral("event.receiptPrintEventImage") + e, false).toBool(); - const int h = value(QStringLiteral("event.receiptImageHeightMm") + e, 18).toInt(); - cfg.imageHeightMm = (h < 10) ? 10 : (h > 60) ? 60 : h; - cfg.imageBase64 = value(QStringLiteral("event.receiptImageDataBase64") + e).toString(); - const QString fmt = value(QStringLiteral("event.receiptImageFormat") + e).toString().trimmed().toLower(); - cfg.imageFormat = fmt.isEmpty() ? QStringLiteral("png") : fmt; - return cfg; + if (m_receiptsConfig.contains(stage_id)) { + return m_receiptsConfig.at(stage_id); + } + static Receipts::ReceiptsConfig defaultCfg; + return defaultCfg; } -void AppDbConfig::setReceiptsConfig(int stage_id, const ReceiptsConfig &cfg) +void AppDbConfig::setReceiptsConfig(int stage_id, const Receipts::ReceiptsConfig &cfg) { - const QString e = QStringLiteral(".E") + QString::number(stage_id); - setValue(QStringLiteral("event.receiptPrintEventQrCode") + e, cfg.printQrCode); - setValue(QStringLiteral("event.receiptEventLinkUrl") + e, cfg.linkUrl); - setValue(QStringLiteral("event.receiptPrintEventQrCodeCaption") + e, cfg.qrCodeCaption); - setValue(QStringLiteral("event.receiptPrintEventImage") + e, cfg.printImage); - setValue(QStringLiteral("event.receiptImageHeightMm") + e, cfg.imageHeightMm); - setValue(QStringLiteral("event.receiptImageDataBase64") + e, cfg.imageBase64); - setValue(QStringLiteral("event.receiptImageFormat") + e, cfg.imageFormat); + m_receiptsConfig[stage_id] = cfg; + save(RECEIPTS, stage_id, cfg.toVariantMap()); } -OFeedConfig AppDbConfig::ofeedConfig(int stage_id) const +const services::OFeedConfig& AppDbConfig::ofeedConfig(int stage_id) const { - const QString prefix = QStringLiteral("ofeed."); - const QString e = QStringLiteral(".E") + QString::number(stage_id); - OFeedConfig cfg; - const QString default_host = QStringLiteral("https://api.orienteerfeed.com"); - cfg.hostUrl = value(prefix + QStringLiteral("hostUrl") + e, default_host).toString(); - cfg.eventId = value(prefix + QStringLiteral("eventId") + e).toString(); - cfg.eventPassword = value(prefix + QStringLiteral("eventPassword") + e).toString(); - const QString origin = value(prefix + QStringLiteral("changelogOrigin") + e).toString(); - cfg.changelogOrigin = origin.isEmpty() ? QStringLiteral("START") : origin; - const QString lcc = value(prefix + QStringLiteral("lastChangelogCall") + e).toString(); - cfg.lastChangelogCall = lcc.isEmpty() ? QDateTime::fromSecsSinceEpoch(0) - : QDateTime::fromString(lcc, Qt::ISODate); - if (!cfg.lastChangelogCall.isValid()) - cfg.lastChangelogCall = QDateTime::fromSecsSinceEpoch(0); - cfg.runXmlValidation = value(prefix + QStringLiteral("runXmlValidation") + e, true).toBool(); - cfg.runChangesProcessing = value(prefix + QStringLiteral("runChangesProcessing") + e, false).toBool(); - cfg.introTourShowed = value(prefix + QStringLiteral("introTourShowed"), false).toBool(); - return cfg; + if (m_ofeedConfig.contains(stage_id)) { + return m_ofeedConfig.at(stage_id); + } + static services::OFeedConfig defaultCfg; + return defaultCfg; } -void AppDbConfig::setOfeedConfig(int stage_id, const OFeedConfig &cfg) +void AppDbConfig::setOfeedConfig(int stage_id, const services::OFeedConfig &cfg) { - const QString prefix = QStringLiteral("ofeed."); - const QString e = QStringLiteral(".E") + QString::number(stage_id); - setValue(prefix + QStringLiteral("hostUrl") + e, cfg.hostUrl); - setValue(prefix + QStringLiteral("eventId") + e, cfg.eventId); - setValue(prefix + QStringLiteral("eventPassword") + e, cfg.eventPassword); - setValue(prefix + QStringLiteral("changelogOrigin") + e, cfg.changelogOrigin); - setValue(prefix + QStringLiteral("lastChangelogCall") + e, cfg.lastChangelogCall.toString(Qt::ISODate)); - setValue(prefix + QStringLiteral("runXmlValidation") + e, cfg.runXmlValidation); - setValue(prefix + QStringLiteral("runChangesProcessing") + e, cfg.runChangesProcessing); - setValue(prefix + QStringLiteral("introTourShowed"), cfg.introTourShowed); + m_ofeedConfig[stage_id] = cfg; + save(OFEED, stage_id, cfg.toVariantMap()); } diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index a20caaeba..faf2bfebf 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -1,63 +1,55 @@ #pragma once #include "eventconfig.h" -#include "receiptsconfig.h" -#include "ofeedconfig.h" +#include "services/oresultsconfig.h" +#include "services/ofeed/ofeedconfig.h" +#include +#include #include -#include #include -#include - -#include -#include +#include +#include namespace Event { -struct QxConfig -{ - QString apiToken; -}; +struct QxConfig { + static QxConfig fromVariantMap(const QVariantMap &map); + QVariantMap toVariantMap() const; -struct OResultsConfig -{ - QString apiKey; - QString eventName; + QString apiToken; }; -class AppDbConfig -{ +class AppDbConfig { public: explicit AppDbConfig() = default; + public: void load(); - void save(const QString &path_to_save = QString()); - - bool isHandicap() const {return eventConfig().handicapLength > 0;} - - int dbVersion() const; - std::optional maximumCardCheckAdvanceSec() const; - EventConfig eventConfig() const; + int dbVersion() const { return m_dbVersion; } + const EventConfig &eventConfig() const { return m_eventConfig; } void setEventConfig(const EventConfig &config); - OResultsConfig oresultsConfig(int stage_id) const; - void setOresultsConfig(int stage_id, const OResultsConfig &config); - ReceiptsConfig receiptsConfig(int stage_id) const; - void setReceiptsConfig(int stage_id, const ReceiptsConfig &config); - OFeedConfig ofeedConfig(int stage_id) const; - void setOfeedConfig(int stage_id, const OFeedConfig &config); + const services::OResultsConfig &oresultsConfig(int stage_id) const; + void setOresultsConfig(int stage_id, const services::OResultsConfig &config); + const Receipts::ReceiptsConfig &receiptsConfig(int stage_id) const; + void setReceiptsConfig(int stage_id, const Receipts::ReceiptsConfig &config); + const services::OFeedConfig &ofeedConfig(int stage_id) const; + void setOfeedConfig(int stage_id, const services::OFeedConfig &config); + const QxConfig &qxConfig() const { return m_qxConfig; } + void setQxConfig(const QxConfig &config); + private: - void setValue(const QStringList &path, const QVariant &val); - void setValue(const QString &path, const QVariant &val) {setValue(path.split('.'), val);} - QVariantMap values() const {return m_data;} - QVariant value(const QStringList &path, const QVariant &default_value = QVariant()) const; - QVariant value(const QString &path, const QVariant &default_value = QVariant()) const { - return value(path.split('.'), default_value); - } - void save_helper(QVariantMap &ret, const QString ¤t_path, const QVariant &val); - QVariantMap setValue_helper(const QVariantMap &m, const QStringList &path, const QVariant &val); + void save(const QString &prefix, const QVariantMap &data); + void save(const QString &prefix, int stage_id, const QVariantMap &data); + private: - QVariantMap m_data; + std::map m_ofeedConfig; + std::map m_receiptsConfig; + std::map m_oresultsConfig; + EventConfig m_eventConfig; + QxConfig m_qxConfig; + int m_dbVersion = 0; }; -} +} // namespace Event diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index 9acdc6e67..fbff1e626 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -43,7 +43,7 @@ EventConfig EventConfig::fromVariantMap(const QVariantMap &values) ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() : drawing_config.toMap(); stage.qxApiToken = stage_values.value("qxApiToken").toString(); - data.stages.insert(stage_id, stage); + data.stages[stage_id] = stage; } data.name = values.value("name").toString(); data.date = values.value("date").toDate(); @@ -65,19 +65,30 @@ EventConfig EventConfig::fromVariantMap(const QVariantMap &values) return data; } +std::optional EventConfig::maximumCardCheckAdvanceSec() const +{ + if(auto sec = cardCheckTimeSec; sec > 0) + return sec; + return {}; +} + bool EventConfig::isRelays() const { return disciplineId == 5 || disciplineId == 6 || disciplineId == 15; } -StageData EventConfig::stageData(int stage_id) const +const StageData& EventConfig::stageData(int stage_id) const { - return stages.value(stage_id); + if (stages.contains(stage_id)) { + return stages.at(stage_id); + } + static StageData sd; + return sd; } void EventConfig::setStageData(int stage_id, const StageData &data) { - stages.insert(stage_id, data); + stages[stage_id] = data; } QVariantMap EventConfig::toVariantMap() const @@ -85,13 +96,13 @@ QVariantMap EventConfig::toVariantMap() const QVariantMap values; values.insert("stageCount", stageCount); QVariantMap stage_values; - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { + for(const auto &[key, val] : stages) { QVariantMap stage; - stage.insert("startDateTime", it.value().startDateTime); - stage.insert("useAllMaps", it.value().useAllMaps); - stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(it.value().drawingConfig)); - stage.insert("qxApiToken", it.value().qxApiToken); - stage_values.insert(QString::number(it.key()), stage); + stage.insert("startDateTime", val.startDateTime); + stage.insert("useAllMaps", val.useAllMaps); + stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(val.drawingConfig)); + stage.insert("qxApiToken", val.qxApiToken); + stage_values.insert(QString::number(key), stage); } values.insert("stage", stage_values); values.insert("name", name); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index 1f6267dca..fa0c91515 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -28,16 +28,21 @@ struct EventConfig KnocOutSprint = 16, Indoor = 19, }; + static std::optional disciplineFromInt(int i); - static EventConfig fromVariantMap(const QVariantMap &values); - QVariantMap toVariantMap() const; + bool isHandicap() const {return handicapLength > 0;} + std::optional maximumCardCheckAdvanceSec() const; + bool isRelays() const; - StageData stageData(int stage_id) const; + const StageData& stageData(int stage_id) const; void setStageData(int stage_id, const StageData &data); + static EventConfig fromVariantMap(const QVariantMap &values); + QVariantMap toVariantMap() const; + int stageCount = 1; - QMap stages; + std::map stages; QString name; QDate date; QTime time; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index 4d67deacb..ff2fb29a6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -127,7 +127,7 @@ void EventDialogWidget::loadParams(const Event::EventConfig ¶ms) ui->ed_stageCount->setValue(params.stageCount); updateStageStartTimeEditors(ui->ed_stageCount->value()); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - const QDateTime start_time = params.stages.value(row + 1).startDateTime; + const QDateTime start_time = params.stageData(row + 1).startDateTime; if(start_time.isValid()) { if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) editor->setDateTime(start_time); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 608c216b9..13cd9f780 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -4,6 +4,7 @@ #include "eventdialogwidget.h" #include "openeventdialog.h" #include "dbschema.h" +#include "plugins/Event/src/eventconfig.h" #include "registrationswidget.h" #include "lentcardssettingspage.h" #include "../../Core/src/widgets/appstatusbar.h" @@ -71,6 +72,8 @@ using qff::getPlugin; namespace Event { +namespace { + class DbEventPayload : public QVariantMap { private: @@ -106,10 +109,8 @@ QByteArray DbEventPayload::toJson() const return jsd.toJson(QJsonDocument::Compact); } -namespace { const auto QBE_EXT = QStringLiteral(".qbe"); - QString singleFileStorageDir() { ConnectionSettings connection_settings; @@ -225,6 +226,11 @@ Event::AppDbConfig *EventPlugin::appDbConfig(bool reload) return m_eventConfig; } +const EventConfig &EventPlugin::eventConfig() +{ + return appDbConfig()->eventConfig(); +} + int EventPlugin::stageCount() { if(eventName().isEmpty()) @@ -312,7 +318,7 @@ void EventPlugin::onInstalled() m_actCreateEvent = new qfw::Action(tr("Create eve&nt")); //m_actCreateEvent->setShortcut("Ctrl+N"); - connect(m_actCreateEvent, &QAction::triggered, this, [this]() { createEvent(); }); + connect(m_actCreateEvent, &QAction::triggered, this, [this]() { createEvent({}, {}); }); m_actEditEvent = new qfw::Action(tr("E&dit event")); m_actEditEvent->setEnabled(false); @@ -458,7 +464,6 @@ void EventPlugin::saveCurrentStageId(int current_stage) auto event_cfg = appDbConfig()->eventConfig(); event_cfg.currentStageId = current_stage; appDbConfig()->setEventConfig(event_cfg); - appDbConfig()->save("event"); } } @@ -853,19 +858,20 @@ bool run_sql_script(qf::core::sql::Query &q, const QStringList &sql_lines) return true; } } -bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &event_params) +bool EventPlugin::createEvent(const QString &event_name, const EventConfig &event_params) { qfLogFuncFrame(); qff::MainWindow *fwk = qff::MainWindow::frameWork(); EventPlugin::ConnectionType connection_type = connectionType(); QStringList existing_event_ids; - if(connection_type == ConnectionType::SingleFile) + if(connection_type == ConnectionType::SingleFile) { existing_event_ids = existingFileEventNames(); - else + } else { existing_event_ids = existingSqlEventNames(); + } QString event_id = event_name; - EventConfig new_params = EventConfig::fromVariantMap(event_params); + auto new_params = event_params; do { qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -892,13 +898,13 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even closeEvent(); - Event::AppDbConfig event_config; + Event::AppDbConfig app_db_config; bool ok = false; //ConnectionSettings connection_settings; - event_config.setEventConfig(new_params); + app_db_config.setEventConfig(new_params); int stage_count = new_params.stageCount; if(stage_count == 0) - stage_count = event_config.eventConfig().stageCount; + stage_count = app_db_config.eventConfig().stageCount; qfInfo() << "createEvent, stage_count:" << stage_count; QF_ASSERT(stage_count > 0, "Stage count have to be greater than 0", return false); @@ -930,24 +936,23 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even ok = run_sql_script(q, create_script); if(!ok) break; - qfDebug() << "creating stages:" << stage_count; - QString stage_table_name = "stages"; - if(connection_type == ConnectionType::SqlServer) { - stage_table_name = event_id + '.' + stage_table_name; - } - // Stage start times are stored in config as event.stage..startDateTime. - q.prepare("INSERT INTO " + stage_table_name + " (id) VALUES (:id)"); - for(int i=0; i.startDateTime. + // q.prepare("INSERT INTO " + stage_table_name + " (id) VALUES (:id)"); + // for(int i=0; isetWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - auto event_data = appDbConfig()->eventConfig(); - event_w->loadParams(event_data); + event_w->loadParams(appDbConfig()->eventConfig()); dlg.setCentralWidget(event_w); if(!dlg.exec()) return; - event_data = event_w->saveParams(); + auto event_data = event_w->saveParams(); appDbConfig()->setEventConfig(event_data); - appDbConfig()->save("event"); } bool EventPlugin::closeEvent() @@ -1320,8 +1323,8 @@ void EventPlugin::deleteEvent(const QString &event_name) .arg(event_name, q.lastErrorText())); } } - -static void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) +namespace { +void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) { dst.setHostName(src.hostName()); dst.setPort(src.port()); @@ -1329,7 +1332,7 @@ static void cloneDbConnection(qfs::Connection &dst, const qfs::Connection &src) dst.setPassword(src.password()); dst.setDatabaseName(src.databaseName()); } - +} bool EventPlugin::importEventFromFile(const QString &src_file, const QString &dest_event_name) { qfLogFuncFrame(); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 93f0f3eab..72bfc6a48 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -2,7 +2,6 @@ #define EVENTPLUGIN_H #include "appdbconfig.h" -#include "stagedata.h" #include @@ -65,6 +64,7 @@ class EventPlugin : public qf::gui::framework::Plugin Q_INVOKABLE void initEventConfig(); Event::AppDbConfig* appDbConfig(bool reload = false); + const Event::EventConfig& eventConfig(); int stageCount(); Q_SLOT void setCurrentStageId(int stage_id); @@ -82,12 +82,12 @@ class EventPlugin : public qf::gui::framework::Plugin - Q_SLOT bool createEvent(const QString &event_name = QString(), const QVariantMap &event_params = QVariantMap()); - Q_SLOT void editEvent(); - Q_SLOT bool closeEvent(); - Q_SLOT bool openEvent(const QString &event_name = QString()); - Q_SLOT void exportEvent_qbe(); - Q_SLOT void importEvent_qbe(); + bool createEvent(const QString &event_name, const EventConfig &event_params); + void editEvent(); + bool closeEvent(); + bool openEvent(const QString &event_name = QString()); + void exportEvent_qbe(); + void importEvent_qbe(); void emitReloadDataRequest() { emit reloadDataRequest(); } Q_SIGNAL void reloadDataRequest(); diff --git a/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h b/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h deleted file mode 100644 index 8b22a5c3d..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/ofeedconfig.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -namespace Event { - -struct OFeedConfig -{ - QString hostUrl; // Default "https://api.orienteerfeed.com" applied by AppDbConfig::ofeedConfig() - QString eventId; - QString eventPassword; - QString changelogOrigin; // Default "START" applied by AppDbConfig::ofeedConfig() - QDateTime lastChangelogCall; // Default QDateTime::fromSecsSinceEpoch(0) applied by AppDbConfig::ofeedConfig() - bool runXmlValidation = true; - bool runChangesProcessing = false; - // Non-stage-specific field, stored as ofeed.introTourShowed - bool introTourShowed = false; -}; - -} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 937f18f16..6cf8113a7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -461,7 +461,6 @@ void OFeedClient::setReceiptImageHeightMm(int height_mm) auto rc = config->receiptsConfig(current_stage); rc.imageHeightMm = height_mm; config->setReceiptsConfig(current_stage, rc); - config->save(QStringLiteral("event")); } QString OFeedClient::receiptEventLinkUrl() const @@ -495,7 +494,6 @@ void OFeedClient::setReceiptEventLinkUrl(QString link_url) auto rc = config->receiptsConfig(current_stage); rc.linkUrl = link_url; config->setReceiptsConfig(current_stage, rc); - config->save(QStringLiteral("event")); } QString OFeedClient::receiptEventQrCodeCaption() const @@ -518,7 +516,6 @@ void OFeedClient::setReceiptEventQrCodeCaption(QString caption) auto rc = config->receiptsConfig(current_stage); rc.qrCodeCaption = caption; config->setReceiptsConfig(current_stage, rc); - config->save(QStringLiteral("event")); } bool OFeedClient::hasCachedEventImage() const @@ -548,7 +545,6 @@ void OFeedClient::setCachedEventImage(const QByteArray &raw_data, const QString rc.imageBase64 = QString::fromLatin1(raw_data.toBase64()); rc.imageFormat = format.toLower(); config->setReceiptsConfig(current_stage, rc); - config->save(QStringLiteral("event")); } void OFeedClient::clearCachedEventImage() @@ -559,7 +555,6 @@ void OFeedClient::clearCachedEventImage() rc.imageBase64.clear(); rc.imageFormat.clear(); config->setReceiptsConfig(current_stage, rc); - config->save(QStringLiteral("event")); } void OFeedClient::ensureEventImageCachedAtStartup() @@ -681,7 +676,6 @@ void OFeedClient::setHostUrl(QString hostUrl) auto cfg = config->ofeedConfig(current_stage); cfg.hostUrl = hostUrl; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } @@ -692,7 +686,6 @@ void OFeedClient::setEventId(QString eventId) auto cfg = config->ofeedConfig(current_stage); cfg.eventId = eventId; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } @@ -703,7 +696,6 @@ void OFeedClient::setEventPassword(QString eventPassword) auto cfg = config->ofeedConfig(current_stage); cfg.eventPassword = eventPassword; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); m_eventImageStartupAttempted = false; } @@ -714,7 +706,6 @@ void OFeedClient::setChangelogOrigin(QString changelogOrigin) auto cfg = config->ofeedConfig(current_stage); cfg.changelogOrigin = changelogOrigin; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); } void OFeedClient::setLastChangelogCall(QDateTime lastChangelogCall) @@ -724,7 +715,6 @@ void OFeedClient::setLastChangelogCall(QDateTime lastChangelogCall) auto cfg = config->ofeedConfig(current_stage); cfg.lastChangelogCall = lastChangelogCall; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); } void OFeedClient::setRunXmlValidation(bool runXmlValidation) @@ -734,7 +724,6 @@ void OFeedClient::setRunXmlValidation(bool runXmlValidation) auto cfg = config->ofeedConfig(current_stage); cfg.runXmlValidation = runXmlValidation; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); } void OFeedClient::setRunChangesProcessing(bool runChangesProcessing) @@ -744,7 +733,6 @@ void OFeedClient::setRunChangesProcessing(bool runChangesProcessing) auto cfg = config->ofeedConfig(current_stage); cfg.runChangesProcessing = runChangesProcessing; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); } bool OFeedClient::introTourShowed() const @@ -761,7 +749,6 @@ void OFeedClient::setIntroTourShowed(bool shown) auto cfg = config->ofeedConfig(current_stage); cfg.introTourShowed = shown; config->setOfeedConfig(current_stage, cfg); - config->save(serviceName().toLower()); } void OFeedClient::testConnection(const QString &host_url, diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h index 2c4500d1c..773ec3400 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.h @@ -9,8 +9,8 @@ class QTimer; class QNetworkAccessManager; -namespace Event { -namespace services { + +namespace Event::services { class OFeedClientSettings : public ServiceSettings { @@ -134,6 +134,6 @@ class OFeedClient : public Service QByteArray zlibCompress(QByteArray data); }; -}} +} #endif // OFEEDCLIENT_H diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.cpp new file mode 100644 index 000000000..6c50a6f5c --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.cpp @@ -0,0 +1,40 @@ +#include "ofeedconfig.h" + +namespace Event::services { + +OFeedConfig::OFeedConfig() +{ + hostUrl = "https://api.orienteerfeed.com"; + changelogOrigin = "START"; + // lastChangelogCall = QDateTime::fromSecsSinceEpoch(0); +} + +OFeedConfig OFeedConfig::fromVariantMap(const QVariantMap& map) +{ + OFeedConfig config; + config.hostUrl = map.value("hostUrl", config.hostUrl).toString(); + config.eventId = map.value("eventId", config.eventId).toString(); + config.eventPassword = map.value("eventPassword", config.eventPassword).toString(); + config.changelogOrigin = map.value("changelogOrigin", config.changelogOrigin).toString(); + config.lastChangelogCall = map.value("lastChangelogCall", config.lastChangelogCall).toDateTime(); + config.runXmlValidation = map.value("runXmlValidation", config.runXmlValidation).toBool(); + config.runChangesProcessing = map.value("runChangesProcessing", config.runChangesProcessing).toBool(); + config.introTourShowed = map.value("introTourShowed", config.introTourShowed).toBool(); + return config; +} + +QVariantMap OFeedConfig::toVariantMap() const +{ + QVariantMap map; + map["hostUrl"] = hostUrl; + map["eventId"] = eventId; + map["eventPassword"] = eventPassword; + map["changelogOrigin"] = changelogOrigin; + map["lastChangelogCall"] = lastChangelogCall; + map["runXmlValidation"] = runXmlValidation; + map["runChangesProcessing"] = runChangesProcessing; + map["introTourShowed"] = introTourShowed; + return map; +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.h b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.h new file mode 100644 index 000000000..21259262c --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedconfig.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace Event::services { + +struct OFeedConfig +{ + OFeedConfig(); + static OFeedConfig fromVariantMap(const QVariantMap& map); + QVariantMap toVariantMap() const; + + QString hostUrl; + QString eventId; + QString eventPassword; + QString changelogOrigin; + QDateTime lastChangelogCall; + bool runXmlValidation = true; + bool runChangesProcessing = false; + // Non-stage-specific field, stored as ofeed.introTourShowed + bool introTourShowed = false; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index 0d8473393..df20127b2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -179,7 +179,6 @@ void OResultsClient::setApiKey(QString apiKey) auto cfg = db->oresultsConfig(current_stage); cfg.apiKey = apiKey; db->setOresultsConfig(current_stage, cfg); - db->save("oresults"); } QString OResultsClient::eventName() const @@ -195,7 +194,6 @@ void OResultsClient::setEventName(const QString &name) auto cfg = db->oresultsConfig(current_stage); cfg.eventName = name; db->setOresultsConfig(current_stage, cfg); - db->save("oresults"); } void OResultsClient::sendCompetitorChange(QString xml) { @@ -220,20 +218,20 @@ void OResultsClient::sendCompetitorChange(QString xml) { reply->deleteLater(); }); } - -static void append_list(QVariantList &lst, const QVariantList &new_lst) +namespace { +void append_list(QVariantList &lst, const QVariantList &new_lst) { lst.insert(lst.count(), new_lst); } -static int mop_start(int runner_start_ms) { +int mop_start(int runner_start_ms) { int stage_id = getPlugin()->currentStageId(); QDateTime event_start = getPlugin()->stageStartDateTime(stage_id); QDateTime runner_start = event_start.addMSecs(runner_start_ms); return event_start.date().startOfDay().msecsTo(runner_start) / 100; } -static int mop_run_status_code( +int mop_run_status_code( int time, bool isDisq, bool isDisqByOrganizer, @@ -257,7 +255,7 @@ static int mop_run_status_code( return 1; // OK return 0; // Unknown } - +} void OResultsClient::onCompetitorChanged(int competitor_id) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.cpp new file mode 100644 index 000000000..a3b657588 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.cpp @@ -0,0 +1,21 @@ +#include "oresultsconfig.h" + +namespace Event::services { + +OResultsConfig OResultsConfig::fromVariantMap(const QVariantMap &map) +{ + OResultsConfig ret; + ret.apiKey = map.value("apiKey").toString(); + ret.eventName = map.value("eventName").toString(); + return ret; +} + +QVariantMap OResultsConfig::toVariantMap() const +{ + QVariantMap ret; + ret["apiKey"] = apiKey; + ret["eventName"] = eventName; + return ret; +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.h b/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.h new file mode 100644 index 000000000..e9e75b36c --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsconfig.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +namespace Event::services { + +struct OResultsConfig +{ + static OResultsConfig fromVariantMap(const QVariantMap &map); + QVariantMap toVariantMap() const; + + QString apiKey; + QString eventName; +}; + +} // namespace Event::services diff --git a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp index 657a67f12..8582f3a1f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp @@ -139,7 +139,7 @@ void PunchingTestService::onTimerTick() // When enabled: 1/badCheckRate chance the runner checked too early (triggers bad-check). // When disabled: natural 1–2 minute window, no bad-check possible. int check_offset_sec; - if (auto cfg = event_plugin->appDbConfig()->maximumCardCheckAdvanceSec(); cfg.has_value()) { + if (auto cfg = event_plugin->appDbConfig()->eventConfig().maximumCardCheckAdvanceSec(); cfg.has_value()) { int max_sec = cfg.value(); if (rng.bounded(static_cast(ss.badCheckRate())) == 0) { // Bad check: checked too early — [max+1, max*3] seconds before start diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index f603b94b1..5772c2cd6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -483,7 +483,7 @@ void QxClientService::pollQxChanges() EventInfo QxClientService::eventInfo() const { auto *event_plugin = getPlugin(); - const auto event_config = event_plugin->appDbConfig()->eventConfig(); + const auto &event_config = event_plugin->appDbConfig()->eventConfig(); EventInfo ei; ei.set_stage(event_plugin->currentStageId()); ei.set_stage_count(event_plugin->stageCount()); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp index 41de67c59..2e6f46827 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp @@ -103,7 +103,6 @@ bool QxClientServiceWidget::saveSettings() stage_data.qxApiToken = ui->edApiToken->text(); event_config.setStageData(current_stage, stage_data); config->setEventConfig(event_config); - config->save(QStringLiteral("event")); } return true; } @@ -188,4 +187,3 @@ void QxClientServiceWidget::exportRuns() } } - diff --git a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp index cff49f1d9..66907e0c6 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp @@ -355,18 +355,18 @@ void OrisImporter::importEvent(int event_id, std::function success_call } auto discipline = discipline_id_opt.value_or(Event::EventConfig::Discipline::LongDistance); qfInfo() << "pocet etap:" << stage_count << "sport id:" << sport_id << "discipline id:" << di; - QVariantMap ecfg; - ecfg["stageCount"] = stage_count; - ecfg["name"] = data.value(QStringLiteral("Name")).toString(); - ecfg["description"] = QString(); - ecfg["date"] = QDate::fromString(data.value(QStringLiteral("Date")).toString(), Qt::ISODate); - ecfg["place"] = data.value(QStringLiteral("Place")).toString(); - ecfg["mainReferee"] = jsonObjectToFullName(data, QStringLiteral("MainReferee")); - ecfg["director"] = jsonObjectToFullName(data, QStringLiteral("Director")); - ecfg["sportId"] = sport_id; - ecfg["disciplineId"] = static_cast(discipline); - ecfg["importId"] = event_id; - ecfg["time"] = QTime::fromString(data.value(QStringLiteral("StartTime")).toString(), QStringLiteral("hh:mm")); + Event::EventConfig ecfg; + ecfg.stageCount = stage_count; + ecfg.name = data.value(QStringLiteral("Name")).toString(); + ecfg.description = QString(); + ecfg.date = QDate::fromString(data.value(QStringLiteral("Date")).toString(), Qt::ISODate); + ecfg.place = data.value(QStringLiteral("Place")).toString(); + ecfg.mainReferee = jsonObjectToFullName(data, QStringLiteral("MainReferee")); + ecfg.director = jsonObjectToFullName(data, QStringLiteral("Director")); + ecfg.sportId = sport_id; + ecfg.disciplineId = static_cast(discipline); + ecfg.importId = event_id; + ecfg.time = QTime::fromString(data.value(QStringLiteral("StartTime")).toString(), QStringLiteral("hh:mm")); if(!getPlugin()->createEvent(QString(), ecfg)) return; diff --git a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp index 8b96e4455..577450b06 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp @@ -185,7 +185,7 @@ bool XmlImporter::importEntries(QXmlStreamReader &reader, const XmlCreators crea } } - const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); int selected_race = event_config.iofXmlRaceNumber; // if entries has more races in (defined in Event), selected race // load from XML & insert to db int items_processed = 0; @@ -806,20 +806,20 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato else return false; try { - QVariantMap ecfg; - ecfg["stageCount"] = 1; - ecfg["name"] = (event_race.name.isEmpty()) ? race_name : event_race.name; - ecfg["description"] = (event_race.name.isEmpty())? QString() : race_name; - ecfg["date"] = event_race.datetime.date(); - ecfg["place"] = QString(); - ecfg["mainReferee"] = QString(); - ecfg["director"] = QString(); - ecfg["sportId"] = static_cast(Event::EventConfig::Sport::OB); - ecfg["disciplineId"] = static_cast(discipline); - ecfg["importId"] = event_id; - ecfg["time"] = event_race.datetime.time(); - ecfg["iofRace"] = 1; - ecfg["iofXmlRaceNumber"] = (races.size() > 1) ? event_race.number : 0; + Event::EventConfig ecfg; + ecfg.stageCount = 1; + ecfg.name = (event_race.name.isEmpty()) ? race_name : event_race.name; + ecfg.description = (event_race.name.isEmpty())? QString() : race_name; + ecfg.date = event_race.datetime.date(); + ecfg.place = QString(); + ecfg.mainReferee = QString(); + ecfg.director = QString(); + ecfg.sportId = static_cast(Event::EventConfig::Sport::OB); + ecfg.disciplineId = static_cast(discipline); + ecfg.importId = event_id; + ecfg.time = event_race.datetime.time(); + ecfg.iofRace = 1; + ecfg.iofXmlRaceNumber = (races.size() > 1) ? event_race.number : 0; return getPlugin()->createEvent(QString(), ecfg); } catch (qf::core::Exception &e) { diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp new file mode 100644 index 000000000..31b61d69f --- /dev/null +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp @@ -0,0 +1,37 @@ +#include "receiptsconfig.h" + +#include + +namespace Receipts { + +ReceiptsConfig::ReceiptsConfig() +{ + qrCodeCaption = "Live Results"; + imageFormat = "png"; +} + +ReceiptsConfig ReceiptsConfig::fromVariantMap(const QVariantMap &map) +{ + ReceiptsConfig config; + config.printQrCode = map.value("printQrCode", config.printQrCode).toBool(); + config.qrCodeCaption = map.value("qrCodeCaption", config.qrCodeCaption).toString(); + config.printImage = map.value("printImage", config.printImage).toBool(); + config.imageHeightMm = map.value("imageHeightMm", config.imageHeightMm).toInt(); + config.imageBase64 = map.value("imageBase64", config.imageBase64).toString(); + config.imageFormat = map.value("imageFormat", config.imageFormat).toString(); + return config; +} + +QVariantMap ReceiptsConfig::toVariantMap() const +{ + QVariantMap ret; + ret["printQrCode"] = printQrCode; + ret["qrCodeCaption"] = qrCodeCaption; + ret["printImage"] = printImage; + ret["imageHeightMm"] = imageHeightMm; + ret["imageBase64"] = imageBase64; + ret["imageFormat"] = imageFormat; + return ret; +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.h similarity index 73% rename from quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h rename to quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.h index a9d4e48e5..35e774cb2 100644 --- a/quickevent/app/quickevent/plugins/Event/src/receiptsconfig.h +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.h @@ -2,10 +2,14 @@ #include -namespace Event { +namespace Receipts { struct ReceiptsConfig { + ReceiptsConfig(); + static ReceiptsConfig fromVariantMap(const QVariantMap &map); + QVariantMap toVariantMap() const; + bool printQrCode = false; QString linkUrl; QString qrCodeCaption; // Default "Live Results" applied by AppDbConfig::receiptsConfig() diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index 32c158973..b3b36b4eb 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -55,7 +55,7 @@ using CardReader::CardReaderPlugin; namespace Receipts { namespace { -Event::ReceiptsConfig currentReceiptsConfig() +ReceiptsConfig currentReceiptsConfig() { const int current_stage = qMax(getPlugin()->currentStageId(), 1); return getPlugin()->appDbConfig()->receiptsConfig(current_stage); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp index 90d2ccfa1..49c78a973 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp @@ -425,7 +425,7 @@ void ReceiptsSettingsPage::save() Q_ASSERT(event_plugin); auto *event_config = event_plugin->appDbConfig(); Q_ASSERT(event_config); - Event::ReceiptsConfig rc; + ReceiptsConfig rc; rc.printQrCode = ui->chkPrintReceiptQrCode->isChecked(); rc.linkUrl = ui->edReceiptQrCodeBaseUrl->text().trimmed(); rc.qrCodeCaption = ui->edReceiptQrCodeCaption->text().trimmed(); @@ -434,7 +434,6 @@ void ReceiptsSettingsPage::save() rc.imageBase64 = m_receiptImageBase64; rc.imageFormat = m_receiptImageFormat; event_config->setReceiptsConfig(m_stageId, rc); - event_config->save(QStringLiteral("event")); } QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index d9831f55c..40e8e5613 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -221,7 +221,7 @@ qf::core::utils::TreeTable RelaysPlugin::nLegsResultsTable(const QString &where_ qfDebug() << "nLegsResultsTable table:" << wt(); return tt; } - +namespace { QPair getClubFromName(QString name) { qf::core::sql::Query q; @@ -230,7 +230,7 @@ QPair getClubFromName(QString name) return qMakePair(q.value(0).toInt(), q.value(1).toString()); return qMakePair(0,""); } - +} qf::core::utils::TreeTable RelaysPlugin::nLegsClassResultsTable(int class_id, int leg_count, int max_places, bool exclude_not_finish) { @@ -579,7 +579,7 @@ QString RelaysPlugin::resultsIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); bool is_iof_race = event_config.iofRace; //auto tt_classes = getPlugin()->nLegsResultsTable("classes.name='D105'", 999, 999999, false); auto tt_classes = getPlugin()->nLegsResultsTable(QString(), 999, 999999, false); @@ -863,7 +863,7 @@ QString RelaysPlugin::startListIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); bool is_iof_race = event_config.iofRace; qf::core::utils::TreeTable tt_classes = startListByClassesTableData(QString(), false); QVariantList start_list{ diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index 3827fbb82..d576c8a0a 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -960,7 +960,7 @@ QString RunsPlugin::resultsIofXml30Stage(int stage_id) { QDateTime stage_start_date_time = getPlugin()->stageStartDateTime(stage_id);//.toTimeSpec(Qt::OffsetFromUTC); qf::core::utils::TreeTable tt1 = stageResultsTable(stage_id, QString(), 0, false, true); - const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); bool is_iof_race = event_config.iofRace; int iof_xml_race_number = event_config.iofXmlRaceNumber; @@ -1179,7 +1179,7 @@ void RunsPlugin::writeCSOSHeader(QTextStream &ts) const auto *evp = getPlugin(); int stage_id = selectedStageId(); QDateTime start_dt = evp->stageStartDateTime(stage_id); - const auto ec = evp->appDbConfig()->eventConfig(); + const auto &ec = evp->appDbConfig()->eventConfig(); static constexpr int HWIDTH = -19; ts << make_width("Kod zavodu", HWIDTH) << ": " << ec.importId << "\r\n"; ts << make_width("Nazev zavodu", HWIDTH) << ": " << ec.name << "\r\n"; @@ -2737,7 +2737,7 @@ QString RunsPlugin::getClubAbbrFromName(QString name) QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::ReportOptionsDialog::VacantsOption vacants_option) { QDateTime start00 = getPlugin()->stageStartDateTime(stage_id); - const auto event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); //console.debug("print_vacants", print_vacants); auto tt1 = startListClassesTable("", vacants_option, quickevent::gui::ReportOptionsDialog::StartTimeFormat::RelativeToClassStart); bool is_iof_race = event_config.iofRace; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 1669d130b..1a5d5c8bb 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -693,7 +693,7 @@ void RunsWidget::onDrawClicked() bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); - Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); bool use_all_maps = stage_data.useAllMaps; qfDebug() << "DrawMethod:" << (int)draw_method << "use_all_maps:" << use_all_maps; QList class_ids; From 32af62c5162d1491b1f7c6d91cdf62123906ff6e Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 18 Jul 2026 01:13:24 +0200 Subject: [PATCH 75/83] Use EventPlugin::eventConfig() directly --- .../plugins/CardReader/src/cardchecker.cpp | 2 +- .../CardReader/src/cardreaderplugin.cpp | 4 +-- .../CardReader/src/cardreaderwidget.cpp | 2 +- .../plugins/Classes/src/classesplugin.cpp | 2 +- .../plugins/Classes/src/classeswidget.cpp | 10 +++---- .../plugins/Classes/src/drawing/ganttitem.cpp | 2 +- .../Classes/src/drawing/ganttscene.cpp | 2 +- .../Competitors/src/competitorwidget.cpp | 10 +++---- .../plugins/Event/src/services/emmaclient.cpp | 10 +++---- .../Event/src/services/ofeed/ofeedclient.cpp | 4 +-- .../Event/src/services/oresultsclient.cpp | 4 +-- .../plugins/Oris/src/orisimporter.cpp | 12 ++++---- .../plugins/Oris/src/xmlimporter.cpp | 4 +-- .../plugins/Receipts/src/receiptsplugin.cpp | 2 +- .../plugins/Receipts/src/receiptswidget.cpp | 2 +- .../plugins/Relays/src/relaysplugin.cpp | 8 ++--- .../plugins/Relays/src/relayswidget.cpp | 2 +- .../plugins/Runs/src/runsplugin.cpp | 30 +++++++++---------- .../Runs/src/runstableitemdelegate.cpp | 4 +-- .../plugins/Runs/src/runstablewidget.cpp | 2 +- .../plugins/Runs/src/runswidget.cpp | 22 +++++++------- .../Runs/src/services/resultsexporter.cpp | 6 ++-- 22 files changed, 73 insertions(+), 73 deletions(-) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp index 9a47d0e5e..4ca899c17 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardchecker.cpp @@ -82,7 +82,7 @@ int CardChecker::startTimeSec(int run_id) std::optional CardChecker::maximumCardCheckAdvanceSec() { - return getPlugin()->appDbConfig()->eventConfig().maximumCardCheckAdvanceSec(); + return getPlugin()->eventConfig().maximumCardCheckAdvanceSec(); } quickevent::core::CourseDef CardChecker::courseCodesForRunId(int run_id) diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp index 684ff258c..d2b21eb18 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp @@ -115,7 +115,7 @@ int CardReaderPlugin::findRunId(int si_id, int si_finish_time, QString *err_msg) *err_msg = QString(); int si_finish_time_msec = getPlugin()->msecToStageStartAM(si_finish_time); qf::core::sql::Query q; - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(is_relays) { q.exec("SELECT id, leg, startTimeMs, finishTimeMs FROM runs WHERE siId=" QF_IARG(si_id) " AND isRunning" @@ -551,7 +551,7 @@ void CardReaderPlugin::setStartTime(int relay_id, int leg, int start_time) { bool CardReaderPlugin::processCardToRunAssignment(int card_id, int run_id) { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(is_relays) { qf::core::sql::Query q; q.execThrow("SELECT relayId, leg, startTimeMs FROM runs WHERE id=" + QString::number(run_id)); diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp index a894ef549..dd0ac7c2f 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderwidget.cpp @@ -488,7 +488,7 @@ void CardReaderWidget::reset() void CardReaderWidget::reload() { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); //QString driver_name = m_cardsModel->sqlConnection().driverName(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp index 3ea47c97e..4fb77506d 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classesplugin.cpp @@ -93,7 +93,7 @@ void ClassesPlugin::createCourses(int stage_id, const QList &co { qfLogFuncFrame(); try { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); qf::core::sql::Transaction transaction(qf::core::sql::Connection::forName()); qf::core::sql::Query q; if (delete_current) diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index d47cf5047..e4a3bce76 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -359,7 +359,7 @@ void ClassesWidget::reload() } m_courseItemDelegate->setCourses(courses); } - ui->chkUseAllMaps->setChecked(getPlugin()->appDbConfig()->eventConfig().stageData(stage_id).useAllMaps); + ui->chkUseAllMaps->setChecked(getPlugin()->eventConfig().stageData(stage_id).useAllMaps); reloadCourseCodes(); } @@ -413,7 +413,7 @@ QString normalize_course_name(const QString &course_name) void ClassesWidget::import_ocad_txt() { - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->eventConfig().isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -501,7 +501,7 @@ void ClassesWidget::import_ocad_v8() lines << QString::fromUtf8(ba).trimmed(); } try { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QMap defined_courses_map; for(const auto &line : lines) { // [classname];coursename;[relay.leg];lenght_km;climb;S1;dist_1;code_1[;dist_n;code_n];dist_finish;F1 @@ -596,7 +596,7 @@ QString dump_element(const QDomElement &el) void ClassesWidget::import_ocad_iofxml_2() { - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->eventConfig().isRelays()) { QMessageBox::warning(this,tr("Warning"),tr("Import does not yet support relays.")); return; } @@ -745,7 +745,7 @@ void ClassesWidget::import_ocad_iofxml_3() coursedef.addClass(class_name); } } - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->eventConfig().isRelays()) { QDomNodeList ndlst = xdoc.elementsByTagName(QStringLiteral("TeamCourseAssignment")); QMap relay_courses; for (int i = 0; i < ndlst.count(); ++i) { diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index 566392053..c4aceeb05 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -63,7 +63,7 @@ StartSlotItem *GanttItem::addStartSlotItem() void GanttItem::load(int stage_id) { qfLogFuncFrame(); - Event::StageData stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); + Event::StageData stage_data = getPlugin()->eventConfig().stageData(stage_id); DrawingConfig dc(stage_data.drawingConfig); QVariantList start_slot_list = dc.startSlots(); diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp index e17be0920..8136a2aa1 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp @@ -23,7 +23,7 @@ GanttScene::GanttScene(QObject * parent) void GanttScene::load(int stage_id) { clear(); - const auto &stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->eventConfig().stageData(stage_id); m_useAllMaps = stage_data.useAllMaps; m_ganttItem = new GanttItem(); addItem(m_ganttItem); diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp index 085c276f6..323ac9831 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp @@ -155,7 +155,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : ui(new Ui::CompetitorWidget) { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); setPersistentSettingsId("CompetitorWidget"); ui->setupUi(this); @@ -205,7 +205,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : connect(ui->tblRuns, &qfw::TableView::editCellRequest, this, [this](QModelIndex index) { auto col = index.column(); if(col == CompetitorRunsModel::col_runs_startTimeMs) { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if (!is_relays) { saveData(); auto row = ui->tblRuns->tableRow(); @@ -477,7 +477,7 @@ void CompetitorWidget::onRegistrationSelected(const QVariantMap &values) qfDebug() << "\t" << s << "->" << values.value(s); doc->setValue(s, values.value(s)); } - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(!is_relays) { // if no class is set, guess class from registration if(ui->cbxClass->currentText().isEmpty()) { @@ -517,7 +517,7 @@ void CompetitorWidget::save() bool CompetitorWidget::saveData() { try { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); auto *doc = qobject_cast(dataController()->document()); if(!is_relays && doc->value(QStringLiteral("classId")).toInt() == 0) { qf::gui::dialogs::MessageBox::showWarning(this, tr("Class should be entered.")); @@ -537,7 +537,7 @@ bool CompetitorWidget::acceptDialogDone(int result) { if (result == QDialog::Accepted) { auto *doc = qobject_cast(dataController()->document()); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if (doc->mode() != Competitors::CompetitorDocument::ModeDelete) { if (doc->value("classId").toInt() == 0 && !is_relays) { QMessageBox::information(this, tr("Competitor form check"), tr("Class must be set.")); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp index 299781a49..b40a05a26 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/emmaclient.cpp @@ -90,7 +90,7 @@ void EmmaClient::exportRadioCodesRacomTxt() QTextStream ts_codes(&f_splitcodes); int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if (is_relays) { qfs::QueryBuilder qb_classes; @@ -193,7 +193,7 @@ void EmmaClient::exportResultsIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".results.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -213,7 +213,7 @@ void EmmaClient::exportStartListIofXml3() QString export_dir = ss.exportDir(); QString file_name = export_dir + '/' + ss.fileNameBase() + ".startlist.xml"; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() @@ -405,7 +405,7 @@ void EmmaClient::exportStartListRacomTxt() const QTextStream ts(&f); ts.setGenerateByteOrderMark(true); // BOM - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); int current_stage = getPlugin()->currentStageId(); qfs::QueryBuilder qb; qb.select2("runs", "startTimeMs, siId, competitorId, isrunning, leg, finishTimeMs") @@ -526,7 +526,7 @@ void EmmaClient::exportStartListRacomCsv() const #else ts.setCodec("UTF-8"); #endif - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); int current_stage = getPlugin()->currentStageId(); const QString separator(";"); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 6cf8113a7..5ace8fc86 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -160,7 +160,7 @@ void OFeedClient::exportResultsIofXml3() m_resultsExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -180,7 +180,7 @@ void OFeedClient::exportStartListIofXml3(std::function on_success) m_startListExportInProgress = true; int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index df20127b2..0afde70b6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -60,7 +60,7 @@ void OResultsClient::stop() { void OResultsClient::exportResultsIofXml3() { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -72,7 +72,7 @@ void OResultsClient::exportResultsIofXml3() void OResultsClient::exportStartListIofXml3(std::function on_success) { int current_stage = getPlugin()->currentStageId(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->startListIofXml30() diff --git a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp index 66907e0c6..9cacd324e 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/orisimporter.cpp @@ -141,7 +141,7 @@ void OrisImporter::syncCurrentEventEntries(std::function success_callba { qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); //if(!qf::gui::dialogs::MessageBox::askYesNo(fwk, tr("All runners entries imported from Oris will be synchronized, manual changes will be lost!"))) - int oris_id = getPlugin()->appDbConfig()->eventConfig().importId; + int oris_id = getPlugin()->eventConfig().importId; if(oris_id == 0) { qf::gui::dialogs::MessageBox::showError(fwk, tr("Cannot find Oris import ID.")); return; @@ -370,7 +370,7 @@ void OrisImporter::importEvent(int event_id, std::function success_call if(!getPlugin()->createEvent(QString(), ecfg)) return; - bool is_relay = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relay = getPlugin()->eventConfig().isRelays(); //QString event_name = getPlugin()->eventName(); qfLogScope("importEvent"); qf::core::sql::Transaction transaction; @@ -468,7 +468,7 @@ const char KEY_ORIG_RUNS[] = "origRuns"; void OrisImporter::syncEventEntries(int event_id, std::function success_callback) { - if(getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if(getPlugin()->eventConfig().isRelays()) { syncRelaysEntries(event_id, success_callback); return; } @@ -770,7 +770,7 @@ void OrisImporter::syncEventEntries(int event_id, std::function success void OrisImporter::importRegistrations(std::function success_callback) { - int sport_id = getPlugin()->appDbConfig()->eventConfig().sportId; + int sport_id = getPlugin()->eventConfig().sportId; int year = QDate::currentDate().addMonths(-2).year(); bool ok; @@ -899,7 +899,7 @@ void OrisImporter::getAndImportClub(const QString &club, const QString &key) void OrisImporter::importMissingOneTimeClubs() { auto *fwk = qf::gui::framework::MainWindow::frameWork(); - auto event_key = getPlugin()->appDbConfig()->eventConfig().orisEventKey; + auto event_key = getPlugin()->eventConfig().orisEventKey; if (event_key.isEmpty()) { QMessageBox::warning(fwk,tr("Warning"),tr("For import one-time clubs, you need to fill ORIS Event Key in File->Event->Edit event")); return; @@ -926,7 +926,7 @@ void OrisImporter::importMissingOneTimeClubs() } } - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->eventConfig().isRelays()) { // also from relays table q.exec("SELECT id, club FROM relays ORDER BY id", qf::core::Exception::Throw); while(q.next()) { diff --git a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp index 577450b06..155eb6078 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp @@ -185,7 +185,7 @@ bool XmlImporter::importEntries(QXmlStreamReader &reader, const XmlCreators crea } } - const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->eventConfig(); int selected_race = event_config.iofXmlRaceNumber; // if entries has more races in (defined in Event), selected race // load from XML & insert to db int items_processed = 0; @@ -476,7 +476,7 @@ bool XmlImporter::importStartlist(QXmlStreamReader &reader, const XmlCreators cr bool XmlImporter::importClasses(QXmlStreamReader &reader, const XmlCreators creator) { // load data from XML - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); qf::core::sql::Transaction transaction; int items_processed = 0; while(reader.readNextStartElement()) { diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index b3b36b4eb..9bacc0389 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -391,7 +391,7 @@ QVariantMap ReceiptsPlugin::receiptTablesData(int card_id) { qfLogFuncFrame() << card_id; QF_TIME_SCOPE("receiptTablesData()"); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QVariantMap ret; quickevent::core::si::ReadCard read_card = getPlugin()->readCard(card_id); quickevent::core::si::CheckedCard checked_card = getPlugin()->checkCard(read_card); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp index 22eecda98..2ba315bbf 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptswidget.cpp @@ -117,7 +117,7 @@ void ReceiptsWidget::reset() void ReceiptsWidget::reload() { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); int current_stage = currentStageId(); qfs::QueryBuilder qb; qb.select2("cards", "id, siId, printerConnectionId") diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index 40e8e5613..90953149b 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -189,7 +189,7 @@ qf::core::utils::TreeTable RelaysPlugin::nLegsResultsTable(const QString &where_ { qfLogFuncFrame() << "leg cnt:" << leg_count; qf::core::utils::TreeTable tt; - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); tt.appendColumn("className", QMetaType(QMetaType::QString)); qfs::QueryBuilder qb; @@ -513,7 +513,7 @@ QVariant RelaysPlugin::startListByClassesTableData(const QString &class_filter, //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; @@ -579,7 +579,7 @@ QString RelaysPlugin::resultsIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->eventConfig(); bool is_iof_race = event_config.iofRace; //auto tt_classes = getPlugin()->nLegsResultsTable("classes.name='D105'", 999, 999999, false); auto tt_classes = getPlugin()->nLegsResultsTable(QString(), 999, 999999, false); @@ -863,7 +863,7 @@ QString RelaysPlugin::startListIofXml30() { QDateTime start00 = getPlugin()->stageStartDateTime(1); qfDebug() << "creating table"; - const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->eventConfig(); bool is_iof_race = event_config.iofRace; qf::core::utils::TreeTable tt_classes = startListByClassesTableData(QString(), false); QVariantList start_list{ diff --git a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp index 3d540b08a..61b90d3f1 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp @@ -392,7 +392,7 @@ QVariant RelaysWidget::startListByClubsTableData(bool with_vacants) //console.info("currentStageTable query:", reportModel.effectiveQuery()); model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(1)); { qf::core::sql::QueryBuilder qb; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index d576c8a0a..dd6ef29cc 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -169,7 +169,7 @@ int RunsPlugin::courseForRun(int run_id) { // TODO: implementation should be dependend on event type and exposed to QML // see: CardCheck pattern - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(is_relays) { return courseForRun_Relays(run_id); } @@ -759,7 +759,7 @@ qf::core::utils::TreeTable RunsPlugin::stageResultsTable(int stage_id, const QSt model.reload(); qf::core::utils::TreeTable tt = model.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { @@ -960,7 +960,7 @@ QString RunsPlugin::resultsIofXml30Stage(int stage_id) { QDateTime stage_start_date_time = getPlugin()->stageStartDateTime(stage_id);//.toTimeSpec(Qt::OffsetFromUTC); qf::core::utils::TreeTable tt1 = stageResultsTable(stage_id, QString(), 0, false, true); - const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->eventConfig(); bool is_iof_race = event_config.iofRace; int iof_xml_race_number = event_config.iofXmlRaceNumber; @@ -1295,7 +1295,7 @@ bool RunsPlugin::exportResultsCsosOverall(int stage_count, const QString &file_n qf::core::sql::QueryBuilder RunsPlugin::runsQuery(int stage_id, int class_id, bool show_offrace) { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); qfs::QueryBuilder qb; qb.select2("runs", "*") .select2("classes", "name") @@ -1429,7 +1429,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesTable(const QString &wher m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("courses.numberOfControls", QMetaType(QMetaType::Int)); tt.appendColumn("courses.startNumber", QMetaType(QMetaType::Int)); @@ -1563,7 +1563,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsTable(const quickevent::gui m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -1632,7 +1632,7 @@ qf::core::utils::TreeTable RunsPlugin::startListStartersTable(const QString &whe qf::core::utils::TreeTable tt; tt.setValue("stageId", stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(stage_id)); tt.appendColumn("competitors.registration", QMetaType(QMetaType::QString)); @@ -1732,7 +1732,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClassesNStagesTable(const int st m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", sel_stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); QVector start00_epoch_sec; for(int stage_id = 1; stage_id <= stages_count; stage_id++) { @@ -1780,7 +1780,7 @@ qf::core::utils::TreeTable RunsPlugin::startListClubsNStagesTable(const int stag m.reload(); auto tt = m.toTreeTable(); tt.setValue("stageId", sel_stage_id); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); tt.setValue("stageStart", getPlugin()->stageStartDateTime(sel_stage_id)); { qf::core::utils::TreeTableColumn c = tt.column(0); @@ -2045,7 +2045,7 @@ void RunsPlugin::report_resultsAwards() return; QVariantMap props; - props["eventConfig"] = getPlugin()->appDbConfig()->eventConfig().toVariantMap(); + props["eventConfig"] = getPlugin()->eventConfig().toVariantMap(); auto tt = stageResultsTable(opts.value("stageId").toInt(), QString(), opts.value("numPlaces").toInt()); qf::gui::reports::ReportViewWidget::showReport(fwk , findReportFile(rep_path) @@ -2069,7 +2069,7 @@ void RunsPlugin::report_resultsNStages() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); @@ -2096,7 +2096,7 @@ void RunsPlugin::report_resultsNStagesSpeaker() return; auto opts = dlg.options(); auto tt = nstagesResultsTable(dlg.sqlWhereExpression(), dlg.stagesCount(), opts.resultNumPlaces(), opts.isResultExcludeDisq()); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QVariantMap props; props["stagesCount"] = dlg.stagesCount(); @@ -2121,7 +2121,7 @@ void RunsPlugin::report_nStagesAwards() return; QVariantMap props; - props["eventConfig"] = getPlugin()->appDbConfig()->eventConfig().toVariantMap(); + props["eventConfig"] = getPlugin()->eventConfig().toVariantMap(); auto tt = nstagesResultsTable(QString(), opts.value("stageId").toInt(), opts.value("numPlaces").toInt()); qf::gui::reports::ReportViewWidget::showReport(fwk , findReportFile(rep_path) @@ -2472,7 +2472,7 @@ void RunsPlugin::export_resultsHtmlNStages() qff::MainWindow *fwk = qff::MainWindow::frameWork(); auto tt1 = nstagesResultsTable(sql_where_expr, stage_id, num_places, exclude_disq); - tt1.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt1.setValue("event", getPlugin()->eventConfig().toVariantMap()); //tt.setValue("stageStart", getPlugin()->stageStartDateTime(stages_count)); QString file_dir = QDir::tempPath() + "/quickevent/overall-e" + QString::number(stage_id); @@ -2737,7 +2737,7 @@ QString RunsPlugin::getClubAbbrFromName(QString name) QString RunsPlugin::startListStageIofXml30(int stage_id, quickevent::gui::ReportOptionsDialog::VacantsOption vacants_option) { QDateTime start00 = getPlugin()->stageStartDateTime(stage_id); - const auto &event_config = getPlugin()->appDbConfig()->eventConfig(); + const auto &event_config = getPlugin()->eventConfig(); //console.debug("print_vacants", print_vacants); auto tt1 = startListClassesTable("", vacants_option, quickevent::gui::ReportOptionsDialog::StartTimeFormat::RelativeToClassStart); bool is_iof_race = event_config.iofRace; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp index 79a5a090f..0014d02c7 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstableitemdelegate.cpp @@ -33,7 +33,7 @@ void RunsTableItemDelegate::setHighlightedClassId(int class_id, int stage_id) void RunsTableItemDelegate::reloadHighlightedClassId() { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); m_classDef.load(m_highlightedClassId, m_stageId, is_relays); //qfInfo() << "interval:" << m_classInterval << "first:" << m_classStartFirst << "last:" << m_classStartLast; } @@ -50,7 +50,7 @@ void RunsTableItemDelegate::paintBackground(QPainter *painter, const QStyleOptio auto *tm = qobject_cast(v->tableModel()); if(!(m && tm)) return; - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(m_highlightedClassId > 0) { if(is_relays) { // check that start time in classes is the same diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index ccd1940f0..c07f3a876 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -173,7 +173,7 @@ void RunsTableWidget::reload(int stage_id, int class_id, bool show_offrace, cons ui->lblClassStart->setText(class_start_time_min >= 0? QString::number(class_start_time_min): "---"); ui->lblClassInterval->setText(class_start_interval_min >= 0? QString::number(class_start_interval_min): "---"); } - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if (!is_relays && m_courseItemDelegate) { m_courseItemDelegate->setCourses(definedCourses()); } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 1a5d5c8bb..2d75f8a63 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -73,7 +73,7 @@ RunsWidget::RunsWidget(QWidget *parent) : ui->cbxDrawMethod->clear(); if(!getPlugin()->isEventOpen()) return; - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(is_relays) { ui->cbxDrawMethod->addItem(tr("Relays first leg"), static_cast(DrawMethod::RelaysFirstLeg)); } @@ -119,7 +119,7 @@ void RunsWidget::reset() } /// Note: You should use QAction::setVisible() to change the visibility of the widget. /// Using QWidget::setVisible(), QWidget::show() and QWidget::hide() does not work. - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); m_toolbarActionLabelLeg->setVisible(is_relays); m_toolbarActionComboLeg->setVisible(is_relays); //qfWarning() << "is relays:" << is_relays << "legs visible:" << m_cbxLeg->isVisible(); @@ -131,7 +131,7 @@ void RunsWidget::reset() void RunsWidget::reload() { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); int stage_id = is_relays? m_cbxLeg->currentData().toInt(): selectedStageId(); int class_id = m_cbxClasses->currentData().toInt(); ui->wRunsTableWidget->reload(stage_id, class_id, m_chkShowOffRace->isChecked()); @@ -508,7 +508,7 @@ QList RunsWidget::runsForClass(int stage_id, int class_id, const QString &e QList RunsWidget::competitorsForClass(int stage_id, int class_id, const QString &extra_where_condition, const QString &order_by) { qfLogFuncFrame() << "stage:" << stage_id << "class:" << class_id; - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QList ret; qf::core::sql::QueryBuilder qb; qb.select2("runs", "id, competitorId") @@ -690,10 +690,10 @@ void RunsWidget::saveLockedForDrawing(int class_id, int stage_id, bool is_locked void RunsWidget::onDrawClicked() { qfLogFuncFrame(); - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); - const auto &stage_data = getPlugin()->appDbConfig()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->eventConfig().stageData(stage_id); bool use_all_maps = stage_data.useAllMaps; qfDebug() << "DrawMethod:" << (int)draw_method << "use_all_maps:" << use_all_maps; QList class_ids; @@ -724,7 +724,7 @@ void RunsWidget::onDrawClicked() try { qf::core::sql::Transaction transaction; for(int class_id : class_ids) { - int handicap_length_ms = getPlugin()->appDbConfig()->eventConfig().handicapLength * 60 * 1000; + int handicap_length_ms = getPlugin()->eventConfig().handicapLength * 60 * 1000; QVector handicap_times; qf::core::sql::QueryBuilder qb; qb.select2("classdefs", "startTimeMin, startIntervalMin, vacantsBefore, vacantEvery, vacantsAfter, mapCount") @@ -772,7 +772,7 @@ void RunsWidget::onDrawClicked() runners_draw_ids = group1 + group2 + group3; } else if(draw_method == DrawMethod::Handicap) { - int stage_count = getPlugin()->appDbConfig()->eventConfig().stageCount; + int stage_count = getPlugin()->eventConfig().stageCount; qf::core::utils::Table results = getPlugin()->nstagesClassResultsTable(stage_count - 1, class_id); QMap competitor_to_run; for(const auto &cc : competitorsForClass(stage_count, class_id)) @@ -1057,7 +1057,7 @@ void RunsWidget::export_results_stage_csv() if(fn.isEmpty()) return; - bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; + bool is_iof_race = getPlugin()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); QFileInfo fi(fn); exp.setOutDir(fi.absolutePath()); @@ -1140,7 +1140,7 @@ void RunsWidget::report_competitorsStatistics() m.setQueryBuilder(qb); m.reload(); qfu::TreeTable tt = m.toTreeTable(); - tt.setValue("event", getPlugin()->appDbConfig()->eventConfig().toVariantMap()); + tt.setValue("event", getPlugin()->eventConfig().toVariantMap()); for (int stage_id = 1; stage_id <= stage_cnt; ++stage_id) { QString prefix = "e" + QString::number(stage_id) + "_"; QString col_runs_count = prefix + "runCount"; @@ -1210,7 +1210,7 @@ void RunsWidget::editCompetitor_helper(const QVariant &id, int mode, int siid) QF_ASSERT(doc != nullptr, "Document is null!", return); if(mode == qfm::DataDocument::ModeInsert) { if(siid == 0) { - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); if(!is_relays) { int class_id = m_cbxClasses->currentData().toInt(); if(class_id > 0) diff --git a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp index 26c94bb7f..ab572e038 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp @@ -73,7 +73,7 @@ bool ResultsExporter::exportResults() const if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::IofXml3)) { int current_stage = getPlugin()->currentStageId(); QString file_name = ss.exportDir() + "/" + getPlugin()->eventName() + "." + Event::RESULTS_IOFXML3_FILE; - bool is_relays = getPlugin()->appDbConfig()->eventConfig().isRelays(); + bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays ? getPlugin()->resultsIofXml30() @@ -94,7 +94,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSVMulti)) { - bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; + bool is_iof_race = getPlugin()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) @@ -106,7 +106,7 @@ bool ResultsExporter::exportResults() const return true; } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::CSV)) { - bool is_iof_race = getPlugin()->appDbConfig()->eventConfig().iofRace; + bool is_iof_race = getPlugin()->eventConfig().iofRace; quickevent::core::exporters::StageResultsCsvExporter exp(is_iof_race); exp.setOutDir(ss.exportDir()); if (!ss.csvSeparator().isNull()) From ebc10174a7326029ba89e99063971908655f1a34 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 18 Jul 2026 13:07:02 +0200 Subject: [PATCH 76/83] Introduce StageConfig and replace StageData --- quickevent/app/quickevent/CMakeLists.txt | 2 +- .../plugins/Classes/src/classeswidget.cpp | 11 +- .../plugins/Classes/src/drawing/classitem.cpp | 10 +- .../plugins/Classes/src/drawing/ganttitem.cpp | 40 ++-- .../plugins/Classes/src/drawing/ganttitem.h | 12 +- .../Classes/src/drawing/ganttscene.cpp | 2 +- .../Classes/src/drawing/startslotheader.cpp | 15 +- .../Classes/src/drawing/startslotitem.cpp | 42 ++-- .../Classes/src/drawing/startslotitem.h | 20 +- .../plugins/Classes/src/editcourseswidget.cpp | 6 +- .../plugins/Event/src/appdbconfig.cpp | 18 ++ .../plugins/Event/src/appdbconfig.h | 4 + .../plugins/Event/src/eventconfig.cpp | 39 ---- .../plugins/Event/src/eventconfig.h | 5 - .../plugins/Event/src/eventdialogwidget.cpp | 143 ++++++-------- .../plugins/Event/src/eventdialogwidget.h | 18 +- .../plugins/Event/src/eventplugin.cpp | 122 ++++++------ .../plugins/Event/src/eventplugin.h | 34 ++-- .../Event/src/services/ofeed/ofeedclient.cpp | 180 +++++++++--------- .../Event/src/services/oresultsclient.cpp | 16 +- .../punchingtest/punchingtestservice.cpp | 2 +- .../Event/src/services/qx/qxclientservice.cpp | 8 +- .../src/services/qx/qxclientservicewidget.cpp | 9 +- .../plugins/Event/src/stageconfig.cpp | 74 +++++++ .../plugins/Event/src/stageconfig.h | 39 ++++ .../quickevent/plugins/Event/src/stagedata.h | 19 -- .../plugins/Receipts/src/receiptsplugin.cpp | 2 +- .../Receipts/src/receiptssettingspage.cpp | 17 +- .../plugins/Relays/src/relaysplugin.cpp | 3 +- .../plugins/Runs/src/runsplugin.cpp | 2 +- .../plugins/Runs/src/runstablemodel.cpp | 4 +- .../plugins/Runs/src/runstablewidget.cpp | 2 +- .../plugins/Runs/src/runswidget.cpp | 5 +- 33 files changed, 474 insertions(+), 451 deletions(-) create mode 100644 quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp create mode 100644 quickevent/app/quickevent/plugins/Event/src/stageconfig.h delete mode 100644 quickevent/app/quickevent/plugins/Event/src/stagedata.h diff --git a/quickevent/app/quickevent/CMakeLists.txt b/quickevent/app/quickevent/CMakeLists.txt index e07ac08da..c9f9a16fe 100644 --- a/quickevent/app/quickevent/CMakeLists.txt +++ b/quickevent/app/quickevent/CMakeLists.txt @@ -60,7 +60,7 @@ add_executable(quickevent plugins/Core/src/widgets/settingsdialog.cpp plugins/Core/src/widgets/settingsdialog.ui - plugins/Event/src/stagedata.h + plugins/Event/src/stageconfig.cpp plugins/Event/src/stageconfig.h plugins/Event/src/connectdbdialogwidget.cpp plugins/Event/src/connectdbdialogwidget.ui plugins/Event/src/connectionsettings.cpp diff --git a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp index e4a3bce76..a5929b302 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/classeswidget.cpp @@ -159,12 +159,9 @@ ClassesWidget::ClassesWidget(QWidget *parent) : connect(ui->tblClasses, &qf::gui::TableView::currentRowChanged, this, &ClassesWidget::reloadCourseCodes); connect(ui->chkUseAllMaps, &QCheckBox::toggled, this, [this](bool checked) { auto evplugin = getPlugin(); - auto *config = evplugin->appDbConfig(); - auto event_config = config->eventConfig(); - auto data = event_config.stageData(selectedStageId()); - data.useAllMaps = checked; - event_config.setStageData(selectedStageId(), data); - config->setEventConfig(event_config); + auto stage_config = evplugin->stageConfig(selectedStageId()); + stage_config.useAllMaps = checked; + evplugin->appDbConfig().setStageConfig(selectedStageId(), stage_config); }); } @@ -359,7 +356,7 @@ void ClassesWidget::reload() } m_courseItemDelegate->setCourses(courses); } - ui->chkUseAllMaps->setChecked(getPlugin()->eventConfig().stageData(stage_id).useAllMaps); + ui->chkUseAllMaps->setChecked(getPlugin()->stageConfig(stage_id).useAllMaps); reloadCourseCodes(); } diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/classitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/classitem.cpp index 07be89988..b59720aed 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/classitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/classitem.cpp @@ -305,8 +305,8 @@ QList ClassItem::findClashes(const QSet &clash_types) QList ret; auto *git = ganttItem(); for (int i = 0; i < git->startSlotItemCount(); ++i) { - StartSlotItem *slot_it = git->startSlotItemAt(i); - if(slot_it->data().isIgnoreClassClashCheck()) + auto *slot_it = git->startSlotItemAt(i); + if(slot_it->config().ignoreClassClashCheck) continue; for (int j = 0; j < slot_it->classItemCount(); ++j) { ClassItem *class_it = slot_it->classItemAt(j); @@ -508,9 +508,9 @@ void ClassItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) if(slot_it->classItemIndex(this) == 0) { // the edited start time was written to the database by the dialog, // move the whole slot to keep the layout consistent with a reload - StartSlotData sd = slot_it->data(); - sd.setStartOffset(qMax(dt.startTimeMin(), 0)); - slot_it->setData(sd); + auto sd = slot_it->config(); + sd.startOffset = qMax(dt.startTimeMin(), 0); + slot_it->setConfig(sd); } if(slot_it->classItemCount() > 1) { // start times of the classes chained after this one shift with its new size diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp index c4aceeb05..08ab2602b 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.cpp @@ -63,9 +63,8 @@ StartSlotItem *GanttItem::addStartSlotItem() void GanttItem::load(int stage_id) { qfLogFuncFrame(); - Event::StageData stage_data = getPlugin()->eventConfig().stageData(stage_id); - DrawingConfig dc(stage_data.drawingConfig); - QVariantList start_slot_list = dc.startSlots(); + const auto &stage_data = getPlugin()->stageConfig(stage_id); + // const auto &start_slot_list = stage_data.drawingConfig.startSlots; qfs::Query q(qfs::Connection::forName()); qf::core::sql::QueryBuilder qb1; @@ -110,11 +109,11 @@ void GanttItem::load(int stage_id) if(slot_ix > curr_slot_ix) { slot_item = addStartSlotItem(); curr_slot_ix = slot_ix; - StartSlotData sd(start_slot_list.value(slot_ix).toMap()); + auto sd = stage_data.drawingConfig.startSlotConfig(slot_ix); if(!cd.value(QStringLiteral("startTimeMin")).isNull()) - sd.setStartOffset(start_time_min); - slot_item->setData(sd); - curr_slot_end_min = sd.startOffset(); + sd.startOffset = start_time_min; + slot_item->setConfig(sd); + curr_slot_end_min = sd.startOffset; curr_slot_is_drawn = true; curr_course_id = -1; } @@ -129,9 +128,9 @@ void GanttItem::load(int stage_id) && (start_time_min == 0 || start_time_min == curr_slot_end_min); if(!chains_to_curr_slot) { slot_item = addStartSlotItem(); - StartSlotData sd; - sd.setStartOffset(start_time_min); - slot_item->setData(sd); + Event::StartSlotConfig sd; + sd.startOffset = start_time_min; + slot_item->setConfig(sd); curr_slot_end_min = start_time_min; curr_slot_is_drawn = false; } @@ -154,20 +153,15 @@ void GanttItem::save(int stage_id) { qfLogFuncFrame(); { - auto *config = getPlugin()->appDbConfig(); - auto event_config = config->eventConfig(); - Event::StageData stage = event_config.stageData(stage_id); - DrawingConfig dc(stage.drawingConfig); - QVariantList start_slots; + auto *event = getPlugin(); + // auto event_config = config->eventConfig(); + auto stage_config = event->stageConfig(stage_id); + stage_config.drawingConfig.startSlots.clear(); for (int i = 0; i < startSlotItemCount(); ++i) { StartSlotItem *slot_it = startSlotItemAt(i); - StartSlotData sd = slot_it->data(); - start_slots << sd; + stage_config.drawingConfig.startSlots.push_back(slot_it->config()); } - dc.setStartSlots(start_slots); - stage.drawingConfig = dc; - event_config.setStageData(stage_id, stage); - config->setEventConfig(event_config); + event->appDbConfig().setStageConfig(stage_id, stage_config); } { QString qs = "UPDATE classdefs SET" @@ -231,7 +225,7 @@ void GanttItem::checkClassClash() QList clashes; for (int i = 0; i < startSlotItemCount(); ++i) { StartSlotItem *slot_it = startSlotItemAt(i); - if(slot_it->data().isIgnoreClassClashCheck()) + if(slot_it->config().ignoreClassClashCheck) continue; for (int j = 0; j < slot_it->classItemCount(); ++j) { ClassItem *class_it = slot_it->classItemAt(j); @@ -239,7 +233,7 @@ void GanttItem::checkClassClash() for(ClassItem *other : clashing_class_list) { // every pair is found from both sides, record it once if(quintptr(class_it) < quintptr(other)) - clashes << ClassClash{class_it, other, class_it->clashWith(other)}; + clashes << ClassClash{.class1=class_it, .class2=other, .type=class_it->clashWith(other)}; } } } diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.h b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.h index 57148dd89..9be8b0437 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.h +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttitem.h @@ -3,6 +3,8 @@ #include "classitem.h" +#include + #include #include @@ -18,14 +20,6 @@ class StartSlotItem; class ClassItem; class GanttRuler; -class DrawingConfig : public QVariantMap -{ -public: - explicit DrawingConfig(const QVariantMap &m = QVariantMap()) : QVariantMap(m) {} - - QF_VARIANTMAP_FIELD(QVariantList, s, setS, tartSlots) -}; - class GanttItem : public QGraphicsRectItem, public IGanttItem { private: @@ -53,7 +47,7 @@ class GanttItem : public QGraphicsRectItem, public IGanttItem StartSlotItem* addStartSlotItem(); private: QList m_startSlotItems; - DrawingConfig m_drawingConfig; + Event::DrawingConfig m_drawingConfig; GanttRuler *m_ganttRuler; QSet m_clashTypesToCheck; }; diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp index 8136a2aa1..ef7f94eb2 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/ganttscene.cpp @@ -23,7 +23,7 @@ GanttScene::GanttScene(QObject * parent) void GanttScene::load(int stage_id) { clear(); - const auto &stage_data = getPlugin()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->stageConfig(stage_id); m_useAllMaps = stage_data.useAllMaps; m_ganttItem = new GanttItem(); addItem(m_ganttItem); diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotheader.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotheader.cpp index c1dd9236b..070ab25b3 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotheader.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotheader.cpp @@ -51,8 +51,6 @@ void paintItemRecursively(QGraphicsItem *it, QPainter *painter, QStyleOptionGrap painter->restore(); } -} - class LockItem : public QGraphicsRectItem { Q_DECLARE_TR_FUNCTIONS(drawing::ClassdefsLockItem) @@ -328,6 +326,7 @@ class SpinnerItem : public QGraphicsRectItem SpinButton *m_btnInc; SpinValueItem *m_value; }; +} StartSlotHeader::StartSlotHeader(StartSlotItem *parent) : Super(parent), IGanttItem(this) @@ -388,7 +387,7 @@ void StartSlotHeader::updateGeometry() m_lockItem->setPos(0, row_h); auto *start_spinner = static_cast(m_startSpinner); start_spinner->setGeometry(QRectF(col1_w, 0, 2 * row_h, row_h)); - start_spinner->setValue(QString::number(slot_it->data().startOffset())); + start_spinner->setValue(QString::number(slot_it->config().startOffset)); auto *interval_spinner = static_cast(m_intervalSpinner); interval_spinner->setGeometry(QRectF(col1_w, row_h, 2 * row_h, row_h)); if(slot_it->isStartIntervalUniform()) { @@ -416,8 +415,8 @@ void StartSlotHeader::updateGeometry() void StartSlotHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - const StartSlotData &dt = startSlotItem()->data(); - if(dt.isIgnoreClassClashCheck()) { + const auto &dt = startSlotItem()->config(); + if(dt.ignoreClassClashCheck) { QColor c("khaki"); c.setAlpha(128); QRectF r = rect(); @@ -436,7 +435,7 @@ void StartSlotHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *o void StartSlotHeader::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { - StartSlotData dt = startSlotItem()->data(); + const auto &dt = startSlotItem()->config(); QMenu menu; QAction *a_append_start_slot = menu.addAction(tr("Append start slot")); QAction *a_set_start = menu.addAction(tr("Set slot start offset")); @@ -445,7 +444,7 @@ void StartSlotHeader::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) //a_locked->setCheckable(true); QAction *a_clash = menu.addAction(tr("Ignore class clash check")); a_clash->setCheckable(true); - a_clash->setChecked(dt.isIgnoreClassClashCheck()); + a_clash->setChecked(dt.ignoreClassClashCheck); QAction *a = menu.exec(event->screenPos()); if(a == a_append_start_slot) { auto *gi = ganttItem(); @@ -463,7 +462,7 @@ void StartSlotHeader::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) o = o->parent(); } bool ok; - int i = QInputDialog::getInt(w, tr("InputDialog"), tr("Start slot offset [min]:"), dt.startOffset(), 0, 1000000, 1, &ok); + int i = QInputDialog::getInt(w, tr("InputDialog"), tr("Start slot offset [min]:"), dt.startOffset, 0, 1000000, 1, &ok); if(ok) { startSlotItem()->setStartOffset(i); } diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.cpp b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.cpp index 1b24cc949..426a7ccb5 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.cpp @@ -61,10 +61,10 @@ ClassItem *StartSlotItem::takeClassItemAt(int ix) void StartSlotItem::setStartOffset(int start_offset) { start_offset = std::max(start_offset, 0); - StartSlotData dt = data(); - if(dt.startOffset() != start_offset) { - dt.setStartOffset(start_offset); - setData(dt); + auto dt = config(); + if(dt.startOffset != start_offset) { + dt.startOffset = start_offset; + setConfig(dt); ganttScene()->setDirty(true); updateGeometry(); ganttItem()->checkClassClash(); @@ -73,8 +73,8 @@ void StartSlotItem::setStartOffset(int start_offset) int StartSlotItem::startOffset() const { - StartSlotData dt = data(); - return dt.startOffset(); + auto dt = config(); + return dt.startOffset; } void StartSlotItem::setStartInterval(int interval_min) @@ -112,16 +112,16 @@ bool StartSlotItem::isStartIntervalUniform() const bool StartSlotItem::isIgnoreClassClashCheck() const { - return data().isIgnoreClassClashCheck(); + return config().ignoreClassClashCheck; } void StartSlotItem::setIgnoreClassClashCheck(bool b) { - auto dt = data(); - if(dt.isIgnoreClassClashCheck() == b) + auto dt = config(); + if(dt.ignoreClassClashCheck == b) return; - dt.setIgnoreClassClashCheck(b); - setData(dt); + dt.ignoreClassClashCheck = b; + setConfig(dt); ganttScene()->setDirty(true); updateGeometry(); ganttItem()->checkClassClash(); @@ -160,22 +160,22 @@ ClassItem *StartSlotItem::addClassItem() return it; } -const StartSlotData& StartSlotItem::data() const +const Event::StartSlotConfig& StartSlotItem::config() const { - return m_data; + return m_config; } -void StartSlotItem::setData(const StartSlotData &data) +void StartSlotItem::setConfig(const Event::StartSlotConfig &data) { - m_data = data; + m_config = data; } void StartSlotItem::updateGeometry() { qfLogFuncFrame(); - auto dt = data(); - int pos_x = minToPx(dt.startOffset()); + const auto &dt = config(); + int pos_x = minToPx(dt.startOffset); double h = m_header->minHeight(); for (int i = 0; i < classItemCount(); ++i) { ClassItem *it = classItemAt(i); @@ -197,13 +197,6 @@ void StartSlotItem::updateGeometry() //qfInfo() << r.left() << r.top() << r.width() << r.height(); setRect(r); m_header->updateGeometry(); - /* - setAcceptDrops(!isLocked()); - for (int i = 0; i < classItemCount(); ++i) { - ClassItem *it = classItemAt(i); - it->setAcceptDrops(!isLocked()); - } - */ } void StartSlotItem::setClassAreaWidth(int px) @@ -251,4 +244,3 @@ void StartSlotItem::dropEvent(QGraphicsSceneDragDropEvent *event) m_dragIn = false; update(); } - diff --git a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.h b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.h index 9da1b2be5..472af5805 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.h +++ b/quickevent/app/quickevent/plugins/Classes/src/drawing/startslotitem.h @@ -3,6 +3,8 @@ #include "iganttitem.h" +#include + #include #include @@ -14,22 +16,12 @@ class ClassItem; class GanttItem; class StartSlotHeader; -class StartSlotData : public QVariantMap -{ -public: - explicit StartSlotData(const QVariantMap &m = QVariantMap()) : QVariantMap(m) {} - - QF_VARIANTMAP_FIELD(int, s, setS, tartOffset) - //QF_VARIANTMAP_FIELD(bool, is, set, Locked) - QF_VARIANTMAP_FIELD(bool, is, set, IgnoreClassClashCheck) -}; - class StartSlotItem : public QGraphicsRectItem, public IGanttItem { private: typedef QGraphicsRectItem Super; public: - StartSlotItem(QGraphicsItem * parent = 0); + StartSlotItem(QGraphicsItem * parent = nullptr); QF_FIELD_IMPL2(int, s, S, lotNumber, 0) @@ -59,15 +51,15 @@ class StartSlotItem : public QGraphicsRectItem, public IGanttItem void updateGeometry(); void setClassAreaWidth(int px); - const StartSlotData& data() const; - void setData(const StartSlotData &data); + const Event::StartSlotConfig& config() const; + void setConfig(const Event::StartSlotConfig &data); void dragEnterEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE; void dragMoveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE; void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE; void dropEvent(QGraphicsSceneDragDropEvent *event) Q_DECL_OVERRIDE; private: - StartSlotData m_data; + Event::StartSlotConfig m_config; QList m_classItems; StartSlotHeader *m_header; bool m_dragIn = false; diff --git a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp index 9de417d7d..5e0eb7eeb 100644 --- a/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp +++ b/quickevent/app/quickevent/plugins/Classes/src/editcourseswidget.cpp @@ -19,6 +19,7 @@ namespace qfw = qf::gui; namespace qfm = qf::gui::model; namespace qfs = qf::core::sql; +namespace { class CoursesTableModel : public qfm::SqlTableModel { Q_OBJECT @@ -66,6 +67,7 @@ class CoursesTableModel : public qfm::SqlTableModel return Super::data(index, role); } }; +} EditCoursesWidget::EditCoursesWidget(int stage_id, QWidget *parent) : Super(parent) @@ -94,7 +96,7 @@ EditCoursesWidget::EditCoursesWidget(int stage_id, QWidget *parent) QHeaderView *hh = ui->tblCourses->horizontalHeader(); hh->setSectionHidden(CoursesTableModel::Col_runCount, true); - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->appDbConfig().eventConfig().isRelays()) { ui->cbRunnersCount->setVisible(false); } else { connect (ui->cbRunnersCount,&QCheckBox::clicked,this,&EditCoursesWidget::updateQuery); @@ -135,7 +137,7 @@ void EditCoursesWidget::updateQuery() qfs::QueryBuilder qb; - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->appDbConfig().eventConfig().isRelays()) { qb.select2("courses", "*") .select("0 AS run_count") .select(code_list_query + "AS code_list") diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index acd44cb79..80c3158cb 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -21,6 +21,7 @@ using namespace Event; namespace { constexpr auto EVENT = "event"; +constexpr auto STAGE = "stage"; constexpr auto RECEIPTS = "receipts"; constexpr auto OFEED = "ofeed"; constexpr auto ORESULTS = "oresults"; @@ -122,6 +123,8 @@ void AppDbConfig::save(const QString &prefix, const QVariantMap &data) val_str = val.toTime().toString(Qt::ISODate); else if(val.typeId() == qMetaTypeId()) val_str = val.toDateTime().toString(Qt::ISODate); + else if(val.typeId() == qMetaTypeId()) + val_str = qf::core::Utils::qvariantToJson(val); else val_str = val.toString(); auto full_key = prefix.isEmpty() ? key : prefix + "." + key; @@ -153,6 +156,21 @@ const services::OResultsConfig& AppDbConfig::oresultsConfig(int stage_id) const return defaultCfg; } +const StageConfig& AppDbConfig::stageConfig(int stage_id) const +{ + if (m_stagesConfig.contains(stage_id)) { + return m_stagesConfig.at(stage_id); + } + static StageConfig defaultCfg; + return defaultCfg; +} + +void AppDbConfig::setStageConfig(int stage_id, const StageConfig &cfg) +{ + m_stagesConfig[stage_id] = cfg; + save(STAGE, stage_id, cfg.toVariantMap()); +} + void AppDbConfig::setOresultsConfig(int stage_id, const services::OResultsConfig &cfg) { m_oresultsConfig[stage_id] = cfg; diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h index faf2bfebf..331079931 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.h @@ -1,6 +1,7 @@ #pragma once #include "eventconfig.h" +#include "plugins/Event/src/stageconfig.h" #include "services/oresultsconfig.h" #include "services/ofeed/ofeedconfig.h" #include @@ -30,6 +31,8 @@ class AppDbConfig { int dbVersion() const { return m_dbVersion; } const EventConfig &eventConfig() const { return m_eventConfig; } void setEventConfig(const EventConfig &config); + const StageConfig &stageConfig(int stage_id) const; + void setStageConfig(int stage_id, const StageConfig &config); const services::OResultsConfig &oresultsConfig(int stage_id) const; void setOresultsConfig(int stage_id, const services::OResultsConfig &config); const Receipts::ReceiptsConfig &receiptsConfig(int stage_id) const; @@ -44,6 +47,7 @@ class AppDbConfig { void save(const QString &prefix, int stage_id, const QVariantMap &data); private: + std::map m_stagesConfig; std::map m_ofeedConfig; std::map m_receiptsConfig; std::map m_oresultsConfig; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index fbff1e626..c97f27987 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -30,21 +30,6 @@ EventConfig EventConfig::fromVariantMap(const QVariantMap &values) EventConfig data; data.stageCount = values.value("stageCount", 1).toInt(); const QVariantMap stages = values.value("stage").toMap(); - for(auto it = stages.cbegin(); it != stages.cend(); ++it) { - const int stage_id = it.key().toInt(); - if(stage_id <= 0) - continue; - const QVariantMap stage_values = it.value().toMap(); - StageData stage; - stage.startDateTime = stage_values.value("startDateTime").toDateTime(); - stage.useAllMaps = stage_values.value("useAllMaps").toBool(); - const QVariant drawing_config = stage_values.value("drawingConfig"); - stage.drawingConfig = drawing_config.userType() == qMetaTypeId() - ? qf::core::Utils::jsonToQVariant(drawing_config.toString()).toMap() - : drawing_config.toMap(); - stage.qxApiToken = stage_values.value("qxApiToken").toString(); - data.stages[stage_id] = stage; - } data.name = values.value("name").toString(); data.date = values.value("date").toDate(); data.time = values.value("time").toTime(); @@ -77,34 +62,10 @@ bool EventConfig::isRelays() const return disciplineId == 5 || disciplineId == 6 || disciplineId == 15; } -const StageData& EventConfig::stageData(int stage_id) const -{ - if (stages.contains(stage_id)) { - return stages.at(stage_id); - } - static StageData sd; - return sd; -} - -void EventConfig::setStageData(int stage_id, const StageData &data) -{ - stages[stage_id] = data; -} - QVariantMap EventConfig::toVariantMap() const { QVariantMap values; values.insert("stageCount", stageCount); - QVariantMap stage_values; - for(const auto &[key, val] : stages) { - QVariantMap stage; - stage.insert("startDateTime", val.startDateTime); - stage.insert("useAllMaps", val.useAllMaps); - stage.insert("drawingConfig", qf::core::Utils::qvariantToJson(val.drawingConfig)); - stage.insert("qxApiToken", val.qxApiToken); - stage_values.insert(QString::number(key), stage); - } - values.insert("stage", stage_values); values.insert("name", name); values.insert("date", date); values.insert("time", time); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h index fa0c91515..6987399c5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.h @@ -1,7 +1,5 @@ #pragma once -#include "stagedata.h" - #include #include #include @@ -35,14 +33,11 @@ struct EventConfig std::optional maximumCardCheckAdvanceSec() const; bool isRelays() const; - const StageData& stageData(int stage_id) const; - void setStageData(int stage_id, const StageData &data); static EventConfig fromVariantMap(const QVariantMap &values); QVariantMap toVariantMap() const; int stageCount = 1; - std::map stages; QString name; QDate date; QTime time; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp index ff2fb29a6..a6081717c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.cpp @@ -1,8 +1,6 @@ #include "eventdialogwidget.h" #include "ui_eventdialogwidget.h" -#include "appdbconfig.h" - #include #include @@ -21,8 +19,9 @@ EventDialogWidget::EventDialogWidget(QWidget *parent) : ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui->stageStartTimesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); ui->stageStartTimesTable->verticalHeader()->hide(); - connect(ui->ed_stageCount, QOverload::of(&QSpinBox::valueChanged), this, &EventDialogWidget::updateStageStartTimeEditors); - updateStageStartTimeEditors(ui->ed_stageCount->value()); + connect(ui->ed_stageCount, QOverload::of(&QSpinBox::valueChanged), this, [this]() { + updateStageStartTimeEditors(saveParams()); + }); connect(ui->ed_iofRace, &QAbstractButton::toggled, ui->frameIofRace, &QWidget::setVisible); ui->frameIofRace->hide(); @@ -72,118 +71,94 @@ void EventDialogWidget::setEventIdEditable(bool b) ui->ed_eventId->setReadOnly(!b); } -void EventDialogWidget::updateStageStartTimeEditors(int stage_count) +void EventDialogWidget::updateStageStartTimeEditors(const EventDialogWidget::Params ¶ms) { - QTableWidget *table = ui->stageStartTimesTable; - const int old_count = table->rowCount(); - if(stage_count < old_count) { - table->setRowCount(stage_count); - updateStageStartTimesTableHeight(); - return; - } - - QDateTime next_start(ui->ed_date->date(), ui->ed_time->time()); - if(old_count > 0) { - if(auto *last_editor = qobject_cast(table->cellWidget(old_count - 1, 1))) - next_start = last_editor->dateTime().addDays(1); - } + QDateTime event_start(params.eventConfig.date, params.eventConfig.time); - table->setRowCount(stage_count); - for(int row = old_count; row < stage_count; ++row) { - auto *stage_item = new QTableWidgetItem(QString::number(row + 1)); + QTableWidget *table = ui->stageStartTimesTable; + table->setRowCount(params.eventConfig.stageCount); + for(int row = 0; row < params.eventConfig.stageCount; ++row) { + auto stage_id = row + 1; + auto *stage_item = new QTableWidgetItem(QString::number(stage_id)); stage_item->setTextAlignment(Qt::AlignCenter); table->setItem(row, 0, stage_item); - auto *editor = new QDateTimeEdit(next_start, table); + auto stage_start = params.stageStarts.value(row, event_start.addDays(row)); + auto *editor = new QDateTimeEdit(stage_start, table); editor->setCalendarPopup(true); editor->setDisplayFormat(QStringLiteral("dd.MM.yyyy HH:mm:ss")); table->setCellWidget(row, 1, editor); - next_start = next_start.addDays(1); } - updateStageStartTimesTableHeight(); -} - -void EventDialogWidget::updateStageStartTimesTableHeight() -{ - QTableWidget *table = ui->stageStartTimesTable; table->resizeRowsToContents(); - const int visible_row_count = qMin(table->rowCount(), 5); int height = table->horizontalHeader()->height() + 2 * table->frameWidth(); - for(int row = 0; row < visible_row_count; ++row) + for(int row = 0; row < visible_row_count; ++row) { height += table->rowHeight(row); + } table->setFixedHeight(height); } -void EventDialogWidget::loadParams(const Event::EventConfig ¶ms) +void EventDialogWidget::loadParams(const EventDialogWidget::Params ¶ms) { - m_data = params; - ui->ed_name->setText(params.name); - ui->ed_date->setDate(params.date.isValid() ? params.date : QDate::currentDate()); - if(params.time.isValid()) - ui->ed_time->setTime(params.time); - - ui->stageStartTimesTable->setRowCount(0); - ui->ed_stageCount->setValue(params.stageCount); - updateStageStartTimeEditors(ui->ed_stageCount->value()); - for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - const QDateTime start_time = params.stageData(row + 1).startDateTime; - if(start_time.isValid()) { - if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) - editor->setDateTime(start_time); - } - } - ui->ed_description->setText(params.description); - ui->ed_place->setText(params.place); - ui->ed_mainReferee->setText(params.mainReferee); - ui->ed_director->setText(params.director); - ui->ed_handicapLength->setValue(params.handicapLength); - if(auto ix = ui->cbxSportId->findData(params.sportId); ix < 0) + ui->ed_name->setText(params.eventConfig.name); + ui->ed_date->setDate(params.eventConfig.date.isValid() ? params.eventConfig.date : QDate::currentDate()); + if(params.eventConfig.time.isValid()) + ui->ed_time->setTime(params.eventConfig.time); + + ui->ed_stageCount->setValue(params.eventConfig.stageCount); + updateStageStartTimeEditors(params); + ui->ed_description->setText(params.eventConfig.description); + ui->ed_place->setText(params.eventConfig.place); + ui->ed_mainReferee->setText(params.eventConfig.mainReferee); + ui->ed_director->setText(params.eventConfig.director); + ui->ed_handicapLength->setValue(params.eventConfig.handicapLength); + if(auto ix = ui->cbxSportId->findData(params.eventConfig.sportId); ix < 0) ui->cbxSportId->setCurrentIndex(0); else ui->cbxSportId->setCurrentIndex(ix); - if(auto ix = ui->cbxDisciplineId->findData(params.disciplineId); ix < 0) + if(auto ix = ui->cbxDisciplineId->findData(params.eventConfig.disciplineId); ix < 0) ui->cbxDisciplineId->setCurrentIndex(0); else ui->cbxDisciplineId->setCurrentIndex(ix); - ui->ed_orisImportId->setText(params.importId > 0 ? QString::number(params.importId) : QString()); - ui->ed_orisRace->setChecked(params.importId > 0); - ui->ed_orisEventKey->setText(params.orisEventKey); - ui->ed_cardChecCheckTimeSec->setValue(params.cardCheckTimeSec); - ui->ed_oneTenthSecResults->setCurrentIndex(params.oneTenthSecResults); - ui->ed_iofRace->setChecked(params.iofRace); - ui->ed_xmlRaceNumber->setValue(params.iofXmlRaceNumber); + ui->ed_orisImportId->setText(params.eventConfig.importId > 0 ? QString::number(params.eventConfig.importId) : QString()); + ui->ed_orisRace->setChecked(params.eventConfig.importId > 0); + ui->ed_orisEventKey->setText(params.eventConfig.orisEventKey); + ui->ed_cardChecCheckTimeSec->setValue(params.eventConfig.cardCheckTimeSec); + ui->ed_oneTenthSecResults->setCurrentIndex(params.eventConfig.oneTenthSecResults); + ui->ed_iofRace->setChecked(params.eventConfig.iofRace); + ui->ed_xmlRaceNumber->setValue(params.eventConfig.iofXmlRaceNumber); } -Event::EventConfig EventDialogWidget::saveParams() +EventDialogWidget::Params EventDialogWidget::saveParams() { - Event::EventConfig data = m_data; - data.stageCount = ui->ed_stageCount->value(); + EventDialogWidget::Params params; + params.eventConfig.stageCount = ui->ed_stageCount->value(); for(int row = 0; row < ui->stageStartTimesTable->rowCount(); ++row) { - if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) - data.stages[row + 1].startDateTime = editor->dateTime(); + if(auto *editor = qobject_cast(ui->stageStartTimesTable->cellWidget(row, 1))) { + params.stageStarts << editor->dateTime(); + } } - data.name = ui->ed_name->text(); - data.date = ui->ed_date->date(); - data.time = ui->ed_time->time(); - data.description = ui->ed_description->text(); - data.place = ui->ed_place->text(); - data.mainReferee = ui->ed_mainReferee->text(); - data.director = ui->ed_director->text(); - data.handicapLength = ui->ed_handicapLength->value(); - data.sportId = ui->cbxSportId->currentData().isNull() + params.eventConfig.name = ui->ed_name->text(); + params.eventConfig.date = ui->ed_date->date(); + params.eventConfig.time = ui->ed_time->time(); + params.eventConfig.description = ui->ed_description->text(); + params.eventConfig.place = ui->ed_place->text(); + params.eventConfig.mainReferee = ui->ed_mainReferee->text(); + params.eventConfig.director = ui->ed_director->text(); + params.eventConfig.handicapLength = ui->ed_handicapLength->value(); + params.eventConfig.sportId = ui->cbxSportId->currentData().isNull() ? static_cast(Event::EventConfig::Sport::OB) : ui->cbxSportId->currentData().toInt(); - data.disciplineId = ui->cbxDisciplineId->currentIndex() <= 0 + params.eventConfig.disciplineId = ui->cbxDisciplineId->currentIndex() <= 0 ? static_cast(Event::EventConfig::Discipline::LongDistance) : ui->cbxDisciplineId->currentData().toInt(); - data.importId = ui->ed_orisImportId->text().toInt(); - data.orisEventKey = ui->ed_orisEventKey->text(); - data.cardCheckTimeSec = ui->ed_cardChecCheckTimeSec->value(); - data.oneTenthSecResults = ui->ed_oneTenthSecResults->currentIndex(); - data.iofRace = ui->ed_iofRace->isChecked(); - data.iofXmlRaceNumber = ui->ed_xmlRaceNumber->value(); - return data; + params.eventConfig.importId = ui->ed_orisImportId->text().toInt(); + params.eventConfig.orisEventKey = ui->ed_orisEventKey->text(); + params.eventConfig.cardCheckTimeSec = ui->ed_cardChecCheckTimeSec->value(); + params.eventConfig.oneTenthSecResults = ui->ed_oneTenthSecResults->currentIndex(); + params.eventConfig.iofRace = ui->ed_iofRace->isChecked(); + params.eventConfig.iofXmlRaceNumber = ui->ed_xmlRaceNumber->value(); + return params; } QString EventDialogWidget::disciplineName(int disc_id) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h index d8f9527b0..2dd9b4f49 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventdialogwidget.h @@ -3,6 +3,7 @@ #include "eventconfig.h" +#include #include namespace Ui { @@ -12,8 +13,13 @@ class EventDialogWidget; class EventDialogWidget : public qf::gui::framework::DialogWidget { Q_OBJECT -private: - typedef qf::gui::framework::DialogWidget Super; + + using Super = qf::gui::framework::DialogWidget; +public: + struct Params { + Event::EventConfig eventConfig; + QList stageStarts; + }; public: explicit EventDialogWidget(QWidget *parent = nullptr); ~EventDialogWidget() Q_DECL_OVERRIDE; @@ -22,16 +28,14 @@ class EventDialogWidget : public qf::gui::framework::DialogWidget QString eventId() const; void setEventIdEditable(bool b); - void loadParams(const Event::EventConfig ¶ms); - Event::EventConfig saveParams(); + void loadParams(const EventDialogWidget::Params ¶ms); + EventDialogWidget::Params saveParams(); static QString disciplineName(int disc_id); static QString sportName(int sport_id); private: - void updateStageStartTimeEditors(int stage_count); - void updateStageStartTimesTableHeight(); + void updateStageStartTimeEditors(const EventDialogWidget::Params ¶ms); - Event::EventConfig m_data; Ui::EventDialogWidget *ui; }; diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 13cd9f780..fc6c44709 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -4,7 +4,9 @@ #include "eventdialogwidget.h" #include "openeventdialog.h" #include "dbschema.h" +#include "plugins/Event/src/appdbconfig.h" #include "plugins/Event/src/eventconfig.h" +#include "plugins/Event/src/stageconfig.h" #include "registrationswidget.h" #include "lentcardssettingspage.h" #include "../../Core/src/widgets/appstatusbar.h" @@ -200,59 +202,53 @@ EventPlugin::EventPlugin(QObject *parent) EventPlugin::~EventPlugin() { - QF_SAFE_DELETE(m_eventConfig); } -void EventPlugin::initEventConfig() +Event::AppDbConfig &EventPlugin::appDbConfig() { - if(m_eventConfig == nullptr) { - m_eventConfig = new Event::AppDbConfig(); - } - else { - qfWarning() << "Event config exists already!"; - } + return m_appDbConfig; } -Event::AppDbConfig *EventPlugin::appDbConfig(bool reload) +const Event::AppDbConfig &EventPlugin::appDbConfig() const { - if(m_eventConfig == nullptr) { - m_eventConfig = new Event::AppDbConfig(); - reload = true; - } - if(reload) { - m_eventConfig->load(); - //emit eventNameChanged(m_eventConfig->eventName()); - } - return m_eventConfig; + return m_appDbConfig; } -const EventConfig &EventPlugin::eventConfig() +const EventConfig &EventPlugin::eventConfig() const { - return appDbConfig()->eventConfig(); + return appDbConfig().eventConfig(); } -int EventPlugin::stageCount() +int EventPlugin::stageCount() const { - if(eventName().isEmpty()) + if(eventName().isEmpty()) { return 0; - return appDbConfig()->eventConfig().stageCount; + } + return appDbConfig().eventConfig().stageCount; +} + +const Event::StageConfig &EventPlugin::stageConfig(int stage_id) const +{ + return appDbConfig().stageConfig(stage_id); } void EventPlugin::setCurrentStageId(int stage_id) { - if(m_currentStageId == stage_id) { + if(currentStageId() == stage_id) { return; } - m_currentStageId = stage_id; + auto c = eventConfig(); + c.currentStageId = stage_id; + appDbConfig().setEventConfig(c); emit currentStageIdChanged(stage_id); } int EventPlugin::currentStageId() const { - return m_currentStageId; + return eventConfig().currentStageId; } -int EventPlugin::stageIdForRun(int run_id) +int EventPlugin::stageIdForRun(int run_id) const { int ret = 0; qfs::QueryBuilder qb; @@ -268,29 +264,29 @@ int EventPlugin::stageIdForRun(int run_id) return ret; } -int EventPlugin::stageStartMsec(int stage_id) +int EventPlugin::stageStartMsec(int stage_id) const { QTime start_time = stageStartTime(stage_id); int ret = start_time.msecsSinceStartOfDay(); return ret; } -QDate EventPlugin::stageStartDate(int stage_id) +QDate EventPlugin::stageStartDate(int stage_id) const { return stageStartDateTime(stage_id).date(); } -QTime EventPlugin::stageStartTime(int stage_id) +QTime EventPlugin::stageStartTime(int stage_id) const { return stageStartDateTime(stage_id).time(); } -QDateTime EventPlugin::stageStartDateTime(int stage_id) +QDateTime EventPlugin::stageStartDateTime(int stage_id) const { - return appDbConfig()->eventConfig().stageData(stage_id).startDateTime; + return appDbConfig().stageConfig(stage_id).startDateTime; } -int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) +int EventPlugin::msecToStageStartAM(int si_am_time_sec, int msec, int stage_id) const { if(si_am_time_sec == 0xEEEE) return quickevent::core::og::TimeMs::UNREAL_TIME_MSEC; @@ -453,17 +449,17 @@ void EventPlugin::loadCurrentStageId() { int stage_id = 1; if(!eventName().isEmpty()) { - stage_id = appDbConfig()->eventConfig().currentStageId; + stage_id = appDbConfig().eventConfig().currentStageId; } setCurrentStageId(stage_id); } void EventPlugin::saveCurrentStageId(int current_stage) { - if(current_stage != appDbConfig()->eventConfig().currentStageId) { - auto event_cfg = appDbConfig()->eventConfig(); + if(current_stage != appDbConfig().eventConfig().currentStageId) { + auto event_cfg = appDbConfig().eventConfig(); event_cfg.currentStageId = current_stage; - appDbConfig()->setEventConfig(event_cfg); + appDbConfig().setEventConfig(event_cfg); } } @@ -543,7 +539,7 @@ QString EventPlugin::classNameById(int class_id) QString EventPlugin::shvApiEventId() const { - return eventName() + "-" + QString::number(m_eventConfig->eventConfig().importId); + return eventName() + "-" + QString::number(eventConfig().importId); } QString EventPlugin::createApiKey(int length) @@ -572,7 +568,7 @@ QString EventPlugin::createApiKey(int length) return key; } -QString EventPlugin::fileNameWithStageAndEventName(const QString &fn, std::optional stage_id) +QString EventPlugin::fileNameWithStageAndEventName(const QString &fn, std::optional stage_id) const { auto ret = eventName(); if(stageCount() > 1) { @@ -582,12 +578,12 @@ QString EventPlugin::fileNameWithStageAndEventName(const QString &fn, std::optio return ret; } -QString EventPlugin::startListIofXml3FileName(std::optional stage_id) +QString EventPlugin::startListIofXml3FileName(std::optional stage_id) const { return fileNameWithStageAndEventName(START_LIST_IOFXML3_FILE, stage_id); } -QString EventPlugin::resultsIofXml3FileName(std::optional stage_id) +QString EventPlugin::resultsIofXml3FileName(std::optional stage_id) const { return fileNameWithStageAndEventName(RESULTS_IOFXML3_FILE, stage_id); } @@ -871,7 +867,7 @@ bool EventPlugin::createEvent(const QString &event_name, const EventConfig &even existing_event_ids = existingSqlEventNames(); } QString event_id = event_name; - auto new_params = event_params; + EventDialogWidget::Params new_params {.eventConfig = event_params, .stageStarts = {}}; do { qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -898,13 +894,9 @@ bool EventPlugin::createEvent(const QString &event_name, const EventConfig &even closeEvent(); - Event::AppDbConfig app_db_config; bool ok = false; //ConnectionSettings connection_settings; - app_db_config.setEventConfig(new_params); - int stage_count = new_params.stageCount; - if(stage_count == 0) - stage_count = app_db_config.eventConfig().stageCount; + int stage_count = new_params.eventConfig.stageCount; qfInfo() << "createEvent, stage_count:" << stage_count; QF_ASSERT(stage_count > 0, "Stage count have to be greater than 0", return false); @@ -963,6 +955,13 @@ bool EventPlugin::createEvent(const QString &event_name, const EventConfig &even qfd::MessageBox::showError(fwk, tr("Cannot create event, database is not open: %1").arg(conn.lastError().text())); } if(ok) { + AppDbConfig cfg; + cfg.setEventConfig(new_params.eventConfig); + for(int i=0; isetWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); - event_w->loadParams(appDbConfig()->eventConfig()); + EventDialogWidget::Params params; + params.eventConfig = eventConfig(); + for(int i=0; iloadParams(params); dlg.setCentralWidget(event_w); if(!dlg.exec()) return; - auto event_data = event_w->saveParams(); - appDbConfig()->setEventConfig(event_data); + auto new_params = event_w->saveParams(); + appDbConfig().setEventConfig(new_params.eventConfig); + for(int i=0; idbVersion() < dbVersion()) { + m_appDbConfig = AppDbConfig(); + m_appDbConfig.load(); + if(m_appDbConfig.dbVersion() < dbVersion()) { qfd::MessageBox::showError(fwk, tr("Event data version (%1) is too low, minimal version is (%2).\nUse: File --> Import --> Event (*.qbe) to convert event to current version.") - .arg(qf::core::Utils::intToVersionString(evc->dbVersion())) + .arg(qf::core::Utils::intToVersionString(m_appDbConfig.dbVersion())) .arg(qf::core::Utils::intToVersionString(dbVersion()))); closeEvent(); ok = false; } - else if(evc->dbVersion() > dbVersion()) { + else if(m_appDbConfig.dbVersion() > dbVersion()) { qfd::MessageBox::showError(fwk, tr("Event was created in more recent QuickEvent version (%1) and the application might not work as expected. Download latest QuickEvent is strongly recommended.") - .arg(qf::core::Utils::intToVersionString(evc->dbVersion()))); + .arg(qf::core::Utils::intToVersionString(m_appDbConfig.dbVersion()))); } } if(ok) { diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 72bfc6a48..ea047a17a 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -2,6 +2,7 @@ #define EVENTPLUGIN_H #include "appdbconfig.h" +#include "plugins/Event/src/stageconfig.h" #include @@ -62,25 +63,25 @@ class EventPlugin : public qf::gui::framework::Plugin static constexpr auto DBEVENT_QX_CHANGE_RECEIVED = "qxChangeReceived"; static constexpr auto DBEVENT_QX_RECCHNG = "qxRecChng"; - Q_INVOKABLE void initEventConfig(); - Event::AppDbConfig* appDbConfig(bool reload = false); - const Event::EventConfig& eventConfig(); - int stageCount(); + Event::AppDbConfig& appDbConfig(); + const Event::AppDbConfig& appDbConfig() const; + const Event::EventConfig& eventConfig() const; + int stageCount() const; + const Event::StageConfig& stageConfig(int stage_id) const; + Q_SLOT void setCurrentStageId(int stage_id); int currentStageId() const; Q_SIGNAL void currentStageIdChanged(int current_stage); - Q_INVOKABLE int stageIdForRun(int run_id); + Q_INVOKABLE int stageIdForRun(int run_id) const; - Q_INVOKABLE int stageStartMsec(int stage_id); - Q_INVOKABLE QDate stageStartDate(int stage_id); - Q_INVOKABLE QTime stageStartTime(int stage_id); - Q_INVOKABLE QDateTime stageStartDateTime(int stage_id); + int stageStartMsec(int stage_id) const; + QDate stageStartDate(int stage_id) const; + QTime stageStartTime(int stage_id) const; + QDateTime stageStartDateTime(int stage_id) const; //Q_INVOKABLE int currentStageStartMsec(); - int msecToStageStartAM(int si_am_time_sec, int msec = 0, int stage_id = 0); - - + int msecToStageStartAM(int si_am_time_sec, int msec = 0, int stage_id = 0) const; bool createEvent(const QString &event_name, const EventConfig &event_params); void editEvent(); @@ -106,9 +107,9 @@ class EventPlugin : public qf::gui::framework::Plugin QString shvApiEventId() const; static QString createApiKey(int length); - QString startListIofXml3FileName(std::optional stage_id = std::nullopt); - QString resultsIofXml3FileName(std::optional stage_id = std::nullopt); - QString fileNameWithStageAndEventName(const QString &fn, std::optional stage_id); + QString startListIofXml3FileName(std::optional stage_id = std::nullopt) const; + QString resultsIofXml3FileName(std::optional stage_id = std::nullopt) const; + QString fileNameWithStageAndEventName(const QString &fn, std::optional stage_id) const; DbSchema* dbSchema(); static int dbVersion(); @@ -164,9 +165,8 @@ class EventPlugin : public qf::gui::framework::Plugin qf::gui::Action *m_actSetCurrentStage = nullptr; qf::gui::Action *m_actExportEvent_qbe = nullptr; qf::gui::Action *m_actImportEvent_qbe = nullptr; - Event::AppDbConfig *m_eventConfig = nullptr; + Event::AppDbConfig m_appDbConfig; bool m_sqlServerConnected = false; - int m_currentStageId = 0; QMap m_classNameCache; qf::gui::framework::DockWidget *m_servicesDockWidget = nullptr; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp index 5ace8fc86..641e40765 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/ofeed/ofeedclient.cpp @@ -336,28 +336,28 @@ void OFeedClient::onDbEventNotify(const QString &domain, int connection_id, cons QString OFeedClient::hostUrl() const { int current_stage = getPlugin()->currentStageId(); - OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + OFeedConfig cfg = getPlugin()->appDbConfig().ofeedConfig(current_stage); return normalized_base_host_url(cfg.hostUrl); } QString OFeedClient::eventId() const { int current_stage = getPlugin()->currentStageId(); - OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + OFeedConfig cfg = getPlugin()->appDbConfig().ofeedConfig(current_stage); return cfg.eventId; } QString OFeedClient::eventPassword() const { int current_stage = getPlugin()->currentStageId(); - OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + OFeedConfig cfg = getPlugin()->appDbConfig().ofeedConfig(current_stage); return cfg.eventPassword; } QString OFeedClient::changelogOrigin() const { int current_stage = getPlugin()->currentStageId(); - OFeedConfig cfg = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + OFeedConfig cfg = getPlugin()->appDbConfig().ofeedConfig(current_stage); return cfg.changelogOrigin; } @@ -365,7 +365,7 @@ bool OFeedClient::isInsertFromOFeed = false; QDateTime OFeedClient::lastChangelogCall() { int current_stage = getPlugin()->currentStageId(); - auto config = getPlugin()->appDbConfig()->ofeedConfig(current_stage); + auto config = getPlugin()->appDbConfig().ofeedConfig(current_stage); // Retrieve the stored value from the configuration auto last_call = config.lastChangelogCall; @@ -373,7 +373,7 @@ QDateTime OFeedClient::lastChangelogCall() { if (!last_call.isValid() || last_call.toString().isEmpty()) { // No valid value exists, set the initial value config.lastChangelogCall = QDateTime::fromSecsSinceEpoch(0); // Default to Unix epoch (1970-01-01T00:00:00Z) - getPlugin()->appDbConfig()->setOfeedConfig(current_stage, config); + getPlugin()->appDbConfig().setOfeedConfig(current_stage, config); // qDebug() << "No lastChangelogCall found. Setting initial value to:" << config.lastChangelogCall.toString(Qt::ISODate); } return config.lastChangelogCall; @@ -381,16 +381,16 @@ QDateTime OFeedClient::lastChangelogCall() { bool OFeedClient::runXmlValidation() { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->ofeedConfig(current_stage).runXmlValidation; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.ofeedConfig(current_stage).runXmlValidation; } bool OFeedClient::runChangesProcessing () { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->ofeedConfig(current_stage).runChangesProcessing; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.ofeedConfig(current_stage).runChangesProcessing; } // QString OFeedClient::receiptConfigKey(const QString &suffix) const @@ -401,53 +401,53 @@ bool OFeedClient::runChangesProcessing () // QVariant OFeedClient::receiptConfigValue(const QString &suffix, const QVariant &default_value) const // { -// return getPlugin()->appDbConfig()->value(receiptConfigKey(suffix), default_value); +// return getPlugin()->appDbConfig().value(receiptConfigKey(suffix), default_value); // } // void OFeedClient::setReceiptConfigValue(const QString &suffix, const QVariant &value) // { // auto *event_config = getPlugin()->appDbConfig(); -// event_config->setValue(receiptConfigKey(suffix), value); -// event_config->save(k_event_config_prefix); +// event_config.setValue(receiptConfigKey(suffix), value); +// event_config.save(k_event_config_prefix); // } bool OFeedClient::printEventImageOnReceipt() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).printImage; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).printImage; } void OFeedClient::setPrintEventImageOnReceipt(bool on) { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto print_config = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto print_config = config.receiptsConfig(current_stage); print_config.printImage = on; - config->setReceiptsConfig(current_stage, print_config); + config.setReceiptsConfig(current_stage, print_config); } bool OFeedClient::printEventQrCodeOnReceipt() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).printQrCode; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).printQrCode; } void OFeedClient::setPrintEventQrCodeOnReceipt(bool on) { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto print_config = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto print_config = config.receiptsConfig(current_stage); print_config.printQrCode = on; - config->setReceiptsConfig(current_stage, print_config); + config.setReceiptsConfig(current_stage, print_config); } int OFeedClient::receiptImageHeightMm() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).imageHeightMm; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).imageHeightMm; } void OFeedClient::setReceiptImageHeightMm(int height_mm) @@ -456,18 +456,18 @@ void OFeedClient::setReceiptImageHeightMm(int height_mm) height_mm = 10; else if(height_mm > 60) height_mm = 60; - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto rc = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto rc = config.receiptsConfig(current_stage); rc.imageHeightMm = height_mm; - config->setReceiptsConfig(current_stage, rc); + config.setReceiptsConfig(current_stage, rc); } QString OFeedClient::receiptEventLinkUrl() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - const QString custom_url = config->receiptsConfig(current_stage).linkUrl; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + const QString custom_url = config.receiptsConfig(current_stage).linkUrl; if(!custom_url.isEmpty()) return custom_url; return defaultReceiptEventLinkUrl(); @@ -489,18 +489,18 @@ QString OFeedClient::defaultReceiptEventLinkUrl() const void OFeedClient::setReceiptEventLinkUrl(QString link_url) { link_url = link_url.trimmed(); - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto rc = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto rc = config.receiptsConfig(current_stage); rc.linkUrl = link_url; - config->setReceiptsConfig(current_stage, rc); + config.setReceiptsConfig(current_stage, rc); } QString OFeedClient::receiptEventQrCodeCaption() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).qrCodeCaption; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).qrCodeCaption; } QString OFeedClient::defaultReceiptEventQrCodeCaption() const @@ -511,11 +511,11 @@ QString OFeedClient::defaultReceiptEventQrCodeCaption() const void OFeedClient::setReceiptEventQrCodeCaption(QString caption) { caption = caption.trimmed(); - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto rc = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto rc = config.receiptsConfig(current_stage); rc.qrCodeCaption = caption; - config->setReceiptsConfig(current_stage, rc); + config.setReceiptsConfig(current_stage, rc); } bool OFeedClient::hasCachedEventImage() const @@ -525,36 +525,36 @@ bool OFeedClient::hasCachedEventImage() const QString OFeedClient::cachedEventImageBase64() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).imageBase64; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).imageBase64; } QString OFeedClient::cachedEventImageFormat() const { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - return config->receiptsConfig(current_stage).imageFormat; + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + return config.receiptsConfig(current_stage).imageFormat; } void OFeedClient::setCachedEventImage(const QByteArray &raw_data, const QString &format) { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto rc = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto rc = config.receiptsConfig(current_stage); rc.imageBase64 = QString::fromLatin1(raw_data.toBase64()); rc.imageFormat = format.toLower(); - config->setReceiptsConfig(current_stage, rc); + config.setReceiptsConfig(current_stage, rc); } void OFeedClient::clearCachedEventImage() { - auto *config = getPlugin()->appDbConfig(); - auto current_stage = config->eventConfig().currentStageId; - auto rc = config->receiptsConfig(current_stage); + auto &config = getPlugin()->appDbConfig(); + auto current_stage = config.eventConfig().currentStageId; + auto rc = config.receiptsConfig(current_stage); rc.imageBase64.clear(); rc.imageFormat.clear(); - config->setReceiptsConfig(current_stage, rc); + config.setReceiptsConfig(current_stage, rc); } void OFeedClient::ensureEventImageCachedAtStartup() @@ -671,84 +671,84 @@ void OFeedClient::refreshEventImageCache(std::function()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.hostUrl = hostUrl; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); m_eventImageStartupAttempted = false; } void OFeedClient::setEventId(QString eventId) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.eventId = eventId; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); m_eventImageStartupAttempted = false; } void OFeedClient::setEventPassword(QString eventPassword) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.eventPassword = eventPassword; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); m_eventImageStartupAttempted = false; } void OFeedClient::setChangelogOrigin(QString changelogOrigin) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.changelogOrigin = changelogOrigin; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); } void OFeedClient::setLastChangelogCall(QDateTime lastChangelogCall) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.lastChangelogCall = lastChangelogCall; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); } void OFeedClient::setRunXmlValidation(bool runXmlValidation) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.runXmlValidation = runXmlValidation; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); } void OFeedClient::setRunChangesProcessing(bool runChangesProcessing) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.runChangesProcessing = runChangesProcessing; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); } bool OFeedClient::introTourShowed() const { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - return config->ofeedConfig(current_stage).introTourShowed; + return config.ofeedConfig(current_stage).introTourShowed; } void OFeedClient::setIntroTourShowed(bool shown) { - auto *config = getPlugin()->appDbConfig(); + auto &config = getPlugin()->appDbConfig(); const int current_stage = getPlugin()->currentStageId(); - auto cfg = config->ofeedConfig(current_stage); + auto cfg = config.ofeedConfig(current_stage); cfg.introTourShowed = shown; - config->setOfeedConfig(current_stage, cfg); + config.setOfeedConfig(current_stage, cfg); } void OFeedClient::testConnection(const QString &host_url, diff --git a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp index 0afde70b6..a322af9bf 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/oresultsclient.cpp @@ -169,31 +169,31 @@ void OResultsClient::onDbEventNotify(const QString &domain, int connection_id, c QString OResultsClient::apiKey() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->oresultsConfig(current_stage).apiKey; + return getPlugin()->appDbConfig().oresultsConfig(current_stage).apiKey; } void OResultsClient::setApiKey(QString apiKey) { int current_stage = getPlugin()->currentStageId(); - auto *db = getPlugin()->appDbConfig(); - auto cfg = db->oresultsConfig(current_stage); + auto &db = getPlugin()->appDbConfig(); + auto cfg = db.oresultsConfig(current_stage); cfg.apiKey = apiKey; - db->setOresultsConfig(current_stage, cfg); + db.setOresultsConfig(current_stage, cfg); } QString OResultsClient::eventName() const { int current_stage = getPlugin()->currentStageId(); - return getPlugin()->appDbConfig()->oresultsConfig(current_stage).eventName; + return getPlugin()->appDbConfig().oresultsConfig(current_stage).eventName; } void OResultsClient::setEventName(const QString &name) { int current_stage = getPlugin()->currentStageId(); - auto *db = getPlugin()->appDbConfig(); - auto cfg = db->oresultsConfig(current_stage); + auto &db = getPlugin()->appDbConfig(); + auto cfg = db.oresultsConfig(current_stage); cfg.eventName = name; - db->setOresultsConfig(current_stage, cfg); + db.setOresultsConfig(current_stage, cfg); } void OResultsClient::sendCompetitorChange(QString xml) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp index 8582f3a1f..f02b587d6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/punchingtest/punchingtestservice.cpp @@ -139,7 +139,7 @@ void PunchingTestService::onTimerTick() // When enabled: 1/badCheckRate chance the runner checked too early (triggers bad-check). // When disabled: natural 1–2 minute window, no bad-check possible. int check_offset_sec; - if (auto cfg = event_plugin->appDbConfig()->eventConfig().maximumCardCheckAdvanceSec(); cfg.has_value()) { + if (auto cfg = event_plugin->appDbConfig().eventConfig().maximumCardCheckAdvanceSec(); cfg.has_value()) { int max_sec = cfg.value(); if (rng.bounded(static_cast(ss.badCheckRate())) == 0) { // Bad check: checked too early — [max+1, max*3] seconds before start diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index 5772c2cd6..21c190fd6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -201,7 +201,7 @@ void QxClientService::postStartListIofXml3(QObject *context, std::function(); int current_stage = ep->currentStageId(); - bool is_relays = ep->appDbConfig()->eventConfig().isRelays(); + bool is_relays = ep->appDbConfig().eventConfig().isRelays(); if (!is_relays) { auto xml = getPlugin()->startListStageIofXml30(current_stage, quickevent::gui::ReportOptionsDialog::VacantsOption::OnlyRunners); uploadSpecFile(SpecFile::StartListIofXml3, xml.toUtf8(), context, call_back); @@ -212,7 +212,7 @@ void QxClientService::postRuns(QObject *context, std::function c { auto *ep = getPlugin(); int current_stage = ep->currentStageId(); - bool is_relays = ep->appDbConfig()->eventConfig().isRelays(); + bool is_relays = ep->appDbConfig().eventConfig().isRelays(); if (!is_relays) { auto runs = getPlugin()->qxExportRunsCsvJson(current_stage); auto json = qf::core::Utils::qvariantToJsonUtf8(runs, false); @@ -275,7 +275,7 @@ QByteArray QxClientService::apiToken() const // always to current stage event on qxhttpd auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - return event_plugin->appDbConfig()->eventConfig().stageData(current_stage).qxApiToken.toUtf8(); + return event_plugin->stageConfig(current_stage).qxApiToken.toUtf8(); } QUrl QxClientService::exchangeServerUrl() const @@ -483,7 +483,7 @@ void QxClientService::pollQxChanges() EventInfo QxClientService::eventInfo() const { auto *event_plugin = getPlugin(); - const auto &event_config = event_plugin->appDbConfig()->eventConfig(); + const auto &event_config = event_plugin->appDbConfig().eventConfig(); EventInfo ei; ei.set_stage(event_plugin->currentStageId()); ei.set_stage_count(event_plugin->stageCount()); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp index 2e6f46827..a36b87c9c 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp @@ -97,12 +97,9 @@ bool QxClientServiceWidget::saveSettings() auto *event_plugin = getPlugin(); auto current_stage = event_plugin->currentStageId(); - auto *config = event_plugin->appDbConfig(); - auto event_config = config->eventConfig(); - auto stage_data = event_config.stageData(current_stage); - stage_data.qxApiToken = ui->edApiToken->text(); - event_config.setStageData(current_stage, stage_data); - config->setEventConfig(event_config); + auto stage_config = event_plugin->stageConfig(current_stage); + stage_config.qxApiToken = ui->edApiToken->text(); + event_plugin->appDbConfig().setStageConfig(current_stage, stage_config); } return true; } diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp new file mode 100644 index 000000000..f5d3c39cf --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp @@ -0,0 +1,74 @@ +#include "stageconfig.h" + +#include +#include + +namespace Event { + +StartSlotConfig StartSlotConfig::fromVariantMap(const QVariantMap& map) +{ + StartSlotConfig config; + config.startOffset = map.value("startOffset").toInt(); + config.ignoreClassClashCheck = map.value("ignoreClassClashCheck").toBool(); + return config; +} + +QVariantMap StartSlotConfig::toVariantMap() const +{ + QVariantMap map; + map["startOffset"] = startOffset; + map["ignoreClassClashCheck"] = ignoreClassClashCheck; + return map; +} + +DrawingConfig DrawingConfig::fromVariantMap(const QVariantMap& map) +{ + DrawingConfig config; + auto lst = map.value("startSlots").toList(); + for (const auto& slot : lst) { + config.startSlots.push_back(StartSlotConfig::fromVariantMap(slot.toMap())); + } + return config; +} + +QVariantMap DrawingConfig::toVariantMap() const +{ + QVariantMap map; + QVariantList lst; + for (const auto& slot : startSlots) { + lst.append(slot.toVariantMap()); + } + map["startSlots"] = lst; + return map; +} + +const StartSlotConfig& DrawingConfig::startSlotConfig(int index) const +{ + if (index < 0 || index >= startSlots.size()) { + static StartSlotConfig defaultSlot; + return defaultSlot; + } + return startSlots[index]; +} + +StageConfig StageConfig::fromVariantMap(const QVariantMap& map) +{ + StageConfig config; + config.startDateTime = map.value("startDateTime").toDateTime(); + config.useAllMaps = map.value("useAllMaps").toBool(); + config.drawingConfig = DrawingConfig::fromVariantMap(map.value("drawingConfig").toMap()); + config.qxApiToken = map.value("qxApiToken").toString(); + return config; +} + +QVariantMap StageConfig::toVariantMap() const +{ + QVariantMap map; + map["startDateTime"] = startDateTime; + map["useAllMaps"] = useAllMaps; + map["drawingConfig"] = drawingConfig.toVariantMap(); + map["qxApiToken"] = qxApiToken; + return map; +} + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.h b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h new file mode 100644 index 000000000..748e312e1 --- /dev/null +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include + +namespace Event { + +struct StartSlotConfig +{ + static StartSlotConfig fromVariantMap(const QVariantMap& map); + QVariantMap toVariantMap() const; + + int startOffset; + bool ignoreClassClashCheck = false; +}; + +struct DrawingConfig +{ + static DrawingConfig fromVariantMap(const QVariantMap& map); + QVariantMap toVariantMap() const; + const StartSlotConfig& startSlotConfig(int index) const; + + std::vector startSlots; +}; + +struct StageConfig +{ + static StageConfig fromVariantMap(const QVariantMap& map); + QVariantMap toVariantMap() const; + + QDateTime startDateTime; + bool useAllMaps = false; + DrawingConfig drawingConfig; + QString qxApiToken; +}; + +} diff --git a/quickevent/app/quickevent/plugins/Event/src/stagedata.h b/quickevent/app/quickevent/plugins/Event/src/stagedata.h deleted file mode 100644 index 8b0e73d92..000000000 --- a/quickevent/app/quickevent/plugins/Event/src/stagedata.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Event { - - -struct StageData -{ - QDateTime startDateTime; - bool useAllMaps = false; - QVariantMap drawingConfig; - QString qxApiToken; -}; - -} - diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp index 9bacc0389..52214d912 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsplugin.cpp @@ -58,7 +58,7 @@ namespace { ReceiptsConfig currentReceiptsConfig() { const int current_stage = qMax(getPlugin()->currentStageId(), 1); - return getPlugin()->appDbConfig()->receiptsConfig(current_stage); + return getPlugin()->appDbConfig().receiptsConfig(current_stage); } QString configuredReceiptEventLinkUrl() diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp index 49c78a973..7f8f97174 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptssettingspage.cpp @@ -389,10 +389,9 @@ void ReceiptsSettingsPage::load() } auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->appDbConfig(); - Q_ASSERT(event_config); - m_stageId = qMax(event_config->eventConfig().currentStageId, 1); - const auto rc = event_config->receiptsConfig(m_stageId); + auto &event_config = event_plugin->appDbConfig(); + m_stageId = qMax(event_config.eventConfig().currentStageId, 1); + const auto &rc = event_config.receiptsConfig(m_stageId); ui->chkPrintReceiptQrCode->setChecked(rc.printQrCode); ui->edReceiptQrCodeBaseUrl->setText(rc.linkUrl); ui->edReceiptQrCodeCaption->setText(rc.qrCodeCaption); @@ -423,8 +422,7 @@ void ReceiptsSettingsPage::save() auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->appDbConfig(); - Q_ASSERT(event_config); + auto &event_config = event_plugin->appDbConfig(); ReceiptsConfig rc; rc.printQrCode = ui->chkPrintReceiptQrCode->isChecked(); rc.linkUrl = ui->edReceiptQrCodeBaseUrl->text().trimmed(); @@ -433,7 +431,7 @@ void ReceiptsSettingsPage::save() rc.imageHeightMm = ui->edReceiptImageHeight->value(); rc.imageBase64 = m_receiptImageBase64; rc.imageFormat = m_receiptImageFormat; - event_config->setReceiptsConfig(m_stageId, rc); + event_config.setReceiptsConfig(m_stageId, rc); } QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const @@ -442,8 +440,7 @@ QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const auto *event_plugin = qf::gui::framework::getPlugin(); Q_ASSERT(event_plugin); - auto *event_config = event_plugin->appDbConfig(); - Q_ASSERT(event_config); + auto &event_config = event_plugin->appDbConfig(); const int stage_id = qMax(m_stageId, 1); const bool print_logo = ui->chkPrintReceiptImage->isChecked(); @@ -511,7 +508,7 @@ QVariantMap ReceiptsSettingsPage::currentTestReceiptData() const int stage_start_time_ms = event_plugin->stageStartMsec(stage_id); if(stage_start_time_ms <= 0) { - QTime tm = event_config->eventConfig().time; + QTime tm = event_config.eventConfig().time; stage_start_time_ms = tm.isValid() ? tm.msecsSinceStartOfDay() : (10 * 60 * 60 * 1000); } diff --git a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp index 90953149b..463e1450b 100644 --- a/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp +++ b/quickevent/app/quickevent/plugins/Relays/src/relaysplugin.cpp @@ -81,8 +81,7 @@ void RelaysPlugin::onInstalled() return; auto *ep = getPlugin(); bool event_open = ep->isEventOpen(); - auto *cfg = event_open ? ep->appDbConfig() : nullptr; - bool is_relays = cfg && cfg->eventConfig().isRelays(); + bool is_relays = event_open && ep->appDbConfig().eventConfig().isRelays(); scw->setPartVisible(featureId(), is_relays); if(event_open && !is_relays && m_partWidget && m_partWidget->isActive()) scw->setActivePart(QStringLiteral("Runs"), true); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index dd6ef29cc..e5477cf67 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -1179,7 +1179,7 @@ void RunsPlugin::writeCSOSHeader(QTextStream &ts) const auto *evp = getPlugin(); int stage_id = selectedStageId(); QDateTime start_dt = evp->stageStartDateTime(stage_id); - const auto &ec = evp->appDbConfig()->eventConfig(); + const auto &ec = evp->appDbConfig().eventConfig(); static constexpr int HWIDTH = -19; ts << make_width("Kod zavodu", HWIDTH) << ": " << ec.importId << "\r\n"; ts << make_width("Nazev zavodu", HWIDTH) << ": " << ec.name << "\r\n"; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 0b1beadca..c900b857e 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -62,7 +62,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const //qfInfo() << flgs; } if(index.column() == col_course_id) { - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->appDbConfig().eventConfig().isRelays()) { flgs &= ~Qt::ItemIsEditable; } } @@ -72,7 +72,7 @@ Qt::ItemFlags RunsTableModel::flags(const QModelIndex &index) const QVariant RunsTableModel::data(const QModelIndex &index, int role) const { if(index.column() == col_course_id && role == Qt::DisplayRole) { - if (getPlugin()->appDbConfig()->eventConfig().isRelays()) { + if (getPlugin()->appDbConfig().eventConfig().isRelays()) { auto start_number = value(index.row(), "startNumber").toInt(); auto leg = value(index.row(), "runs.leg").toInt(); return QStringLiteral("%1.%2").arg(start_number).arg(leg); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index c07f3a876..0344ae22c 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -58,7 +58,7 @@ RunsTableWidget::RunsTableWidget(QWidget *parent) : ui->tblRuns->setItemDelegate(m_runsTableItemDelegate); auto *event_plugin = getPlugin(); connect(event_plugin, &EventPlugin::eventOpenChanged, this, [this, event_plugin](bool is_open) { - if (is_open && !event_plugin->appDbConfig()->eventConfig().isRelays() && !m_courseItemDelegate) { + if (is_open && !event_plugin->appDbConfig().eventConfig().isRelays() && !m_courseItemDelegate) { m_courseItemDelegate = new CourseItemDelegate(ui->tblRuns); m_courseItemDelegate->setNullText(tr("Implicit")); ui->tblRuns->setItemDelegateForColumn(RunsTableModel::col_course_id, m_courseItemDelegate); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp index 2d75f8a63..fbc475ca4 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runswidget.cpp @@ -425,8 +425,7 @@ void RunsWidget::settleDownInPartWidget(::PartWidget *part_widget) auto updateMenuEnabled = [part_widget]() { auto *ep = getPlugin(); - auto *cfg = ep->isEventOpen() ? ep->appDbConfig() : nullptr; - bool enabled = !(cfg && cfg->eventConfig().isRelays()); + bool enabled = !(ep->isEventOpen() && ep->appDbConfig().eventConfig().isRelays()); for(const char *path : {"print", "import", "export"}) { if(auto *a = part_widget->menuBar()->actionForPath(path)) { a->setEnabled(enabled); @@ -693,7 +692,7 @@ void RunsWidget::onDrawClicked() bool is_relays = getPlugin()->eventConfig().isRelays(); int stage_id = selectedStageId(); DrawMethod draw_method = DrawMethod(ui->cbxDrawMethod->currentData().toInt()); - const auto &stage_data = getPlugin()->eventConfig().stageData(stage_id); + const auto &stage_data = getPlugin()->stageConfig(stage_id); bool use_all_maps = stage_data.useAllMaps; qfDebug() << "DrawMethod:" << (int)draw_method << "use_all_maps:" << use_all_maps; QList class_ids; From bf098885181c92aa44a1c878e2543467fb1f15f2 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 18 Jul 2026 13:47:07 +0200 Subject: [PATCH 77/83] Load STAGE config in AppDbConfig::load --- quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 80c3158cb..58afa4d0b 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -96,6 +96,7 @@ void AppDbConfig::load() target[stage.toInt()] = fromVariantMap(val.toMap()); } }; + load_stage_config(STAGE, m_stagesConfig, StageConfig::fromVariantMap); load_stage_config(RECEIPTS, m_receiptsConfig, Receipts::ReceiptsConfig::fromVariantMap); load_stage_config(ORESULTS, m_oresultsConfig, services::OResultsConfig::fromVariantMap); load_stage_config(OFEED, m_ofeedConfig, services::OFeedConfig::fromVariantMap); From 3bebb302cf860285a9f623de8834b2bc2bed298f Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 18 Jul 2026 20:24:59 +0200 Subject: [PATCH 78/83] Remove QX API token and load stages from DB Disable Qx client/service and remove qxApiToken from StageConfig. Populate missing STAGE entries from the database. Fix typo in helper name and add static_cast for a bounds check. --- .../plugins/Event/src/appdbconfig.cpp | 19 ++++++++++++++++--- .../Event/src/services/qx/qxclientservice.cpp | 7 ++----- .../src/services/qx/qxclientservicewidget.cpp | 2 +- .../plugins/Event/src/stageconfig.cpp | 4 +--- .../plugins/Event/src/stageconfig.h | 1 - 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 58afa4d0b..26eb93c71 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -55,7 +55,7 @@ void AppDbConfig::load() m[path.mid(1).join('.')] = value; config[group] = m; }; - const auto set_gropu_stage_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { + const auto set_group_stage_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { auto stage = path.value(1); auto m1 = config.value(group).toMap(); auto m2 = m1.value(stage).toMap(); @@ -77,8 +77,8 @@ void AppDbConfig::load() const auto group = path.value(0); if (group == EVENT || group == QX) { set_group_value(group, path, v); - } else if (group == RECEIPTS || group == ORESULTS || group == OFEED) { - set_gropu_stage_value(group, path, v); + } else if (group == STAGE || group == RECEIPTS || group == ORESULTS || group == OFEED) { + set_group_stage_value(group, path, v); } else { config[key] = v; } @@ -96,6 +96,19 @@ void AppDbConfig::load() target[stage.toInt()] = fromVariantMap(val.toMap()); } }; + { + auto stages = config.value(STAGE).toMap(); + Query stages_q(conn); + stages_q.exec("SELECT * FROM stages ORDER BY id", qf::core::Exception::Throw); + while(stages_q.next()) { + const auto stage_id = stages_q.value("id").toString(); + if(stages.contains(stage_id)) + continue; + set_group_stage_value(STAGE, QStringList{stage_id, "startDateTime"}, stages_q.value("startDateTime").toDateTime()); + set_group_stage_value(STAGE, QStringList{stage_id, "useAllMaps"}, stages_q.value("useAllMaps").toBool()); + set_group_stage_value(STAGE, QStringList{stage_id, "drawingConfig"}, stages_q.value("drawingConfig").toString()); + } + } load_stage_config(STAGE, m_stagesConfig, StageConfig::fromVariantMap); load_stage_config(RECEIPTS, m_receiptsConfig, Receipts::ReceiptsConfig::fromVariantMap); load_stage_config(ORESULTS, m_oresultsConfig, services::OResultsConfig::fromVariantMap); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp index 21c190fd6..3c368151f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservice.cpp @@ -271,11 +271,8 @@ int QxClientService::eventId() const QByteArray QxClientService::apiToken() const { - // API token must not be cached to enable service point - // always to current stage event on qxhttpd - auto *event_plugin = getPlugin(); - auto current_stage = event_plugin->currentStageId(); - return event_plugin->stageConfig(current_stage).qxApiToken.toUtf8(); + // Dead service + return {}; } QUrl QxClientService::exchangeServerUrl() const diff --git a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp index a36b87c9c..167a46ea7 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/qx/qxclientservicewidget.cpp @@ -98,7 +98,7 @@ bool QxClientServiceWidget::saveSettings() auto current_stage = event_plugin->currentStageId(); auto stage_config = event_plugin->stageConfig(current_stage); - stage_config.qxApiToken = ui->edApiToken->text(); + // stage_config.qxApiToken = ui->edApiToken->text(); event_plugin->appDbConfig().setStageConfig(current_stage, stage_config); } return true; diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp index f5d3c39cf..0277733c4 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp @@ -44,7 +44,7 @@ QVariantMap DrawingConfig::toVariantMap() const const StartSlotConfig& DrawingConfig::startSlotConfig(int index) const { - if (index < 0 || index >= startSlots.size()) { + if (index < 0 || index >= static_cast(startSlots.size())) { static StartSlotConfig defaultSlot; return defaultSlot; } @@ -57,7 +57,6 @@ StageConfig StageConfig::fromVariantMap(const QVariantMap& map) config.startDateTime = map.value("startDateTime").toDateTime(); config.useAllMaps = map.value("useAllMaps").toBool(); config.drawingConfig = DrawingConfig::fromVariantMap(map.value("drawingConfig").toMap()); - config.qxApiToken = map.value("qxApiToken").toString(); return config; } @@ -67,7 +66,6 @@ QVariantMap StageConfig::toVariantMap() const map["startDateTime"] = startDateTime; map["useAllMaps"] = useAllMaps; map["drawingConfig"] = drawingConfig.toVariantMap(); - map["qxApiToken"] = qxApiToken; return map; } diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.h b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h index 748e312e1..66b883e20 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stageconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h @@ -33,7 +33,6 @@ struct StageConfig QDateTime startDateTime; bool useAllMaps = false; DrawingConfig drawingConfig; - QString qxApiToken; }; } From 41c5cce570613f909c461ed8d40fbe033f1012e7 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 19 Jul 2026 12:55:45 +0200 Subject: [PATCH 79/83] Use eventDbName instead of eventName Refactor EventPlugin API and update call sites to use the eventDbName property and signals. Simplify AppDbConfig path handling: pass keys and integer stage_id instead of QStringList and parse key sections. Add linkUrl to ReceiptsConfig serialization. Miscellaneous cleanups: remove unused functions, fix nullptr constructor arg, update QML property calls, and qualify getPlugin usage. --- .../plugins/Event/src/appdbconfig.cpp | 24 +++--- .../plugins/Event/src/eventplugin.cpp | 81 ++++++++----------- .../plugins/Event/src/eventplugin.h | 7 +- .../Event/src/services/emmaclientwidget.cpp | 4 +- .../plugins/Event/src/services/service.cpp | 2 +- .../plugins/Receipts/src/receiptsconfig.cpp | 2 + .../awards/results_stage_awards-apple.qml | 6 +- .../awards/results_stage_awards-apple2.qml | 6 +- .../awards/results_stage_awards-covid.qml | 6 +- .../reports/awards/results_stage_awards.qml | 6 +- .../Runs/src/printawardsoptionsdialogwidget.h | 2 +- .../Runs/src/services/resultsexporter.cpp | 2 +- quickevent/app/quickevent/src/partwidget.cpp | 11 +-- 13 files changed, 65 insertions(+), 94 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 26eb93c71..dab077820 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -50,16 +50,16 @@ void AppDbConfig::load() Q_ASSERT(conn.isOpen()); QVariantMap config; - const auto set_group_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { + const auto set_group_value = [&config](const QString &group, const QString &key, const QVariant &value) { auto m = config.value(group).toMap(); - m[path.mid(1).join('.')] = value; + m[key] = value; config[group] = m; }; - const auto set_group_stage_value = [&config](const QString &group, const QStringList &path, const QVariant &value) { - auto stage = path.value(1); + const auto set_group_stage_value = [&config](const QString &group, int stage_id, const QString &key, const QVariant &value) { + auto stage = QString::number(stage_id); auto m1 = config.value(group).toMap(); auto m2 = m1.value(stage).toMap(); - m2[path.mid(2).join('.')] = value; + m2[key] = value; m1[stage] = m2; config[group] = m1; }; @@ -73,12 +73,12 @@ void AppDbConfig::load() QVariant val = q.value(1); QString type = q.value(2).toString(); QVariant v = qf::core::Utils::retypeStringValue(val.toString(), type); - auto path = key.split('.'); - const auto group = path.value(0); + const auto group = key.section('.', 0, 0); if (group == EVENT || group == QX) { - set_group_value(group, path, v); + set_group_value(group, key.section('.', 1), v); } else if (group == STAGE || group == RECEIPTS || group == ORESULTS || group == OFEED) { - set_group_stage_value(group, path, v); + auto stage_id = key.section('.', 1, 1).toInt(); + set_group_stage_value(group, stage_id, key.section('.', 2), v); } else { config[key] = v; } @@ -104,9 +104,9 @@ void AppDbConfig::load() const auto stage_id = stages_q.value("id").toString(); if(stages.contains(stage_id)) continue; - set_group_stage_value(STAGE, QStringList{stage_id, "startDateTime"}, stages_q.value("startDateTime").toDateTime()); - set_group_stage_value(STAGE, QStringList{stage_id, "useAllMaps"}, stages_q.value("useAllMaps").toBool()); - set_group_stage_value(STAGE, QStringList{stage_id, "drawingConfig"}, stages_q.value("drawingConfig").toString()); + set_group_stage_value(STAGE, stage_id.toInt(), "startDateTime", stages_q.value("startDateTime").toDateTime()); + set_group_stage_value(STAGE, stage_id.toInt(), "useAllMaps", stages_q.value("useAllMaps").toBool()); + set_group_stage_value(STAGE, stage_id.toInt(), "drawingConfig", stages_q.value("drawingConfig").toString()); } } load_stage_config(STAGE, m_stagesConfig, StageConfig::fromVariantMap); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index fc6c44709..139435eaf 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -193,7 +193,7 @@ EventPlugin::EventPlugin(QObject *parent) { connect(this, &EventPlugin::installed, this, &EventPlugin::onInstalled);//, Qt::QueuedConnection); connect(this, &EventPlugin::currentStageIdChanged, this, &EventPlugin::saveCurrentStageId); - connect(this, &EventPlugin::eventNameChanged, [this](const QString &event_name) { + connect(this, &EventPlugin::eventDbNameChanged, [this](const QString &event_name) { setEventOpen(!event_name.isEmpty()); }); connect(this, &Event::EventPlugin::dbEventNotify, this, &Event::EventPlugin::onDbEventNotify, Qt::QueuedConnection); @@ -221,7 +221,7 @@ const EventConfig &EventPlugin::eventConfig() const int EventPlugin::stageCount() const { - if(eventName().isEmpty()) { + if(eventDbName().isEmpty()) { return 0; } return appDbConfig().eventConfig().stageCount; @@ -319,7 +319,7 @@ void EventPlugin::onInstalled() m_actEditEvent = new qfw::Action(tr("E&dit event")); m_actEditEvent->setEnabled(false); connect(m_actEditEvent, &QAction::triggered, this, &EventPlugin::editEvent); - connect(this, &EventPlugin::eventNameChanged, [this](const QString &event_name) { + connect(this, &EventPlugin::eventDbNameChanged, [this](const QString &event_name) { this->m_actEditEvent->setEnabled(!event_name.isEmpty()); }); @@ -336,14 +336,13 @@ void EventPlugin::onInstalled() connect(m_actImportEvent_qbe, &QAction::triggered, this, &EventPlugin::importEvent_qbe); if(auto *sb = qobject_cast(fwk->statusBar())) { - connect(this, &EventPlugin::eventNameChanged, sb, &Core::AppStatusBar::setEventName); + connect(this, &EventPlugin::eventDbNameChanged, sb, &Core::AppStatusBar::setEventName); connect(this, &EventPlugin::currentStageIdChanged, sb, &Core::AppStatusBar::setStageNo); connect(sb, &Core::AppStatusBar::stageClicked, this, &EventPlugin::setCurrentStage); } - connect(this, &EventPlugin::eventNameChanged, this, &EventPlugin::updateWindowTitle); + connect(this, &EventPlugin::eventDbNameChanged, this, &EventPlugin::updateWindowTitle); connect(this, &EventPlugin::currentStageIdChanged, this, &EventPlugin::updateWindowTitle); connect(fwk, &qff::MainWindow::applicationLaunched, this, &EventPlugin::connectToSqlServer); - connect(this, &EventPlugin::eventOpenChanged, this, &EventPlugin::onEventOpened); qfw::Action *a_import = fwk->menuBar()->actionForPath("file/import", false); Q_ASSERT(a_import); @@ -440,20 +439,11 @@ void EventPlugin::onInstalled() void EventPlugin::updateWindowTitle() const { - QString title = QStringLiteral("%1 E%2").arg(eventName()).arg(currentStageId()); + QString title = QStringLiteral("%1 E%2").arg(eventDbName()).arg(currentStageId()); qff::MainWindow *fwk = qff::MainWindow::frameWork(); fwk->setWindowTitle(title); } -void EventPlugin::loadCurrentStageId() -{ - int stage_id = 1; - if(!eventName().isEmpty()) { - stage_id = appDbConfig().eventConfig().currentStageId; - } - setCurrentStageId(stage_id); -} - void EventPlugin::saveCurrentStageId(int current_stage) { if(current_stage != appDbConfig().eventConfig().currentStageId) { @@ -495,7 +485,7 @@ void EventPlugin::emitDbEvent(const QString &domain, const QVariant &data, bool return; } DbEventPayload dbpl; - dbpl.setEventName(eventName()); + dbpl.setEventName(eventDbName()); dbpl.setDomain(domain); dbpl.setData(data); dbpl.setconnectionId(connection_id); @@ -539,7 +529,7 @@ QString EventPlugin::classNameById(int class_id) QString EventPlugin::shvApiEventId() const { - return eventName() + "-" + QString::number(eventConfig().importId); + return eventDbName() + "-" + QString::number(eventConfig().importId); } QString EventPlugin::createApiKey(int length) @@ -570,7 +560,7 @@ QString EventPlugin::createApiKey(int length) QString EventPlugin::fileNameWithStageAndEventName(const QString &fn, std::optional stage_id) const { - auto ret = eventName(); + auto ret = eventDbName(); if(stageCount() > 1) { ret += QStringLiteral(".e%1").arg(stage_id.value_or(currentStageId())); } @@ -630,7 +620,7 @@ void EventPlugin::onDbEvent(const QString &name, QSqlDriver::NotificationSource qfWarning() << "DbNotify with invalid event name, payload:" << event_name << payload.toString(); return; } - if(event_name == eventName()) { + if(event_name == eventDbName()) { QVariant data = dbpl.data(); if (dbpl.domain() == DBEVENT_QX_RECCHNG) { qfMessage() << "from postgres:" << data; @@ -677,14 +667,6 @@ void EventPlugin::repairStageStarts(const qf::core::sql::Connection &from_conn, } } -void EventPlugin::onEventOpened() -{ - if(!isEventOpen()) - return; - qfLogFuncFrame() << "stage count:" << stageCount(); - loadCurrentStageId(); -} - EventPlugin::ConnectionType EventPlugin::connectionType() const { ConnectionSettings connection_settings; @@ -928,22 +910,22 @@ bool EventPlugin::createEvent(const QString &event_name, const EventConfig &even ok = run_sql_script(q, create_script); if(!ok) break; - // qfDebug() << "creating stages:" << stage_count; - // QString stage_table_name = "stages"; - // if(connection_type == ConnectionType::SqlServer) { - // stage_table_name = event_id + '.' + stage_table_name; - // } - // // Stage start times are stored in config as event.stage..startDateTime. - // q.prepare("INSERT INTO " + stage_table_name + " (id) VALUES (:id)"); - // for(int i=0; isetWindowTitle(tr("Edit event")); - event_w->setEventId(eventName()); + event_w->setEventId(eventDbName()); event_w->setEventIdEditable(false); EventDialogWidget::Params params; params.eventConfig = eventConfig(); @@ -1001,7 +983,7 @@ bool EventPlugin::closeEvent() { qfLogFuncFrame(); m_classNameCache.clear(); - setEventName(QString()); + setEventDbName(QString()); setEventOpen(false); return true; } @@ -1064,7 +1046,7 @@ bool EventPlugin::openEvent(const QString &_event_name) break; } } - if(!eventName().isEmpty() && db_event_names.contains(eventName()) && !ok) // dialog canceled and event is already open => no change + if(!eventDbName().isEmpty() && db_event_names.contains(eventDbName()) && !ok) // dialog canceled and event is already open => no change return true; closeEvent(); @@ -1127,7 +1109,7 @@ bool EventPlugin::openEvent(const QString &_event_name) } if(ok) { connection_settings.setEventName(event_name); - setEventName(event_name); + setEventDbName(event_name); //emit reloadDataRequest(); } @@ -1135,6 +1117,7 @@ bool EventPlugin::openEvent(const QString &_event_name) m_actEditEvent->setEnabled(ok); m_actExportEvent_qbe->setEnabled(ok); setEventOpen(ok); + emit currentStageIdChanged(currentStageId()); return ok; } @@ -1318,7 +1301,7 @@ void EventPlugin::exportEvent_qbe() void EventPlugin::deleteEvent(const QString &event_name) { qff::MainWindow *fwk = qff::MainWindow::frameWork(); - if(event_name == eventName()) + if(event_name == eventDbName()) closeEvent(); if(connectionType() == ConnectionType::SingleFile) { const QString fn = eventNameToFileName(event_name); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index ea047a17a..4f80bf804 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -31,7 +31,7 @@ class EventPlugin : public qf::gui::framework::Plugin Q_PROPERTY(int currentStageId READ currentStageId NOTIFY currentStageIdChanged) Q_PROPERTY(int stageCount READ stageCount) - Q_PROPERTY(QString eventName READ eventName WRITE setEventName NOTIFY eventNameChanged) + Q_PROPERTY(QString eventDbName READ eventDbName WRITE setEventDbName NOTIFY eventDbNameChanged) Q_PROPERTY(bool eventOpen READ isEventOpen WRITE setEventOpen NOTIFY eventOpenChanged) Q_PROPERTY(bool sqlServerConnected READ isSqlServerConnected NOTIFY sqlServerConnectedChanged) private: @@ -43,7 +43,7 @@ class EventPlugin : public qf::gui::framework::Plugin ~EventPlugin() override; QF_PROPERTY_BOOL_IMPL(e, E, ventOpen) - QF_PROPERTY_IMPL(QString, e, E, ventName) + QF_PROPERTY_IMPL(QString, e, E, ventDbName) /// strange is that 'quickboxDbEvent' just doesn't work without any error /// from psql doc: Commonly, the channel name is the same as the name of some table in the database @@ -69,7 +69,6 @@ class EventPlugin : public qf::gui::framework::Plugin int stageCount() const; const Event::StageConfig& stageConfig(int stage_id) const; - Q_SLOT void setCurrentStageId(int stage_id); int currentStageId() const; Q_SIGNAL void currentStageIdChanged(int current_stage); @@ -129,9 +128,7 @@ class EventPlugin : public qf::gui::framework::Plugin QStringList existingSqlEventNames() const; QStringList existingFileEventNames(const QString &dir = QString()) const; - void onEventOpened(); void connectToSqlServer(); - void loadCurrentStageId(); void saveCurrentStageId(int current_stage); void setCurrentStage(); void onDbEvent(const QString & name, QSqlDriver::NotificationSource source, const QVariant & payload); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/emmaclientwidget.cpp b/quickevent/app/quickevent/plugins/Event/src/services/emmaclientwidget.cpp index 48833f987..a6094fbe6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/emmaclientwidget.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/emmaclientwidget.cpp @@ -32,7 +32,7 @@ EmmaClientWidget::EmmaClientWidget(QWidget *parent) ui->chExportStartListXml30->setCheckState((ss.exportStartListTypeXml3()) ? Qt::Checked : Qt::Unchecked); ui->chExportResultsXml30->setCheckState((ss.exportResultTypeXml3()) ? Qt::Checked : Qt::Unchecked); if (ui->edFileNameBase->text().isEmpty()) - ui->edFileNameBase->setText(getPlugin()->eventName()); + ui->edFileNameBase->setText(getPlugin()->eventDbName()); if (ss.startExportType() == EmmaClientSettings::StartExportType::CSV) ui->rbRacomStartCsv->setChecked(true); } @@ -106,7 +106,7 @@ bool EmmaClientWidget::saveSettings() type = EmmaClientSettings::StartExportType::CSV; ss.setStartExportType(type); if (ss.fileNameBase().isEmpty()) - ss.setFileNameBase(getPlugin()->eventName()); + ss.setFileNameBase(getPlugin()->eventDbName()); svc->setSettings(ss); if(!dir.isEmpty()) { diff --git a/quickevent/app/quickevent/plugins/Event/src/services/service.cpp b/quickevent/app/quickevent/plugins/Event/src/services/service.cpp index 0c469327c..45e49ade8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/service.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/service.cpp @@ -50,7 +50,7 @@ void Service::onEventOpen() { auto *event_plugin = getPlugin(); if(event_plugin->isEventOpen()) { - loadSettingsForEvent(event_plugin->eventName()); + loadSettingsForEvent(event_plugin->eventDbName()); ServiceSettings ss = settings(); if(ss.isAutoStart()) { run(); diff --git a/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp index 31b61d69f..cd96fb522 100644 --- a/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp +++ b/quickevent/app/quickevent/plugins/Receipts/src/receiptsconfig.cpp @@ -14,6 +14,7 @@ ReceiptsConfig ReceiptsConfig::fromVariantMap(const QVariantMap &map) { ReceiptsConfig config; config.printQrCode = map.value("printQrCode", config.printQrCode).toBool(); + config.linkUrl = map.value("linkUrl", config.linkUrl).toString(); config.qrCodeCaption = map.value("qrCodeCaption", config.qrCodeCaption).toString(); config.printImage = map.value("printImage", config.printImage).toBool(); config.imageHeightMm = map.value("imageHeightMm", config.imageHeightMm).toInt(); @@ -26,6 +27,7 @@ QVariantMap ReceiptsConfig::toVariantMap() const { QVariantMap ret; ret["printQrCode"] = printQrCode; + ret["linkUrl"] = linkUrl; ret["qrCodeCaption"] = qrCodeCaption; ret["printImage"] = printImage; ret["imageHeightMm"] = imageHeightMm; diff --git a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple.qml b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple.qml index e80bdac46..d6191578d 100644 --- a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple.qml +++ b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple.qml @@ -114,7 +114,7 @@ Report { halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold //text: root.eventConfig.event.mainReferee - text: root.eventConfig.mainReferee() + text: root.eventConfig.mainReferee } Para { width: "%" @@ -139,7 +139,7 @@ Report { width: "%" halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold - text: root.eventConfig.director() + text: root.eventConfig.director } Para { width: "%" @@ -158,5 +158,3 @@ Report { } } } - - diff --git a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple2.qml b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple2.qml index 5247d40b3..db6b6be86 100644 --- a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple2.qml +++ b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-apple2.qml @@ -116,7 +116,7 @@ Report { halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold //text: root.eventConfig.event.mainReferee - text: root.eventConfig.mainReferee() + text: root.eventConfig.mainReferee } Para { width: "%" @@ -141,7 +141,7 @@ Report { width: "%" halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold - text: root.eventConfig.director() + text: root.eventConfig.director } Para { width: "%" @@ -161,5 +161,3 @@ Report { } } } - - diff --git a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-covid.qml b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-covid.qml index 25da2d8cc..4e0f1d00e 100644 --- a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-covid.qml +++ b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards-covid.qml @@ -137,7 +137,7 @@ Report { halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold //text: root.eventConfig.event.mainReferee - text: root.eventConfig.mainReferee() + text: root.eventConfig.mainReferee } Para { width: "%" @@ -163,7 +163,7 @@ Report { width: "%" halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold - text: root.eventConfig.director() + text: root.eventConfig.director } Para { width: "%" @@ -183,5 +183,3 @@ Report { } } } - - diff --git a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards.qml b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards.qml index ff02358c1..e61e125a3 100644 --- a/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards.qml +++ b/quickevent/app/quickevent/plugins/Runs/qml/reports/awards/results_stage_awards.qml @@ -114,7 +114,7 @@ Report { halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold //text: root.eventConfig.event.mainReferee - text: root.eventConfig.mainReferee() + text: root.eventConfig.mainReferee } Para { width: "%" @@ -139,7 +139,7 @@ Report { width: "%" halign: Frame.AlignHCenter textStyle: myStyle.textStyleBold - text: root.eventConfig.director() + text: root.eventConfig.director } Para { width: "%" @@ -158,5 +158,3 @@ Report { } } } - - diff --git a/quickevent/app/quickevent/plugins/Runs/src/printawardsoptionsdialogwidget.h b/quickevent/app/quickevent/plugins/Runs/src/printawardsoptionsdialogwidget.h index aa2796ccd..4de289604 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/printawardsoptionsdialogwidget.h +++ b/quickevent/app/quickevent/plugins/Runs/src/printawardsoptionsdialogwidget.h @@ -15,7 +15,7 @@ class PrintAwardsOptionsDialogWidget : public qf::gui::framework::DialogWidget private: using Super = qf::gui::framework::DialogWidget; public: - explicit PrintAwardsOptionsDialogWidget(QWidget *parent = 0); + explicit PrintAwardsOptionsDialogWidget(QWidget *parent = nullptr); ~PrintAwardsOptionsDialogWidget(); QVariantMap printOptions() const; diff --git a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp index ab572e038..99b1e6a8b 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/services/resultsexporter.cpp @@ -72,7 +72,7 @@ bool ResultsExporter::exportResults() const } if(ss.outputFormat() == static_cast(ResultsExporterSettings::OutputFormat::IofXml3)) { int current_stage = getPlugin()->currentStageId(); - QString file_name = ss.exportDir() + "/" + getPlugin()->eventName() + "." + Event::RESULTS_IOFXML3_FILE; + QString file_name = ss.exportDir() + "/" + getPlugin()->eventDbName() + "." + Event::RESULTS_IOFXML3_FILE; bool is_relays = getPlugin()->eventConfig().isRelays(); QString str = is_relays diff --git a/quickevent/app/quickevent/src/partwidget.cpp b/quickevent/app/quickevent/src/partwidget.cpp index 7140fa89c..1d2accb73 100644 --- a/quickevent/app/quickevent/src/partwidget.cpp +++ b/quickevent/app/quickevent/src/partwidget.cpp @@ -10,13 +10,11 @@ PartWidget::PartWidget(const QString& title, const QString &feature_id, QWidget *parent) : Super(feature_id, parent) { - using namespace qf::gui::framework; - setPersistentSettingsId(featureId()); setTitle(title); connect(this, &PartWidget::activeChanged, this, &PartWidget::onActiveChanged); - auto *event_plugin = getPlugin(); + auto *event_plugin = qf::gui::framework::getPlugin(); connect(event_plugin, &Event::EventPlugin::currentStageIdChanged, this, &PartWidget::resetPartRequest); connect(event_plugin, &Event::EventPlugin::eventOpenChanged, this, &PartWidget::resetPartRequest); connect(event_plugin, &Event::EventPlugin::reloadDataRequest, this, &PartWidget::resetPartRequest); @@ -27,12 +25,11 @@ void PartWidget::onActiveChanged() if(isActive()) { qf::gui::framework::MainWindow *fwk = qf::gui::framework::MainWindow::frameWork(); QF_ASSERT(fwk != nullptr, "Invalid FrameWork", return); - qf::gui::framework::Plugin *event_plugin = fwk->plugin("Event", qf::core::Exception::Throw); - bool sql_connected = event_plugin->property("sqlServerConnected").toBool(); - QString event_name = event_plugin->property("eventName").toString(); + auto *event_plugin = qf::gui::framework::getPlugin(); + bool sql_connected = event_plugin->isSqlServerConnected(); + QString event_name = event_plugin->eventDbName(); if(sql_connected && !event_name.isEmpty()) { emit reloadPartRequest(); } } } - From 6794769051f85300bfc2f212f0587478b32681ac Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 19 Jul 2026 12:59:56 +0200 Subject: [PATCH 80/83] Fix clang tidy errors --- quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp | 1 - quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp | 4 +--- quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp index c97f27987..c14eac7cd 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventconfig.cpp @@ -29,7 +29,6 @@ EventConfig EventConfig::fromVariantMap(const QVariantMap &values) { EventConfig data; data.stageCount = values.value("stageCount", 1).toInt(); - const QVariantMap stages = values.value("stage").toMap(); data.name = values.value("name").toString(); data.date = values.value("date").toDate(); data.time = values.value("time").toTime(); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 139435eaf..014938767 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -200,9 +200,7 @@ EventPlugin::EventPlugin(QObject *parent) connect(qf::gui::framework::Application::instance(), &qf::gui::framework::Application::qxRecChng, this, &EventPlugin::onRecChng); } -EventPlugin::~EventPlugin() -{ -} +EventPlugin::~EventPlugin() = default; Event::AppDbConfig &EventPlugin::appDbConfig() { diff --git a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp index 155eb6078..2afc4d9d2 100644 --- a/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp +++ b/quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp @@ -818,7 +818,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato ecfg.disciplineId = static_cast(discipline); ecfg.importId = event_id; ecfg.time = event_race.datetime.time(); - ecfg.iofRace = 1; + ecfg.iofRace = true; ecfg.iofXmlRaceNumber = (races.size() > 1) ? event_race.number : 0; return getPlugin()->createEvent(QString(), ecfg); } From a7b2f8099c951fe72a2d30bd321913af5b39ef07 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 19 Jul 2026 13:29:29 +0200 Subject: [PATCH 81/83] Only persist changed config values Add changedValues helper to compute diffs between QVariantMaps. Use it in setters to save only modified entries and skip saving when data is empty. Add setQxConfig to support Qx config updates. --- .../plugins/Event/src/appdbconfig.cpp | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index dab077820..775c46afa 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -27,6 +27,16 @@ constexpr auto OFEED = "ofeed"; constexpr auto ORESULTS = "oresults"; constexpr auto QX = "qx"; +QVariantMap changedValues(const QVariantMap &old_values, const QVariantMap &new_values) +{ + QVariantMap ret; + for (const auto &[key, val] : new_values.asKeyValueRange()) { + if(old_values.value(key) != val) + ret.insert(key, val); + } + return ret; +} + } QxConfig QxConfig::fromVariantMap(const QVariantMap &map) @@ -122,6 +132,10 @@ void AppDbConfig::save(const QString &prefix, int stage_id, const QVariantMap &d void AppDbConfig::save(const QString &prefix, const QVariantMap &data) { + if(data.isEmpty()) { + return; + } + using namespace qf::core::sql; Connection conn = Connection::forName(); @@ -157,8 +171,9 @@ void AppDbConfig::save(const QString &prefix, const QVariantMap &data) void AppDbConfig::setEventConfig(const EventConfig &config) { + const QVariantMap changed_values = changedValues(m_eventConfig.toVariantMap(), config.toVariantMap()); m_eventConfig = config; - save(EVENT, config.toVariantMap()); + save(EVENT, changed_values); } const services::OResultsConfig& AppDbConfig::oresultsConfig(int stage_id) const @@ -181,14 +196,16 @@ const StageConfig& AppDbConfig::stageConfig(int stage_id) const void AppDbConfig::setStageConfig(int stage_id, const StageConfig &cfg) { + const QVariantMap changed_values = changedValues(stageConfig(stage_id).toVariantMap(), cfg.toVariantMap()); m_stagesConfig[stage_id] = cfg; - save(STAGE, stage_id, cfg.toVariantMap()); + save(STAGE, stage_id, changed_values); } void AppDbConfig::setOresultsConfig(int stage_id, const services::OResultsConfig &cfg) { + const QVariantMap changed_values = changedValues(oresultsConfig(stage_id).toVariantMap(), cfg.toVariantMap()); m_oresultsConfig[stage_id] = cfg; - save(ORESULTS, stage_id, cfg.toVariantMap()); + save(ORESULTS, stage_id, changed_values); } const Receipts::ReceiptsConfig& AppDbConfig::receiptsConfig(int stage_id) const @@ -202,8 +219,9 @@ const Receipts::ReceiptsConfig& AppDbConfig::receiptsConfig(int stage_id) const void AppDbConfig::setReceiptsConfig(int stage_id, const Receipts::ReceiptsConfig &cfg) { + const QVariantMap changed_values = changedValues(receiptsConfig(stage_id).toVariantMap(), cfg.toVariantMap()); m_receiptsConfig[stage_id] = cfg; - save(RECEIPTS, stage_id, cfg.toVariantMap()); + save(RECEIPTS, stage_id, changed_values); } const services::OFeedConfig& AppDbConfig::ofeedConfig(int stage_id) const @@ -217,6 +235,14 @@ const services::OFeedConfig& AppDbConfig::ofeedConfig(int stage_id) const void AppDbConfig::setOfeedConfig(int stage_id, const services::OFeedConfig &cfg) { + const QVariantMap changed_values = changedValues(ofeedConfig(stage_id).toVariantMap(), cfg.toVariantMap()); m_ofeedConfig[stage_id] = cfg; - save(OFEED, stage_id, cfg.toVariantMap()); + save(OFEED, stage_id, changed_values); +} + +void AppDbConfig::setQxConfig(const QxConfig &config) +{ + const QVariantMap changed_values = changedValues(m_qxConfig.toVariantMap(), config.toVariantMap()); + m_qxConfig = config; + save(QX, changed_values); } From 43cbba5900d5f8b0d044363bb5231137d946afc8 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 19 Jul 2026 20:14:18 +0200 Subject: [PATCH 82/83] Remove table stages --- .../plugins/Core/src/widgets/appstatusbar.cpp | 8 ++++++-- .../plugins/Core/src/widgets/appstatusbar.h | 12 +++--------- .../quickevent/plugins/Event/qml/DbSchema.qml | 19 +------------------ .../plugins/Event/sql/create_db_psql.sql | 18 ++++-------------- .../plugins/Event/sql/create_db_sqlite.sql | 18 ++++-------------- .../plugins/Event/src/appdbconfig.cpp | 4 ++-- .../plugins/Event/src/eventplugin.cpp | 11 ++++++----- 7 files changed, 26 insertions(+), 64 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp index d64f5b955..28efcbfc2 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.cpp @@ -39,9 +39,13 @@ AppStatusBar::AppStatusBar(QWidget *parent) AppStatusBar::~AppStatusBar() = default; -void AppStatusBar::setEventName(const QString &event_name) +QString AppStatusBar::eventDbName() const +{ + return m_lblEvent->text(); +} + +void AppStatusBar::setEventDbName(const QString &event_name) { - m_eventName = event_name; m_lblEvent->setText(event_name); } diff --git a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h index cd8f4734e..33cdbe31a 100644 --- a/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h +++ b/quickevent/app/quickevent/plugins/Core/src/widgets/appstatusbar.h @@ -13,22 +13,17 @@ namespace Core { class AppStatusBar : public qf::gui::StatusBar { Q_OBJECT - - Q_PROPERTY(QString eventName READ eventName WRITE setEventName NOTIFY eventNameChanged) - Q_PROPERTY(int stageNo READ stageNo WRITE setStageNo NOTIFY stageNoChanged) private: typedef qf::gui::StatusBar Super; public: AppStatusBar(QWidget *parent = nullptr); ~AppStatusBar() Q_DECL_OVERRIDE; - QString eventName() const {return m_eventName;} - Q_SLOT void setEventName(const QString &event_name); - Q_SIGNAL void eventNameChanged(); + QString eventDbName() const; + void setEventDbName(const QString &event_name); int stageNo() const {return m_stageNo;} - Q_SLOT void setStageNo(int stage_no); - Q_SIGNAL void stageNoChanged(); + void setStageNo(int stage_no); Q_SIGNAL void stageClicked(); void showProgress(const QString &msg, int completed, int total) Q_DECL_OVERRIDE; @@ -38,7 +33,6 @@ class AppStatusBar : public qf::gui::StatusBar QLabel *m_lblEvent; QPushButton *m_btCurrentStage; - QString m_eventName; int m_stageNo = 0; }; diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index dff9e5d07..f3fd50ba9 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -31,22 +31,6 @@ Schema { Index { fields: ['ckey']; primary: true } ] }, - Table { name: 'stages' - fields: [ - Field { name: 'id'; type: Int {} }, - Field { name: 'startDateTime'; type: DateTime {} }, - Field { name: 'useAllMaps' - type: Boolean {} - defaultValue: false - notNull: true - }, - Field { name: 'drawingConfig'; type: String {} } - // Field { name: 'qxApiToken'; type: String {} } - ] - indexes: [ - Index {fields: ['id']; primary: true } - ] - }, Table { name: 'courses' fields: [ Field { name: 'id'; type: Serial { primaryKey: true } }, @@ -150,7 +134,7 @@ Schema { Field { name: 'relayLegCount'; type: Int { } } ] indexes: [ - Index {fields: ['stageId']; references: ForeignKeyReference {table: 'stages'; fields: ['id']; } }, + Index {fields: ['stageId']}, Index {fields: ['classId']; references: ForeignKeyReference {table: 'classes'; fields: ['id']; } }, Index {fields: ['courseId']; references: ForeignKeyReference {table: 'courses'; fields: ['id']; } } ] @@ -294,7 +278,6 @@ Schema { onDelete: 'RESTRICT'; } }, - Index {fields: ['stageId']; references: ForeignKeyReference {table: 'stages'; fields: ['id']; } }, Index {fields: ['relayId', 'leg']; unique: false }, Index {fields: ['stageId', 'siId']; unique: false } // might be duplicate to enable SI card sharing in not overlapping runs ] diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql index 1b5767339..e3e97837a 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_psql.sql @@ -24,15 +24,6 @@ CREATE TABLE {{eventId}}.config ( CONSTRAINT config_pkey PRIMARY KEY (ckey) ); ; --- create table: {{eventId}}.stages; -CREATE TABLE {{eventId}}.stages ( - id integer, - startDateTime timestamp with time zone, - useAllMaps boolean NOT NULL DEFAULT false, - drawingConfig character varying, - CONSTRAINT stages_pkey PRIMARY KEY (id) -); -; -- create table: {{eventId}}.courses; CREATE TABLE {{eventId}}.courses ( id serial PRIMARY KEY, @@ -93,10 +84,10 @@ CREATE TABLE {{eventId}}.classdefs ( drawLock boolean NOT NULL DEFAULT false, relayStartNumber integer, relayLegCount integer, - CONSTRAINT classdefs_foreign0 FOREIGN KEY (stageId) REFERENCES {{eventId}}.stages (id) ON UPDATE RESTRICT ON DELETE RESTRICT, CONSTRAINT classdefs_foreign1 FOREIGN KEY (classId) REFERENCES {{eventId}}.classes (id) ON UPDATE RESTRICT ON DELETE RESTRICT, CONSTRAINT classdefs_foreign2 FOREIGN KEY (courseId) REFERENCES {{eventId}}.courses (id) ON UPDATE RESTRICT ON DELETE RESTRICT ); +CREATE INDEX classdefs_ix0 ON {{eventId}}.classdefs (stageId); COMMENT ON COLUMN {{eventId}}.classdefs.vacantsBefore IS 'place n vacants gap before first competitor in class start list'; COMMENT ON COLUMN {{eventId}}.classdefs.vacantEvery IS 'place vacant every n-th competitor in class start list'; COMMENT ON COLUMN {{eventId}}.classdefs.vacantsAfter IS 'place n vacants gap after last competitor in class start list'; @@ -151,11 +142,10 @@ CREATE TABLE {{eventId}}.runs ( cardLent boolean NOT NULL DEFAULT false, cardReturned boolean NOT NULL DEFAULT false, importId integer, - CONSTRAINT runs_foreign0 FOREIGN KEY (competitorId) REFERENCES {{eventId}}.competitors (id) ON UPDATE RESTRICT ON DELETE RESTRICT, - CONSTRAINT runs_foreign1 FOREIGN KEY (stageId) REFERENCES {{eventId}}.stages (id) ON UPDATE RESTRICT ON DELETE RESTRICT + CONSTRAINT runs_foreign0 FOREIGN KEY (competitorId) REFERENCES {{eventId}}.competitors (id) ON UPDATE RESTRICT ON DELETE RESTRICT ); -CREATE INDEX runs_ix2 ON {{eventId}}.runs (relayId, leg); -CREATE INDEX runs_ix3 ON {{eventId}}.runs (stageId, siId); +CREATE INDEX runs_ix1 ON {{eventId}}.runs (relayId, leg); +CREATE INDEX runs_ix2 ON {{eventId}}.runs (stageId, siId); COMMENT ON COLUMN {{eventId}}.runs.corridorTime IS 'DateTime when competitor entered start corridor. (Experimental)'; COMMENT ON COLUMN {{eventId}}.runs.checkTimeMs IS 'in miliseconds'; COMMENT ON COLUMN {{eventId}}.runs.startTimeMs IS 'in miliseconds'; diff --git a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql index 640c65c58..98f56b7c7 100644 --- a/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql +++ b/quickevent/app/quickevent/plugins/Event/sql/create_db_sqlite.sql @@ -23,15 +23,6 @@ CREATE TABLE config ( CONSTRAINT config_pkey PRIMARY KEY (ckey) ); ; --- create table: stages; -CREATE TABLE stages ( - id integer, - startDateTime timestamp, - useAllMaps boolean NOT NULL DEFAULT 0, - drawingConfig character varying, - CONSTRAINT stages_pkey PRIMARY KEY (id) -); -; -- create table: courses; CREATE TABLE courses ( id integer PRIMARY KEY, @@ -92,10 +83,10 @@ CREATE TABLE classdefs ( drawLock boolean NOT NULL DEFAULT 0, relayStartNumber integer, relayLegCount integer, - CONSTRAINT classdefs_foreign0 FOREIGN KEY (stageId) REFERENCES stages (id) ON UPDATE RESTRICT ON DELETE RESTRICT, CONSTRAINT classdefs_foreign1 FOREIGN KEY (classId) REFERENCES classes (id) ON UPDATE RESTRICT ON DELETE RESTRICT, CONSTRAINT classdefs_foreign2 FOREIGN KEY (courseId) REFERENCES courses (id) ON UPDATE RESTRICT ON DELETE RESTRICT ); +CREATE INDEX classdefs_ix0 ON classdefs (stageId); -- comments not suported for driver: SQLITE -- COMMENT ON COLUMN classdefs.vacantsBefore IS 'place n vacants gap before first competitor in class start list'; -- comments not suported for driver: SQLITE @@ -156,11 +147,10 @@ CREATE TABLE runs ( cardLent boolean NOT NULL DEFAULT 0, cardReturned boolean NOT NULL DEFAULT 0, importId integer, - CONSTRAINT runs_foreign0 FOREIGN KEY (competitorId) REFERENCES competitors (id) ON UPDATE RESTRICT ON DELETE RESTRICT, - CONSTRAINT runs_foreign1 FOREIGN KEY (stageId) REFERENCES stages (id) ON UPDATE RESTRICT ON DELETE RESTRICT + CONSTRAINT runs_foreign0 FOREIGN KEY (competitorId) REFERENCES competitors (id) ON UPDATE RESTRICT ON DELETE RESTRICT ); -CREATE INDEX runs_ix2 ON runs (relayId, leg); -CREATE INDEX runs_ix3 ON runs (stageId, siId); +CREATE INDEX runs_ix1 ON runs (relayId, leg); +CREATE INDEX runs_ix2 ON runs (stageId, siId); -- comments not suported for driver: SQLITE -- COMMENT ON COLUMN runs.corridorTime IS 'DateTime when competitor entered start corridor. (Experimental)'; -- comments not suported for driver: SQLITE diff --git a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp index 775c46afa..e813b8cf9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/appdbconfig.cpp @@ -107,9 +107,9 @@ void AppDbConfig::load() } }; { - auto stages = config.value(STAGE).toMap(); + auto stages = config.value(STAGE).toMap(); Query stages_q(conn); - stages_q.exec("SELECT * FROM stages ORDER BY id", qf::core::Exception::Throw); + stages_q.exec("SELECT * FROM stages ORDER BY id", !qf::core::Exception::Throw); while(stages_q.next()) { const auto stage_id = stages_q.value("id").toString(); if(stages.contains(stage_id)) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index bc750e2f1..47127c5b9 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -335,7 +335,7 @@ void EventPlugin::onInstalled() connect(m_actImportEvent_qbe, &QAction::triggered, this, &EventPlugin::importEvent_qbe); if(auto *sb = qobject_cast(fwk->statusBar())) { - connect(this, &EventPlugin::eventDbNameChanged, sb, &Core::AppStatusBar::setEventName); + connect(this, &EventPlugin::eventDbNameChanged, sb, &Core::AppStatusBar::setEventDbName); connect(this, &EventPlugin::currentStageIdChanged, sb, &Core::AppStatusBar::setStageNo); connect(sb, &Core::AppStatusBar::stageClicked, this, &EventPlugin::setCurrentStage); } @@ -653,7 +653,7 @@ void EventPlugin::repairStageStarts(const qf::core::sql::Connection &from_conn, { qfs::Query to_q(to_conn); qfs::Query from_q(from_conn); - from_q.exec("SELECT * FROM stages ORDER BY id"); + from_q.exec("SELECT * FROM stages ORDER BY id", !qf::core::Exception::Throw); while(from_q.next()) { int ix = from_q.fieldIndex(QStringLiteral("startDate")); if(ix < 0) @@ -1045,9 +1045,10 @@ bool EventPlugin::openEvent(const QString &_event_name) break; } } - if(!eventDbName().isEmpty() && db_event_names.contains(eventDbName()) && !ok) // dialog canceled and event is already open => no change + if(!eventDbName().isEmpty() && db_event_names.contains(eventDbName()) && !ok) { + // dialog canceled and event is already open => no change return true; - + } closeEvent(); if(ok) { @@ -1092,7 +1093,7 @@ bool EventPlugin::openEvent(const QString &_event_name) } } if(ok) { - m_appDbConfig = AppDbConfig(); + m_appDbConfig = AppDbConfig(); m_appDbConfig.load(); if(m_appDbConfig.dbVersion() < dbVersion()) { qfd::MessageBox::showError(fwk, tr("Event data version (%1) is too low, minimal version is (%2).\nUse: File --> Import --> Event (*.qbe) to convert event to current version.") From 8e304620df88577bbf1f53982e40741b5d502b9c Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Mon, 20 Jul 2026 13:17:06 +0200 Subject: [PATCH 83/83] Parse JSON drawingConfig and repair stage starts Accept drawingConfig as a JSON string or QVariantMap and add DrawingConfig::fromString. Use startDateTime when repairing stages and call repairStageStarts once after copying tables. --- .../plugins/Event/src/eventplugin.cpp | 34 +++++++++++++------ .../plugins/Event/src/stageconfig.cpp | 29 ++++++++++++++-- .../plugins/Event/src/stageconfig.h | 1 + 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 47127c5b9..386c86cd0 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -652,17 +653,32 @@ void EventPlugin::onRegistrationsDockVisibleChanged(bool on) void EventPlugin::repairStageStarts(const qf::core::sql::Connection &from_conn, const qf::core::sql::Connection &to_conn) { qfs::Query to_q(to_conn); + to_q.prepare("INSERT INTO config (ckey, cvalue, ctype) VALUES (:key, :value, :type)"); + qfs::Query from_q(from_conn); from_q.exec("SELECT * FROM stages ORDER BY id", !qf::core::Exception::Throw); while(from_q.next()) { - int ix = from_q.fieldIndex(QStringLiteral("startDate")); + int ix = from_q.fieldIndex(QStringLiteral("startDateTime")); if(ix < 0) break; - QDate d = from_q.value(ix).toDate(); - QTime t = from_q.value("startTime").toTime(); - QDateTime dt(d, t); - int id = from_q.value("id").toInt(); - to_q.exec("UPDATE stages SET startDateTime=" QF_SARG(dt.toString(Qt::ISODate)) " WHERE id=" QF_IARG(id)); + auto stage_id = from_q.value("id").toInt(); + StageConfig stage_config; + stage_config.startDateTime = from_q.value(ix).toDateTime(); + stage_config.drawingConfig = DrawingConfig::fromString(from_q.value("drawingConfig").toString()); + stage_config.useAllMaps = from_q.value("useAllMaps").toBool(); + auto make_key = [stage_id](const QString& key) {return QStringLiteral("stage.%1.%2").arg(stage_id).arg(key);}; + to_q.bindValue(":key", make_key("startDateTime")); + to_q.bindValue(":value", stage_config.startDateTime); + to_q.bindValue(":type", "QDateTime"); + to_q.exec(); + to_q.bindValue(":key", make_key("drawingConfig")); + to_q.bindValue(":value", qf::core::Utils::qvariantToJson(stage_config.drawingConfig.toVariantMap())); + to_q.bindValue(":type", "QString"); + to_q.exec(); + to_q.bindValue(":key", make_key("useAllMaps")); + to_q.bindValue(":value", stage_config.useAllMaps); + to_q.bindValue(":type", "bool"); + to_q.exec(); } } @@ -1407,7 +1423,7 @@ bool EventPlugin::convertSqlEvent(const QString &from_event, const QString &to_e } QString EventPlugin::copyEventSchema(qfs::Connection &imp_conn, qfs::Connection &exp_conn, - const QString &dest_schema_name) + const QString &dest_schema_name) { qff::MainWindow *fwk = qff::MainWindow::frameWork(); QString err_str; @@ -1436,12 +1452,10 @@ QString EventPlugin::copyEventSchema(qfs::Connection &imp_conn, qfs::Connection err_str = copy_sql_table(table_name, rec, imp_conn, exp_conn); if(!err_str.isEmpty()) break; - if(table_name == QLatin1String("stages")) { - repairStageStarts(imp_conn, exp_conn); - } } if(!err_str.isEmpty()) break; + repairStageStarts(imp_conn, exp_conn); transaction.commit(); } while(false); return err_str; diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp index 0277733c4..bff47a2d8 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.cpp @@ -1,7 +1,11 @@ #include "stageconfig.h" -#include #include +#include + +#include +#include +#include namespace Event { @@ -21,6 +25,21 @@ QVariantMap StartSlotConfig::toVariantMap() const return map; } +DrawingConfig DrawingConfig::fromString(const QString& str) +{ + DrawingConfig config; + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(str.toUtf8(), &parseError); + if (parseError.error == QJsonParseError::NoError) { + if (doc.isObject()) { + config = fromVariantMap(doc.object().toVariantMap()); + } + } else { + qfWarning() << "Failed to parse drawing config JSON:" << parseError.errorString(); + } + return config; +} + DrawingConfig DrawingConfig::fromVariantMap(const QVariantMap& map) { DrawingConfig config; @@ -56,7 +75,13 @@ StageConfig StageConfig::fromVariantMap(const QVariantMap& map) StageConfig config; config.startDateTime = map.value("startDateTime").toDateTime(); config.useAllMaps = map.value("useAllMaps").toBool(); - config.drawingConfig = DrawingConfig::fromVariantMap(map.value("drawingConfig").toMap()); + auto v = map.value("drawingConfig"); + if (v.userType() == QMetaType::QVariantMap) { + config.drawingConfig = DrawingConfig::fromVariantMap(v.toMap()); + } + else if (v.userType() == QMetaType::QString) { + config.drawingConfig = DrawingConfig::fromString(v.toString()); + } return config; } diff --git a/quickevent/app/quickevent/plugins/Event/src/stageconfig.h b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h index 66b883e20..c286f534e 100644 --- a/quickevent/app/quickevent/plugins/Event/src/stageconfig.h +++ b/quickevent/app/quickevent/plugins/Event/src/stageconfig.h @@ -18,6 +18,7 @@ struct StartSlotConfig struct DrawingConfig { + static DrawingConfig fromString(const QString& str); static DrawingConfig fromVariantMap(const QVariantMap& map); QVariantMap toVariantMap() const; const StartSlotConfig& startSlotConfig(int index) const;