Skip to content

Commit

Permalink
v1.0.0-beta.5
Browse files Browse the repository at this point in the history
  • Loading branch information
archibalduk committed Mar 6, 2021
1 parent 2754b14 commit eb14bbe
Show file tree
Hide file tree
Showing 91 changed files with 1,133 additions and 92 deletions.
124 changes: 90 additions & 34 deletions EHM_Jersey_Generator.pro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
QT += core gui
QT += concurrent

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

Expand All @@ -22,25 +23,37 @@ DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += warn_on

SOURCES += \
batch_generator/batch_generator.cpp \
common/text.cpp \
jersey/design_item.cpp \
jersey/font_item.cpp \
jersey/font_server.cpp \
jersey/generic_design_server.cpp \
jersey/jersey.cpp \
jersey/jersey_image_item.cpp \
jersey/jersey_image_server.cpp \
jersey/team_design_server.cpp \
main.cpp \
mainwindow.cpp \
ui/batch_generator_widget.cpp \
ui/colour_widget.cpp \
ui/preview_widget.cpp \
ui/settings_widget.cpp

HEADERS += \
dimensions.h \
batch_generator/batch_generator.h \
common/dimensions.h \
common/text.h \
jersey/design_item.h \
jersey/font_item.h \
jersey/font_server.h \
jersey/generic_design_server.h \
jersey/jersey.h \
jersey/jersey_image_item.h \
jersey/jersey_image_server.h \
jersey/team_design_server.h \
mainwindow.h \
ui/batch_generator_widget.h \
ui/colour_widget.h \
ui/preview_widget.h \
ui/settings_widget.h
Expand All @@ -50,41 +63,84 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

#QXlsx library
Debug:LIBS += -L"$$_PRO_FILE_PWD_/qxlsx/lib" -lQXlsx_debug
Release:LIBS += -L"$$_PRO_FILE_PWD_/qxlsx/lib" -lQXlsx
INCLUDEPATH += $$_PRO_FILE_PWD_/qxlsx/include

RESOURCES += \
EHM_Jersey_Generator.qrc

DISTFILES += \
README.md \
images/layer_foreground/ana-foreground.png \
images/layer_foreground/ari-foreground.png \
images/layer_foreground/bos-foreground.png \
images/layer_foreground/buf-foreground.png \
images/layer_foreground/car-foreground.png \
images/layer_foreground/cgy-foreground-01.png \
images/layer_foreground/cgy-foreground-02.png \
images/layer_foreground/chi-foreground.png \
images/layer_foreground/clb-foreground.png \
images/layer_foreground/col-foreground.png \
images/layer_foreground/dal-foreground.png \
images/layer_foreground/det-foreground.png \
images/layer_foreground/edm-foreground.png \
images/layer_foreground/fla-foreground.png \
images/layer_foreground/lak-foreground.png \
images/layer_foreground/min-foreground.png \
images/layer_foreground/mtl-foreground.png \
images/layer_trim/ana-trim.png \
images/layer_trim/ari-trim.png \
images/layer_trim/bos-trim.png \
images/layer_trim/buf-trim.png \
images/layer_trim/car-trim.png \
images/layer_trim/cgy-trim.png \
images/layer_trim/chi-trim.png \
images/layer_trim/clb-trim.png \
images/layer_trim/col-trim.png \
images/layer_trim/dal-trim.png \
images/layer_trim/det-trim.png \
images/layer_trim/edm-trim.png \
images/layer_trim/fla-trim.png \
images/layer_trim/lak-trim.png \
images/layer_trim/min-trim.png \
images/layer_trim/mtl-trim.png
generic_jerseys.xlsx \
images/layer_foreground/ana-foreground-2020.png \
images/layer_foreground/ari-foreground-2020.png \
images/layer_foreground/bos-foreground-2020.png \
images/layer_foreground/buf-foreground-2020.png \
images/layer_foreground/car-foreground-2020.png \
images/layer_foreground/cgy-foreground-2020-01.png \
images/layer_foreground/cgy-foreground-2020-02.png \
images/layer_foreground/chi-foreground-2020.png \
images/layer_foreground/clb-foreground-2020.png \
images/layer_foreground/col-foreground-2020.png \
images/layer_foreground/dal-foreground-2020.png \
images/layer_foreground/det-foreground-2020.png \
images/layer_foreground/edm-foreground-2020.png \
images/layer_foreground/fla-foreground-2020.png \
images/layer_foreground/lak-foreground-2020.png \
images/layer_foreground/min-foreground-2020.png \
images/layer_foreground/mtl-foreground-2020.png \
images/layer_foreground/nas-foreground-2020.png \
images/layer_foreground/njd-foreground-2020.png \
images/layer_foreground/nyi-foreground-2020.png \
images/layer_foreground/nyr-foreground-2020.png \
images/layer_foreground/ott-foreground-2020.png \
images/layer_foreground/phi-foreground-2020.png \
images/layer_foreground/pit-foreground-2020.png \
images/layer_foreground/sjs-foreground-2020.png \
images/layer_foreground/stl-foreground-2020.png \
images/layer_foreground/tbl-foreground-2020.png \
images/layer_foreground/tor-foreground-2020.png \
images/layer_foreground/van-foreground-2020.png \
images/layer_foreground/veg-foreground-2020.png \
images/layer_foreground/was-foreground-2020.png \
images/layer_foreground/wpg-foreground-2020.png \
images/layer_trim/ana-trim-2020.png \
images/layer_trim/ari-trim-2020.png \
images/layer_trim/bos-trim-2020.png \
images/layer_trim/buf-trim-2020.png \
images/layer_trim/car-trim-2020.png \
images/layer_trim/cgy-trim-2020.png \
images/layer_trim/chi-trim-2020.png \
images/layer_trim/clb-trim-2020.png \
images/layer_trim/col-trim-2020.png \
images/layer_trim/dal-trim-2020.png \
images/layer_trim/det-trim-2020.png \
images/layer_trim/edm-trim-2020.png \
images/layer_trim/fla-trim-2020.png \
images/layer_trim/lak-trim-2020.png \
images/layer_trim/min-trim-2020.png \
images/layer_trim/mtl-trim-2020.png \
images/layer_trim/nas-trim-2020.png \
images/layer_trim/njd-trim-2020.png \
images/layer_trim/nyi-trim-2020.png \
images/layer_trim/nyr-trim-2020.png \
images/layer_trim/ott-trim-2020.png \
images/layer_trim/phi-trim-2020.png \
images/layer_trim/pit-trim-2020.png \
images/layer_trim/sjs-trim-2020-01.png \
images/layer_trim/sjs-trim-2020-02.png \
images/layer_trim/stl-trim-2020-01.png \
images/layer_trim/stl-trim-2020-02.png \
images/layer_trim/stl-trim-2020-03.png \
images/layer_trim/tbl-trim-2020.png \
images/layer_trim/tor-trim-2020.png \
images/layer_trim/van-trim-2020.png \
images/layer_trim/veg-trim-2020-01.png \
images/layer_trim/veg-trim-2020-02.png \
images/layer_trim/was-trim-2020.png \
images/layer_trim/wpg-trim-2020.png \
qxlsx/lib/QXlsx.lib \
qxlsx/lib/QXlsx_debug.lib \
team_jerseys.xlsx
215 changes: 215 additions & 0 deletions batch_generator/batch_generator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include "batch_generator.h"

// Application headers
#include "../common/text.h"
#include "../jersey/jersey.h"
#include "xlsxdocument.h"

// Qt headers
#include <QApplication>
#include <QElapsedTimer>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QProgressDialog>
#include <QtConcurrent>

// --- Constructor --- //
BatchGenerator::BatchGenerator(const QString &input_file_path,
const QString &output_file_path,
const QString &generic_jersey_design_file_path,
const QString &team_jersey_design_file_path)
: input_file_path_(input_file_path), output_folder_path_(output_file_path)
{
// Process the generic and team jersey layer design files
generic_jersey_designs_.init(generic_jersey_design_file_path);
team_jersey_designs_.init(team_jersey_design_file_path);
}

// --- Batch jersey image generation --- //
bool BatchGenerator::generate()
{
// Timer and progress dialog
QProgressDialog progress(QObject::tr("Processing spreadsheet"), QString(), 0, 1);
progress.setWindowTitle(
QObject::tr("Generating jerseys (using %L1 threads)").arg(QThread::idealThreadCount()));
progress.show();
QApplication::processEvents();

QXlsx::Document spreadsheet(input_file_path_);
if (!spreadsheet.load()) {
QMessageBox::critical(nullptr,
QObject::tr("Spreadsheet error"),
QObject::tr("Unable to open %1.").arg(input_file_path_));
progress.close();
return false;
}

// Spreadsheet dimensions
const auto row_count{spreadsheet.dimension().lastRow()};
const auto first_row{1}; // Row 0 = header row

// Reset the progress dialog
progress.setLabelText(QObject::tr("Processing %L1 rows of data").arg(row_count - first_row));
progress.setMaximum(row_count);
QApplication::processEvents();

QElapsedTimer timer;
timer.start();

// Create a QFutureWatcher and connect signals and slots.
QFutureWatcher<void> futureWatcher;
QObject::connect(&futureWatcher,
&QFutureWatcher<void>::finished,
&progress,
&QProgressDialog::reset);
QObject::connect(&progress,
&QProgressDialog::canceled,
&futureWatcher,
&QFutureWatcher<void>::cancel);
QObject::connect(&futureWatcher,
&QFutureWatcher<void>::progressRangeChanged,
&progress,
&QProgressDialog::setRange);
QObject::connect(&futureWatcher,
&QFutureWatcher<void>::progressValueChanged,
&progress,
&QProgressDialog::setValue);

// Buffer the row references
std::vector<qint32> buffer;
for (qint32 i = first_row; i < row_count; ++i)
buffer.push_back(i);

// Jersey generation lambda
std::function<bool(int &)> generate =
[this, &spreadsheet, &progress, &futureWatcher](const int &i) {
const auto player_surname{spreadsheet.read(i, PLAYER_SECOND_NAME).toString().trimmed()};
if (player_surname.isEmpty())
return true;

Jersey jersey(player_surname, spreadsheet.read(i, JERSEY_NUMBER).toInt());
jersey.setColours(spreadsheet.read(i, BACKGROUND_COLOUR).toString(),
spreadsheet.read(i, FOREGROUND_COLOUR).toString(),
spreadsheet.read(i, TRIM_COLOUR).toString());
jersey.usePresetImage(true); // Use preset images where possible
jersey.setImages(Text(spreadsheet.read(i, CLUB_NAME).toString()),
generic_jersey_designs_,
team_jersey_designs_);
jersey.generate();

const auto output_file_path{
QString("%1/%2_%3_%4.png")
.arg(output_folder_path_,
spreadsheet.read(i, PLAYER_FIRST_NAME).toString().trimmed(),
player_surname,
spreadsheet.read(i, PLAYER_DATE_OF_BIRTH)
.toString()
.replace(".", "_")
.replace("/", "_"))};
const auto result{jersey.save(output_file_path)};

if (!result) {
futureWatcher.cancel();
progress.cancel();
QMessageBox::critical(nullptr,
QObject::tr("File write error (row %L1").arg(i),
QObject::tr("Unable to save %1 to the disk.")
.arg(output_file_path));
return false;
}

return true;
};

// Start the computation
futureWatcher.setFuture(QtConcurrent::map(buffer, generate));

// Display the dialog and start the event loop.
progress.exec();
futureWatcher.waitForFinished();

// Calculate the time elapsed once complete
const qreal elapsed{qreal(timer.elapsed()) / 1'000}; // 1,000 milliseconds -> seconds
progress.close();

QMessageBox::information(nullptr,
QObject::tr("Complete"),
QObject::tr(
"Batch generation of %L1 row(s) complete in %L2 second(s).")
.arg(buffer.size())
.arg(elapsed));

return true;
}

// --- Increment the progress dialog
void BatchGenerator::updateProgressDialog(QProgressDialog &progress,
const qint32 &total_rows_processed,
QElapsedTimer &timer) const
{
const qreal elapsed{static_cast<qreal>(timer.elapsed()) / 1'000};
const qreal remaining{
(((static_cast<qreal>(progress.maximum()) / static_cast<qreal>(total_rows_processed))
* elapsed)
- elapsed)
/ 1'000};

progress.setLabelText(QString("%L1 seconds elapsed (%L2 seconds remaining)")
.arg(static_cast<qint32>(elapsed))
.arg(static_cast<qint32>(remaining)));
progress.setValue(total_rows_processed);
QApplication::processEvents();
}

/* OLD ITERATION CODE BELOW */
/*
// Process each row
quint32 total_jerseys_generated{0};
for (qint32 i = first_row; i < row_count; ++i) {
const auto player_surname{spreadsheet.read(i, PLAYER_SECOND_NAME).toString().trimmed()};
if (player_surname.isEmpty())
continue;
Jersey jersey(player_surname, spreadsheet.read(i, JERSEY_NUMBER).toInt());
jersey.setColours(spreadsheet.read(i, BACKGROUND_COLOUR).toString(),
spreadsheet.read(i, FOREGROUND_COLOUR).toString(),
spreadsheet.read(i, TRIM_COLOUR).toString());
jersey.usePresetImage(true); // Use preset images where possible
jersey.setImages(Text(spreadsheet.read(i, CLUB_NAME).toString()),
generic_jersey_designs_,
team_jersey_designs_);
jersey.generate();
const auto output_file_path{
QString("%1/%2_%3_%4.png")
.arg(output_folder_path_,
spreadsheet.read(i, PLAYER_FIRST_NAME).toString().trimmed(),
player_surname,
spreadsheet.read(i, PLAYER_DATE_OF_BIRTH)
.toString()
.replace(".", "_")
.replace("/", "_"))};
const auto result{jersey.save(output_file_path)};
if (i % PROGRESS_BAR_REFRESH_RATE == 0)
updateProgressDialog(progress, i, timer);
if (!result) {
progress.cancel();
QMessageBox::critical(
nullptr,
QObject::tr("File write error (row %L1 of %L2)").arg(i).arg(row_count - row_count),
QObject::tr("Unable to save %1 to the disk.").arg(output_file_path));
return false;
}
++total_jerseys_generated;
}
const qreal elapsed{qreal(timer.elapsed()) / 1'000};
progress.accept();
progress.close();
QApplication::processEvents();
*/
Loading

0 comments on commit eb14bbe

Please sign in to comment.