From b76e9cafced274948b5432a98b0f328a2c96ea93 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Fri, 1 Mar 2024 19:58:12 +0100 Subject: [PATCH] Implement DBEVENT_RUN_CHANGED + signal Event::dbEvent(...) --- libqf/libqfcore/src/sql/query.cpp | 28 +++- libqf/libqfcore/src/sql/query.h | 3 + libqf/libqfcore/src/utils/table.cpp | 22 ++-- libqf/libqfcore/src/utils/table.h | 1 + .../CardReader/src/cardreaderplugin.cpp | 8 ++ .../Competitors/src/competitordocument.cpp | 69 +++++++--- .../Competitors/src/competitorswidget.cpp | 30 ++++- .../Competitors/src/competitorwidget.cpp | 123 ++++++++++-------- .../Competitors/src/competitorwidget.h | 2 +- .../plugins/Event/src/eventplugin.cpp | 12 +- .../plugins/Event/src/eventplugin.h | 9 +- .../Event/src/services/shvapi/client.cpp | 4 +- .../Event/src/services/shvapi/nodes.cpp | 61 ++++++++- .../plugins/Event/src/services/shvapi/nodes.h | 14 +- .../src/services/shvapi/rpcsqlresult.cpp | 13 ++ .../Event/src/services/shvapi/rpcsqlresult.h | 8 +- .../plugins/Runs/src/cardflagsdialog.cpp | 2 +- .../plugins/Runs/src/cardflagsdialog.h | 10 +- .../plugins/Runs/src/runflagsdialog.cpp | 2 +- .../plugins/Runs/src/runflagsdialog.h | 11 +- .../plugins/Runs/src/runsplugin.cpp | 65 ++++++++- .../quickevent/plugins/Runs/src/runsplugin.h | 7 +- .../plugins/Runs/src/runstablemodel.cpp | 61 ++++----- .../plugins/Runs/src/runstablemodel.h | 22 ++-- .../plugins/Runs/src/runstablewidget.cpp | 47 +------ 25 files changed, 427 insertions(+), 207 deletions(-) diff --git a/libqf/libqfcore/src/sql/query.cpp b/libqf/libqfcore/src/sql/query.cpp index 6c03c5954..ffc38d4de 100644 --- a/libqf/libqfcore/src/sql/query.cpp +++ b/libqf/libqfcore/src/sql/query.cpp @@ -8,7 +8,7 @@ #include #include -using namespace qf::core::sql; +namespace qf::core::sql { Query::Query(const QSqlDatabase &db) : Super(db) @@ -176,3 +176,29 @@ void Query::execCommandsThrow(const QStringList &commands, const QMapvalues[col] = val; diff --git a/libqf/libqfcore/src/utils/table.h b/libqf/libqfcore/src/utils/table.h index ee048ebc7..fdb64da6a 100644 --- a/libqf/libqfcore/src/utils/table.h +++ b/libqf/libqfcore/src/utils/table.h @@ -368,6 +368,7 @@ class QFCORE_DECL_EXPORT TableRow //QVector& valuesRef() {return d->values;} const QVector& values() const {return d->values;} QVariantMap valuesMap(bool full_names = false) const; + QVariantMap dirtyValuesMap() const; //! Dirty flag nastavi, jen kdyz je value jina, nez ta, co uz tam byla. void setValue(int col, const QVariant &v); diff --git a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp index ecbbde184..59b8d80ee 100644 --- a/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp +++ b/quickevent/app/quickevent/plugins/CardReader/src/cardreaderplugin.cpp @@ -529,6 +529,14 @@ bool CardReaderPlugin::processCardToRunAssignment(int card_id, int run_id) setStartTime(relay_id, leg + 1, new_next_leg_start_time); int competitor_id = getPlugin()->competitorForRun(next_leg_run_id); getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_COMPETITOR_EDITED, competitor_id); + QVariantList param { + next_leg_run_id, + QVariantMap { + {"runs.id", next_leg_run_id}, + {"runs.startTimeMs", new_next_leg_start_time}, + } + }; + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, param); } } } diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp index 0ef0879ff..d889e5264 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitordocument.cpp @@ -1,5 +1,8 @@ #include "competitordocument.h" +#include +#include + #include #include @@ -7,11 +10,11 @@ #include #include #include -#include using namespace Competitors; using qf::qmlwidgets::framework::getPlugin; using Event::EventPlugin; +using Runs::RunsPlugin; CompetitorDocument::CompetitorDocument(QObject *parent) : Super(parent) @@ -30,6 +33,17 @@ bool CompetitorDocument::saveData() { qfLogFuncFrame(); RecordEditMode old_mode = mode(); + QMap old_records; + auto *runs_plugin = getPlugin(); + if (old_mode == DataDocument::ModeEdit) { + auto competitor_id = dataId().toInt(); + qf::core::sql::Query q(sqlModel()->connectionName()); + q.exec(QStringLiteral("SELECT id FROM runs WHERE competitorId = %1").arg(competitor_id)); + while(q.next()) { + int run_id = q.value(0).toInt(); + old_records[run_id] = runs_plugin->runRecord(run_id); + } + } bool siid_dirty = isDirty("competitors.siId"); bool class_dirty = isDirty("competitors.classId"); bool ret = Super::saveData(); @@ -52,24 +66,37 @@ bool CompetitorDocument::saveData() q.exec(qf::core::Exception::Throw); m_lastInsertedRunsIds << q.lastInsertId().toInt(); } - if(m_isEmitDbEventsOnSave) + if(m_isEmitDbEventsOnSave) { getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED); + for (auto run_id : m_lastInsertedRunsIds) { + auto rec = runs_plugin->runRecord(run_id); + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, rec}); + } + } } else if(old_mode == DataDocument::ModeEdit) { competitor_id = dataId().toInt(); if(siid_dirty) { qfDebug() << "updating SIID in run tables"; - if(siid_dirty) { - int competitor_id = dataId().toInt(); - qf::core::sql::Query q(sqlModel()->connectionName()); - q.prepare("UPDATE runs SET siId=:siId WHERE competitorId=:competitorId", qf::core::Exception::Throw); - q.bindValue(":competitorId", competitor_id); - q.bindValue(":siId", siid()); - q.exec(qf::core::Exception::Throw); + int competitor_id = dataId().toInt(); + qf::core::sql::Query q(sqlModel()->connectionName()); + q.prepare("UPDATE runs SET siId=:siId WHERE competitorId=:competitorId", qf::core::Exception::Throw); + q.bindValue(":competitorId", competitor_id); + q.bindValue(":siId", siid()); + q.exec(qf::core::Exception::Throw); + } + if(m_isEmitDbEventsOnSave) { + if(class_dirty) { + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED); + } + for(const auto &[run_id, old_record] : old_records.asKeyValueRange()) { + auto record = runs_plugin->runRecord(run_id); + auto diff = qf::core::sql::recordDiff(old_record, record); + if (!diff.isEmpty()) { + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, diff}); + } } } - if(class_dirty && m_isEmitDbEventsOnSave) - getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED); } else { competitor_id = dataId().toInt(); @@ -83,19 +110,29 @@ bool CompetitorDocument::saveData() bool CompetitorDocument::dropData() { bool ret = false; - auto id = dataId(); + auto competitor_id = dataId().toInt(); + QList run_ids; + { + qf::core::sql::Query q(sqlModel()->connectionName()); + q.exec(QStringLiteral("SELECT id FROM runs WHERE competitorId = %1").arg(competitor_id)); + while(q.next()) { + run_ids << q.value(0).toInt(); + } + } { qf::core::sql::Query q(sqlModel()->connectionName()); - q.prepare("DELETE FROM runs WHERE competitorId = :competitorId"); - q.bindValue(":competitorId", id); - ret = q.exec(); + ret = q.exec(QStringLiteral("DELETE FROM runs WHERE competitorId = %1").arg(competitor_id)); if(!ret) qfError() << q.lastError().text(); } if(ret) { ret = Super::dropData(); - if(m_isEmitDbEventsOnSave) + if(m_isEmitDbEventsOnSave) { getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED); + for (auto run_id : run_ids) { + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, {}}); + } + } } return ret; } diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorswidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorswidget.cpp index 3ed0e9129..a032e8353 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorswidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorswidget.cpp @@ -47,6 +47,34 @@ using qf::qmlwidgets::framework::getPlugin; using Event::EventPlugin; using Competitors::CompetitorsPlugin; +class CompetitorsModel : public qfm::SqlTableModel +{ + using Super = qfm::SqlTableModel; +public: + CompetitorsModel(QObject *parent ) : Super(parent) {} + + bool postRow(int row_no, bool throw_exc) override + { + qfu::TableRow &row_ref = m_table.rowRef(row_no); + auto competitor_id = row_ref.value("competitors.id").toInt(); + QVariantMap dirty_rec; + if (!row_ref.isInsert()) { + Q_ASSERT(competitor_id > 0); + dirty_rec = row_ref.dirtyValuesMap(); + } + auto ret = Super::postRow(row_no, throw_exc); + if (!dirty_rec.isEmpty()) { + qf::core::sql::Query q; + q.exec(QStringLiteral("SELECT id FROM runs WHERE competitorId = %1").arg(competitor_id)); + while(q.next()) { + int run_id = q.value(0).toInt(); + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, dirty_rec}); + } + } + return ret; + } +}; + CompetitorsWidget::CompetitorsWidget(QWidget *parent) : Super(parent), ui(new Ui::CompetitorsWidget) @@ -60,7 +88,7 @@ CompetitorsWidget::CompetitorsWidget(QWidget *parent) : ui->tblCompetitors->setPersistentSettingsId("tblCompetitors"); ui->tblCompetitors->setRowEditorMode(qfw::TableView::EditRowsMixed); ui->tblCompetitors->setInlineEditSaveStrategy(qfw::TableView::OnEditedValueCommit); - qfm::SqlTableModel *m = new qfm::SqlTableModel(this); + qfm::SqlTableModel *m = new CompetitorsModel(this); m->addColumn("id").setReadOnly(true); m->addColumn("classes.name", tr("Class")); m->addColumn("competitors.startNumber", tr("SN", "start number")).setToolTip(tr("Start number")); diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp index b50cc6095..cd8190a08 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.cpp @@ -40,7 +40,7 @@ namespace { class CompetitorRunsModel : public quickevent::core::og::SqlTableModel { - Q_DECLARE_TR_FUNCTIONS(RunsModel) + Q_DECLARE_TR_FUNCTIONS(CompetitorRunsModel) private: using Super = quickevent::core::og::SqlTableModel; public: @@ -60,7 +60,74 @@ class CompetitorRunsModel : public quickevent::core::og::SqlTableModel col_COUNT }; private: - QVariant value(int row_ix, int column_ix) const override; + QVariant value(int row_ix, int column_ix) const override + { + if(column_ix == col_runs_runFlags) { + qf::core::utils::TableRow row = tableRow(row_ix); + bool is_disqualified = row.value(QStringLiteral("runs.disqualified")).toBool(); + bool is_disqualified_by_organizer = row.value(QStringLiteral("runs.disqualifiedByOrganizer")).toBool(); + bool mis_punch = row.value(QStringLiteral("runs.misPunch")).toBool(); + bool bad_check = row.value(QStringLiteral("runs.badCheck")).toBool(); + bool not_start = row.value(QStringLiteral("runs.notStart")).toBool(); + bool not_finish = row.value(QStringLiteral("runs.notFinish")).toBool(); + bool not_competing = row.value(QStringLiteral("runs.notCompeting")).toBool(); + QStringList sl; + if(is_disqualified) + sl << tr("DISQ", "Disqualified"); + if(is_disqualified_by_organizer) + sl << tr("DO", "disqualifiedByOrganizer"); + if(mis_punch) + sl << tr("MP", "MisPunch"); + if(bad_check) + sl << tr("BC", "BadCheck"); + if(not_competing) + sl << tr("NC", "NotCompeting"); + if(not_start) + sl << tr("DNS", "DidNotStart"); + if(not_finish) + sl << tr("DNF", "DidNotFinish"); + if(sl.isEmpty()) + return QStringLiteral(""); + else + return sl.join(','); + } + else if(column_ix == col_runs_cardFlags) { + qf::core::utils::TableRow row = tableRow(row_ix); + bool card_rent_requested = row.value(QStringLiteral("runs.cardLent")).toBool(); + bool card_returned = row.value(QStringLiteral("runs.cardReturned")).toBool(); + bool card_in_lent_table = row.value(QStringLiteral("cardInLentTable")).toBool(); + QStringList sl; + if(card_rent_requested) + sl << tr("CR", "Card rent requested"); + if(card_in_lent_table) + sl << tr("CT", "Card in lent cards table"); + if(card_returned) + sl << tr("RET", "Card returned"); + if(sl.isEmpty()) + return QStringLiteral(""); + else + return sl.join(','); + } + return Super::value(row_ix, column_ix); + } + + bool postRow(int row_no, bool throw_exc) override + { + auto &row_ref = m_table.rowRef(row_no); + auto run_id = row_ref.value("runs.id").toInt(); + Q_ASSERT(run_id > 0); + QVariantMap dirty_rec; + for (const auto &[k, v] : row_ref.dirtyValuesMap().asKeyValueRange()) { + if (k.startsWith("runs.")) { + dirty_rec[k] = v; + } + } + auto ret = Super::postRow(row_no, throw_exc); + if (!dirty_rec.isEmpty()) { + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, dirty_rec}); + } + return ret; + } }; CompetitorRunsModel::CompetitorRunsModel(QObject *parent) @@ -110,7 +177,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) : connect(ui->edFind, &FindRegistrationEdit::registrationSelected, this, &CompetitorWidget::onRegistrationSelected); dataController()->setDocument(new Competitors::CompetitorDocument(this)); - m_runsModel = (RunsTableModel*) new CompetitorRunsModel(this); + m_runsModel = new CompetitorRunsModel(this); ui->tblRuns->setTableModel(m_runsModel); ui->tblRuns->setPersistentSettingsId(ui->tblRuns->objectName()); ui->tblRuns->setInlineEditSaveStrategy(qf::qmlwidgets::TableView::OnManualSubmit); @@ -357,54 +424,4 @@ bool CompetitorWidget::saveData() return false; } -QVariant CompetitorRunsModel::value(int row_ix, int column_ix) const -{ - if(column_ix == col_runs_runFlags) { - qf::core::utils::TableRow row = tableRow(row_ix); - bool is_disqualified = row.value(QStringLiteral("runs.disqualified")).toBool(); - bool is_disqualified_by_organizer = row.value(QStringLiteral("runs.disqualifiedByOrganizer")).toBool(); - bool mis_punch = row.value(QStringLiteral("runs.misPunch")).toBool(); - bool bad_check = row.value(QStringLiteral("runs.badCheck")).toBool(); - bool not_start = row.value(QStringLiteral("runs.notStart")).toBool(); - bool not_finish = row.value(QStringLiteral("runs.notFinish")).toBool(); - bool not_competing = row.value(QStringLiteral("runs.notCompeting")).toBool(); - QStringList sl; - if(is_disqualified) - sl << tr("DISQ", "Disqualified"); - if(is_disqualified_by_organizer) - sl << tr("DO", "disqualifiedByOrganizer"); - if(mis_punch) - sl << tr("MP", "MisPunch"); - if(bad_check) - sl << tr("BC", "BadCheck"); - if(not_competing) - sl << tr("NC", "NotCompeting"); - if(not_start) - sl << tr("DNS", "DidNotStart"); - if(not_finish) - sl << tr("DNF", "DidNotFinish"); - if(sl.isEmpty()) - return QStringLiteral(""); - else - return sl.join(','); - } - else if(column_ix == col_runs_cardFlags) { - qf::core::utils::TableRow row = tableRow(row_ix); - bool card_rent_requested = row.value(QStringLiteral("runs.cardLent")).toBool(); - bool card_returned = row.value(QStringLiteral("runs.cardReturned")).toBool(); - bool card_in_lent_table = row.value(QStringLiteral("cardInLentTable")).toBool(); - QStringList sl; - if(card_rent_requested) - sl << tr("CR", "Card rent requested"); - if(card_in_lent_table) - sl << tr("CT", "Card in lent cards table"); - if(card_returned) - sl << tr("RET", "Card returned"); - if(sl.isEmpty()) - return QStringLiteral(""); - else - return sl.join(','); - } - return Super::value(row_ix, column_ix); -} diff --git a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.h b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.h index bad278a86..0a7c570f8 100644 --- a/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.h +++ b/quickevent/app/quickevent/plugins/Competitors/src/competitorwidget.h @@ -37,7 +37,7 @@ private slots: void showRunsTable(int stage_id); private: Ui::CompetitorWidget *ui; - RunsTableModel *m_runsModel; + quickevent::core::og::SqlTableModel *m_runsModel; }; #endif // COMPETITORWIDGET_H diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index af9cc2de2..0b2959799 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -104,6 +104,7 @@ static auto QBE_EXT = QStringLiteral(".qbe"); const char* EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED = "competitorCountsChanged"; const char* EventPlugin::DBEVENT_CARD_READ = "cardRead"; const char* EventPlugin::DBEVENT_COMPETITOR_EDITED = "competitorEdited"; +const char* EventPlugin::DBEVENT_RUN_CHANGED = "runChanged"; const char* EventPlugin::DBEVENT_CARD_PROCESSED_AND_ASSIGNED = "cardProcessedAndAssigned"; const char* EventPlugin::DBEVENT_PUNCH_RECEIVED = "punchReceived"; const char* EventPlugin::DBEVENT_REGISTRATIONS_IMPORTED = "registrationsImported"; @@ -446,6 +447,9 @@ void EventPlugin::emitDbEvent(const QString &domain, const QVariant &data, bool { qfLogFuncFrame() << "domain:" << domain << "payload:" << data; int connection_id = qf::core::sql::Connection::defaultConnection().connectionId(); + QTimer::singleShot(0, this, [this, domain, data]() { + emit dbEvent(domain, data); + }); if(loopback) { // emit queued //emit dbEventNotify(domain, payload); @@ -453,8 +457,9 @@ void EventPlugin::emitDbEvent(const QString &domain, const QVariant &data, bool emit dbEventNotify(domain, connection_id, data); }); } - if(connectionType() == ConnectionType::SingleFile) + if(isSingleUser()) { return; + } DbEventPayload dbpl; dbpl.setEventName(eventName()); dbpl.setDomain(domain); @@ -590,6 +595,11 @@ EventPlugin::ConnectionType EventPlugin::connectionType() const return connection_settings.connectionType(); } +bool EventPlugin::isSingleUser() const +{ + return connectionType() == ConnectionType::SingleFile; +} + QStringList EventPlugin::existingSqlEventNames() const { qfs::Connection conn(QSqlDatabase::database()); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 50100981e..9278b385f 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -42,6 +42,7 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin static const char* DBEVENT_COMPETITOR_COUNTS_CHANGED; //< number of competitors in classes changed static const char* DBEVENT_CARD_READ; static const char* DBEVENT_COMPETITOR_EDITED; + static const char* DBEVENT_RUN_CHANGED; static const char* DBEVENT_CARD_PROCESSED_AND_ASSIGNED; static const char* DBEVENT_PUNCH_RECEIVED; static const char* DBEVENT_REGISTRATIONS_IMPORTED; @@ -83,7 +84,10 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin Q_SIGNAL void sqlServerConnectedChanged(bool is_open); Q_INVOKABLE void emitDbEvent(const QString &domain, const QVariant &data = QVariant(), bool loopback = true); + /// emitted only if loopback is not set Q_SIGNAL void dbEventNotify(const QString &domain, int connection_id, const QVariant &payload); + /// emitted always + Q_SIGNAL void dbEvent(const QString &domain, const QVariant &payload); Q_INVOKABLE QString sqlDriverName(); @@ -94,12 +98,11 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin Q_SLOT void onInstalled(); public: - // event wide signals - //Q_SIGNAL void editStartListRequest(int stage_id, int class_id, int competitor_id); + ConnectionType connectionType() const; + bool isSingleUser() const; private: void setSqlServerConnected(bool ok); - ConnectionType connectionType() const; QStringList existingSqlEventNames() const; QStringList existingFileEventNames(const QString &dir = QString()) const; diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp index c4173d1ba..457cea2af 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/client.cpp @@ -57,7 +57,9 @@ Client::Client(QObject *parent) auto *stage = new shv::iotqt::node::ShvNode("stage", event); for (auto i = 0; i < event_plugin->stageCount(); i++) { auto *nd = new shv::iotqt::node::ShvNode(std::to_string(i + 1), stage); - new StartListStarterNode(i, nd); + auto *runs = new SqlViewNode("runs", nd); + auto qb = getPlugin()->runsQuery(i + 1); + runs->setQueryBuilder(qb); } new SqlNode(m_rootNode); } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.cpp index fa7d519e0..e645007d1 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.cpp @@ -1,12 +1,17 @@ #include "nodes.h" +#include "rpcsqlresult.h" #include "../../eventplugin.h" #include #include #include +#include #include +#include + +#include using namespace shv::chainpack; @@ -49,6 +54,26 @@ RpcValue DotAppNode::callMethod(const StringViewList &shv_path, const std::strin // EventNode //========================================================= static auto METH_CURRENT_STAGE = "currentStage"; +static auto SIG_RUN_CHANGED = "runChanged"; + +EventNode::EventNode(shv::iotqt::node::ShvNode *parent) +: Super("event", parent) +{ + auto *event_plugin = getPlugin(); + connect(event_plugin, &EventPlugin::dbEvent, this, [this](const QString &domain, const QVariant &payload) { + if (domain == Event::EventPlugin::DBEVENT_RUN_CHANGED) { + auto param = shv::coreqt::rpc::qVariantToRpcValue(payload); + Q_ASSERT(param.isList()); + Q_ASSERT(param.asList().value(0).toInt() > 0); + RpcSignal sig; + sig.setShvPath(shvPath()); + sig.setMethod(SIG_RUN_CHANGED); + sig.setParams(param); + qfDebug() << "emit:" << sig.toPrettyString(); + emitSendRpcMessage(sig); + } + }); +} const std::vector &EventNode::metaMethods() { @@ -56,6 +81,7 @@ const std::vector &EventNode::metaMethods() {Rpc::METH_DIR, MetaMethod::Signature::RetParam, MetaMethod::Flag::None, Rpc::ROLE_BROWSE}, {Rpc::METH_LS, MetaMethod::Signature::RetParam, MetaMethod::Flag::None, Rpc::ROLE_BROWSE}, {METH_CURRENT_STAGE, MetaMethod::Signature::RetVoid, MetaMethod::Flag::IsGetter, Rpc::ROLE_READ}, + {SIG_RUN_CHANGED, MetaMethod::Signature::VoidParam, MetaMethod::Flag::IsSignal, Rpc::ROLE_READ}, }; return meta_methods; } @@ -79,7 +105,12 @@ static auto METH_RECORD = "record"; static auto METH_SET_RECORD = "setRecord"; static auto SIG_REC_CHNG = "recchng"; -const std::vector &StartListStarterNode::metaMethods() +void SqlViewNode::setQueryBuilder(const qf::core::sql::QueryBuilder &qb) +{ + m_queryBuilder = qb; +} + +const std::vector &SqlViewNode::metaMethods() { static std::vector meta_methods { {Rpc::METH_DIR, MetaMethod::Signature::RetParam, MetaMethod::Flag::None, Rpc::ROLE_BROWSE}, @@ -92,12 +123,38 @@ const std::vector &StartListStarterNode::metaMethods() return meta_methods; } -RpcValue StartListStarterNode::callMethod(const StringViewList &shv_path, const std::string &method, const shv::chainpack::RpcValue ¶ms, const shv::chainpack::RpcValue &user_id) +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 where = m.value("where").to(); + auto qb = m_queryBuilder; + if (!where.isEmpty()) { + qb.where(where); + } + qf::core::sql::Query q; + QString qs = qb.toString(); + q.exec(qs, qf::core::Exception::Throw); + auto res = RpcSqlResult::fromQuery(q); + return res.toRpcValue(); + } + if(method == METH_RECORD) { + auto id = params.toInt(); + auto qb = m_queryBuilder; + 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 shvapi::recordToMap(q.record()); + } + else { + return RpcValue::Map{}; + } } } return Super::callMethod(shv_path, method, params, user_id); diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.h b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.h index 5bdd103e0..16b4b1b82 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/nodes.h @@ -2,6 +2,8 @@ #include "shvnode.h" +#include + namespace Event::services::shvapi { class DotAppNode : public shvapi::ShvNode @@ -23,27 +25,27 @@ class EventNode : public shvapi::ShvNode using Super = shvapi::ShvNode; public: - explicit EventNode(shv::iotqt::node::ShvNode *parent) : Super("event", parent) {} + 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 StartListStarterNode : public shvapi::ShvNode +class SqlViewNode : public shvapi::ShvNode { Q_OBJECT using Super = shvapi::ShvNode; public: - explicit StartListStarterNode(int stage, shv::iotqt::node::ShvNode *parent) - : Super("startliststarter", parent) - , m_stage(stage) + explicit SqlViewNode(const std::string &name, shv::iotqt::node::ShvNode *parent) + : Super(name, parent) {} + void setQueryBuilder(const qf::core::sql::QueryBuilder &qb); 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; private: - int m_stage; + qf::core::sql::QueryBuilder m_queryBuilder; }; } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.cpp b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.cpp index 3594c28c6..266520480 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.cpp @@ -157,6 +157,7 @@ RpcSqlResult RpcSqlResult::fromQuery(QSqlQuery &q) QSqlField fld = rec.field(i); RpcSqlField rfld; rfld.name = fld.name(); + rfld.name.replace("__", "."); rfld.type = fld.metaType().id(); ret.fields.append(rfld); } @@ -180,4 +181,16 @@ RpcSqlResult RpcSqlResult::fromQuery(QSqlQuery &q) return ret; } +shv::chainpack::RpcValue::Map 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; +} + } diff --git a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.h b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.h index f17d0b3ee..942e72dc6 100644 --- a/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.h +++ b/quickevent/app/quickevent/plugins/Event/src/services/shvapi/rpcsqlresult.h @@ -1,11 +1,14 @@ #pragma once +#include + #include #include -namespace shv::chainpack { class RpcResponse; class RpcValue; } +namespace shv::chainpack { class RpcResponse; } class QSqlQuery; +class QSqlRecord; namespace Event::services::shvapi { @@ -44,7 +47,8 @@ class RpcSqlResult static RpcSqlResult fromVariant(const QVariant &v); static RpcSqlResult fromRpcValue(const shv::chainpack::RpcValue &rv); static RpcSqlResult fromQuery(QSqlQuery &q); - }; +shv::chainpack::RpcValue::Map recordToMap(const QSqlRecord &rec); + } diff --git a/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.cpp b/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.cpp index 350fa8b97..90fdba459 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.cpp @@ -21,7 +21,7 @@ CardFlagsDialog::~CardFlagsDialog() delete ui; } -void CardFlagsDialog::load(RunsTableModel *model, int row) +void CardFlagsDialog::load(quickevent::core::og::SqlTableModel *model, int row) { m_model = model; m_row = row; diff --git a/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.h b/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.h index f07adfeed..80c9d667b 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.h +++ b/quickevent/app/quickevent/plugins/Runs/src/cardflagsdialog.h @@ -1,9 +1,8 @@ -#ifndef RUNS_CARDFLAGSDIALOG_H -#define RUNS_CARDFLAGSDIALOG_H +#pragma once #include -class RunsTableModel; +namespace quickevent::core::og { class SqlTableModel; } namespace Runs { @@ -19,16 +18,15 @@ class CardFlagsDialog : public QDialog explicit CardFlagsDialog(QWidget *parent = nullptr); ~CardFlagsDialog() override; - void load(RunsTableModel *model, int row); + void load(quickevent::core::og::SqlTableModel *model, int row); void save(); private: void updateStatus(); private: Ui::CardFlagsDialog *ui; - RunsTableModel *m_model; + quickevent::core::og::SqlTableModel *m_model; int m_row; }; } // namespace Runs -#endif // RUNS_CARDFLAGSDIALOG_H diff --git a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp index 328a324ff..be85c400c 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp @@ -24,7 +24,7 @@ RunFlagsDialog::~RunFlagsDialog() delete ui; } -void RunFlagsDialog::load(RunsTableModel *model, int row) +void RunFlagsDialog::load(quickevent::core::og::SqlTableModel *model, int row) { m_model = model; m_row = row; diff --git a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.h b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.h index 743f426b9..6d0781a81 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.h @@ -1,9 +1,8 @@ -#ifndef RUNS_RUNFLAGSDIALOG_H -#define RUNS_RUNFLAGSDIALOG_H +#pragma once #include -class RunsTableModel; +namespace quickevent::core::og { class SqlTableModel; } namespace Runs { @@ -18,18 +17,16 @@ class RunFlagsDialog : public QDialog explicit RunFlagsDialog(QWidget *parent = nullptr); ~RunFlagsDialog() override; - void load(RunsTableModel *model, int row); + void load(quickevent::core::og::SqlTableModel *model, int row); void save(); private: void updateStatus(); bool isDisqualified() const; private: Ui::RunFlagsDialog *ui; - RunsTableModel *m_model; + quickevent::core::og::SqlTableModel *m_model; int m_row; bool m_isDisqualified; }; - } // namespace Runs -#endif // RUNS_RUNFLAGSDIALOG_H diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp index 3e9041110..763a94536 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.cpp @@ -5,6 +5,7 @@ #include "eventstatisticswidget.h" #include "printawardsoptionsdialogwidget.h" #include "services/resultsexporter.h" +#include "partwidget.h" #include "../../CardReader/src/cardreaderplugin.h" #include "../../Competitors/src/competitorsplugin.h" #include "../../Event/src/eventplugin.h" @@ -13,7 +14,6 @@ #include #include #include -#include "partwidget.h" #include #include @@ -38,8 +38,7 @@ #include #include #include - -#include +#include namespace qfw = qf::qmlwidgets; namespace qff = qf::qmlwidgets::framework; @@ -1097,6 +1096,66 @@ bool RunsPlugin::exportResultsCsosOverall(int stage_count, const QString &file_n return true; } +qf::core::sql::QueryBuilder RunsPlugin::runsQuery(int stage_id, int class_id, bool show_offrace) +{ + bool is_relays = getPlugin()->eventConfig()->isRelays(); + qfs::QueryBuilder qb; + qb.select2("runs", "*") + .select2("classes", "name") + .select2("competitors", "id, registration, licence, ranking, siId, note") + .select("COALESCE(lastName, '') || ' ' || COALESCE(firstName, '') AS competitorName") + .select("lentcards.siid IS NOT NULL AS cardInLentTable") + + // run table model contains relayName column even in individual race + .select("COALESCE(relays.club, '') || ' ' || COALESCE(relays.name, '') AS relayName") + + .select("'' AS runFlags") + .select("'' AS cardFlags") + .from("runs") + .join("runs.competitorId", "competitors.id") + .joinRestricted("runs.siid", "lentcards.siid", "NOT lentcards.ignored") + .join("runs.relayId", "relays.id") + .orderBy("runs.id"); + if(is_relays) { + qb.select("relays.number AS startNumber") + .join("relays.classId", "classes.id"); + int leg = stage_id; + if(leg > 0) + qb.where("runs.leg=" QF_IARG(leg)); + } + else { + qb.select("competitors.startNumber AS competitors__startNumber") + .join("competitors.classId", "classes.id"); + if(stage_id > 0) { + qb.where("runs.stageId=" QF_IARG(stage_id)); + } + } + if(class_id > 0) { + if(is_relays) + qb.where("relays.classId=" + QString::number(class_id)); + else + qb.where("competitors.classId=" + QString::number(class_id)); + } + if(!show_offrace) + qb.where("runs.isRunning"); + return qb; +} + +QVariantMap RunsPlugin::runRecord(int run_id) +{ + auto qb = runsQuery(0); + qb.where("runs.id = " + QString::number(run_id)); + qf::core::sql::Query q; + QString qs = qb.toString(); + q.exec(qs, qf::core::Exception::Throw); + if (q.next()) { + return qf::core::sql::recordToMap(q.record()); + } + else { + return {}; + } +} + qf::core::utils::TreeTable RunsPlugin::startListClassesTable(const QString &where_expr, const bool insert_vacants, const quickevent::gui::ReportOptionsDialog::StartTimeFormat start_time_format) { int stage_id = selectedStageId(); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.h b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.h index 51ba5a07e..e48973cae 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runsplugin.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runsplugin.h @@ -26,7 +26,7 @@ namespace qf { } } -//namespace quickevent { namespace core { class CourseDef; class CodeDef; }} +namespace qf::core::sql { class QueryBuilder; } namespace Runs { @@ -47,8 +47,6 @@ class RunsPlugin : public qf::qmlwidgets::framework::Plugin qf::qmlwidgets::framework::PartWidget *partWidget() {return m_partWidget;} - //Q_SIGNAL void nativeInstalled(); - const qf::core::utils::Table& runnersTable(int stage_id); Q_SLOT void clearRunnersTableCache(); @@ -84,6 +82,9 @@ class RunsPlugin : public qf::qmlwidgets::framework::Plugin Q_INVOKABLE bool exportResultsCsosStage(int stage_id, const QString &file_name); Q_INVOKABLE bool exportResultsCsosOverall(int stage_count, const QString &file_name); + qf::core::sql::QueryBuilder runsQuery(int stage_id, int class_id = 0, bool show_offrace = false); + QVariantMap runRecord(int run_id); + qf::core::utils::TreeTable startListClassesTable(const QString &where_expr, const bool insert_vacants, const quickevent::gui::ReportOptionsDialog::StartTimeFormat start_time_format); qf::core::utils::TreeTable startListClubsTable(const quickevent::gui::ReportOptionsDialog::StartTimeFormat start_time_format, const quickevent::gui::ReportOptionsDialog::StartlistOrderFirstBy order_first_by); qf::core::utils::TreeTable startListStartersTable(const QString &where_expr); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 10ac0d7ad..55826d716 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -2,6 +2,7 @@ #include #include +#include "../../Event/src/eventplugin.h" #include #include @@ -13,6 +14,9 @@ #include +using qf::qmlwidgets::framework::getPlugin; +using Event::EventPlugin; + RunsTableModel::RunsTableModel(QObject *parent) : Super(parent) { @@ -327,42 +331,31 @@ void RunsTableModel::onDataChanged(const QModelIndex &top_left, const QModelInde bool RunsTableModel::postRow(int row_no, bool throw_exc) { - bool is_single_user = sqlConnection().driverName().endsWith(QLatin1String("SQLITE"), Qt::CaseInsensitive); - if(is_single_user) - return Super::postRow(row_no, throw_exc); - - if(isDirty(row_no, col_runs_startTimeMs)) { - int run_id = value(row_no, col_runs_id).toInt(); - int orig_msec = origValue(row_no, col_runs_startTimeMs).toInt(); - int db_msec = 0; - - //qf::core::sql::Transaction transaction(); - QString qs = "SELECT id, startTimeMs FROM runs WHERE id=" QF_IARG(run_id); // " FOR UPDATE"; - qf::core::sql::Query q(sqlConnection()); - q.exec(qs, qf::core::Exception::Throw); - if(q.next()) { - db_msec = q.value("startTimeMs").toInt(); - } - if(orig_msec == db_msec) { - bool ret = Super::postRow(row_no, throw_exc); - //transaction.commit(); - /* - QVariant v = value(row_no, col_runs_finishTimeMs); - if(!v.isNull()) { - getPlugin()->reloadTimesFromCard(run_id); - reloadRow(row_no); + int run_id = value(row_no, col_runs_id).toInt(); + if(!getPlugin()->isSingleUser()) { + if(isDirty(row_no, col_runs_startTimeMs)) { + int orig_msec = origValue(row_no, col_runs_startTimeMs).toInt(); + int db_msec = 0; + QString qs = "SELECT id, startTimeMs FROM runs WHERE id=" QF_IARG(run_id); // " FOR UPDATE"; + qf::core::sql::Query q(sqlConnection()); + q.exec(qs, qf::core::Exception::Throw); + if(q.next()) { + db_msec = q.value("startTimeMs").toInt(); + } + if(orig_msec != db_msec) { + QString err_msg = tr("Mid-air collision setting start time, reload table and try it again."); + setValue(row_no, col_runs_startTimeMs, db_msec); + if(throw_exc) + QF_EXCEPTION(err_msg); + return false; } - */ - return ret; - } - else { - QString err_msg = tr("Mid-air collision setting start time, reload table and try it again."); - setValue(row_no, col_runs_startTimeMs, db_msec); - if(throw_exc) - QF_EXCEPTION(err_msg); - return false; } } - return Super::postRow(row_no, throw_exc); + auto dirty_vals = tableRow(row_no).dirtyValuesMap(); + auto ret = Super::postRow(row_no, throw_exc); + if (!dirty_vals.isEmpty()) { + getPlugin()->emitDbEvent(Event::EventPlugin::DBEVENT_RUN_CHANGED, QVariantList {run_id, dirty_vals}); + } + return ret; } diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h index 3105137ed..2f9e002eb 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.h @@ -36,22 +36,22 @@ class RunsTableModel : public quickevent::core::og::SqlTableModel RunsTableModel(QObject *parent = nullptr); int columnCount(const QModelIndex &) const override { return col_COUNT; } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; - //bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE; - Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + //bool setData(const QModelIndex &index, const QVariant &value, int role) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; using Super::value; - QVariant value(int row_ix, int column_ix) const Q_DECL_OVERRIDE; + QVariant value(int row_ix, int column_ix) const override; using Super::setValue; - bool setValue(int row_ix, int column_ix, const QVariant &val) Q_DECL_OVERRIDE; + bool setValue(int row_ix, int column_ix, const QVariant &val) override; - bool postRow(int row_no, bool throw_exc) Q_DECL_OVERRIDE; + bool postRow(int row_no, bool throw_exc) override; - QStringList mimeTypes() const Q_DECL_OVERRIDE; - QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; - Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; - //bool canDropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) const Q_DECL_OVERRIDE; - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE; + QStringList mimeTypes() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + Qt::DropActions supportedDropActions() const override; + //bool canDropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; void switchStartTimes(int r1, int r2); Q_SIGNAL void startTimesSwitched(int id1, int id2, const QString &err_msg); diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp index 86c4f4cb4..11fc925bf 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablewidget.cpp @@ -135,7 +135,6 @@ void RunsTableWidget::clear() void RunsTableWidget::reload(int stage_id, int class_id, bool show_offrace, const QString &sort_column, int select_competitor_id) { qfLogFuncFrame() << "class id:" << class_id; - bool is_relays = getPlugin()->eventConfig()->isRelays(); { int class_start_time_min = 0; int class_start_interval_min = 0; @@ -150,50 +149,8 @@ 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): "---"); } - /* - qfs::QueryBuilder qb2; - qb2.select("siId, MAX(punchDateTime) AS punchDateTime") - .from("stationsbackup") - .where("stageId=" QF_IARG(stage_id)) - .groupBy("siId") - .as("checktimes"); - */ - qfs::QueryBuilder qb; - qb.select2("runs", "*") - .select2("classes", "name") - .select("COALESCE(relays.club, '') || ' ' || COALESCE(relays.name, '') AS relayName") - .select2("competitors", "id, registration, licence, ranking, siId, note") - //.select2("checktimes", "punchDateTime") - .select("COALESCE(lastName, '') || ' ' || COALESCE(firstName, '') AS competitorName") - .select("lentcards.siid IS NOT NULL AS cardInLentTable") - .select("'' AS runFlags") - .select("'' AS cardFlags") - .from("runs") - .join("runs.competitorId", "competitors.id") - .joinRestricted("runs.siid", "lentcards.siid", "NOT lentcards.ignored") - //.joinQuery("runs.siid", qb2, "siId") - .join("runs.relayId", "relays.id") - .orderBy("runs.id");//.limit(10); - if(is_relays) { - qb.select("relays.number AS startNumber"); - qb.join("relays.classId", "classes.id"); - int leg = stage_id; - if(leg > 0) - qb.where("runs.leg=" QF_IARG(leg)); - } - else { - qb.select("competitors.startNumber AS competitors__startNumber"); - qb.join("competitors.classId", "classes.id"); - qb.where("runs.stageId=" QF_IARG(stage_id)); - } - if(class_id > 0) { - if(is_relays) - qb.where("relays.classId=" + QString::number(class_id)); - else - qb.where("competitors.classId=" + QString::number(class_id)); - } - if(!show_offrace) - qb.where("runs.isRunning"); + bool is_relays = getPlugin()->eventConfig()->isRelays(); + auto qb = getPlugin()->runsQuery(stage_id, class_id, show_offrace); qfDebug() << qb.toString(); m_runsTableItemDelegate->setHighlightedClassId(class_id, stage_id); m_runsModel->setQueryBuilder(qb, false);