Skip to content

Commit

Permalink
Merge pull request #983 from arnost00/relay-import-start-numbers-qe3
Browse files Browse the repository at this point in the history
Relay import start numbers qe3
  • Loading branch information
fvacek authored Oct 7, 2024
2 parents 335a8c0 + b066dfc commit 8885e82
Show file tree
Hide file tree
Showing 14 changed files with 8,837 additions and 15,816 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.18.4)

set(WITH_QE_SHVAPI OFF CACHE BOOL "Build SHV API service with QuickEvent")
set(QF_BUILD_QML_PLUGINS ON CACHE BOOL "Build with QML Plugins support")

project(quickbox LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
Expand Down
10 changes: 10 additions & 0 deletions quickevent/app/quickevent/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ qt6_add_translation(QM_FILES
quickevent-uk_UA.ts
)

qt_add_lupdate(quickevent TS_FILES
quickevent-cs_CZ.ts
quickevent-fr_FR.ts
quickevent-nb_NO.ts
quickevent-nl_BE.ts
quickevent-pl_PL.ts
quickevent-ru_RU.ts
quickevent-uk_UA.ts
)

target_sources(quickevent PRIVATE ${QM_FILES})
target_include_directories(quickevent PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(quickevent PUBLIC libquickeventcore libquickeventgui libqfqmlwidgets libsiut)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,14 +356,14 @@
<item row="1" column="1">
<widget class="QSpinBox" name="ed_xmlRaceNumber">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;IOF Eventor race number - if nonzero, user as &amp;lt;Race&amp;gt; node and for attribute of &amp;lt;Start&amp;gt; node for IOF XML exports&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;IOF Eventor race number - if nonzero, used as &amp;lt;Race&amp;gt; node and for attribute of &amp;lt;Start&amp;gt; node for IOF XML exports&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="ed_iofRace">
<property name="toolTip">
<string>IOF Eventor race - user for IOF XML exports</string>
<string>IOF Eventor race - used for IOF XML exports</string>
</property>
<property name="text">
<string>Is IOF Race (data from Eventor)</string>
Expand Down
8 changes: 4 additions & 4 deletions quickevent/app/quickevent/plugins/Oris/src/txtimporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void TxtImporter::importCompetitorsCSV()
qf::qmlwidgets::framework::MainWindow *fwk = qf::qmlwidgets::framework::MainWindow::frameWork();
qf::qmlwidgets::dialogs::MessageBox mbx(fwk);
mbx.setIcon(QMessageBox::Information);
mbx.setText(tr("Import comma separated values UTF8 text files with header."));
mbx.setText(tr("Import UTF8 text file with comma separated values with first row as header.<br/>Separator is comma(,)"));
mbx.setInformativeText(tr("Each row should have following columns: "
"<ol>"
"<li>Registration</li>"
Expand Down Expand Up @@ -268,7 +268,7 @@ void TxtImporter::importRunsCzeCSV()
qf::qmlwidgets::framework::MainWindow *fwk = qf::qmlwidgets::framework::MainWindow::frameWork();
qf::qmlwidgets::dialogs::MessageBox mbx(fwk);
mbx.setIcon(QMessageBox::Information);
mbx.setText(tr("Import comma separated values UTF8 text files with header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is Czech registration)."));
mbx.setText(tr("Import UTF8 text file with comma separated values with first row as header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is Czech registration)."));
mbx.setInformativeText(tr("Each row should have following columns: "
"<ol>"
"<li>Registration <i>- key</i></li>"
Expand Down Expand Up @@ -382,7 +382,7 @@ void TxtImporter::importRunsIdCSV()
qf::qmlwidgets::framework::MainWindow *fwk = qf::qmlwidgets::framework::MainWindow::frameWork();
qf::qmlwidgets::dialogs::MessageBox mbx(fwk);
mbx.setIcon(QMessageBox::Information);
mbx.setText(tr("Import comma separated values UTF8 text files with header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is <b>id</b> in module(table) <b>runs</b>)."));
mbx.setText(tr("Import UTF8 text file with comma separated values with first row as header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is <b>id</b> in module(table) <b>runs</b>)."));
mbx.setInformativeText(tr("Each row should have following columns: "
"<ol>"
"<li>Runs Id <i>- key</i></li>"
Expand Down Expand Up @@ -496,7 +496,7 @@ void TxtImporter::importRunsIofCSV()
qf::qmlwidgets::framework::MainWindow *fwk = qf::qmlwidgets::framework::MainWindow::frameWork();
qf::qmlwidgets::dialogs::MessageBox mbx(fwk);
mbx.setIcon(QMessageBox::Information);
mbx.setText(tr("Import comma separated values UTF8 text files with header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is IOF ID)."));
mbx.setText(tr("Import UTF8 text file with comma separated values with first row as header.<br/>Separator is semicolon(;).<br/>Updates only existing runners (key is IOF ID)."));
mbx.setInformativeText(tr("Each row should have following columns: "
"<ol>"
"<li>IOF ID <i>- key</i></li>"
Expand Down
4 changes: 2 additions & 2 deletions quickevent/app/quickevent/plugins/Oris/src/xmlimporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ bool XmlImporter::importEntries(QXmlStreamReader &reader, const XmlCreators crea
it++;
}
bool ok;
QString item = QInputDialog::getItem(qf::qmlwidgets::framework::MainWindow::frameWork(), tr("Select which race import)"),
QString item = QInputDialog::getItem(qf::qmlwidgets::framework::MainWindow::frameWork(), tr("Select which race import"),
tr("Races:"), items, 0, false, &ok);
if (ok && !item.isEmpty())
selected_race = races[item];
Expand Down Expand Up @@ -778,7 +778,7 @@ bool XmlImporter::importEvent(QXmlStreamReader &reader, const XmlCreators creato
it++;
}
bool ok;
QString item = QInputDialog::getItem(qf::qmlwidgets::framework::MainWindow::frameWork(), tr("Select which race import)"),
QString item = QInputDialog::getItem(qf::qmlwidgets::framework::MainWindow::frameWork(), tr("Select which race import"),
tr("Races:"), items, 0, false, &ok);
if (ok && !item.isEmpty())
event_race = races[item];
Expand Down
128 changes: 128 additions & 0 deletions quickevent/app/quickevent/plugins/Relays/src/relayswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <qf/core/sql/transaction.h>
#include <qf/core/assert.h>
#include <qf/core/utils/treetable.h>
#include <qf/core/utils/csvreader.h>
#include <QCheckBox>
#include <QInputDialog>
#include <QLabel>
Expand Down Expand Up @@ -148,6 +149,11 @@ void RelaysWidget::settleDownInPartWidget(::PartWidget *part_widget)
a_relays->addActionInto(a);
connect(a, &qfw::Action::triggered, this, &RelaysWidget::relays_assignNumbers);
}
{
qfw::Action *a = new qfw::Action("importBibs", tr("&Import bibs from CSV"));
a_relays->addActionInto(a);
connect(a, &qfw::Action::triggered, this, &RelaysWidget::relays_importBibs);
}

qfw::Action *a_print = part_widget->menuBar()->actionForPath("print");
a_print->setText(tr("&Print"));
Expand Down Expand Up @@ -557,3 +563,125 @@ void RelaysWidget::export_results_iofxml3() {
QString fn = getPlugin<EventPlugin>()->eventName() + ".results.iof30.xml";
save_xml_file(getPlugin<RelaysPlugin>()->resultsIofXml30(), fn);
}

void RelaysWidget::relays_importBibs() {
qf::qmlwidgets::framework::MainWindow *fwk = qf::qmlwidgets::framework::MainWindow::frameWork();
qf::qmlwidgets::dialogs::MessageBox mbx(fwk);
mbx.setIcon(QMessageBox::Information);
mbx.setText(tr("Import UTF8 text file with comma separated values with first row as header.<br/>Separator is semicolon(;).<br/>Updates only existing relays (key is Club, Relay Name & Class)."));
mbx.setInformativeText(tr("Each row should have following columns: "
"<ol>"
"<li>Club abbr <i>- key (part1)</i></li>"
"<li>Relay name <i>- key (part2)</i></li>"
"<li>Start number (Bib)</li>"
"<li>Class (Optional - if not filed, trying to guess from the starting number)</li>"
"</ol>"));

mbx.setDoNotShowAgainPersistentKey("importRelaysBibsCSV");
int res = mbx.exec();
if(res != QMessageBox::Ok)
return;
QString fn = qfd::FileDialog::getOpenFileName(fwk, tr("Open file"), QString(), tr("CSV files (*.csv *.txt)"));
if(fn.isEmpty())
return;

QMap<QString, int> classes_map; // classes.name->classes.id
std::map<int, int> classes_map_bibs; // classes.name->classes.id
qf::core::sql::Query q;
q.exec("SELECT classes.id, relayStartNumber, name FROM classdefs JOIN classes ON classdefs.classid = classes.id WHERE stageId=1", qf::core::Exception::Throw);
while(q.next()) {
classes_map[q.value(2).toString()] = q.value(0).toInt();
classes_map_bibs[q.value(1).toInt()] = q.value(0).toInt();
}

try {
QFile f(fn);
if(!f.open(QFile::ReadOnly))
QF_EXCEPTION(tr("Cannot open file '%1' for reading.").arg(fn));
QTextStream ts(&f);
qf::core::utils::CSVReader reader(&ts);
reader.setSeparator(';');
enum {ColRelClub = 0, ColRelName, ColBib, ColClass};

qfLogScope("importRelaysBibsCSV");
qf::core::sql::Transaction transaction;
qf::core::sql::Query q2;
q.prepare("SELECT id FROM relays WHERE club=:club AND name=:name AND classId=:classId", qf::core::Exception::Throw);
q2.prepare("UPDATE relays SET number=:number WHERE id=:id", qf::core::Exception::Throw);

int n = 0;
int i = 0;
QSet<int> loaded_numbers;

while (!ts.atEnd()) {
QStringList line = reader.readCSVLineSplitted();
if(line.count() <= 1)
QF_EXCEPTION(tr("Fields separation error, invalid CSV format, Error reading CSV line: [%1]").arg(line.join(';').mid(0, 100)));
if(n++ == 0) { // skip first row (header)
qfDebug() << "Import CSV - skip header line";
continue;
}
QString relay_club = line.value(ColRelClub).trimmed();
QString relay_name = line.value(ColRelName).trimmed();
int relay_bib = line.value(ColBib).toInt();
QString relay_class = line.value(ColClass).trimmed();
if(relay_club.isEmpty() || relay_name.isEmpty()) {
QF_EXCEPTION(tr("Error reading CSV line: [%1]").arg(line.join(';')));
}
int class_id = -1;
if (relay_class.isEmpty() && relay_bib > 0) {
// guess class from bib number
for (auto&item : classes_map_bibs)
{
if (item.first <= relay_bib)
class_id = item.second;
}
if (class_id == -1)
QF_EXCEPTION(tr("Cannot guess class name from bib: '%1'").arg(relay_bib));
}
else if (!relay_class.isEmpty() && relay_bib >= 0){
class_id = classes_map.value(relay_class,-1);
if(class_id == -1)
QF_EXCEPTION(tr("Undefined class name: '%1'").arg(relay_class));
}
else {
if (relay_bib == 0)
qfWarning() << "Import CSV line" << n << "with" << relay_club << relay_name <<", cannot update, bib number 0 without class name";
else
qfWarning() << "Import CSV line" << n << "with" << relay_club << relay_name <<", cannot update, bib number"<< relay_bib <<"is negative";
}
if (relay_bib > 0) { // zero is for clear bib, negative is ignored
if (loaded_numbers.contains(relay_bib))
qfWarning() << "Import CSV line" << n << "with" << relay_club << relay_name <<", duplicate bib number"<< relay_bib;
else
loaded_numbers.insert(relay_bib);
}

q.bindValue(":club", relay_club);
q.bindValue(":name", relay_name);
q.bindValue(":classId", class_id);

q.exec(qf::core::Exception::Throw);
if(q.next()) {
// if club & name found in db - start update data
int relay_id = q.value(0).toInt();

if (relay_bib != 0) {
q2.bindValue(":number", relay_bib);
q2.bindValue(":id", relay_id);
q2.exec(qf::core::Exception::Throw);
i++;
qfDebug() << "Import CSV line" << n << "with" << relay_club << relay_name <<"bib"<< relay_bib << "["<< relay_class << "|"<< class_id << "].";
}
}
else
qfWarning() << "CSV line" << n << "with" << relay_club << relay_name <<"bib"<< relay_bib << "["<< relay_class << "|"<< class_id << "] not found in database.";
}
transaction.commit();
qfInfo() << fn << "Imported"<< i << "of" << n-1 << "data lines"; // -1 is header
QMessageBox::information(this, tr("Information"), QString(tr("Import file finished. Imported %1 of %2 lines\n\nPress refresh button to show imported data.").arg(i).arg(n-1)));
}
catch (const qf::core::Exception &e) {
qf::qmlwidgets::dialogs::MessageBox::showException(fwk, e);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class RelaysWidget : public QFrame
QVariant startListByClubsTableData();

void relays_assignNumbers();
void relays_importBibs();

void print_start_list_classes();
void print_start_list_clubs();
Expand Down
Loading

0 comments on commit 8885e82

Please sign in to comment.