diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..15e77a976 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,80 @@ +Checks: + -*, + cppcoreguidelines-*, + bugprone-*, + modernize-*, + hicpp-*, + clang-analyzer-*, + misc-*, + readability-*, + -bugprone-easily-swappable-parameters, + -bugprone-implicit-widening-of-multiplication-result, + -bugprone-integer-division, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-parent-virtual-call, + -bugprone-suspicious-missing-comma, + -clang-analyzer-core.UndefinedBinaryOperatorResult, + -clang-analyzer-cplusplus.NewDeleteLeaks, + -clang-analyzer-optin.cplusplus.VirtualCall, + -clang-analyzer-security.FloatLoopCounter, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-explicit-virtual-functions, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-prefer-member-initializer, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-member-init, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-static-cast-downcast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-special-member-functions, + -hicpp-avoid-c-arrays, + -hicpp-avoid-goto, + -hicpp-braces-around-statements, + -hicpp-deprecated-headers, + -hicpp-explicit-conversions, + -hicpp-member-init, + -hicpp-multiway-paths-covered, + -hicpp-named-parameter, + -hicpp-no-array-decay, + -hicpp-signed-bitwise, + -hicpp-special-member-functions, + -hicpp-use-emplace, + -hicpp-use-equals-default, + -hicpp-use-equals-delete, + -hicpp-use-override, + -hicpp-vararg, + -misc-const-correctness, + -misc-include-cleaner, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-unused-parameters, + -modernize-pass-by-value, + -modernize-return-braced-init-list, + -modernize-use-default-member-init, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -modernize-use-using, + -readability-avoid-const-params-in-decls, + -readability-braces-around-statements, + -readability-convert-member-functions-to-static, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-implicit-bool-conversion, + -readability-inconsistent-declaration-parameter-name, + -readability-isolate-declaration, + -readability-magic-numbers, + -readability-named-parameter, + -readability-non-const-parameter, + -readability-qualified-auto, + -readability-redundant-access-specifiers, + -readability-simplify-boolean-expr, diff --git a/.github/actions/appimage/action.yml b/.github/actions/appimage/action.yml index bfe5d957b..0dfd54b68 100644 --- a/.github/actions/appimage/action.yml +++ b/.github/actions/appimage/action.yml @@ -34,6 +34,13 @@ runs: chmod +x ./*AppImage shell: bash + - name: Remove not needed SQL plugins + run: | + rm ${{ env.Qt6_DIR }}/plugins/sqldrivers/libqsqlmimer.so + rm ${{ env.Qt6_DIR }}/plugins/sqldrivers/libqsqlmysql.so + rm ${{ env.Qt6_DIR }}/plugins/sqldrivers/libqsqlodbc.so + shell: bash + - name: Create AppImage run: | LD_LIBRARY_PATH="${{ github.workspace }}/install/usr/lib:$LD_LIBRARY_PATH" \ diff --git a/.github/actions/run-linter/action.yml b/.github/actions/run-linter/action.yml index 3ce2c25c7..41cadd33d 100644 --- a/.github/actions/run-linter/action.yml +++ b/.github/actions/run-linter/action.yml @@ -11,8 +11,17 @@ runs: - name: Setup CMake uses: ./.github/actions/cmake with: + qt_version: 6.5.3 + use_qt6: ON + modules: qtserialport qtmultimedia additional_cmake_args: -DCMAKE_GLOBAL_AUTOGEN_TARGET=ON -DCMAKE_AUTOGEN_ORIGIN_DEPENDS=OFF + # workaround for clang-tidy false positive + - uses: mjp41/workaround8649@c8550b715ccdc17f89c8d5c28d7a48eeff9c94a8 + if: runner.os == 'Linux' + with: + os: ubuntu-latest + - name: Build autogenerated stuff shell: bash run: cmake --build ${{github.workspace}}/build --parallel "$(nproc)" --target autogen diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 21765ad1f..79acd25b1 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -23,7 +23,7 @@ jobs: - name: Setup CMake uses: ./.github/actions/cmake with: - qt_version: 6.5.2 + qt_version: 6.6.3 use_qt6: ON modules: qtserialport qtmultimedia additional_cmake_args: -DCMAKE_INSTALL_PREFIX='${{ github.workspace }}/install/usr' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ffafbadb1..8f270cd2c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v3 with: submodules: true - + - name: Run clang-tidy uses: ./.github/actions/run-linter with: diff --git a/libquickevent/libquickeventcore/src/runstatus.cpp b/libquickevent/libquickeventcore/src/runstatus.cpp index c0341f2e6..c0da15bdb 100644 --- a/libquickevent/libquickeventcore/src/runstatus.cpp +++ b/libquickevent/libquickeventcore/src/runstatus.cpp @@ -2,8 +2,7 @@ #include "og/timems.h" #include -namespace quickevent { -namespace core { +namespace quickevent::core { QStringList RunStatus::runsTableColumns() { @@ -13,7 +12,6 @@ QStringList RunStatus::runsTableColumns() RunStatus RunStatus::fromQuery(qf::core::sql::Query &q) { RunStatus new_obj; - new_obj.m_disqualified = q.value("runs.disqualified").toBool(); new_obj.m_disqualifiedByOrganizer = q.value("runs.disqualifiedByOrganizer").toBool(); new_obj.m_notCompeting = q.value("runs.notCompeting").toBool(); new_obj.m_missingPunch = q.value("runs.misPunch").toBool(); @@ -26,7 +24,6 @@ RunStatus RunStatus::fromQuery(qf::core::sql::Query &q) RunStatus RunStatus::fromTreeTableRow(const qf::core::utils::TreeTableRow &ttr) { RunStatus new_obj; - new_obj.m_disqualified = ttr.value(QStringLiteral("disqualified")).toBool(); new_obj.m_disqualifiedByOrganizer = ttr.value("disqualifiedByOrganizer").toBool(); new_obj.m_notCompeting = ttr.value("notCompeting").toBool(); new_obj.m_missingPunch = ttr.value("misPunch").toBool(); @@ -38,26 +35,29 @@ RunStatus RunStatus::fromTreeTableRow(const qf::core::utils::TreeTableRow &ttr) bool RunStatus::isOk() const { - return !m_disqualified && !m_notCompeting; + // the `runs.disqualified` is autogenerated since 3.1.0 + return !(m_disqualifiedByOrganizer + || m_notCompeting + || m_missingPunch + || m_didNotStart + || m_didNotFinish + || m_overTime); } int RunStatus::ogTime() const { if (m_notCompeting) return quickevent::core::og::TimeMs::NOT_COMPETITING_TIME_MSEC; - if (m_disqualified) { - if (m_disqualifiedByOrganizer) - return quickevent::core::og::TimeMs::DISQ_TIME_MSEC; - if (m_missingPunch) - return quickevent::core::og::TimeMs::MISPUNCH_TIME_MSEC; - if (m_didNotStart) - return quickevent::core::og::TimeMs::NOT_START_TIME_MSEC; - if (m_didNotFinish) - return quickevent::core::og::TimeMs::NOT_FINISH_TIME_MSEC; - if (m_overTime) - return quickevent::core::og::TimeMs::OVERTIME_TIME_MSEC; + if (m_disqualifiedByOrganizer) return quickevent::core::og::TimeMs::DISQ_TIME_MSEC; - } + if (m_missingPunch) + return quickevent::core::og::TimeMs::MISPUNCH_TIME_MSEC; + if (m_didNotStart) + return quickevent::core::og::TimeMs::NOT_START_TIME_MSEC; + if (m_didNotFinish) + return quickevent::core::og::TimeMs::NOT_FINISH_TIME_MSEC; + if (m_overTime) + return quickevent::core::og::TimeMs::OVERTIME_TIME_MSEC; return 0; } @@ -65,19 +65,16 @@ QString RunStatus::toXmlExportString() const { if (m_notCompeting) return QStringLiteral("NotCompeting"); - if (m_disqualified) { - if (m_disqualifiedByOrganizer) - return QStringLiteral("Disqualified"); - if (m_missingPunch) - return QStringLiteral("MissingPunch"); - if (m_didNotStart) - return QStringLiteral("DidNotStart"); - if (m_didNotFinish) - return QStringLiteral("DidNotFinish"); - if (m_overTime) - return QStringLiteral("OverTime"); + if (m_disqualifiedByOrganizer) return QStringLiteral("Disqualified"); - } + if (m_missingPunch) + return QStringLiteral("MissingPunch"); + if (m_didNotStart) + return QStringLiteral("DidNotStart"); + if (m_didNotFinish) + return QStringLiteral("DidNotFinish"); + if (m_overTime) + return QStringLiteral("OverTime"); return QStringLiteral("OK"); } @@ -86,19 +83,16 @@ QString RunStatus::toEmmaExportString() const { if (m_notCompeting) return QStringLiteral("NC "); - if (m_disqualified) { - if (m_disqualifiedByOrganizer) - return QStringLiteral("DISQ"); - if (m_missingPunch) - return QStringLiteral("MP "); - if (m_didNotStart) - return QStringLiteral("DNS "); - if (m_didNotFinish) - return QStringLiteral("DNF "); - if (m_overTime) - return QStringLiteral("OVRT"); + if (m_disqualifiedByOrganizer) return QStringLiteral("DISQ"); - } + if (m_missingPunch) + return QStringLiteral("MP "); + if (m_didNotStart) + return QStringLiteral("DNS "); + if (m_didNotFinish) + return QStringLiteral("DNF "); + if (m_overTime) + return QStringLiteral("OVRT"); return QStringLiteral("O.K."); } @@ -106,19 +100,16 @@ QString RunStatus::toHtmlExportString() const { if (m_notCompeting) return QStringLiteral("NC"); - if (m_disqualified) { - if (m_disqualifiedByOrganizer) - return QStringLiteral("DISQ"); - if (m_missingPunch) - return QStringLiteral("MP"); - if (m_didNotStart) - return QStringLiteral("DNS"); - if (m_didNotFinish) - return QStringLiteral("DNF"); - if (m_overTime) - return QStringLiteral("OVRT"); + if (m_disqualifiedByOrganizer) return QStringLiteral("DISQ"); - } + if (m_missingPunch) + return QStringLiteral("MP"); + if (m_didNotStart) + return QStringLiteral("DNS"); + if (m_didNotFinish) + return QStringLiteral("DNF"); + if (m_overTime) + return QStringLiteral("OVRT"); return QStringLiteral("OK"); } @@ -126,21 +117,17 @@ QString RunStatus::toString() const { if (m_notCompeting) return tr("NC", "Not Competing"); - if (m_disqualified) { - if (m_disqualifiedByOrganizer) - return tr("DISQ", "Disqualified"); - if (m_missingPunch) - return tr("MP", "Missing Punch"); - if (m_didNotStart) - return tr("DNS", "Did Not Start"); - if (m_didNotFinish) - return tr("DNF", "Did Not Finish"); - if (m_overTime) - return tr("OVRT", "Over Time"); + if (m_disqualifiedByOrganizer) return tr("DISQ", "Disqualified"); - } + if (m_missingPunch) + return tr("MP", "Missing Punch"); + if (m_didNotStart) + return tr("DNS", "Did Not Start"); + if (m_didNotFinish) + return tr("DNF", "Did Not Finish"); + if (m_overTime) + return tr("OVRT", "Over Time"); return tr("OK"); } -} // namespace core -} // namespace quickevent +} diff --git a/libquickevent/libquickeventcore/src/runstatus.h b/libquickevent/libquickeventcore/src/runstatus.h index d364f1c60..87c992c46 100644 --- a/libquickevent/libquickeventcore/src/runstatus.h +++ b/libquickevent/libquickeventcore/src/runstatus.h @@ -5,8 +5,7 @@ #include #include -namespace quickevent { -namespace core { +namespace quickevent::core { class QUICKEVENTCORE_DECL_EXPORT RunStatus { @@ -25,7 +24,6 @@ class QUICKEVENTCORE_DECL_EXPORT RunStatus QString toHtmlExportString() const; QString toString() const; - bool idDisqualified() const { return m_disqualified; } bool isDisqualifiedByOrganizer() const { return m_disqualifiedByOrganizer; } bool isNotCompeting() const { return m_notCompeting; } bool isMissingPunch() const { return m_missingPunch; } @@ -35,7 +33,6 @@ class QUICKEVENTCORE_DECL_EXPORT RunStatus static QStringList runsTableColumns(); private: - bool m_disqualified = false; bool m_disqualifiedByOrganizer = false; bool m_notCompeting = false; bool m_missingPunch = false; @@ -44,4 +41,4 @@ class QUICKEVENTCORE_DECL_EXPORT RunStatus bool m_overTime = false; }; -}} +} diff --git a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml index 95701a129..fd3b8b182 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/DbSchema.qml @@ -190,7 +190,9 @@ Schema { //notNull: true }, Field { name: 'relayId'; type: Int {} }, - + Field { name: 'corridorTime'; type: DateTime {} + comment: 'DateTime when competitor entered start corridor. (Experimental)' + }, Field { name: 'checkTimeMs'; type: Int {} comment: 'in miliseconds' }, @@ -204,7 +206,7 @@ Schema { comment: 'in miliseconds' }, Field { name: 'timeMs'; type: Int {} - comment: 'in miliseconds since event run' + comment: 'in miliseconds' }, Field { name: 'isRunning'; type: Boolean { } @@ -235,8 +237,7 @@ Schema { Cancelled */ Field { name: 'disqualified'; type: Boolean { } // Disqualified - defaultValue: false; - notNull: true + generatedAs: 'disqualifiedByOrganizer OR misPunch OR notStart OR notFinish OR badCheck OR overTime OR notCompeting' }, Field { name: 'disqualifiedByOrganizer'; type: Boolean { } // Disqualified by Org defaultValue: false; @@ -498,7 +499,7 @@ Schema { } ] Component.onCompleted: { - Log.info("DbSchema created"); + //Log.info("DbSchema created"); } } 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 f5361c7f7..9b7d082cd 100644 --- a/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml +++ b/quickevent/app/quickevent/plugins/Event/qml/sql/def/Field.qml @@ -9,6 +9,7 @@ QtObject { property var defaultValue: null property bool notNull: false property string comment + property string generatedAs function createSqlScript(options) { @@ -25,6 +26,11 @@ QtObject { else def += defaultValue; } + if (generatedAs) { + def += ' GENERATED ALWAYS AS ('; + def += generatedAs; + def += ') VIRTUAL'; + } return def; } diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp index 0b2959799..24539aff5 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.cpp @@ -87,9 +87,7 @@ DbEventPayload DbEventPayload::fromJson(const QByteArray &json) QVariantMap m = jsd.toVariant().toMap(); return DbEventPayload(m); } - else { - qfError() << "JSON parse error:" << error.errorString(); - } + qfError() << "JSON parse error:" << error.errorString(); return DbEventPayload(); } @@ -99,31 +97,37 @@ QByteArray DbEventPayload::toJson() const return jsd.toJson(QJsonDocument::Compact); } -static auto QBE_EXT = QStringLiteral(".qbe"); +/// 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 +/// I guess that channel name cannot contain capital letters to work +const char* const EventPlugin::DBEVENT_NOTIFY_NAME = "quickbox_db_event"; -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"; -const char* EventPlugin::DBEVENT_STAGE_START_CHANGED = "stageStartChanged"; +const char* const EventPlugin::DBEVENT_COMPETITOR_COUNTS_CHANGED = "competitorCountsChanged"; +const char* const EventPlugin::DBEVENT_CARD_READ = "cardRead"; +const char* const EventPlugin::DBEVENT_COMPETITOR_EDITED = "competitorEdited"; +const char* const EventPlugin::DBEVENT_RUN_CHANGED = "runChanged"; +const char* const EventPlugin::DBEVENT_CARD_PROCESSED_AND_ASSIGNED = "cardProcessedAndAssigned"; +const char* const EventPlugin::DBEVENT_PUNCH_RECEIVED = "punchReceived"; +const char* const EventPlugin::DBEVENT_REGISTRATIONS_IMPORTED = "registrationsImported"; +const char* const EventPlugin::DBEVENT_STAGE_START_CHANGED = "stageStartChanged"; -static QString singleFileStorageDir() +namespace { +const auto QBE_EXT = QStringLiteral(".qbe"); + +QString singleFileStorageDir() { ConnectionSettings connection_settings; QString ret = connection_settings.singleWorkingDir(); return ret; } -static QString eventNameToFileName(const QString &event_name) +QString eventNameToFileName(const QString &event_name) { QString ret = singleFileStorageDir() + '/' + event_name + QBE_EXT; return ret; } -static QString fileNameToEventName(const QString &file_name) +QString fileNameToEventName(const QString &file_name) { QString fn = file_name; fn.replace("\\", "/"); @@ -133,11 +137,7 @@ static QString fileNameToEventName(const QString &file_name) event_name = event_name.mid(0, event_name.length() - QBE_EXT.length()); return event_name; } - -/// 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 -/// I guess that channel name cannot contain capital letters to work -const char *EventPlugin::DBEVENT_NOTIFY_NAME = "quickbox_db_event"; +} EventPlugin::EventPlugin(QObject *parent) : Super("Event", parent) @@ -343,14 +343,14 @@ void EventPlugin::onInstalled() tb->setObjectName("EventToolbar"); tb->setWindowTitle(tr("Event")); { - QToolButton *bt_stage = new QToolButton(); + auto *bt_stage = new QToolButton(); //bt_stage->setFlat(true); bt_stage->setAutoRaise(true); bt_stage->setCheckable(true); tb->addWidget(bt_stage); m_cbxStage = new QComboBox(); connect(m_cbxStage, &QComboBox::activated, this, &EventPlugin::onCbxStageActivated); - connect(this, &EventPlugin::currentStageIdChanged, [bt_stage](int stage_id) { + 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); @@ -364,7 +364,7 @@ void EventPlugin::onInstalled() connect(m_actEditStage, &QAction::triggered, this, &EventPlugin::editStage); tb->addAction(m_actEditStage); - connect(bt_stage, &QPushButton::clicked, [this, act_stage](bool checked) { + connect(bt_stage, &QPushButton::clicked, this, [this, act_stage](bool checked) { act_stage->setVisible(checked); m_actEditStage->setVisible(checked); }); @@ -428,12 +428,10 @@ void EventPlugin::saveCurrentStageId(int current_stage) void EventPlugin::editStage() { - qfLogFuncFrame();// << "id:" << id << "mode:" << mode; + //qfLogFuncFrame();// << "id:" << id << "mode:" << mode; int stage_id = currentStageId(); - if(stage_id < 0) - return; - Event::StageWidget *w = new Event::StageWidget(); - auto fwk = qf::qmlwidgets::framework::MainWindow::frameWork(); + auto *w = new Event::StageWidget(); + auto *fwk = qf::qmlwidgets::framework::MainWindow::frameWork(); qfd::Dialog dlg(QDialogButtonBox::Save | QDialogButtonBox::Cancel, fwk); dlg.setDefaultButton(QDialogButtonBox::Save); dlg.setCentralWidget(w); @@ -508,10 +506,10 @@ DbSchema *EventPlugin::dbSchema() return new DbSchema(this); } -int EventPlugin::minDbVersion() +int EventPlugin::dbVersion() { qff::MainWindow *fwk = qff::MainWindow::frameWork(); - int db_version; + int db_version = 0; QMetaObject::invokeMethod(fwk, "dbVersion", Qt::DirectConnection , Q_RETURN_ARG(int, db_version)); return db_version; @@ -657,7 +655,7 @@ void EventPlugin::connectToSqlServer() dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dlg.setDefaultButton(QDialogButtonBox::Ok); dlg.setSavePersistentPosition(false); - ConnectDbDialogWidget *conn_w = new ConnectDbDialogWidget(); + auto *conn_w = new ConnectDbDialogWidget(); dlg.setCentralWidget(conn_w); while(!connect_ok) { conn_w->loadSettings(); @@ -738,12 +736,12 @@ void EventPlugin::connectToSqlServer() openEvent(conn_w->eventName()); } } - -static bool run_sql_script(qf::core::sql::Query &q, const QStringList &sql_lines) +namespace { +bool run_sql_script(qf::core::sql::Query &q, const QStringList &sql_lines) { qfLogFuncFrame(); QVariantMap replacements; - replacements["minDbVersion"] = EventPlugin::minDbVersion(); + replacements["minDbVersion"] = EventPlugin::dbVersion(); for(auto cmd : sql_lines) { if(cmd.isEmpty()) continue; @@ -760,7 +758,7 @@ static 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) { qfLogFuncFrame(); @@ -777,7 +775,7 @@ bool EventPlugin::createEvent(const QString &event_name, const QVariantMap &even do { qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - EventDialogWidget *event_w = new EventDialogWidget(); + auto *event_w = new EventDialogWidget(); event_w->setWindowTitle(tr("Create event")); event_w->setEventId(event_id); event_w->loadParams(new_params); @@ -879,7 +877,7 @@ void EventPlugin::editEvent() qff::MainWindow *fwk = qff::MainWindow::frameWork(); qfd::Dialog dlg(fwk); dlg.setButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - EventDialogWidget *event_w = new EventDialogWidget(); + auto *event_w = new EventDialogWidget(); event_w->setWindowTitle(tr("Edit event")); event_w->setEventId(eventName()); event_w->setEventIdEditable(false); @@ -983,14 +981,14 @@ bool EventPlugin::openEvent(const QString &_event_name) } if(ok) { EventConfig *evc = eventConfig(true); - if(evc->dbVersion() < minDbVersion()) { + 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())) - .arg(qf::core::Utils::intToVersionString(minDbVersion()))); + .arg(qf::core::Utils::intToVersionString(dbVersion()))); closeEvent(); ok = false; } - else if(evc->dbVersion() > minDbVersion()) { + else if(evc->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()))); } @@ -1030,17 +1028,25 @@ static QString copy_sql_table(const QString &table_name, const QSqlRecord &dest_ return QString(); } const QSqlRecord src_rec = from_q.record(); + + auto dest_db_version = EventPlugin::dbVersion(); + bool is_import_runs_table = table_name == QLatin1String("runs"); // copy only fields which can be found in both records QSqlRecord rec; for (int i = 0; i < dest_rec.count(); ++i) { QString fld_name = dest_rec.fieldName(i); + if (is_import_runs_table && fld_name == "disqualified" && dest_db_version >= 30100) { + // disqualified field is autogenerated since 3.1.0 + continue; + } if(src_rec.indexOf(fld_name) >= 0) { qfDebug() << fld_name << "\t added to imported fields since it is present in both databases"; rec.append(dest_rec.field(i)); } } bool is_import_offrace = false; - if(table_name == QLatin1String("runs")) { + if(is_import_runs_table) { + is_import_runs_table = true; if(!src_rec.contains("isRunning") && dest_rec.contains("isRunning") && src_rec.contains("offRace")) { is_import_offrace = true; rec.append(dest_rec.field("isRunning")); @@ -1066,7 +1072,7 @@ static QString copy_sql_table(const QString &table_name, const QSqlRecord &dest_ QString fld_name = fld.name(); //qfDebug() << "copy:" << fld_name << from_q.value(fld_name); QVariant v; - if((fld_name.compare(QLatin1String("isRunning"), Qt::CaseInsensitive) == 0)) { + if(is_import_runs_table && fld_name.compare(QLatin1String("isRunning"), Qt::CaseInsensitive) == 0) { if(is_import_offrace) { bool offrace = from_q.value(QStringLiteral("offRace")).toBool(); v = offrace? QVariant(): QVariant(true); diff --git a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h index 9278b385f..7d1ccd634 100644 --- a/quickevent/app/quickevent/plugins/Event/src/eventplugin.h +++ b/quickevent/app/quickevent/plugins/Event/src/eventplugin.h @@ -38,15 +38,15 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin QF_PROPERTY_BOOL_IMPL(e, E, ventOpen) QF_PROPERTY_IMPL(QString, e, E, ventName) - static const char *DBEVENT_NOTIFY_NAME; - 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; - static const char* DBEVENT_STAGE_START_CHANGED; + static const char* const DBEVENT_NOTIFY_NAME; + static const char* const DBEVENT_COMPETITOR_COUNTS_CHANGED; //< number of competitors in classes changed + static const char* const DBEVENT_CARD_READ; + static const char* const DBEVENT_COMPETITOR_EDITED; + static const char* const DBEVENT_RUN_CHANGED; + static const char* const DBEVENT_CARD_PROCESSED_AND_ASSIGNED; + static const char* const DBEVENT_PUNCH_RECEIVED; + static const char* const DBEVENT_REGISTRATIONS_IMPORTED; + static const char* const DBEVENT_STAGE_START_CHANGED; Q_INVOKABLE void initEventConfig(); Event::EventConfig* eventConfig(bool reload = false); @@ -94,7 +94,7 @@ class EventPlugin : public qf::qmlwidgets::framework::Plugin Q_INVOKABLE QString classNameById(int class_id); DbSchema* dbSchema(); - static int minDbVersion(); + static int dbVersion(); Q_SLOT void onInstalled(); public: diff --git a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp index be85c400c..dac968afa 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runflagsdialog.cpp @@ -42,7 +42,7 @@ void RunFlagsDialog::load(quickevent::core::og::SqlTableModel *model, int row) void RunFlagsDialog::save() { qf::core::utils::TableRow &table_row = m_model->tableRowRef(m_row); - table_row.setValue(QStringLiteral("runs.disqualified"), isDisqualified()); + // table_row.setValue(QStringLiteral("runs.disqualified"), isDisqualified()); // autogenerated column table_row.setValue(QStringLiteral("runs.misPunch"), ui->cbxMisPunch->isChecked()); table_row.setValue(QStringLiteral("runs.badCheck"), ui->cbxBadCheck->isChecked()); table_row.setValue(QStringLiteral("runs.notStart"), ui->cbxNotStart->isChecked()); @@ -53,21 +53,19 @@ void RunFlagsDialog::save() m_model->postRow(m_row, qf::core::Exception::Throw); } -void RunFlagsDialog::updateStatus() { - if (ui->cbxNotCompeting->isChecked()) { - ui->runStatusText->setText("Not competing"); - return; - } - ui->runStatusText->setText(isDisqualified() ? "Disqualified" : "OK"); +void RunFlagsDialog::updateStatus() +{ + ui->runStatusText->setText(isDisqualified() ? tr("Disqualified") : tr("OK")); } bool RunFlagsDialog::isDisqualified() const { return ui->cbxMisPunch->isChecked() || - ui->cbxBadCheck->isChecked() || - ui->cbxNotStart->isChecked() || - ui->cbxNotFinish->isChecked() || - ui->cbxDisqualifiedByOrganizer->isChecked() || - ui->cbxOverTime->isChecked(); + ui->cbxBadCheck->isChecked() || + ui->cbxNotCompeting->isChecked() || + ui->cbxNotStart->isChecked() || + ui->cbxNotFinish->isChecked() || + ui->cbxDisqualifiedByOrganizer->isChecked() || + ui->cbxOverTime->isChecked(); } } // namespace Runs diff --git a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp index 54965fef0..1fcbeb014 100644 --- a/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp +++ b/quickevent/app/quickevent/plugins/Runs/src/runstablemodel.cpp @@ -72,7 +72,6 @@ QVariant RunsTableModel::value(int row_ix, int column_ix) const { if(column_ix == col_runFlags) { qf::core::utils::TableRow row = tableRow(row_ix); - bool is_disqualified = row.value(QStringLiteral("runs.disqualified")).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(); @@ -95,14 +94,11 @@ QVariant RunsTableModel::value(int row_ix, int column_ix) const sl << tr("DO", "disqualifiedByOrganizer"); if(over_time) sl << tr("OT", "OverTime"); - if(is_disqualified && !mis_punch && !bad_check && !not_start && !not_finish && !is_disqualified_by_organizer && !over_time) - sl << tr("DSQ", "Disqualified"); if(sl.isEmpty()) return QStringLiteral(""); - else - return sl.join(','); + return sl.join(','); } - else if(column_ix == col_cardFlags) { + if(column_ix == col_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(); @@ -116,10 +112,9 @@ QVariant RunsTableModel::value(int row_ix, int column_ix) const sl << tr("RET", "Card returned"); if(sl.isEmpty()) return QStringLiteral(""); - else - return sl.join(','); + return sl.join(','); } - else if(column_ix == col_runs_isRunning) { + if(column_ix == col_runs_isRunning) { bool is_running = Super::value(row_ix, column_ix).toBool(); return is_running; } @@ -159,7 +154,7 @@ bool RunsTableModel::setValue(int row_ix, int column_ix, const QVariant &val) } return Super::setValue(row_ix, column_ix, val); } - else if(column_ix == col_runs_penaltyTimeMs) { + if(column_ix == col_runs_penaltyTimeMs) { int penalty_ms = val.toInt(); int old_penalty_ms = Super::value(row_ix, col_runs_penaltyTimeMs).toInt(); int time_ms = value(row_ix, col_runs_timeMs).toInt(); @@ -169,7 +164,7 @@ bool RunsTableModel::setValue(int row_ix, int column_ix, const QVariant &val) } return Super::setValue(row_ix, column_ix, val); } - else if(column_ix == col_runs_timeMs) { + if(column_ix == col_runs_timeMs) { int rt = val.toInt(); if(rt == 0) { /// run time cannot be 0 @@ -177,22 +172,20 @@ bool RunsTableModel::setValue(int row_ix, int column_ix, const QVariant &val) Super::setValue(row_ix, col_runs_penaltyTimeMs, QVariant()); return Super::setValue(row_ix, column_ix, QVariant()); } - else { - QVariant start_ms = value(row_ix, col_runs_startTimeMs); - if(!start_ms.isNull()) { - int penalty_ms = value(row_ix, col_runs_penaltyTimeMs).toInt(); - int finish_ms = val.toInt() + start_ms.toInt() - penalty_ms; - if(finish_ms > 0) { - Super::setValue(row_ix, col_runs_finishTimeMs, finish_ms); - } - else { - Super::setValue(row_ix, col_runs_finishTimeMs, QVariant()); - } + QVariant start_ms = value(row_ix, col_runs_startTimeMs); + if(!start_ms.isNull()) { + int penalty_ms = value(row_ix, col_runs_penaltyTimeMs).toInt(); + int finish_ms = val.toInt() + start_ms.toInt() - penalty_ms; + if(finish_ms > 0) { + Super::setValue(row_ix, col_runs_finishTimeMs, finish_ms); + } + else { + Super::setValue(row_ix, col_runs_finishTimeMs, QVariant()); } - return Super::setValue(row_ix, column_ix, val); } + return Super::setValue(row_ix, column_ix, val); } - else if(column_ix == col_runs_startTimeMs) { + if(column_ix == col_runs_startTimeMs) { if(!val.isNull()) { int start_ms = val.toInt(); int finish_ms = value(row_ix, col_runs_finishTimeMs).toInt(); @@ -212,7 +205,7 @@ bool RunsTableModel::setValue(int row_ix, int column_ix, const QVariant &val) return ret; } -static auto MIME_TYPE = QStringLiteral("application/quickevent.startTime"); +static const auto MIME_TYPE = QStringLiteral("application/quickevent.startTime"); QStringList RunsTableModel::mimeTypes() const { @@ -224,7 +217,7 @@ QStringList RunsTableModel::mimeTypes() const QMimeData *RunsTableModel::mimeData(const QModelIndexList &indexes) const { qfLogFuncFrame(); - QMimeData *mimeData = new QMimeData(); + auto *mimeData = new QMimeData(); QByteArray encoded_data = QString::number(indexes.value(0).row()).toUtf8(); mimeData->setData(MIME_TYPE, encoded_data); return mimeData; @@ -294,8 +287,8 @@ void RunsTableModel::switchStartTimes(int r1, int r2) } else { //qf::core::sql::Transaction transaction(sqlConnection()); - quickevent::core::og::TimeMs t1 = v1.value(); - quickevent::core::og::TimeMs t2 = v2.value(); + auto t1 = v1.value(); + auto t2 = v2.value(); int msec1 = -1, msec2 = -1; qf::core::sql::Query q(sqlConnection()); QString qs = "SELECT id, startTimeMs FROM runs WHERE id IN (" QF_IARG(id1) ", " QF_IARG(id2) ")"; diff --git a/quickevent/app/quickevent/src/application.cpp b/quickevent/app/quickevent/src/application.cpp index 8f71e8920..07a33589d 100644 --- a/quickevent/app/quickevent/src/application.cpp +++ b/quickevent/app/quickevent/src/application.cpp @@ -59,13 +59,9 @@ Application::Application(int &argc, char **argv, AppCliOptions *cli_opts) //qf::qmlwidgets::reports::ReportProcessor::qmlEngineImportPaths().append(plugin_path); } -Application::~Application() -{ -} - Application *Application::instance(bool must_exist) { - Application *ret = qobject_cast(Super::instance()); + auto *ret = qobject_cast(Super::instance()); if(!ret && must_exist) { qfFatal("Application instance MUST exist."); } @@ -74,7 +70,8 @@ Application *Application::instance(bool must_exist) int Application::dbVersion() { - return 11100; + // equals to minimal app version compatible with this DB + return 30100; } QString Application::versionString() const diff --git a/quickevent/app/quickevent/src/application.h b/quickevent/app/quickevent/src/application.h index 13995dc0f..a8e17acd7 100644 --- a/quickevent/app/quickevent/src/application.h +++ b/quickevent/app/quickevent/src/application.h @@ -15,7 +15,7 @@ class Application : public qf::qmlwidgets::framework::Application typedef qf::qmlwidgets::framework::Application Super; public: Application(int & argc, char ** argv, AppCliOptions *cli_opts); - ~Application() Q_DECL_OVERRIDE; + ~Application() override = default; static Application* instance(bool must_exist = true); diff --git a/quickevent/app/quickevent/src/appversion.h b/quickevent/app/quickevent/src/appversion.h index 01cc97d07..81e43c885 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.0.7" +#define APP_VERSION "3.1.0"