Skip to content

Commit

Permalink
Merge pull request Quick-Box#962 from arnost00/extend-imports-xml-csv…
Browse files Browse the repository at this point in the history
…-world-races-qe3

Add IOF XML import & some CSV imports & some support for Eventor for QE3
  • Loading branch information
fvacek authored Mar 28, 2024
2 parents 19f3db6 + cf74430 commit 8c3b93c
Show file tree
Hide file tree
Showing 36 changed files with 2,272 additions and 307 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ namespace quickevent {
namespace core {
namespace exporters {

StageResultsCsvExporter::StageResultsCsvExporter(QObject *parent)
: Super(parent)
StageResultsCsvExporter::StageResultsCsvExporter(bool is_iof_race, QObject *parent)
: Super(parent),
m_isIofRace(is_iof_race)
{
}

Expand Down Expand Up @@ -52,7 +53,13 @@ void StageResultsCsvExporter::exportClasses(bool single_file)
csv_dir.mkpath(sub_dir);

if (single_file) {
QFile f_csv(csv_dir.absolutePath() + '/' + sub_dir + '/' + "results.csv");
QString file_name = outFile();
if (file_name.isEmpty())
file_name = "results.csv";
QString path = csv_dir.absolutePath() +'/';
if (!simplePath())
path += sub_dir + '/';
QFile f_csv(path + file_name);
qfInfo() << "Generating:" << f_csv.fileName();
if (!f_csv.open(QFile::WriteOnly))
qfError() << "Cannot open file" << f_csv.fileName() + "for writing.";
Expand Down Expand Up @@ -102,17 +109,18 @@ void StageResultsCsvExporter::exportClass(int class_id, QTextStream &csv)
QString qs = qb.toString();
qs.replace("{{stage_id}}", QString::number(currentStage()));
qs.replace("{{class_id}}", QString::number(class_id));
QString with_dns = (withDidNotStart()) ? "" : " AND runs.finishTimeMs>0";
qf::core::sql::Query q = execSql(qs);
if(q.next()) {
QString class_name = q.value("classes.name").toString();
qf::core::sql::QueryBuilder qb2;
qb2.select2("competitors", "registration, lastName, firstName, country, club")
qb2.select2("competitors", "registration, lastName, firstName, country, club, iofId, startNumber, licence")
.select("COALESCE(competitors.lastName, '') || ' ' || COALESCE(competitors.firstName, '') AS competitorName")
.select2("runs", "*")
.select2("clubs","name, abbr")
.from("competitors")
.join("LEFT JOIN clubs ON substr(competitors.registration, 1, 3) = clubs.abbr")
.joinRestricted("competitors.id", "runs.competitorId", "runs.stageId={{stage_id}} AND runs.isRunning AND runs.finishTimeMs>0", "JOIN")
.joinRestricted("competitors.id", "runs.competitorId", "runs.stageId={{stage_id}} AND runs.isRunning"+with_dns, "JOIN")
.where("competitors.classId={{class_id}}")
.orderBy("runs.notCompeting, runs.disqualified, runs.timeMs");
QString qs2 = qb2.toString();
Expand All @@ -124,11 +132,12 @@ void StageResultsCsvExporter::exportClass(int class_id, QTextStream &csv)
int prev_time_ms = 0;
QString spos; // keep last number when same time
while(q2.next()) {
pos++;
auto run_status = quickevent::core::RunStatus::fromQuery(q2);
int time_ms = q2.value(QStringLiteral("timeMs")).toInt();
QString stime = og::TimeMs(time_ms).toString('.');
if(run_status.isOk()) {
bool is_finish = q2.value(QStringLiteral("finishTimeMs")).toInt() > 0;
if(run_status.isOk() && is_finish) {
pos++;
if(time_ms != prev_time_ms)
spos = QString::number(pos);
}
Expand All @@ -143,25 +152,62 @@ void StageResultsCsvExporter::exportClass(int class_id, QTextStream &csv)
if (club.isEmpty())
club = q2.value("competitors.registration").toString().left(3);
}

if (m_isIofRace)
csv << q2.value("competitors.iofId").toString() << m_separator;
else
csv << q2.value("competitors.registration").toString() << m_separator;
csv << q2.value("competitors.startNumber").toString() << m_separator;
csv << class_name << m_separator;
csv << spos << m_separator;
csv << q2.value("competitorName").toString() << m_separator;
csv << club << m_separator;
csv << q2.value("competitors.country").toString() << m_separator;
if (m_isIofRace) {
QString country_abbr;
qf::core::sql::QueryBuilder qb3;
qb3.select2("clubs","name, abbr")
.from("competitors")
.join("LEFT JOIN clubs ON competitors.country = clubs.name");
qf::core::sql::Query q3 = execSql(qb3.toString());
if(q3.next())
country_abbr = q2.value("clubs.abbr").toString();

csv << q2.value("competitors.country").toString() << m_separator;
csv << country_abbr << m_separator;
}
else {
csv << q2.value("competitors.licence").toString() << m_separator;
csv << q2.value("competitors.iofId").toString() << m_separator;
csv << q2.value("competitors.registration").toString().left(3) << m_separator;
}
csv << stime << m_separator;
csv << run_status.toHtmlExportString();
QString rs = run_status.toHtmlExportString();
csv << ((rs == "OK" && !is_finish) ? "ERR" : rs); // older races without proper run flags
csv << Qt::endl;
}
}
}

void StageResultsCsvExporter::exportCsvHeader(QTextStream &csv)
{
if (m_isIofRace)
csv << "IofId" << m_separator;
else
csv << "Reg" << m_separator;
csv << "Bib" << m_separator;
csv << "Class" << m_separator;
csv << "Position" << m_separator;
csv << "Name" << m_separator;
csv << "Club" << m_separator;
csv << "Country" << m_separator;
if (m_isIofRace) {
csv << "Country" << m_separator;
csv << "CountryAbbr" << m_separator;
}
else {
csv << "Lic" << m_separator;
csv << "IofId" << m_separator;
csv << "ClubAbbr" << m_separator;
}
csv << "Time" << m_separator;
csv << "Status";
csv << Qt::endl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ class QUICKEVENTCORE_DECL_EXPORT StageResultsCsvExporter : public FileExporter

using Super = FileExporter;
public:
StageResultsCsvExporter(QObject *parent = nullptr);
QF_PROPERTY_IMPL(QString, o, O, utFile)
QF_PROPERTY_IMPL(bool, s, S, implePath)
QF_PROPERTY_IMPL(bool, w, W, ithDidNotStart)
public:
StageResultsCsvExporter(bool is_iof_race = false, QObject *parent = nullptr);
void generateCsvMulti();
void generateCsvSingle();
void setSeparator(QChar sep) { m_separator = sep; }
Expand All @@ -25,6 +29,7 @@ class QUICKEVENTCORE_DECL_EXPORT StageResultsCsvExporter : public FileExporter
void exportCsvHeader(QTextStream &csv);
private:
QChar m_separator = ';';
bool m_isIofRace = false;
};

}}}
Expand Down
1 change: 1 addition & 0 deletions quickevent/app/quickevent/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ add_executable(quickevent
plugins/Oris/src/orisimporter.cpp
plugins/Oris/src/orisplugin.cpp
plugins/Oris/src/txtimporter.cpp
plugins/Oris/src/xmlimporter.cpp
plugins/Receipts/src/receiptsplugin.cpp
plugins/Receipts/src/receiptsprinter.cpp
#plugins/Receipts/src/receiptsprinteroptions.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ quickevent::core::si::CheckedCard CardCheckerFreeOrderCpp::checkCard(const quick
}

error_mis_punch = !map_of_control_codes.isEmpty();
checked_punches = map_of_control_codes.values();
checked_card.setMisPunch(error_mis_punch);

quickevent::core::si::CheckedPunch finish_punch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <plugins/Event/src/eventplugin.h>
#include <plugins/Runs/src/findrunnerwidget.h>
#include <plugins/Competitors/src/competitorsplugin.h>
#include <plugins/Runs/src/runflagsdialog.h>

#include <QSettings>
#include <QFile>
Expand Down Expand Up @@ -86,11 +87,11 @@ class Model : public quickevent::core::og::SqlTableModel
col_classes_name,
col_competitorName,
col_competitors_registration,
col_competirors_bib,
col_runs_startTimeMs,
col_runs_timeMs,
col_runs_finishTimeMs,
col_runs_misPunch,
col_runs_disqualified,
col_runFlags,
col_runs_cardLent,
col_runs_cardReturned,
col_cards_checkTime,
Expand All @@ -102,7 +103,11 @@ class Model : public quickevent::core::og::SqlTableModel
public:
explicit Model(QObject *parent);

int columnCount(const QModelIndex &) const override { return col_COUNT; }
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;

using Super::value;
QVariant value(int row_ix, int column_ix) const Q_DECL_OVERRIDE;
};

Model::Model(QObject *parent)
Expand All @@ -114,12 +119,12 @@ Model::Model(QObject *parent)
setColumn(col_classes_name, ColumnDefinition("classes.name", tr("Class")));
setColumn(col_competitorName, ColumnDefinition("competitorName", tr("Name")));
setColumn(col_competitors_registration, ColumnDefinition("competitors.registration", tr("Reg")));
setColumn(col_competirors_bib, ColumnDefinition("competitors.startNumber", tr("Bib")));
setColumn(col_runs_startTimeMs, ColumnDefinition("runs.startTimeMs", tr("Start")).setCastType(qMetaTypeId<quickevent::core::og::TimeMs>()).setReadOnly(true));
setColumn(col_runs_timeMs, ColumnDefinition("runs.timeMs", tr("Time")).setCastType(qMetaTypeId<quickevent::core::og::TimeMs>()).setReadOnly(true));
setColumn(col_runs_finishTimeMs, ColumnDefinition("runs.finishTimeMs", tr("Finish")).setCastType(qMetaTypeId<quickevent::core::og::TimeMs>()).setReadOnly(true));
setColumn(col_runs_misPunch, ColumnDefinition("runs.misPunch", tr("Error")).setToolTip(tr("Card mispunch")).setReadOnly(true));
setColumn(col_runs_disqualified, ColumnDefinition("runs.disqualified", tr("DISQ")).setToolTip(tr("Disqualified")));
setColumn(col_runs_cardLent, ColumnDefinition("cardLent", tr("RT")).setToolTip(tr("Card in rent table")).setReadOnly(true).setCastType(QMetaType::Bool));
setColumn(col_runFlags, ColumnDefinition("runFlags", tr("Run flags")).setReadOnly(true));
setColumn(col_runs_cardLent, ColumnDefinition("cardLent", tr("RT")).setToolTip(tr("Card in rent table")).setReadOnly(true).setCastType(QVariant::Bool));
setColumn(col_runs_cardReturned, ColumnDefinition("runs.cardReturned", tr("R")).setToolTip(tr("Card returned")));
setColumn(col_cards_checkTime, ColumnDefinition("cards.checkTime", tr("CTIME")).setToolTip(tr("Card check time")).setReadOnly(true));
setColumn(col_cards_startTime, ColumnDefinition("cards.startTime", tr("STIME")).setToolTip(tr("Card start time")).setReadOnly(true));
Expand Down Expand Up @@ -160,6 +165,45 @@ QVariant Model::data(const QModelIndex &index, int role) const
}
return Super::data(index, role);
}


QVariant Model::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();
bool not_finish = row.value(QStringLiteral("runs.notFinish")).toBool();
bool is_disqualified_by_organizer = row.value(QStringLiteral("runs.disqualifiedByOrganizer")).toBool();
bool over_time = row.value(QStringLiteral("runs.overTime")).toBool();
bool not_competing = row.value(QStringLiteral("runs.notCompeting")).toBool();
QStringList sl;
if(not_competing)
sl << tr("NC", "NotCompeting");
if(mis_punch)
sl << tr("MP", "MisPunch");
if(bad_check)
sl << tr("BC", "BadCheck");
if(not_start)
sl << tr("DNS", "DidNotStart");
if(not_finish)
sl << tr("DNF", "DidNotFinish");
if(is_disqualified_by_organizer)
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 Super::value(row_ix, column_ix);
}

}

CardReaderWidget::CardReaderWidget(QWidget *parent)
Expand Down Expand Up @@ -205,6 +249,17 @@ CardReaderWidget::CardReaderWidget(QWidget *parent)
}
ui->tblCards->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tblCards, &qfw::TableView::customContextMenuRequested, this, &CardReaderWidget::onCustomContextMenuRequest);

connect(ui->tblCards, &qfw::TableView::editCellRequest, this, [this](QModelIndex index) {
auto col = index.column();
if(col == Model::col_runFlags) {
Runs::RunFlagsDialog dlg(this);
dlg.load(m_cardsModel, ui->tblCards->toTableModelRowNo(ui->tblCards->currentIndex().row()));
if(dlg.exec()) {
dlg.save();
}
}
}, Qt::QueuedConnection);
}

CardReaderWidget::~CardReaderWidget()
Expand Down Expand Up @@ -407,11 +462,12 @@ void CardReaderWidget::reload()
int current_stage = getPlugin<CardReaderPlugin>()->currentStageId();
qfs::QueryBuilder qb;
qb.select2("cards", "id, siId, runId, checkTime, startTime, finishTime, runIdAssignError")
.select2("runs", "id, startTimeMs, timeMs, finishTimeMs, misPunch, disqualified, cardReturned")
.select2("competitors", "registration")
.select2("runs", "id, startTimeMs, timeMs, finishTimeMs, misPunch, disqualified, badCheck, notStart, notFinish, disqualifiedByOrganizer, overTime, notCompeting, cardReturned")
.select2("competitors", "registration, startNumber")
.select2("classes", "name")
.select("COALESCE(lastName, '') || ' ' || COALESCE(firstName, '') AS competitorName")
.select("lentcards.siid IS NOT NULL OR runs.cardLent AS cardLent")
.select("'' AS runFlags")
.from("cards")
.joinRestricted("cards.siId", "lentcards.siid", "NOT lentcards.ignored")
.join("cards.runId", "runs.id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ namespace Ui {
class CardReaderWidget;
}

namespace quickevent::core::og { class SqlTableModel; }

namespace qf {
namespace core { namespace model { class SqlTableModel; } }
namespace qmlwidgets {
class Action;
namespace framework { class PartWidget; class Plugin; }
Expand Down Expand Up @@ -108,7 +109,7 @@ private slots:
private:
Ui::CardReaderWidget *ui;
qf::qmlwidgets::Action *m_actAssignCard = nullptr;
qf::core::model::SqlTableModel *m_cardsModel = nullptr;
quickevent::core::og::SqlTableModel *m_cardsModel = nullptr;
quickevent::gui::audio::Player *m_audioPlayer = nullptr;
siut::DeviceDriver *f_siDriver = nullptr;
siut::CommPort *m_commPort = nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ CompetitorWidget::CompetitorWidget(QWidget *parent) :
}

connect(ui->edFind, &FindRegistrationEdit::registrationSelected, this, &CompetitorWidget::onRegistrationSelected);
connect(ui->btnSwitchNames, &QPushButton::clicked, this, &CompetitorWidget::onSwitchNames);

dataController()->setDocument(new Competitors::CompetitorDocument(this));
m_runsModel = new CompetitorRunsModel(this);
Expand Down Expand Up @@ -424,4 +425,12 @@ bool CompetitorWidget::saveData()
return false;
}

void CompetitorWidget::onSwitchNames()
{
auto *doc = dataController()->document();
QString fn = doc->value("firstname").toString();
QString ln = doc->value("lastname").toString();
doc->setValue("firstname",ln);
doc->setValue("lastname",fn);
}

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class CompetitorWidget : public qf::qmlwidgets::framework::DataDialogWidget

private slots:
void onRegistrationSelected(const QVariantMap &values);
void onSwitchNames();
private:
Q_SLOT bool loadRunsTable();
Q_SLOT bool saveRunsTable();
Expand Down
Loading

0 comments on commit 8c3b93c

Please sign in to comment.