, InterpTextInfo>(fout, styles, gdi.getTL(), yscale, xscale, offsetY, offsetX);
-
- fout << "";
+ HTMLWriter::formatTL, InterpTextInfo>(fout, imgWriter, styles, gdi.getTL(), yscale, xscale, offsetY, offsetX);
+
+ fout << "";
char bf1[256];
char bf2[256];
GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256);
GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256);
//fout << "Skapad av MeOS: " << bf1 << " "<< bf2 << "\n";
- fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS: " << bf1 << " "<< bf2 << "\n";
+ fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS: " << bf1 << " " << bf2 << "\n";
fout << "
\n";
fout << "\n";
@@ -341,18 +367,29 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
if (fout.bad())
return throw std::exception("Bad output stream");
- writeTableHTML(gdi, fout, title, false, refreshTimeOut, scale);
+ wchar_t drive[20];
+ wchar_t dir[MAX_PATH];
+ wchar_t name[MAX_PATH];
+ wchar_t ext[MAX_PATH];
+ _wsplitpath_s(file.c_str(), drive, dir, name, ext);
+ wstring path = wstring(drive) + dir;
+
+ writeTableHTML(gdi, fout, title, true, path, false, refreshTimeOut, scale);
}
-void HTMLWriter::writeTableHTML(gdioutput &gdi,
- ostream &fout,
- const wstring &title,
+void HTMLWriter::writeTableHTML(gdioutput& gdi,
+ ostream& fout,
+ const wstring& title,
+ bool includeImages,
+ const wstring& imageDirectoryDestination,
bool simpleFormat,
int refreshTimeOut,
double scale) {
if (scale <= 0)
scale = 1.0;
+ ImageWriter imgWriter(imageDirectoryDestination, includeImages);
+
fout << "" << endl;
fout << "\n\n";
fout << "\n";
@@ -366,14 +403,14 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
fout << "\n";
fout << "\n";
- auto &TL = gdi.getTL();
+ auto& TL = gdi.getTL();
auto it = TL.begin();
int MaxX = gdi.getPageX() - 100;
- map tableCoordinates;
+ map tableCoordinates;
//Get x-coordinates
- while (it!=TL.end()) {
- tableCoordinates[it->xp]=0;
+ while (it != TL.end()) {
+ tableCoordinates[it->xp] = 0;
++it;
}
@@ -384,47 +421,47 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
++mit;
}
tableCoordinates[MaxX] = kr;
-
+
vector sizeSet(kr + 1, false);
fout << "\n";
- int linecounter=0;
- it=TL.begin();
+ int linecounter = 0;
+ it = TL.begin();
- vector< pair > > rows;
+ vector< pair > > rows;
rows.reserve(TL.size() / 3);
vector ypRow;
int minHeight = 100000;
- while (it!=TL.end()) {
- int y=it->yp;
- vector row;
+ while (it != TL.end()) {
+ int y = it->yp;
+ vector row;
int subnormal = 0;
int normal = 0;
int header = 0;
int mainheader = 0;
- while (it!=TL.end() && it->yp==y) {
+ while (it != TL.end() && it->yp == y) {
if (!gdioutput::skipTextRender(it->format)) {
row.push_back(&*it);
switch (it->getGdiFont()) {
- case fontLarge:
- case boldLarge:
- case boldHuge:
- mainheader++;
- break;
- case boldText:
- case italicMediumPlus:
- case fontMediumPlus:
- header++;
- break;
- case fontSmall:
- case italicSmall:
- subnormal++;
- break;
- default:
- normal++;
+ case fontLarge:
+ case boldLarge:
+ case boldHuge:
+ mainheader++;
+ break;
+ case boldText:
+ case italicMediumPlus:
+ case fontMediumPlus:
+ header++;
+ break;
+ case fontSmall:
+ case italicSmall:
+ subnormal++;
+ break;
+ default:
+ normal++;
}
}
++it;
@@ -444,27 +481,27 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
int last = ypRow.size();
ypRow.push_back(y);
if (last > 0) {
- minHeight = min(minHeight, ypRow[last] - ypRow[last-1]);
+ minHeight = min(minHeight, ypRow[last] - ypRow[last - 1]);
}
}
int numMin = 0;
for (size_t gCount = 1; gCount < rows.size(); gCount++) {
- int h = ypRow[gCount] - ypRow[gCount-1];
+ int h = ypRow[gCount] - ypRow[gCount - 1];
if (h == minHeight)
numMin++;
}
if (numMin == 0)
numMin = 1;
- int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5);
+ int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5);
for (size_t gCount = 1; gCount + 1 < rows.size(); gCount++) {
int type = rows[gCount].first;
- int lastType = gCount > 0 ? rows[gCount-1].first : 0;
+ int lastType = gCount > 0 ? rows[gCount - 1].first : 0;
int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0;
if (type == 0 && (lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2))
continue; // No reclassify
- int h = ypRow[gCount] - ypRow[gCount-1];
+ int h = ypRow[gCount] - ypRow[gCount - 1];
if (h > hdrLimit && rows[gCount].first == 0)
rows[gCount].first = 2;
}
@@ -472,12 +509,12 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
ypRow.clear();
string lineclass;
for (size_t gCount = 0; gCount < rows.size(); gCount++) {
- vector &row = rows[gCount].second;
+ vector& row = rows[gCount].second;
int type = rows[gCount].first;
- int lastType = gCount > 0 ? rows[gCount-1].first : 0;
+ int lastType = gCount > 0 ? rows[gCount - 1].first : 0;
int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0;
- vector::iterator rit;
+ vector::iterator rit;
fout << "" << endl;
if (simpleFormat) {
@@ -498,48 +535,55 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
lineclass = "";
}
else
- lineclass = (linecounter&1) ? " class=\"e1\"" : " class=\"e0\"";
+ lineclass = (linecounter & 1) ? " class=\"e1\"" : " class=\"e0\"";
linecounter++;
}
- for (size_t k=0;kxp];
+ for (size_t k = 0; k < row.size(); k++) {
+ int thisCol = tableCoordinates[row[k]->xp];
-if (k == 0 && thisCol != 0)
-fout << "| | ";
+ if (k == 0 && thisCol != 0)
+ fout << " | ";
-int nextCol;
-if (row.size() == k + 1)
-nextCol = tableCoordinates.rbegin()->second;
-else
-nextCol = tableCoordinates[row[k + 1]->xp];
+ int nextCol;
+ if (row.size() == k + 1)
+ nextCol = tableCoordinates.rbegin()->second;
+ else
+ nextCol = tableCoordinates[row[k + 1]->xp];
-int colspan = nextCol - thisCol;
+ int colspan = nextCol - thisCol;
-assert(colspan > 0);
+ assert(colspan > 0);
-string style;
+ string style;
-if (row[k]->format&textRight)
-style = " style=\"text-align:right\"";
+ if (row[k]->format & textRight)
+ style = " style=\"text-align:right\"";
-if (colspan == 1 && !sizeSet[thisCol]) {
- fout << " xp - row[k]->xp) : (MaxX - row[k]->xp)) << "\">";
- sizeSet[thisCol] = true;
-}
-else if (colspan > 1)
-fout << " | ";
-else
-fout << " | ";
+ if (colspan == 1 && !sizeSet[thisCol]) {
+ fout << " | xp - row[k]->xp) : (MaxX - row[k]->xp)) << "\">";
+ sizeSet[thisCol] = true;
+ }
+ else if (colspan > 1)
+ fout << " | ";
+ else
+ fout << " | ";
-gdiFonts font = row[k]->getGdiFont();
-string starttag, endtag;
-getStyle(styles, font, gdioutput::narrow(row[k]->font), "", starttag, endtag);
-
-fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag << " | " << endl;
+ if ((row[k]->format & 0xFF) == textImage) {
+ int imgW = int((row[k]->textRect.right - row[k]->textRect.left) * scale);
+ int imgH = int((row[k]->textRect.bottom - row[k]->textRect.top) * scale);
+ imgWriter.write(fout, "", "", row[k]->text, imgW, imgH);
+ fout << "" << endl;
+ }
+ else {
+ gdiFonts font = row[k]->getGdiFont();
+ string starttag, endtag;
+ getStyle(styles, font, gdioutput::narrow(row[k]->font), "", starttag, endtag);
+ fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag << "" << endl;
+ }
}
fout << "
\n";
@@ -555,7 +599,7 @@ fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag <
GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256);
GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256);
wstring meos = getMeosCompectVersion();
- fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS "
+ fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS "
<< gdioutput::toUTF8(meos) << ": " << bf1 << " " << bf2 << "\n";
fout << "
\n";
}
@@ -781,8 +825,11 @@ void HTMLWriter::generate(gdioutput &gdi,
double scale) const {
int w, h;
gdi.getTargetDimension(w, h);
+
+
+ ImageWriter imgWriter(L"", false);
- string meos = "MeOS: " + gdioutput::toUTF8(getMeosCompectVersion()) + "";
+ string meos = "MeOS: " + gdioutput::toUTF8(getMeosCompectVersion()) + "";
int margin = (w * marginPercent) / 100;
int height = nRows * gdi.getLineHeight();
@@ -886,7 +933,7 @@ void HTMLWriter::generate(gdioutput &gdi,
double xscale = 1.2 * scale;
int offsetY = 0, offsetX = 0;
- formatTL, InterpPrintTextInfo>(sout, styles, p.text, yscale, xscale, offsetY, offsetX);
+ formatTL, InterpPrintTextInfo>(sout, imgWriter, styles, p.text, yscale, xscale, offsetY, offsetX);
output = innerpage;
replaceAll(output, "@P", itos(ipCounter++));
@@ -921,17 +968,27 @@ void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title
checkWriteAccess(file);
ofstream fout(file.c_str());
- write(gdi, fout, title, contentsDescription, respectPageBreak, typeTag, refresh,
+ wchar_t drive[20];
+ wchar_t dir[MAX_PATH];
+ wchar_t name[MAX_PATH];
+ wchar_t ext[MAX_PATH];
+ _wsplitpath_s(file.c_str(), drive, dir, name, ext);
+ wstring path = wstring(drive) + dir;
+
+ write(gdi, fout, title, true, path, contentsDescription, respectPageBreak, typeTag, refresh,
rows, cols, time_ms, margin, scale);
}
-void HTMLWriter::write(gdioutput &gdi, ostream &fout, const wstring &title, const wstring &contentsDescription,
+void HTMLWriter::write(gdioutput &gdi, ostream &fout, const wstring &title,
+ bool includeImages,
+ const wstring& imageDirectoryDestination,
+ const wstring &contentsDescription,
bool respectPageBreak, const string &typeTag, int refresh,
int rows, int cols, int time_ms, int margin, double scale) {
if (typeTag == "table")
- writeTableHTML(gdi, fout, title, false, refresh, scale);
+ writeTableHTML(gdi, fout, title, includeImages, imageDirectoryDestination, false, refresh, scale);
else if (typeTag == "free") {
- writeHTML(gdi, fout, title, refresh, scale);
+ writeHTML(gdi, fout, title, includeImages, imageDirectoryDestination, refresh, scale);
}
else {
/* auto res = tCache.find(typeTag);
@@ -972,6 +1029,44 @@ void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title
param.timePerPage, param.margin, param.htmlScale);
}
+void HTMLWriter::write(gdioutput& gdi, ostream& fout, const wstring& title, int refresh, oListParam& param, const oEvent& oe) {
+ write(gdi, fout, title, true, L"", param.getContentsDescriptor(oe), param.pageBreak, param.htmlTypeTag,
+ refresh != 0 ? refresh : param.timePerPage / 1000, param.htmlRows, param.nColumns,
+ param.timePerPage, param.margin, param.htmlScale);
+}
+
void HTMLWriter::getPage(const oEvent &oe, string &out) const {
out = page;
-}
\ No newline at end of file
+}
+
+void HTMLWriter::ImageWriter::write(ostream& fout, const string& xp, const string& yp, const wstring& img, int width, int height) {
+ if (!writeImages) {
+ if (xp.empty())
+ fout << " ";
+ }
+ else {
+ if (img.empty() || img[0] != 'L')
+ throw meosException("Unsupported image");
+ uint64_t imgId = _wcstoui64(img.c_str() + 1, nullptr, 10);
+
+ if (!savedFiles.count(imgId)) {
+ if (!destination.empty()) {
+ auto& data = image.getRawData(imgId);
+ wstring d = destination + img + L".png";
+ ofstream out(d, ofstream::out | ofstream::binary);
+ out.write((const char *)data.data(), data.size());
+ savedFiles[imgId] = "L" + itos(imgId) + ".png";
+ }
+ else {
+ savedFiles[imgId] = "/meos?image=ID" + itos(imgId) + ".png";
+ }
+ }
+ string style;
+ if (xp.size() > 0)
+ style = " style=\"position:absolute;left:" + xp + "px;top:" + yp + "px\"";
+
+ fout << "
";
+
+ }
+}
diff --git a/code/HTMLWriter.h b/code/HTMLWriter.h
index c8c1c9b..dd8e401 100644
--- a/code/HTMLWriter.h
+++ b/code/HTMLWriter.h
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,6 +39,29 @@ class HTMLWriter {
static string localize(const string &in);
+
+ class ImageWriter {
+ wstring destination;
+ const bool writeImages;
+ const wstring imageDirectoryDestination;
+ map savedFiles;
+ public:
+ ImageWriter(const wstring& dst, bool writeImages) : destination(dst), writeImages(writeImages) {}
+
+
+ void write(ostream &fout, const string &xp, const string &yp, const wstring &img, int width, int height);
+ };
+
+ template
+ static void formatTL(ostream& fout,
+ ImageWriter& imageWriter,
+ const map< pair, pair >& styles,
+ const T& tl,
+ double& yscale,
+ double& xscale,
+ int& offsetY,
+ int& offsetX);
+
public:
static void reset() {
@@ -76,10 +99,15 @@ public:
void getPage(const oEvent &oe, string &out) const;
- static void writeHTML(gdioutput &gdi, ostream &dout, const wstring &title, int refreshTimeOut, double scale);
+ static void writeHTML(gdioutput &gdi, ostream &dout, const wstring &title,
+ bool includeImages,
+ const wstring& imageDirectoryDestination,
+ int refreshTimeOut, double scale);
static void writeTableHTML(gdioutput &gdi, ostream &fout,
const wstring &title,
+ bool includeImages,
+ const wstring &imageDirectoryDestination,
bool simpleFormat,
int refreshTimeOut,
double scale);
@@ -92,23 +120,17 @@ public:
static void writeHTML(gdioutput &gdi, const wstring &file,
const wstring &title, int refreshTimeOut, double scale);
- static void write(gdioutput &gdi, const wstring &file, const wstring &title, const wstring &contentsDescription,
- bool respectPageBreak, const string &typeTag, int refresh,
- int rows, int cols, int time_ms, int margin, double scale);
+ static void write(gdioutput& gdi, const wstring& file, const wstring& title, int refresh, oListParam& param, const oEvent& oe);
+ static void write(gdioutput& gdi, ostream& fout, const wstring& title, int refresh, oListParam& param, const oEvent& oe);
- static void write(gdioutput &gdi, ostream &fout, const wstring &title, const wstring &contentsDescription,
- bool respectPageBreak, const string &typeTag, int refresh,
- int rows, int cols, int time_ms, int margin, double scale);
-
- static void write(gdioutput &gdi, const wstring &file, const wstring &title, int refresh, oListParam ¶m, const oEvent &oe);
-
- template
- static void formatTL(ostream &fout,
- const map< pair, pair > &styles,
- const T &tl,
- double &yscale,
- double &xscale,
- int &offsetY,
- int &offsetX);
+ static void write(gdioutput& gdi, const wstring& file, const wstring& title, const wstring& contentsDescription,
+ bool respectPageBreak, const string& typeTag, int refresh,
+ int rows, int cols, int time_ms, int margin, double scale);
+ static void write(gdioutput& gdi, ostream& fout, const wstring& title,
+ bool includeImages,
+ const wstring& imageDirectoryDestination,
+ const wstring& contentsDescription,
+ bool respectPageBreak, const string& typeTag, int refresh,
+ int rows, int cols, int time_ms, int margin, double scale);
};
\ No newline at end of file
diff --git a/code/MeOSFeatures.cpp b/code/MeOSFeatures.cpp
index 0195120..119142d 100644
--- a/code/MeOSFeatures.cpp
+++ b/code/MeOSFeatures.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/MeOSFeatures.h b/code/MeOSFeatures.h
index baeb596..29d8303 100644
--- a/code/MeOSFeatures.h
+++ b/code/MeOSFeatures.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/MeosSQL.cpp b/code/MeosSQL.cpp
index de7939d..02e4d31 100644
--- a/code/MeosSQL.cpp
+++ b/code/MeosSQL.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -99,6 +99,11 @@ string C_INT64(string name)
return " "+name+" BIGINT NOT NULL DEFAULT 0, ";
}
+string C_UINT64(string name)
+{
+ return " " + name + " BIGINT UNSIGNED NOT NULL DEFAULT 0, ";
+}
+
string C_STRING(string name, int len=64)
{
char bf[16];
@@ -451,8 +456,21 @@ void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) {
sql = sql.substr(0, sql.length() - 2);
query.execute(sql);
}
+ if (!eCol.count("BDate")) {
+ string sql = "ALTER TABLE " + db + " ";
+ sql += "ADD COLUMN " + C_INT("BDate");
+ sql = sql.substr(0, sql.length() - 2);
+ query.execute(sql);
+ }
+ }
+ else if (db == "oPunch") {
+ if (!eCol.count("Unit")) {
+ string sql = "ALTER TABLE " + db + " ";
+ sql += "ADD COLUMN " + C_INT("Unit");
+ sql = sql.substr(0, sql.length() - 2);
+ query.execute(sql);
+ }
}
-
if (dc) {
// Ugrade table
string sqlAdd = dc->generateSQLDefinition(eCol);
@@ -478,7 +496,8 @@ bool MeosSQL::openDB(oEvent *oe)
return 0;
}
monitorId = 0;
- string dbname(oe->currentNameId.begin(), oe->currentNameId.end());//WCS
+ string dbname(oe->currentNameId.begin(), oe->currentNameId.end());
+ bool tookLock = false;
try {
auto query = con->query();
@@ -489,11 +508,29 @@ bool MeosSQL::openDB(oEvent *oe)
auto row = res.at(0);
int version = row["Version"];
-
if (version < oEvent::dbVersion) {
+ if (version <= 88) {
+ query.exec("LOCK TABLE MeOSMain.oEvent WRITE");
+ tookLock = true;
+
+ query.reset();
+ query << "SELECT Version FROM oEvent WHERE NameId=" << quote << dbname;
+ auto resV = query.store();
+ if (res && res.num_rows() >= 1) {
+ version = res.at(0)["Version"];
+ }
+ }
+
query.reset();
query << "UPDATE oEvent SET Version=" << oEvent::dbVersion << " WHERE Id=" << int(row["Id"]);
query.execute();
+ if (version <= 88) {
+ upgradeTimeFormat(dbname);
+ }
+
+ if (tookLock) {
+ con->query().exec("UNLOCK TABLES");
+ }
}
else if (version > oEvent::dbVersion) {
alert("A newer version av MeOS is required.");
@@ -524,6 +561,10 @@ bool MeosSQL::openDB(oEvent *oe)
}
}
catch (const Exception& er) {
+ if (tookLock && con) {
+ con->query().exec("UNLOCK TABLES");
+ }
+
setDefaultDB();
alert(string(er.what()) + " MySQL Error. Select DB.");
return 0;
@@ -588,6 +629,7 @@ bool MeosSQL::openDB(oEvent *oe)
<< C_INT("CardNo")
<< C_UINT("ReadId")
<< C_UINT("Voltage")
+ << C_INT("BDate")
<< C_STRING("Punches", 16*190) << C_END();
query.execute();
@@ -657,9 +699,12 @@ bool MeosSQL::openDB(oEvent *oe)
query << C_START("oPunch")
<< C_INT("CardNo")
<< C_INT("Time")
- << C_INT("Type") << C_END();
+ << C_INT("Type")
+ << C_INT("Unit") << C_END();
query.execute();
+ upgradeDB("oPunch", nullptr);
+
query.reset();
query << C_START("oMonitor")
<< C_STRING("Client")
@@ -691,6 +736,13 @@ bool MeosSQL::openDB(oEvent *oe)
// Create runner/club DB
createRunnerDB(oe, query);
+
+ query.reset();
+ query << C_START_noid("oImage")
+ << C_UINT64("Id")
+ << C_TEXT("Filename")
+ << " Image LONGBLOB)" << engine();
+ query.execute();
}
catch (const Exception& er){
alert(string(er.what()) + " MySQL Error.");
@@ -979,9 +1031,9 @@ OpFailStatus MeosSQL::uploadRunnerDB(oEvent *oe)
auto query = con->query();
query << "INSERT INTO dbRunner SET " <<
"Name=" << quote << rdb[k].name <<
- ", ExtId=" << rdb[k].extId << ", Club=" << rdb[k].clubNo <<
+ ", ExtId=" << rdb[k].getExtId() << ", Club=" << rdb[k].clubNo <<
", CardNo=" << rdb[k].cardNo << ", Sex=" << quote << rdb[k].getSex() <<
- ", Nation=" << quote << rdb[k].getNationality() << ", BirthYear=" << rdb[k].birthYear;
+ ", Nation=" << quote << rdb[k].getNationality() << ", BirthYear=" << rdb[k].getBirthDateInt();
try {
query.execute();
@@ -1031,7 +1083,7 @@ bool MeosSQL::storeData(oDataInterface odi, const RowWrapper &row, unsigned long
}
}
else {
- __int64 val = row[(const char*)it_int->name].ulonglong();
+ __int64 val = row[(const char*)it_int->name].longlong();
__int64 oldVal = *(it_int->data64);
if (val != oldVal) {
memcpy(it_int->data64, &val, 8);
@@ -1476,7 +1528,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
RunnerDBEntry &dbn = db->dbe();
if (sex.length()==1)
dbn.sex = sex[0];
- dbn.birthYear = short(atoi(birth.c_str()));
+ dbn.setBirthDate(atoi(birth.c_str()));
if (nat.length()==3) {
dbn.national[0] = nat[0];
@@ -1546,6 +1598,7 @@ void MeosSQL::storeCard(const RowWrapper &row, oCard &c)
c.cardNo = row["CardNo"];
c.readId = row["ReadId"];
c.miliVolt = row["Voltage"];
+ c.batteryDate = row["BDate"];
c.importPunches(string(row["Punches"]));
c.sqlUpdated = row["Modified"];
@@ -1565,10 +1618,10 @@ void MeosSQL::storePunch(const RowWrapper &row, oFreePunch &p, bool rehash)
}
else {
p.CardNo = row["CardNo"];
- p.Time = row["Time"];
- p.Type = row["Type"];
+ p.punchTime = row["Time"];
+ p.type = row["Type"];
}
-
+ p.punchUnit = row["Unit"];
p.sqlUpdated = row["Modified"];
p.counter = row["Counter"];
p.Removed = row["Removed"];
@@ -2178,6 +2231,7 @@ OpFailStatus MeosSQL::syncUpdate(oCard *c, bool forceWriteAll)
auto queryset = con->query();
queryset << " CardNo=" << c->cardNo
<< ", ReadId=" << c->readId << ", Voltage=" << max(0, c->miliVolt)
+ << ", BDate=" << c->batteryDate
<< ", Punches=" << quote << c->getPunchString();
return syncUpdate(queryset, "oCard", c);
@@ -2287,6 +2341,77 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t)
return syncRead(forceRead, t, true);
}
+void MeosSQL::upgradeTimeFormat(const string & dbname) {
+ bool ok = false;
+ try {
+ con->select_db(dbname);
+ ok = true;
+ }
+ catch (const Exception &) {
+ }
+
+ if (ok) {
+ auto query = con->query();
+ query.exec("LOCK TABLES oEvent WRITE, oClass WRITE, oControl WRITE, "
+ "oCourse WRITE, oPunch WRITE, oRunner WRITE, oTeam WRITE");
+ }
+ else
+ return;
+
+ auto upgradeCol = [this](const string &db, const string &col) {
+ auto query = con->query();
+ string v = "UPDATE " + db + " SET " + col + "=" + col + "*10 WHERE " + col + "<>-1";
+ try {
+ query.execute(v);
+ }
+ catch (const Exception &) {
+ return false;
+ }
+ return true;
+ };
+
+ auto alter = [this](const string &db, const string &col) {
+ auto query = con->query();
+ string v = "ALTER TABLE " + db + " MODIFY COLUMN " + col + " INT NOT NULL DEFAULT 0";
+ try {
+ query.execute(v);
+ }
+ catch (const Exception &) {
+ return false;
+ }
+ return true;
+
+ };
+ upgradeCol("oEvent", "ZeroTime");
+ upgradeCol("oEvent", "MaxTime");
+ upgradeCol("oEvent", "DiffTime");
+
+ upgradeCol("oClass", "FirstStart");
+ upgradeCol("oClass", "StartInterval");
+ upgradeCol("oClass", "MaxTime");
+
+ upgradeCol("oControl", "TimeAdjust");
+ upgradeCol("oControl", "MinTime");
+
+ upgradeCol("oCourse", "RTimeLimit");
+
+ upgradeCol("oPunch", "Time");
+
+ upgradeCol("oRunner", "StartTime");
+ upgradeCol("oRunner", "FinishTime");
+ upgradeCol("oRunner", "InputTime");
+ alter("oRunner", "TimeAdjust");
+ upgradeCol("oRunner", "TimeAdjust");
+ upgradeCol("oRunner", "EntryTime");
+
+ upgradeCol("oTeam", "StartTime");
+ upgradeCol("oTeam", "FinishTime");
+ upgradeCol("oTeam", "InputTime");
+ alter("oTeam", "TimeAdjust");
+ upgradeCol("oTeam", "TimeAdjust");
+ upgradeCol("oTeam", "EntryTime");
+}
+
OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t, bool readRecursive)
{
errorMessage.clear();
@@ -2536,7 +2661,7 @@ OpFailStatus MeosSQL::syncReadControls(oEvent *oe, const set &controls) {
int counter = row["Counter"];
string modified = row["Modified"];
- pControl pc = oe->getControl(id, false);
+ pControl pc = oe->getControl(id, false, false);
if (!pc) {
oControl oc(oe, id);
success = min(success, syncRead(true, &oc));
@@ -2550,7 +2675,7 @@ OpFailStatus MeosSQL::syncReadControls(oEvent *oe, const set &controls) {
// processedCourses should now be empty, unless there are local controls not yet added.
for(set::iterator it = processedControls.begin(); it != processedControls.end(); ++it) {
- pControl pc = oe->getControl(*it, false);
+ pControl pc = oe->getControl(*it, false, false);
if (pc) {
success = min(success, syncUpdate(pc, true));
}
@@ -2647,7 +2772,7 @@ OpFailStatus MeosSQL::syncUpdate(oControl *c, bool forceWriteAll) {
auto queryset = con->query();
queryset << " Name=" << quote << toString(c->Name) << ", "
<< " Numbers=" << quote << toString(c->codeNumbers()) << ","
- << " Status=" << c->Status
+ << " Status=" << int(c->Status)
<< c->getDI().generateSQLSet(forceWriteAll);
return syncUpdate(queryset, "oControl", c);
@@ -2826,8 +2951,9 @@ OpFailStatus MeosSQL::syncUpdate(oFreePunch *c, bool forceWriteAll)
}
auto queryset = con->query();
queryset << " CardNo=" << c->CardNo << ", "
- << " Type=" << c->Type << ","
- << " Time=" << c->Time;
+ << " Type=" << c->type << ","
+ << " Time=" << c->punchTime << ","
+ << " Unit=" << c->punchUnit;
return syncUpdate(queryset, "oPunch", c);
}
@@ -2974,38 +3100,55 @@ OpFailStatus MeosSQL::syncUpdate(QueryWrapper &updateqry,
if (ob->isRemoved())
return opStatusOK;
bool setId = false;
-
+ bool update = false;
if (ob->Id > 0) {
- query << "SELECT Id FROM " << oTable << " WHERE Id=" << ob->Id;
+ query << "SELECT Removed FROM " << oTable << " WHERE Id=" << ob->Id;
auto res=query.store();
if (res.empty())
setId = true;
else if (ob->isImplicitlyCreated()) {
return opStatusWarning;//XXX Should we read this object?
}
+ else {
+ int removed = res.at(0).at(0);
+ if (removed) {
+ update = true;
+ }
+ }
}
else {
assert(!ob->isImplicitlyCreated());
}
query.reset();
- query << "INSERT INTO " << oTable << " SET " << updateqry.str();
+ if (update) {
+ query << "UPDATE " << oTable << " SET Removed = 0, " << updateqry.str();
+ }
+ else {
+ query << "INSERT INTO " << oTable << " SET " << updateqry.str();
- if (setId)
- query << ", Id=" << ob->Id;
+ if (setId)
+ query << ", Id=" << ob->Id;
+ }
if (writeTime) {
query << ", Modified='" << ob->getTimeStampN() << "'";
}
+ if (update) {
+ query << " WHERE Id=" << ob->Id;
+ }
+
ResNSel res=query.execute();
if (res) {
- if (ob->Id > 0 && ob->Id!=(int)res.insert_id) {
- ob->correctionNeeded = true;
- }
+ if (!update) {
+ if (ob->Id > 0 && ob->Id != (int)res.insert_id) {
+ ob->correctionNeeded = true;
+ }
- if (ob->Id != res.insert_id)
- ob->changeId((int)res.insert_id);
+ if (ob->Id != res.insert_id)
+ ob->changeId((int)res.insert_id);
+ }
updateCounter(oTable, ob->Id, 0);
ob->oe->updateFreeId(ob);
@@ -3059,8 +3202,12 @@ OpFailStatus MeosSQL::syncUpdate(QueryWrapper &updateqry,
bool MeosSQL::checkOldVersion(oEvent *oe, RowWrapper &row) {
int dbv=int(row["BuildVersion"]);
- if ( dbvupdateChanged();
+ if (dbv < buildVersion) {
+ string bv = "UPDATE oEvent SET BuildVersion=if (BuildVersion<" +
+ itos(buildVersion) + "," + itos(buildVersion) + ",BuildVersion) WHERE Id = " + itos(oe->Id);
+
+ con->query().exec(bv);
+ }
else if (dbv>buildVersion)
return true;
@@ -3552,7 +3699,7 @@ bool MeosSQL::syncListControl(oEvent *oe) {
if (int(row["Removed"])) {
st = opStatusOK;
- oControl *c = oe->getControl(Id, false);
+ oControl *c = oe->getControl(Id, false, false);
if (c && !c->Removed) {
c->Removed = true;
@@ -3562,7 +3709,7 @@ bool MeosSQL::syncListControl(oEvent *oe) {
}
}
else {
- oControl *c = oe->getControl(Id, false);
+ oControl *c = oe->getControl(Id, false, false);
if (c) {
if (isOld(counter, modified, c))
st = syncRead(false, c);
@@ -3848,11 +3995,12 @@ bool MeosSQL::dropDatabase(oEvent *oe)
return 0;
}
+ string error;
try {
con->drop_db(CmpDataBase);
}
- catch (const Exception& ) {
- //Don't care if we fail.
+ catch (const Exception& ex) {
+ error = ex.what();
}
try {
@@ -3860,7 +4008,10 @@ bool MeosSQL::dropDatabase(oEvent *oe)
query << "DELETE FROM oEvent WHERE NameId=" << quote << CmpDataBase;
query.execute();
}
- catch (const Exception& ) {
+ catch (const Exception& ex) {
+ if (!error.empty())
+ error += ", ";
+ error += ex.what();
//Don't care if we fail.
}
@@ -3874,6 +4025,9 @@ bool MeosSQL::dropDatabase(oEvent *oe)
catch (const Exception&) {
}
+ if (!error.empty())
+ throw meosException(error);
+
return true;
}
@@ -3930,7 +4084,9 @@ int getTypeId(const oBase &ob)
}
static int skipped = 0, notskipped = 0, readent = 0;
-void MeosSQL::synchronized(const oBase &entity) {
+void MeosSQL::synchronized(oBase &entity) {
+ entity.Modified.setStamp(entity.sqlUpdated);
+
int id = getTypeId(entity);
readTimes[make_pair(id, entity.getId())] = GetTickCount();
readent++;
@@ -4460,3 +4616,96 @@ OpFailStatus MeosSQL::synchronizeUpdate(oBase *obj) {
return OpFailStatus::opStatusFail;
}
+OpFailStatus MeosSQL::enumerateImages(vector>& images) {
+ try {
+ auto query = con->query();
+ images.clear();
+ auto res = query.store("SELECT Id, Filename FROM oImage");
+ if (res) {
+ for (int i = 0; i < res.num_rows(); i++) {
+ auto row = res.at(i);
+ wstring fileName = fromUTF((string)row["Filename"]);
+ uint64_t id = row["Id"].ulonglong();
+ images.emplace_back(fileName, id);
+ }
+ }
+ }
+ catch (const Exception& ) {
+ return OpFailStatus::opStatusFail;
+ }
+
+ return OpFailStatus::opStatusOK;
+}
+
+OpFailStatus MeosSQL::getImage(uint64_t id, wstring& fileName, vector& data) {
+ try {
+ auto query = con->query();
+ auto res = query.store("SELECT * FROM oImage WHERE id=" + itos(id));
+ if (res && res.num_rows() > 0) {
+ auto row = res.at(0);
+ fileName = fromUTF((string)row["Filename"]);
+ row["Image"].storeBlob(data);
+ return OpFailStatus::opStatusOK;
+ }
+ }
+ catch (const Exception&) {
+ }
+
+ return OpFailStatus::opStatusFail;
+}
+
+string hexEncode(const vector& data) {
+ string out;
+ out.reserve(4 + data.size() * 2);
+ out.append("X'");
+
+ char table[17] = "0123456789ABCDEF";
+ char block[33];
+ block[32] = 0;
+
+ for (int j = 0; j < data.size();) {
+ if (j + 16 < data.size()) {
+ for (int i = 0; i < 32; ) {
+ uint8_t b = data[j];
+ int bLow = b & 0xF;
+ int bHigh = (b >> 4) & 0xF;
+ block[i++] = table[bHigh];
+ block[i++] = table[bLow];
+ j++;
+ }
+ }
+ else {
+ int i = 0;
+ while (j < data.size()) {
+ uint8_t b = data[j];
+ int bLow = b & 0xF;
+ int bHigh = (b >> 4) & 0xF;
+ block[i++] = table[bHigh];
+ block[i++] = table[bLow];
+ j++;
+ }
+ block[i] = 0;
+ }
+
+ out.append(block);
+ }
+ out.append("'");
+ return out;
+}
+
+OpFailStatus MeosSQL::storeImage(uint64_t id, const wstring& fileName, const vector& data) {
+ try {
+ auto query = con->query();
+ auto res = query.store("SELECT Id FROM oImage WHERE Id=" + itos(id));
+ if (res.empty()) {
+ query << ("INSERT INTO oImage SET Id=" + itos(id) + ", Filename=")
+ << quote << toString(fileName) << ", Image=" << hexEncode(data);
+ query.execute();
+ }
+ }
+ catch (Exception &) {
+ return OpFailStatus::opStatusFail;
+ }
+
+ return OpFailStatus::opStatusOK;
+}
diff --git a/code/MeosSQL.h b/code/MeosSQL.h
index 55b6290..fccd011 100644
--- a/code/MeosSQL.h
+++ b/code/MeosSQL.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -131,7 +131,7 @@ protected:
bool checkOldVersion(oEvent *oe, RowWrapper &row);
map, DWORD> readTimes;
- void synchronized(const oBase &entity);
+ void synchronized(oBase &entity);
bool skipSynchronize(const oBase &entity) const;
ResNSel updateCounter(const char *oTable, int id, QueryWrapper *updateqry);
@@ -186,9 +186,14 @@ protected:
OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll);
OpFailStatus syncRead(bool forceRead, oTeam *t);
+ void upgradeTimeFormat(const string &dbname);
public:
+ OpFailStatus enumerateImages(vector>& images);
+ OpFailStatus getImage(uint64_t id, wstring &fileName, vector &data);
+ OpFailStatus storeImage(uint64_t id, const wstring& fileName, const vector& data);
+
bool synchronizeList(oEvent *oe, oListId lid);
OpFailStatus synchronizeUpdate(oBase *obj);
diff --git a/code/Printer.h b/code/Printer.h
index db7b7fb..53bb1d5 100644
--- a/code/Printer.h
+++ b/code/Printer.h
@@ -4,7 +4,7 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/RestService.cpp b/code/RestService.cpp
index 73c3358..6c20fd1 100644
--- a/code/RestService.cpp
+++ b/code/RestService.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/RestService.h b/code/RestService.h
index eebbe3b..2310cf4 100644
--- a/code/RestService.h
+++ b/code/RestService.h
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
-Copyright (C) 2009-2022 Melin Software HB
+Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/RunnerDB.cpp b/code/RunnerDB.cpp
index 9de2948..85186b7 100644
--- a/code/RunnerDB.cpp
+++ b/code/RunnerDB.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -237,12 +237,12 @@ wstring RunnerWDBEntry::getFamilyName() const
__int64 RunnerWDBEntry::getExtId() const
{
- return dbe().extId;
+ return dbe().getExtId();
}
void RunnerWDBEntry::setExtId(__int64 id)
{
- dbe().extId = id;
+ dbe().setExtId(id);
}
void RunnerDBEntryV2::init(const RunnerDBEntryV1 &dbe)
@@ -303,7 +303,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const wchar_t *name,
en.cardNo = card;
en.clubNo = club;
e.setName(name);
- en.extId = extId;
+ en.setExtId(extId);
if (!check(en) ) {
rdb.pop_back();
@@ -336,7 +336,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const char *nameUTF,
en.cardNo = card;
en.clubNo = club;
e.setNameUTF(nameUTF);
- en.extId = extId;
+ en.setExtId(extId);
if (!check(en) ) {
rdb.pop_back();
@@ -550,16 +550,16 @@ RunnerWDBEntry *RunnerDB::getRunnerByName(const wstring &name, int clubId,
int bestYear = 0;
for (size_t k = 0;k0)
return (RunnerWDBEntry *)&rwdb[bestMatch];
}
- return 0;
+ return nullptr;
}
void RunnerDB::setupIdHash() const
@@ -569,7 +569,7 @@ void RunnerDB::setupIdHash() const
for (size_t k=0; k &clubIdMap)
if (dbe == nullptr) {
dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo());
if (dbe)
- dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
+ dbe->dbe().setBirthYear(r.getDCI().getInt("BirthYear"));
}
else {
if (dbe->getExtId() == 0) { // Only update entries not in national db.
dbe->setName(r.getName().c_str());
dbe->dbe().clubNo = localClubId;
- dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
+ dbe->dbe().setBirthYear(r.getDCI().getInt("BirthYear"));
}
}
}
@@ -1251,13 +1251,13 @@ const shared_ptr &RunnerDB::getRunnerTB() {
auto table = make_shared(oe, 20, L"Löpardatabasen", "runnerdb");
table->addColumn("Index", 70, true, true);
- table->addColumn("Id", 70, true, true);
+ table->addColumn("Externt Id", 70, true, true);
table->addColumn("Namn", 200, false);
table->addColumn("Klubb", 200, false);
table->addColumn("SI", 70, true, true);
table->addColumn("Nationalitet", 70, false, true);
table->addColumn("Kön", 50, false, true);
- table->addColumn("Födelseår", 70, true, true);
+ table->addColumn("RunnerBirthDate", 70, true, true);
table->addColumn("Anmäl", 120, false, true);
table->setTableProp(Table::CAN_INSERT|Table::CAN_DELETE|Table::CAN_PASTE);
@@ -1330,8 +1330,8 @@ void RunnerDB::refreshRunnerTableData(Table &table) {
bool found = false;
pRunner r = nullptr;
- if (rdb[k].extId != 0)
- found = runnerInEvent.lookup(rdb[k].extId, runnerId);
+ if (rdb[k].getExtId() != 0)
+ found = runnerInEvent.lookup(rdb[k].getExtId(), runnerId);
else if (rdb[k].cardNo != 0) {
found = runnerInEvent.lookup(rdb[k].cardNo + cardIdConstant, runnerId);
if (found) {
@@ -1404,8 +1404,8 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
table.set(row++, it, TID_INDEX, itow(index+1), false, cellEdit);
wchar_t bf[16];
- oBase::converExtIdentifierString(rn.extId, bf);
- table.set(row++, it, TID_ID, bf, false, cellEdit);
+ oBase::converExtIdentifierString(rn.getExtId(), bf);
+ table.set(row++, it, TID_ID, bf, canEdit, cellEdit);
r.initName();
table.set(row++, it, TID_NAME, r.name, canEdit, cellEdit);
@@ -1421,14 +1421,14 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
table.set(row++, it, TID_NATIONAL, nat, canEdit, cellEdit);
wchar_t sex[2] = {wchar_t(rn.sex), 0};
table.set(row++, it, TID_SEX, sex, canEdit, cellEdit);
- table.set(row++, it, TID_YEAR, itow(rn.birthYear), canEdit, cellEdit);
+ table.set(row++, it, TID_YEAR, rn.getBirthDate(), canEdit, cellEdit);
int runnerId;
bool found = false;
pRunner cr = nullptr;
- if (rn.extId != 0)
- found = db->runnerInEvent.lookup(rn.extId, runnerId);
+ if (rn.getExtId() != 0)
+ found = db->runnerInEvent.lookup(rn.getExtId(), runnerId);
else if (rn.cardNo != 0) {
found = db->runnerInEvent.lookup(rn.cardNo + cardIdConstant, runnerId);
if (found) {
@@ -1467,8 +1467,29 @@ pair oDBRunnerEntry::inputData(int id, const wstring &input,
throw meosException("Not initialized");
RunnerWDBEntry &r = db->rwdb[index];
RunnerDBEntry &rd = db->rdb[index];
+ static bool hasWarnedId = false;
switch(id) {
+ case TID_ID: {
+ wchar_t bf[16];
+ auto key = oBase::converExtIdentifierString(input);
+ oBase::converExtIdentifierString(key, bf);
+
+ if (compareStringIgnoreCase(bf, input)) {
+ throw meosException(L"Cannot represent ID X#" + input);
+ }
+
+ if (key != r.getExtId() && !hasWarnedId) {
+ if (oe->gdiBase().askOkCancel(L"warn:changeid") == gdioutput::AskAnswer::AnswerCancel)
+ throw meosCancel();
+ hasWarnedId = true;
+ }
+
+ r.setExtId(key);
+ db->idhash.clear();
+ output = bf;
+ }
+ break;
case TID_NAME:
r.setName(input.c_str());
r.getName(output);
@@ -1503,8 +1524,8 @@ pair oDBRunnerEntry::inputData(int id, const wstring &input,
output = r.getSex();
break;
case TID_YEAR:
- rd.birthYear = short(_wtoi(input.c_str()));
- output = itow(r.getBirthYear());
+ rd.setBirthDate(input);
+ output = rd.getBirthDate();
break;
case TID_CLUB:
@@ -1529,7 +1550,7 @@ void oDBRunnerEntry::fillInput(int id, vector< pair > &out, siz
void oDBRunnerEntry::remove() {
RunnerWDBEntry &r = db->rwdb[index];
r.remove();
- db->idhash.remove(r.dbe().extId);
+ db->idhash.remove(r.dbe().getExtId());
wstring cname(canonizeName(r.name));
multimap::const_iterator it = db->nhash.find(cname);
@@ -1823,6 +1844,20 @@ vector> RunnerDB::getRunnerSuggestions(const wstring
else
setupAutoCompleteHash(AutoHashMode::Runners);
+ // Check if database key
+ int64_t id = 0;
+ for (int j = 0; j < key.length(); j++) {
+ if (key[j] >= '0' && key[j] <= '9') {
+ id = oBase::converExtIdentifierString(key);
+ wchar_t bf[16];
+ oBase::converExtIdentifierString(id, bf);
+ if (compareStringIgnoreCase(key, bf))
+ id = 0;
+
+ break;
+ }
+ }
+
vector< pair > outOrder;
set> ix;
wchar_t bf[256];
@@ -1866,8 +1901,15 @@ vector> RunnerDB::getRunnerSuggestions(const wstring
if (res != runnerHash.end())
res->second.match(*this, ix, nameParts);
}
-
}
+
+ if (id > 0) {
+ auto r = getRunnerById(id);
+ if (r) {
+ ix.emplace(1000, r->getIndex());
+ }
+ }
+
if (ix.empty())
return ret;
@@ -1896,3 +1938,85 @@ vector> RunnerDB::getRunnerSuggestions(const wstring
}
return ret;
}
+
+const wstring& RunnerDBEntry::getBirthDate() const {
+ int year = getBirthYear();
+ if (year <= 0 || year>9999)
+ return _EmptyWString;
+
+ int month = getBirthMonth();
+ if (month > 0 && month <= 12) {
+ int day = getBirthDay();
+ if (day > 0 && day <= 31) {
+ wchar_t bf[16];
+ swprintf_s(bf, L"%d-%02d-%02d", year, month, day);
+ wstring& res = StringCache::getInstance().wget();
+ res = bf;
+ return res;
+ }
+ }
+ return itow(year);
+}
+
+void RunnerDBEntry::setBirthDate(const wstring& in) {
+ SYSTEMTIME st;
+ if (convertDateYMS(in, st, true) > 0) {
+ setBirthYear(st.wYear);
+ setBirthMonth(st.wMonth);
+ setBirthDay(st.wDay);
+ }
+ else {
+ int year = _wtoi(in.c_str());
+ if (year > 1900 && year < 9999)
+ setBirthYear(year);
+ else
+ setBirthYear(0);
+
+ setBirthMonth(0);
+ setBirthDay(0);
+ }
+}
+
+void RunnerDBEntry::setBirthDate(int dateOrYear) {
+ if (dateOrYear > 0 && dateOrYear < 100)
+ dateOrYear = extendYear(dateOrYear);
+
+ if ((dateOrYear > 1900 && dateOrYear < 9999) || dateOrYear == 0) {
+ setBirthYear(dateOrYear);
+ setBirthMonth(0);
+ setBirthDay(0);
+ return;
+ }
+ int d = dateOrYear % 100;
+ dateOrYear /= 100;
+
+ int m = dateOrYear % 100;
+ dateOrYear /= 100;
+
+ int y = extendYear(dateOrYear);
+ if (d > 0 && d <= 31 && m > 0 && m <= 12 && y > 1900 && y < 9999) {
+ setBirthYear(y);
+ setBirthMonth(m);
+ setBirthDay(d);
+ }
+ else if (y > 1900 && y < 9999) {
+ setBirthYear(y);
+ }
+ else {
+ setBirthYear(0);
+ setBirthMonth(0);
+ setBirthDay(0);
+ }
+}
+
+int RunnerDBEntry::getBirthDateInt() const {
+ int y = getBirthYear();
+ int m = getBirthMonth();
+ int d = getBirthDay();
+
+ if (y > 0 && y < 9999 && m > 0 && d > 0)
+ return y * 10000 + m * 100 + d;
+ else
+ return y;
+}
+
diff --git a/code/RunnerDB.h b/code/RunnerDB.h
index c75b5a9..e7750e8 100644
--- a/code/RunnerDB.h
+++ b/code/RunnerDB.h
@@ -11,7 +11,7 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -97,11 +97,13 @@ struct RunnerDBEntry {
int clubNo;
char national[3];
char sex;
+private:
short int birthYear;
short int reserved;
/** End of V1*/
__int64 extId;
+public:
bool isRemoved() const { return (reserved & 1) == 1; }
void remove() { reserved |= 1; }
@@ -111,6 +113,22 @@ struct RunnerDBEntry {
bool operator==(const RunnerDBEntry &d) const {
return memcmp(this, &d, sizeof(RunnerDBEntry)) == 0;
}
+
+ int getBirthYear() const { return birthYear; }
+ int getBirthMonth() const { return (reserved >> 2) & 0xF; }// 4 bits
+ int getBirthDay() const { return (reserved >> 6) & 0x1F; } // 5 bits
+
+ void setBirthYear(int year) { birthYear = year; }
+ void setBirthMonth(int month) { reserved = (reserved & (~(0xF << 2))) | ((0xF & month) << 2); }// 4 bits
+ void setBirthDay(int day) { reserved = (reserved & (~(0x1F << 6))) | ((0x1F & day) << 6); } // 5 bits
+
+ const wstring& getBirthDate() const;
+ void setBirthDate(const wstring& in);
+ void setBirthDate(int dateOrYear);
+ int getBirthDateInt() const;
+
+ void setExtId(__int64 id) { extId = id; }
+ __int64 getExtId() const { return extId; }
};
class RunnerDB;
@@ -125,6 +143,8 @@ public:
void init(RunnerDB *p, size_t ix);
RunnerWDBEntry();
+ size_t getIndex() const { return ix; }
+
// Link to narrow DB Entry
const RunnerDBEntry &dbe() const;
RunnerDBEntry &dbe();
@@ -145,14 +165,14 @@ public:
wstring getFamilyName() const;
wstring getNationality() const;
- int getBirthYear() const {return dbe().birthYear;}
+ int getBirthYear() const {return dbe().getBirthYear(); }
wstring getSex() const;
__int64 getExtId() const;
void setExtId(__int64 id);
- bool isRemoved() const {return (dbe().reserved & 1) == 1;}
- void remove() {dbe().reserved |= 1;}
+ bool isRemoved() const { return dbe().isRemoved(); }
+ void remove() { dbe().remove(); }
};
typedef vector RunnerDBVector;
diff --git a/code/SportIdent.cpp b/code/SportIdent.cpp
index 0a05bec..3f20b51 100644
--- a/code/SportIdent.cpp
+++ b/code/SportIdent.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -46,11 +46,11 @@
//#define DEBUG_SI
SI_StationData::SI_StationData() {
- stationNumber=0;
- stationMode=0;
- extended=false;
- handShake=false;
- autoSend=false;
+ stationNumber = 0;
+ stationMode = 0;
+ extended = false;
+ handShake = false;
+ autoSend = false;
radioChannel = 0;
}
@@ -64,19 +64,28 @@ SI_StationInfo::SI_StationInfo()
localZeroTime=0;
}
-SportIdent::SportIdent(HWND hWnd, DWORD Id, bool readVoltage) : readVoltage(readVoltage)
-{
- ClassId=Id;
- hWndNotify=hWnd;
+SportIdent::SportIdent(HWND hWnd, DWORD Id, bool readVoltage) : readVoltage(readVoltage) {
+ ClassId = Id;
+ hWndNotify = hWnd;
- //hComm=0;
- //ThreadHandle=0;
- n_SI_Info=0;
+ n_SI_Info = 0;
InitializeCriticalSection(&SyncObj);
- tcpPortOpen=0;
- serverSocket=0;
+ tcpPortOpen = 0;
+ serverSocket = 0;
+ punchMap.resize(31, 0);
+ punchMap[oPunch::SpecialPunch::PunchStart] = oPunch::SpecialPunch::PunchStart;
+ punchMap[oPunch::SpecialPunch::PunchCheck] = oPunch::SpecialPunch::PunchCheck;
+ punchMap[oPunch::SpecialPunch::PunchFinish] = oPunch::SpecialPunch::PunchFinish;
+}
+
+void SportIdent::resetPunchMap() {
+ punchMap.resize(31, 0);
+ fill(punchMap.begin(), punchMap.end(), 0);
+ punchMap[oPunch::SpecialPunch::PunchStart] = oPunch::SpecialPunch::PunchStart;
+ punchMap[oPunch::SpecialPunch::PunchCheck] = oPunch::SpecialPunch::PunchCheck;
+ punchMap[oPunch::SpecialPunch::PunchFinish] = oPunch::SpecialPunch::PunchFinish;
}
SportIdent::~SportIdent()
@@ -299,7 +308,7 @@ string decode(BYTE *bf, int read)
bool SportIdent::openComListen(const wchar_t *com, DWORD BaudRate) {
closeCom(com);
- SI_StationInfo *si = findStation(com);
+ SI_StationInfo *si = findStationInt(com);
if (!si) {
SI_Info[n_SI_Info].ComPort=com;
@@ -309,6 +318,9 @@ bool SportIdent::openComListen(const wchar_t *com, DWORD BaudRate) {
}
si->data.clear();
+ if (si->ComPort == L"TEST")
+ return true; // Passive test
+
wstring comfile=wstring(L"//./")+com;
si->hComm = CreateFile( comfile.c_str(),
GENERIC_READ | GENERIC_WRITE,
@@ -355,7 +367,7 @@ bool SportIdent::tcpAddPort(int port, DWORD zeroTime)
{
closeCom(L"TCP");
- SI_StationInfo *si = findStation(L"TCP");
+ SI_StationInfo *si = findStationInt(L"TCP");
if (!si) {
SI_Info[n_SI_Info].ComPort=L"TCP";
@@ -374,7 +386,7 @@ bool SportIdent::openCom(const wchar_t *com)
{
closeCom(com);
- SI_StationInfo *si = findStation(com);
+ SI_StationInfo *si = findStationInt(com);
if (!si) {
SI_Info[n_SI_Info].ComPort=com;
@@ -386,7 +398,7 @@ bool SportIdent::openCom(const wchar_t *com)
si->data.clear();
if (si->ComPort == L"TEST") {
- return true;
+ return false;
}
wstring comfile=wstring(L"//./")+com;
@@ -511,9 +523,7 @@ bool SportIdent::openCom(const wchar_t *com)
return true;
}
-
-SI_StationInfo *SportIdent::findStation(const wstring &com)
-{
+SI_StationInfo* SportIdent::findStationInt(const wstring& com) {
if (com == L"TEST" && n_SI_Info < 30) {
if (n_SI_Info == 0 || SI_Info[n_SI_Info - 1].ComPort != com) {
SI_Info[n_SI_Info].ComPort = com;
@@ -521,6 +531,26 @@ SI_StationInfo *SportIdent::findStation(const wstring &com)
}
}
+ for (int i = 0; i < n_SI_Info; i++)
+ if (com == SI_Info[i].ComPort)
+ return &SI_Info[i];
+
+ return 0;
+}
+
+void SportIdent::addTestStation(const wstring& com) {
+ SI_Info[n_SI_Info].ComPort = com;
+ n_SI_Info++;
+}
+
+const SI_StationInfo *SportIdent::findStation(const wstring &com) const
+{
+ if (com == L"TEST" && n_SI_Info < 30) {
+ if (n_SI_Info == 0 || SI_Info[n_SI_Info - 1].ComPort != com) {
+ const_cast(this)->addTestStation(com);
+ }
+ }
+
for(int i=0;iComPort==L"TCP") {
if (tcpPortOpen) {
@@ -890,7 +920,7 @@ int SportIdent::MonitorTCPSI(WORD port, int localZeroTime)
}
}
else
- addPunch(op.CodeTime/10, op.CodeNo, op.SICardNo, 0);
+ addPunch(op.CodeTime, op.CodeNo, op.SICardNo, 0);
}
else r=-1;
@@ -933,10 +963,10 @@ bool SportIdent::MonitorTEST(SI_StationInfo &si)
SICard card(ConvertedTimeStatus::Hour12);
card.StartPunch.Code = 1;
- int t = card.StartPunch.Time = 3600*8 + rand()%1000;
+ int t = card.StartPunch.Time = timeConstHour*8 + rand()%1000;
card.FinishPunch.Code = 2;
- card.FinishPunch.Time = card.StartPunch.Time + 1800 + rand() % 3600;
+ card.FinishPunch.Time = card.StartPunch.Time + timeConstHour/2 + rand() % timeConstHour;
card.CardNumber = tc.cardNo;
for (size_t k = 0; k < tc.punches.size(); k++) {
@@ -947,8 +977,8 @@ bool SportIdent::MonitorTEST(SI_StationInfo &si)
}
addCard(card);
- //Sleep(300 + rand()%600);
- Sleep(0);
+ Sleep(300 + rand()%600);
+ //Sleep(0);
if (++longSleepIter > 20) {
Sleep(100 + rand() % 600);
longSleepIter = 0;
@@ -1002,12 +1032,15 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
DWORD Card=MAKELONG(MAKEWORD(bf[7], bf[6]), MAKEWORD(bf[5], bf[4]));
- if (Series<=4 && Series>=1)
- Card=ShortCard+100000*Series;
+ if (Series <= 4 && Series >= 1)
+ Card = ShortCard + 100000 * Series;
DWORD Time=0;
- if (bf[8]&0x1) Time=3600*12;
- Time+=MAKEWORD(bf[10], bf[9]);
+ if (bf[8] & 0x1) Time = timeConstHour * 12;
+ Time += MAKEWORD(bf[10], bf[9])*timeConstSecond;
+ uint8_t tss = bf[11]; // Sub second 1/256 seconds
+ int tenth = (((100 * tss) / 256) + 4) / 10;
+ Time += tenth;
#ifdef DEBUG_SI
char str[128];
sprintf_s(str, "EXTENDED: Card = %d, Station = %d, StationMode = %d", Card, Station, si.StationMode);
@@ -1040,9 +1073,9 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
//if (Series!=1)
// Card+=100000*Series;
- DWORD Time=MAKEWORD(bf[8], bf[7]);
+ DWORD Time = MAKEWORD(bf[8], bf[7]) * timeConstSecond;
BYTE p=bf[1];
- if (p&0x1) Time+=3600*12;
+ if (p&0x1) Time+=timeConstHour*12;
#ifdef DEBUG_SI
char str[128];
@@ -1100,7 +1133,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
bf[0]=chRead;
readBytes(bf+1, 200, hComm);
//GetSI5DataExt(hComm);
- MessageBox(NULL, L"Programmera stationen utan AUTOSEND!", NULL, MB_OK);
+ MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
}
break;
@@ -1108,7 +1141,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
BYTE bf[200];
bf[0]=chRead;
readBytes(bf+1, 200, hComm);
- MessageBox(NULL, L"Programmera stationen utan AUTOSEND!", NULL, MB_OK);
+ MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
}
break;
case 0xE8:{
@@ -1125,7 +1158,6 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
// MessageBox(NULL, "SI-card not supported", NULL, MB_OK);
// break;
default:
-
BYTE bf[128];
bf[0]=chRead;
int rb=readBytes(bf+1, 120, hComm);
@@ -1146,6 +1178,9 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
st+=d;
}
}
+
+ if (chRead == 0xEF)
+ MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
//MessageBox(NULL, st.c_str(), "Unknown SI response", MB_OK);
}
}
@@ -1650,8 +1685,6 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card)
analyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code);
analyseSI5Time(data+9, card.CheckPunch.Time, card.CheckPunch.Code);
-// card.StartPunch=MAKEWORD(data[4], data[3]);
-// card.FinishPunch=MAKEWORD(data[6], data[5]);
card.nPunch=data[7]-1;
data+=16;
@@ -1660,7 +1693,7 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card)
if (k<30) {
DWORD basepointer=3*(k%5)+1+(k/5)*16;
DWORD code=data[basepointer];
- DWORD time;//=MAKEWORD(data[basepointer+2],data[basepointer+1]);
+ DWORD time;
DWORD slask;
analyseSI5Time(data+basepointer+1, time, slask);
@@ -1710,29 +1743,29 @@ bool SportIdent::getCard9Data(BYTE *data, SICard &card)
int series = data[24] & 15;
card.convertedTime = ConvertedTimeStatus::Hour24;
- analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code);
- analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code);
- analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code);
+ analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code, useSubsecondMode);
+ analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code, useSubsecondMode);
+ analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code, false);
if (series == 1) {
// SI Card 9
card.nPunch=min(int(data[22]), 50);
for(unsigned k=0;k> 1) & 0x1F;
control=cn;
- time=MAKEWORD(ptl, pth)+3600*12*(dt0&0x1);
+ time = MAKEWORD(ptl, pth) * timeConstSecond + timeConstHour * 12 * (dt0 & 0x1);
}
else {
control=-1;
@@ -1810,9 +1843,9 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
// DWORD control;
// DWORD time;
card.convertedTime = ConvertedTimeStatus::Hour24;
- analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code);
- analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code);
- analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code);
+ analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code, useSubsecondMode);
+ analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code, useSubsecondMode);
+ analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code, false);
card.nPunch=min(int(data[2]), 192);
int i;
@@ -1843,12 +1876,12 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
data+=128-16;
for(unsigned k=0;k>6)&0x3);
- time=MAKEWORD(ptl, pth)+3600*12*(ptd&0x1);
+ time = timeConstSecond * MAKEWORD(ptl, pth) + timeConstHour * 12 * (ptd & 0x1);
+ if (!subSecond) {
+ control = cn + 256 * ((ptd >> 6) & 0x3);
+ }
+ else {
+ control = 0;
+ uint8_t tss = data[1]; // Sub second 1/256 seconds
+ int tenth = (((100 * tss) / 256) + 4) / 10;
+ time += tenth;
+ }
return true;
}
else
@@ -1880,15 +1921,15 @@ bool SportIdent::analysePunch(BYTE *data, DWORD &time, DWORD &control) {
}
}
-void SportIdent::analyseSI5Time(BYTE *data, DWORD &time, DWORD &control)
+void SportIdent::analyseSI5Time(BYTE* data, DWORD& time, DWORD& control)
{
- if (*LPWORD(data)!=0xEEEE) {
- time=MAKEWORD(data[1], data[0]);
- control=0;
+ if (*LPWORD(data) != 0xEEEE) {
+ time = MAKEWORD(data[1], data[0]) * timeConstSecond;
+ control = 0;
}
else {
- control=-1;
- time=0;
+ control = -1;
+ time = 0;
}
}
@@ -1906,17 +1947,17 @@ void SICard::analyseHour12Time(DWORD zeroTime) {
}
void SIPunch::analyseHour12Time(DWORD zeroTime) {
- if (Code != -1 && Time>=0 && Time <=12*3600) {
- if (zeroTime < 12 * 3600) {
+ if (Code != -1 && Time>=0 && Time <=12*timeConstHour) {
+ if (zeroTime < 12 * timeConstHour) {
//Förmiddag
if (Time < zeroTime)
- Time += 12 * 3600; //->Eftermiddag
+ Time += 12 * timeConstHour; //->Eftermiddag
}
else {
//Eftermiddag
- if (Time >= zeroTime % (12 * 3600)) {
+ if (Time >= zeroTime % (12 * timeConstHour)) {
//Eftermiddag
- Time += 12 * 3600;
+ Time += 12 * timeConstHour;
}
// else Efter midnatt OK.
}
@@ -1985,50 +2026,67 @@ void SportIdent::addCard(const SICard &sic)
PostMessage(hWndNotify, WM_USER, ClassId, 0);
}
-void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode)
-{
+void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode) {
+ if (!useSubsecondMode)
+ Time -= (Time % timeConstSecond);
+
SICard sic(ConvertedTimeStatus::Hour24);
- sic.CardNumber=Card;
+ sic.CardNumber = Card;
sic.StartPunch.Code = -1;
sic.CheckPunch.Code = -1;
sic.FinishPunch.Code = -1;
- if (Mode==0 || Mode == 11){ // 11 is dongle
- if (Station>30){
- sic.Punch[0].Code=Station;
- sic.Punch[0].Time=Time;
- sic.nPunch=1;
+ auto mapPunch = [this](int code) {
+ if (code > 0 && code < punchMap.size() && punchMap[code] > 0)
+ return punchMap[code];
+ else
+ return code;
+ };
+
+ if (Mode == 0 || Mode == 11) { // 11 is dongle
+ int code = (Station & 0xFFFF);
+ int mappedCode = mapPunch(code);
+ int unit = 0;
+ if (mappedCode != code)
+ unit = code;
+ else
+ unit = (Station >> 16) & 0xFFFF;
+
+ if (mappedCode > 30) {
+ sic.Punch[0].Code = Station;
+ sic.Punch[0].Time = Time;
+ sic.nPunch = 1;
}
- else if (Station == oPunch::PunchStart) {
+ else if (mappedCode == oPunch::PunchStart) {
sic.StartPunch.Time = Time;
- sic.StartPunch.Code = oPunch::PunchStart;
+ sic.StartPunch.Code = unit;
}
- else if (Station == oPunch::PunchCheck) {
+ else if (mappedCode == oPunch::PunchCheck) {
sic.CheckPunch.Time = Time;
- sic.CheckPunch.Code = oPunch::PunchCheck;
+ sic.CheckPunch.Code = unit;
}
- else{
- sic.FinishPunch.Time=Time;
- sic.FinishPunch.Code = oPunch::PunchFinish;
+ else {
+ sic.FinishPunch.Time = Time;
+ sic.FinishPunch.Code = unit;
}
}
- else{
- if (Mode==0x02 || Mode == 50){
- sic.Punch[0].Code=Station;
- sic.Punch[0].Time=Time;
- sic.nPunch=1;
+ else {
+ if (Mode == 0x02 || Mode == 50) {
+ sic.Punch[0].Code = Station;
+ sic.Punch[0].Time = Time;
+ sic.nPunch = 1;
}
else if (Mode == 3) {
- sic.StartPunch.Time=Time;
- sic.StartPunch.Code = oPunch::PunchStart;
+ sic.StartPunch.Time = Time;
+ sic.StartPunch.Code = Station;
}
else if (Mode == 10) {
- sic.CheckPunch.Time=Time;
- sic.CheckPunch.Code = oPunch::PunchCheck;
+ sic.CheckPunch.Time = Time;
+ sic.CheckPunch.Code = Station;
}
- else{
- sic.FinishPunch.Time=Time;
- sic.FinishPunch.Code = oPunch::PunchFinish;
+ else {
+ sic.FinishPunch.Time = Time;
+ sic.FinishPunch.Code = Station;
}
}
sic.punchOnly = true;
@@ -2084,9 +2142,8 @@ void start_si_thread(void *ptr)
}
}
-void SportIdent::startMonitorThread(const wchar_t *com)
-{
- SI_StationInfo *si = findStation(com);
+void SportIdent::startMonitorThread(const wchar_t *com) {
+ SI_StationInfo *si = findStationInt(com);
if (si && (si->hComm || si->ComPort==L"TCP" || si->ComPort == L"TEST"))
{
@@ -2119,7 +2176,7 @@ void checkport_si_thread(void *ptr)
*port=0; //No SI found here
else {
bool valid = true;
- SI_StationInfo *sii = si.findStation(bf);
+ const SI_StationInfo *sii = ((const SportIdent &)si).findStation(bf);
if (sii) {
if (sii->data.empty() || sii->data[0].stationNumber>=1024 || sii->data[0].stationMode>15 ||
!(sii->data[0].autoSend || sii->data[0].handShake))
@@ -2178,7 +2235,7 @@ bool SportIdent::autoDetect(list &ComPorts)
bool SportIdent::isPortOpen(const wstring &com)
{
- SI_StationInfo *si = findStation(com);
+ const SI_StationInfo *si = findStation(com);
if (si && si->ComPort==L"TCP")
return tcpPortOpen && serverSocket;
@@ -2186,25 +2243,61 @@ bool SportIdent::isPortOpen(const wstring &com)
return si!=0 && si->hComm && si->ThreadHandle;
}
-void SportIdent::getInfoString(const wstring &com, vector &infov)
-{
+
+bool SportIdent::isAnyOpenUnkownUnit() const {
+ if (tcpPortOpen && serverSocket)
+ return true;
+
+ for (int i = 0; i < n_SI_Info; i++) {
+ auto& si = SI_Info[i];
+ auto& com = si.ComPort;
+
+ if (com == L"TCP")
+ continue;
+
+ if (com == L"TEST")
+ return true;
+
+ if (!(si.hComm && si.ThreadHandle))
+ continue; // Not open
+
+ if (si.data.empty())
+ return true; // Listen mode (no contact made)
+
+ switch (si.data[0].stationMode) {
+ case 2: // Known modes
+ case 50:
+ case 4:
+ case 3:
+ case 5:
+ case 7:
+ case 10:
+ continue;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+void SportIdent::getInfoString(const wstring &com, vector> &infov) const {
infov.clear();
- SI_StationInfo *si = findStation(com);
+ const SI_StationInfo *si = findStation(com);
if (com==L"TCP") {
if (!si || !tcpPortOpen || !serverSocket) {
- infov.push_back(L"TCP: "+lang.tl(L"ej aktiv."));
+ infov.emplace_back(false, L"TCP: "+lang.tl(L"ej aktiv."));
return;
}
wchar_t bf[128];
swprintf_s(bf, lang.tl(L"TCP: Port %d, Nolltid: %s").c_str(), tcpPortOpen, L"00:00:00");//WCS
- infov.push_back(bf);
+ infov.emplace_back(false, bf);
return;
}
if (!(si!=0 && si->hComm && si->ThreadHandle)) {
- infov.push_back(com+L": "+lang.tl(L"ej aktiv."));
+ infov.emplace_back(false, com+L": "+lang.tl(L"ej aktiv."));
return;
}
@@ -2221,7 +2314,7 @@ void SportIdent::getInfoString(const wstring &com, vector &infov)
switch(da.stationMode){
case 2:
case 50:
- info+=lang.tl(L"Kontrol");
+ info+=lang.tl(L"Kontroll");
break;
case 4:
info+=lang.tl(L"MÃ¥l");
@@ -2256,12 +2349,15 @@ void SportIdent::getInfoString(const wstring &com, vector &infov)
else if (da.handShake) info+=lang.tl(L"handskakning.");
else info+=lang.tl(L"[VARNING] ingen/okänd.");
- infov.push_back(info);
+ infov.emplace_back(false, info);
+
+ if (da.autoSend && da.stationMode == 5)
+ infov.emplace_back(true, lang.tl("Programmera stationen utan AUTOSEND"));
}
}
static string formatTimeN(int t) {
- const wstring &wt = formatTime(t);
+ const wstring &wt = formatTime(t, SubSecond::Auto);
string nt(wt.begin(), wt.end());
return nt;
}
@@ -2411,7 +2507,7 @@ unsigned int SICard::calculateHash() const {
}
string SICard::serializePunches() const {
- string ser;
+ string ser = "*";// Mark of time factor
if (CheckPunch.Code != -1)
ser += "C-" + itos(CheckPunch.Time);
@@ -2437,24 +2533,31 @@ void SICard::deserializePunches(const string &arg) {
StartPunch.Code = -1;
CheckPunch.Code = -1;
vector out;
- split(arg, ";", out);
+ int timeFactor = 10;
+ if (arg.length() > 1 && arg[0] == '*') {
+ split(arg.c_str() + 2, ";", out);
+ timeFactor = 1;
+ }
+ else {
+ split(arg, ";", out);
+ }
nPunch = 0;
for (size_t k = 0; k< out.size(); k++) {
vector mark;
split(out[k], "-", mark);
- if (mark.size() != 2)
+ if (mark.size() != 2 || mark[0].empty())
throw std::exception("Invalid string");
DWORD *tp = 0;
- if (mark[0] == "F") {
- FinishPunch.Code = 1;
+ if (mark[0][0] == 'F') {
+ FinishPunch.Code = atoi(mark[0].c_str() + 1);
tp = &FinishPunch.Time;
}
- else if (mark[0] == "S") {
- StartPunch.Code = 1;
+ else if (mark[0][0] == 'S') {
+ StartPunch.Code = atoi(mark[0].c_str() + 1);
tp = &StartPunch.Time;
}
- else if (mark[0] == "C") {
- CheckPunch.Code = 1;
+ else if (mark[0][0] == 'C') {
+ CheckPunch.Code = atoi(mark[0].c_str() + 1);
tp = &CheckPunch.Time;
}
else {
@@ -2462,12 +2565,51 @@ void SICard::deserializePunches(const string &arg) {
tp = &Punch[nPunch++].Time;
}
- *tp = atoi(mark[1].c_str());
+ *tp = atoi(mark[1].c_str()) * timeFactor;
}
if (out.size() == 1)
punchOnly = true;
}
+int SICard::getFirstTime() const {
+ if (StartPunch.Time > 0)
+ return StartPunch.Time;
+
+ for (int i = 0; i < nPunch; i++) {
+ if (Punch[i].Time > 0)
+ return Punch[i].Time;
+ }
+
+ if (FinishPunch.Time > 0)
+ return FinishPunch.Time;
+
+ return 0;
+}
+
+
+map SportIdent::getSpecialMappings() const {
+ map res;
+ for (int j = 1; j < punchMap.size(); j++) {
+ if (punchMap[j] > 0)
+ res[j] = oPunch::SpecialPunch(punchMap[j]);
+ }
+ return res;
+}
+
+void SportIdent::addSpecialMapping(int code, oPunch::SpecialPunch p) {
+ if (code > 0 && code < punchMap.size())
+ punchMap[code] = p;
+ else
+ throw std::exception("Not supported");
+}
+
+void SportIdent::removeSpecialMapping(int code) {
+ if (code > 0 && code < punchMap.size())
+ punchMap[code] = 0;
+ else
+ throw std::exception("Not supported");
+}
+
void SportIdent::addTestCard(int cardNo, const vector &punches) {
testCards.emplace(cardNo, punches);
}
diff --git a/code/SportIdent.h b/code/SportIdent.h
index 3f02d11..580d93c 100644
--- a/code/SportIdent.h
+++ b/code/SportIdent.h
@@ -1,19 +1,15 @@
// SportIdent.h: interface for the SportIdent class.
//
//////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_)
-#define AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_
-
-#if _MSC_VER > 1000
#pragma once
-#endif // _MSC_VER > 1000
#include
+#include
+#include "oPunch.h"
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -108,6 +104,8 @@ struct SICard
string serializePunches() const;
void deserializePunches(const string &arg);
+
+ int getFirstTime() const;
};
struct SI_StationData {
@@ -154,9 +152,11 @@ struct SI_StationInfo
};
-class SportIdent
-{
+class SportIdent {
protected:
+
+ bool useSubsecondMode = false;
+
bool readSI6Block(HANDLE hComm, BYTE *data);
bool readSystemData(SI_StationInfo *si, int retry=2);
bool readSystemDataV2(SI_StationInfo &si);
@@ -195,7 +195,7 @@ protected:
void getSI9DataExt(HANDLE hComm);
void analyseSI5Time(BYTE *data, DWORD &time, DWORD &control);
- bool analysePunch(BYTE *data, DWORD &time, DWORD &control);
+ bool analysePunch(BYTE *data, DWORD &time, DWORD &control, bool subSecond);
void analyseTPunch(BYTE *data, DWORD &time, DWORD &control);
//Card read waiting to be processed.
@@ -227,13 +227,25 @@ protected:
bool readVoltage;
+ vector punchMap;
+ SI_StationInfo* findStationInt(const wstring& com);
+ void addTestStation(const wstring& com);
+
public:
- SI_StationInfo *findStation(const wstring &com);
+
+ map getSpecialMappings() const;
+ void addSpecialMapping(int code, oPunch::SpecialPunch);
+ void removeSpecialMapping(int code);
+
+ const SI_StationInfo *findStation(const wstring &com) const;
/** Log debug data. */
void debugLog(const wchar_t *ptr);
- void getInfoString(const wstring &com, vector &info);
+ void getInfoString(const wstring &com, vector> &info) const;
+
+ bool isAnyOpenUnkownUnit() const;
+
bool isPortOpen(const wstring &com);
bool autoDetect(list &ComPorts);
void stopMonitorThread();
@@ -250,13 +262,14 @@ public:
void closeCom(const wchar_t *com);
bool openCom(const wchar_t *com);
bool tcpAddPort(int port, DWORD zeroTime);
-
bool openComListen(const wchar_t *com, DWORD BaudRate);
SportIdent(HWND hWnd, DWORD Id, bool readVoltage);
+
+ void setSubSecondMode(bool subSec) { useSubsecondMode = subSec; }
+ void resetPunchMap();
+
virtual ~SportIdent();
friend void start_si_thread(void *ptr);
};
-
-#endif // !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_)
diff --git a/code/StdAfx.h b/code/StdAfx.h
index 1c976c3..c32655d 100644
--- a/code/StdAfx.h
+++ b/code/StdAfx.h
@@ -1,21 +1,12 @@
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently, but
-// are changed infrequently
-//
-
-#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
-#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
+#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX
-// Windows Header Files:
+
#include
#include
+#include "timeconstants.hpp"
// C RunTime Header Files
@@ -51,4 +42,3 @@ const extern string _EmptyString;
const extern string _VacantName;
const extern wstring _EmptyWString;
-#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
diff --git a/code/TabAuto.cpp b/code/TabAuto.cpp
index 170f5b8..bf7ebf9 100644
--- a/code/TabAuto.cpp
+++ b/code/TabAuto.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -716,7 +716,7 @@ void AutoMachine::startCancelInterval(gdioutput &gdi, const char *startCommand,
void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Resultatutskrift / export");
- wstring time = (state == State::Create && interval <= 0) ? L"10:00" : getTimeMS(interval);
+ wstring time = (state == State::Create && interval <= 0) ? L"10:00" : formatTimeMS(interval, false, SubSecond::Off);
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
if (state == State::Create) {
@@ -822,12 +822,12 @@ void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
}
}
-void PrintResultMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
+void PrintResultMachine::save(oEvent& oe, gdioutput& gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
wstring minute = gdi.getText("Interval");
- int t = convertAbsoluteTimeMS(minute);
+ int t = convertAbsoluteTimeMS(minute) / timeConstSecond;
- if (t < 2 || t>7200) {
+ if (t < 2 || t > 7200) {
throw meosException("Intervallet måste anges på formen MM:SS.");
}
doExport = gdi.isChecked("DoExport");
@@ -980,7 +980,7 @@ void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
gdi.pushX();
gdi.fillDown();
vector< pair > d;
- oe.fillControls(d, oEvent::CTCourseControl);
+ oe.fillControls(d, oEvent::ControlType::CourseControl);
gdi.addItem("Controls", d);
gdi.setSelection("Controls", controls);
gdi.popX();
@@ -998,7 +998,7 @@ void PrewarningMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
controlsSI.clear();
for (set::iterator it = controls.begin(); it != controls.end(); ++it) {
- pControl pc = oe.getControl(*it, false);
+ pControl pc = oe.getControl(*it, false, false);
if (pc) {
vector n;
pc->getNumbers(n);
@@ -1152,7 +1152,7 @@ void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
sic.punchOnly = true;
sic.nPunch = 1;
sic.Punch[0].Code = radio;
- sic.Punch[0].Time = 600 + rand() % 1200 + r->getStartTime();
+ sic.Punch[0].Time = timeConstHour/10 + rand() % (1200*timeConstSecond) + r->getStartTime();
si.addCard(sic);
}
}
@@ -1205,7 +1205,7 @@ void SplitsMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
if (doProcess) {
//Try exporting.
oe.exportIOFSplits(oEvent::IOF20, file.c_str(), true, false,
- set(), -1, false, true, true, false);
+ set(), -1, false, true, true, false, false);
interval = iv;
synchronize = true;
}
@@ -1245,7 +1245,7 @@ void SplitsMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
if ((interval>0 && ast==SyncTimer) || (interval==0 && ast==SyncDataUp)) {
if (!file.empty())
oe->exportIOFSplits(oEvent::IOF20, file.c_str(), true, false, classes,
- leg, false, true, true, false);
+ leg, false, true, true, false, false);
}
}
@@ -1276,16 +1276,16 @@ void SaveMachine::status(gdioutput &gdi) {
void SaveMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
if (interval>0 && ast==SyncTimer) {
if (!baseFile.empty()) {
- wstring file = baseFile + L"meos_backup_" + oe->getDate() + L"_" + itow(saveIter++) + L".xml";
+ wstring file = baseFile + L"meos_backup_" + oe->getDate() + L"_" + itow(saveIter++) + L".meosxml";
oe->autoSynchronizeLists(true);
- oe->save(file);
+ oe->save(file, false);
}
}
}
void SaveMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Säkerhetskopiering");
- wstring time=state == State::Create ? L"10:00" : getTimeMS(interval);
+ wstring time=state == State::Create ? L"10:00" : formatTimeMS(interval, false, SubSecond::Off);
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
int cx = gdi.getCX();
@@ -1295,12 +1295,12 @@ void SaveMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
gdi.setCX(cx);
}
-void SaveMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
+void SaveMachine::save(oEvent& oe, gdioutput& gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
- wstring minute=gdi.getText("Interval");
- int t=convertAbsoluteTimeMS(minute);
+ wstring minute = gdi.getText("Interval");
+ int t = convertAbsoluteTimeMS(minute) / timeConstSecond;
- if (t<2 || t>7200) {
+ if (t < 2 || t>7200) {
throw meosException("Intervallet måste anges på formen MM:SS.");
}
wstring f = gdi.getText("BaseFile");
diff --git a/code/TabAuto.h b/code/TabAuto.h
index c83054a..ce8223f 100644
--- a/code/TabAuto.h
+++ b/code/TabAuto.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabBase.cpp b/code/TabBase.cpp
index ffd674b..369acba 100644
--- a/code/TabBase.cpp
+++ b/code/TabBase.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabBase.h b/code/TabBase.h
index 707c448..2916f27 100644
--- a/code/TabBase.h
+++ b/code/TabBase.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabClass.cpp b/code/TabClass.cpp
index 2add24a..d882cc1 100644
--- a/code/TabClass.cpp
+++ b/code/TabClass.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -76,10 +76,10 @@ TabClass::TabClass(oEvent *poe):TabBase(poe)
void TabClass::clearCompetitionData() {
currentResultModuleTags.clear();
pSettings.clear();
- pSavedDepth = 3600;
- pFirstRestart = 3600;
+ pSavedDepth = timeConstHour;
+ pFirstRestart = timeConstHour;
pTimeScaling = 1.0;
- pInterval = 120;
+ pInterval = 2 * timeConstMinute;
currentStage = -1;
EditChanged = false;
@@ -241,6 +241,9 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
return true;
}
else if (bi.id == "ApplyForking") {
+ int maxForking = gdi.getTextNo("MaxForkings");
+ if (maxForking < 2)
+ throw meosException("Du måste ange minst två gafflingsvarienater");
showForkingGuide = false;
pClass pc = oe->getClass(ClassId);
@@ -259,7 +262,7 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
allR[k]->setCourseId(0);
}
}
- pair res = pc->autoForking(forkingSetup);
+ pair res = pc->autoForking(forkingSetup, maxForking);
gdi.alert("Created X distinct forkings using Y courses.#" +
itos(res.first) + "#" + itos(res.second));
loadPage(gdi);
@@ -307,6 +310,10 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
gdi.setSelection("AllStages", set());
gdi.disableInput("AssignCourses");
}
+ else if (bi.id == "AllCourses") {
+ gdi.setSelection("AllCourses", { -1 });
+ //gdi.enableInput("AssignCourses");
+ }
else if (bi.id == "ShowForking") {
if (!checkClassSelected(gdi))
return false;
@@ -469,7 +476,7 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
int nst = oe->convertAbsoluteTime(st);
if (nst >= 0 && warnDrawStartTime(gdi, nst, true)) {
- nst = 3600;
+ nst = timeConstHour;
st = oe->getAbsTime(nst);
}
if (nst>0)
@@ -695,8 +702,27 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
EditChanged=true;
if (ii.id=="NStage")
gdi.enableInput("SetNStage");
+ else if (ii.id == "CourseFilter") {
+ gdi.addTimeoutMilli(500, "FilterCourseTimer", MultiCB);
+ }
//else if (ii.id=="")
}
+ else if (type == GUI_TIMER) {
+ TimerInfo& ti = *(TimerInfo*)(data);
+ if (ti.id == "FilterCourseTimer") {
+ const wstring &filter = gdi.getText("CourseFilter");
+ if (filter != courseFilter) {
+ courseFilter = filter;
+ vector> out;
+ oe->getCourses(out, courseFilter, true, false);
+ set sel;
+ gdi.getSelection("AllCourses", sel);
+ gdi.addItem("AllCourses", out);
+ gdi.setSelection("AllCourses", sel);
+ }
+ }
+
+ }
return 0;
}
@@ -832,8 +858,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
else ds.ctrl = 0;
// Save settings with class
- ds.firstStart = 3600;
- ds.interval = 120;
+ ds.firstStart = timeConstHour;
+ ds.interval = 2 * timeConstMinute;
ds.vacant = 1;
res.push_back(ds);
@@ -1023,7 +1049,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.pushX();
gdi.fillRight();
- gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, L"Första (ordinarie) start:");
+ gdi.addInput("FirstStart", oe->getAbsTime(timeConstHour), 10, 0, L"Första (ordinarie) start:");
gdi.addInput("MinInterval", L"2:00", 10, 0, L"Minsta startintervall:");
gdi.addInput("Vacances", getDefaultVacant(), 10, 0, L"Andel vakanser:");
gdi.fillDown();
@@ -1085,7 +1111,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "SelectAllNoneP") {
bool select = bi.getExtraInt() != 0;
- for (int k = 0; k < oe->getNumClasses(); k++) {
+ const int nc = oe->getNumClasses();
+ for (int k = 0; k < nc; k++) {
gdi.check("PLUse" + itos(k), select);
gdi.setInputStatus("First" + itos(k), select);
}
@@ -1107,8 +1134,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
pInterval = interval;
oListParam par;
-
- for (int k = 0; k < oe->getNumClasses(); k++) {
+ const int nc = oe->getNumClasses();
+ for (int k = 0; k < nc; k++) {
if (!gdi.hasWidget("PLUse" + itos(k)))
continue;
BaseInfo *biu = gdi.setText("PLUse" + itos(k), L"", false);
@@ -1260,7 +1287,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "DrawAll") {
int origin = bi.getExtraInt();
- wstring firstStart = oe->getAbsTime(3600);
+ wstring firstStart = oe->getAbsTime(timeConstHour);
wstring minInterval = L"2:00";
wstring vacances = getDefaultVacant();
if (gdi.hasWidget("Vacances")) {
@@ -2529,7 +2556,7 @@ void TabClass::showClassSettings(gdioutput &gdi)
if (ci.hasFixedTime) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
- ii = &gdi.addInput(xp + classW + width, y, "I" + itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
+ ii = &gdi.addInput(xp + classW + width, y, "I" + itos(id), formatTime(ci.interval*drawInfo.baseInterval, SubSecond::Auto), 7, DrawClassesCB);
if (ci.hasFixedTime) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
@@ -3323,9 +3350,24 @@ bool TabClass::loadPage(gdioutput &gdi)
gdi.fillDown();
gdi.addListBox("Classes", 200, showAdvanced ? 512 : 420, ClassesCB, L"").isEdit(false).ignore(true);
- gdi.setTabStops("Classes", 185);
+ gdi.setTabStops("Classes", 170);
oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone);
+
+ bool hasIgnoreStart = false;
+ bool hasFreeStart = false;
+
+ if (!showAdvanced) {
+ vector clsList;
+ oe->getClasses(clsList, false);
+ for (auto c : clsList) {
+ if (c->ignoreStartPunch())
+ hasIgnoreStart = true;
+ if (c->hasFreeStart())
+ hasFreeStart = true;
+ }
+ }
+
gdi.newColumn();
gdi.dropLine(2);
@@ -3419,11 +3461,15 @@ bool TabClass::loadPage(gdioutput &gdi)
gdi.addCheckbox("NoTiming", "Utan tidtagning", 0);
}
- if (showAdvanced) {
+ if (showAdvanced || hasIgnoreStart || hasFreeStart) {
gdi.dropLine(2);
gdi.popX();
- gdi.addCheckbox("FreeStart", "Fri starttid", 0, false, "Klassen lottas inte, startstämpling");
- gdi.addCheckbox("IgnoreStart", "Ignorera startstämpling", 0, false, "Uppdatera inte starttiden vid startstämpling");
+
+ if (showAdvanced || hasFreeStart)
+ gdi.addCheckbox("FreeStart", "Fri starttid", 0, false, "Klassen lottas inte, startstämpling");
+
+ if (showAdvanced || hasIgnoreStart)
+ gdi.addCheckbox("IgnoreStart", "Ignorera startstämpling", 0, false, "Uppdatera inte starttiden vid startstämpling");
gdi.dropLine(2);
gdi.popX();
}
@@ -3721,8 +3767,8 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
return;
}
- int firstStart = 3600,
- interval = 120,
+ int firstStart = timeConstHour,
+ interval = 2 * timeConstMinute,
vac = _wtoi(lastNumVac.c_str());
int pairSize = lastPairSize;
@@ -3787,12 +3833,12 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
if (method == oEvent::DrawMethod::Pursuit || method == oEvent::DrawMethod::ReversePursuit) {
gdi.addInput("MaxAfter", lastMaxAfter, 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart").setSynchData(&lastMaxAfter);
- gdi.addInput("TimeRestart", oe->getAbsTime(firstStart + 3600), 8, 0, L"Första omstartstid:");
+ gdi.addInput("TimeRestart", oe->getAbsTime(firstStart + timeConstHour), 8, 0, L"Första omstartstid:");
gdi.addInput("ScaleFactor", lastScaleFactor, 8, 0, L"Tidsskalning:").setSynchData(&lastScaleFactor);
}
if (method != oEvent::DrawMethod::Simultaneous)
- gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
+ gdi.addInput("Interval", formatTime(interval, SubSecond::Auto), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
if ((method == oEvent::DrawMethod::Random ||
method == oEvent::DrawMethod::SOFT ||
@@ -3944,9 +3990,9 @@ void TabClass::pursuitDialog(gdioutput &gdi) {
gdi.fillRight();
- gdi.addInput("MaxAfter", formatTime(pSavedDepth), 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart");
- gdi.addInput("TimeRestart", L"+" + formatTime(pFirstRestart), 8, 0, L"Första omstartstid:", L"Ange tiden relativt klassens första start");
- gdi.addInput("Interval", formatTime(pInterval), 8, 0, L"Startintervall:", L"Ange startintervall för minutstart");
+ gdi.addInput("MaxAfter", formatTime(pSavedDepth, SubSecond::Off), 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart");
+ gdi.addInput("TimeRestart", L"+" + formatTime(pFirstRestart, SubSecond::Off), 8, 0, L"Första omstartstid:", L"Ange tiden relativt klassens första start");
+ gdi.addInput("Interval", formatTime(pInterval, SubSecond::Off), 8, 0, L"Startintervall:", L"Ange startintervall för minutstart");
wchar_t bf[32];
swprintf_s(bf, L"%f", pTimeScaling);
gdi.addInput("ScaleFactor", bf, 8, 0, L"Tidsskalning:");
@@ -4027,7 +4073,7 @@ void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK
int cx = gdi.getCX();
int width = gdi.scaleLength(230);
gdi.addListBox("Classes", 200, 480, classesCB, L"Klasser:", L"", true);
- gdi.setTabStops("Classes", 185);
+ gdi.setTabStops("Classes", 170);
gdi.fillRight();
gdi.pushX();
@@ -4258,6 +4304,9 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
gdi.dropLine(2);
gdi.pushY();
+
+ courseFilter = L"";
+ gdi.addInput("CourseFilter", courseFilter, 16, MultiCB, L"Filtrera:");
gdi.addListBox("AllCourses", 180, 300, 0, L"Banor:", L"", true);
oe->fillCourses(gdi, "AllCourses", true);
int bxp = gdi.getCX();
@@ -4292,6 +4341,9 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
}
}
+ gdi.dropLine();
+ gdi.addInput("MaxForkings", L"100", 5, nullptr, L"Max antal gaffllingsvarianter att skapa:",
+ L"Det uppskattade antalet startade lag i klassen är ett lämpligt värde.");
gdi.dropLine();
gdi.fillRight();
gdi.addButton("ApplyForking", "Calculate and apply forking", MultiCB);
@@ -4300,9 +4352,11 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
gdi.setCX(bxp);
gdi.setCY(byp);
+ gdi.addButton("AllCourses", "Välj allt", MultiCB);
gdi.fillDown();
gdi.addButton("ClearCourses", "Clear selections", MultiCB);
+ gdi.setCX(bxp);
gdi.addString("", 10, "help:assignforking");
gdi.addString("", ty, tx, boldLarge, L"Assign courses and apply forking to X#" + pc->getName());
@@ -4384,7 +4438,7 @@ void TabClass::getClassSettingsTable(gdioutput &gdi, GUICALLBACK cb) {
gdi.addString("", yp, f, 1, "Direktanmälan");
vector< pair > arg;
- oe->fillCourses(arg, true);
+ oe->getCourses(arg, L"", true);
for (size_t k = 0; k < cls.size(); k++) {
pClass it = cls[k];
@@ -4534,8 +4588,11 @@ void TabClass::updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDe
if (st == STChange) {
if (typeid(sdataBase) != typeid(ListBoxInfo)) {
InputInfo sdII = dynamic_cast(sdataBase);
+ string rp;
+ gdi.getWidgetRestorePoint(sdKey, rp);
gdi.removeWidget(sdKey);
- gdi.addSelection(sdII.getX(), sdII.getY(), sdKey, sdII.getWidth(), 200, MultiCB);
+ gdi.addSelection(sdII.getX(), sdII.getY(), sdKey, int(sdII.getWidth()/gdi.getScale()), 200, MultiCB);
+ gdi.setWidgetRestorePoint(sdKey, rp);
setParallelOptions(sdKey, gdi, pc, leg);
}
else if (forceWrite) {
@@ -4545,9 +4602,12 @@ void TabClass::updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDe
else {
if (typeid(sdataBase) != typeid(InputInfo)) {
ListBoxInfo sdLBI = dynamic_cast(sdataBase);
+ string rp;
+ gdi.getWidgetRestorePoint(sdKey, rp);
gdi.removeWidget(sdKey);
string val = "-";
gdi.addInput(sdLBI.getX(), sdLBI.getY(), sdKey, pc->getStartDataS(leg), 8, MultiCB);
+ gdi.setWidgetRestorePoint(sdKey, rp);
}
else if (forceWrite) {
gdi.setText(sdKey, pc->getStartDataS(leg), true);
@@ -4678,12 +4738,12 @@ void TabClass::writeDrawInfo(gdioutput &gdi, const DrawInfo &drawInfoIn) {
gdi.setText("Vacances", itow(int(drawInfoIn.vacancyFactor *100.0)) + L"%");
gdi.setText("Extra", itow(int(drawInfoIn.extraFactor * 100.0) ) + L"%");
- gdi.setText("BaseInterval", formatTime(drawInfoIn.baseInterval));
+ gdi.setText("BaseInterval", formatTime(drawInfoIn.baseInterval, SubSecond::Off));
gdi.check("AllowNeighbours", drawInfoIn.allowNeighbourSameCourse);
gdi.check("CoursesTogether", drawInfoIn.coursesTogether);
- gdi.setText("MinInterval", formatTime(drawInfoIn.minClassInterval));
- gdi.setText("MaxInterval", formatTime(drawInfoIn.maxClassInterval));
+ gdi.setText("MinInterval", formatTime(drawInfoIn.minClassInterval, SubSecond::Off));
+ gdi.setText("MaxInterval", formatTime(drawInfoIn.maxClassInterval, SubSecond::Off));
gdi.setText("nFields", drawInfoIn.nFields);
gdi.setText("FirstStart", oe->getAbsTime(drawInfoIn.firstStart));
}
@@ -4739,10 +4799,10 @@ bool TabClass::warnDrawStartTime(gdioutput &gdi, const wstring &firstStart) {
bool TabClass::warnDrawStartTime(gdioutput &gdi, int time, bool absTime) {
if (absTime)
- time = oe->getRelativeTime(formatTimeHMS(time));
+ time = oe->getRelativeTime(formatTimeHMS(time, SubSecond::Off));
- if (!hasWarnedStartTime && (time > 3600 * 11 && !oe->useLongTimes())) {
- bool res = gdi.ask(L"warn:latestarttime#" + itow(time/3600));
+ if (!hasWarnedStartTime && (time > timeConstHour * 11 && !oe->useLongTimes())) {
+ bool res = gdi.ask(L"warn:latestarttime#" + itow(time/timeConstHour));
if (res)
hasWarnedStartTime = true;
return !res;
@@ -4812,7 +4872,7 @@ void DrawSettingsCSV::write(gdioutput &gdi, const oEvent &oe, const wstring &fn,
else line.emplace_back("");
line.push_back(gdi.narrow(oe.getAbsTime(ci.firstStart)));
- line.push_back(gdi.narrow(formatTime(ci.interval)));
+ line.push_back(gdi.narrow(formatTime(ci.interval, SubSecond::Off)));
line.push_back(itos(ci.vacant));
writer.outputRow(line);
}
@@ -5130,8 +5190,8 @@ public:
else if (type == GuiEventType::GUI_BUTTON) {
if (info.id == "AddGroup") {
int id = 1;
- int firstStart = 3600;
- int length = 3600;
+ int firstStart = timeConstHour;
+ int length = timeConstHour;
for (auto &g : oe.getStartGroups(false)) {
id = max(id, g.first+1);
firstStart = max(firstStart, g.second.lastStart);
diff --git a/code/TabClass.h b/code/TabClass.h
index 4561cdc..5ab1c9e 100644
--- a/code/TabClass.h
+++ b/code/TabClass.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,9 +33,9 @@ class TabClass :
int maxTime;
PursuitSettings(oClass &c) {
- firstTime = 3600;
+ firstTime = timeConstHour;
use = c.interpretClassType() != ctOpen;
- maxTime = 3600;
+ maxTime = timeConstHour;
}
};
@@ -103,6 +103,9 @@ class TabClass :
wstring lastScaleFactor;
wstring lastMaxAfter;
+ // Filter for course assignment
+ wstring courseFilter;
+
bool lastHandleBibs;
// Generate a table with class settings
void showClassSettings(gdioutput &gdi);
diff --git a/code/TabClub.cpp b/code/TabClub.cpp
index 9caa2cc..a166d2a 100644
--- a/code/TabClub.cpp
+++ b/code/TabClub.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -351,8 +351,8 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
gdi.fillDown();
gdi.popX();
-
- TabList::customTextLines(*oe, "IVExtra", gdi);
+ gdi.dropLine(2.5);
+ TabList::customTextLines(*oe, "IVExtra", true, gdi);
gdi.dropLine(1);
@@ -364,7 +364,8 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
oe->getDI().fillDataFields(gdi);
}
else if (bi.id == "SaveSettings") {
- oe->getDI().saveDataFields(gdi);
+ set modified;
+ oe->getDI().saveDataFields(gdi, modified);
TabList::saveExtraLines(*oe, "IVExtra", gdi);
diff --git a/code/TabClub.h b/code/TabClub.h
index 1d286f9..a8fb9c8 100644
--- a/code/TabClub.h
+++ b/code/TabClub.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabCompetition.cpp b/code/TabCompetition.cpp
index 2f977ee..082751e 100644
--- a/code/TabCompetition.cpp
+++ b/code/TabCompetition.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -133,6 +133,8 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
oe->updateStartTimes(delta);
}
+ oe->supportSubSeconds(gdi.isChecked("SubSecond"));
+
oe->setDate(date, true);
oe->useLongTimes(longTimes);
oe->setName(gdi.getText("Name"), true);
@@ -163,7 +165,7 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
return false;
gdi.setWaitCursor(true);
- if (oe->open(fileName, true, false)) {
+ if (oe->open(fileName, true, false, false)) {
gdi.setWindowTitle(oe->getTitleName());
resetSaveTimer();
@@ -171,7 +173,7 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
wstring base = constructBase(L"base", L"");
wchar_t newBase[_MAX_PATH];
getUserFile(newBase, base.c_str());
- oe->save(newBase);
+ oe->save(newBase, false);
return true;
}
@@ -188,7 +190,7 @@ bool TabCompetition::exportFileAs(HWND hWnd, gdioutput &gdi)
return false;
gdi.setWaitCursor(true);
- if (!oe->save(fileName.c_str())) {
+ if (!oe->save(fileName.c_str(), false)) {
gdi.alert(L"Fel: Filen " + fileName+ L" kunde inte skrivas.");
return false;
}
@@ -662,7 +664,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(3);
gdi.popX();
- gdi.addCheckbox("Clear", "Nollställ databaser", 0, true);
+ gdi.addCheckbox("Clear", "Nollställ databaser");
+ gdi.addCheckbox("IncludeWithoutClub", "Inkludera klubblösa");
+
gdi.dropLine(3);
gdi.popX();
@@ -680,6 +684,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setWaitCursor(true);
gdi.addString("", 0, "Importerar...");
bool clear = gdi.isChecked("Clear");
+ bool requireClub = !gdi.isChecked("IncludeWithoutClub");
wstring club = gdi.getText("ClubFile");
wstring cmp = gdi.getText("CmpFile");
if (club == cmp)
@@ -698,7 +703,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (clubCsv)
throw meosException("Klubbfil får inte anges vid CSV import.");
- oe->importXML_IOF_Data(club, cmp, clear);
+ oe->importXML_IOF_Data(club, cmp, requireClub, clear);
}
gdi.dropLine();
@@ -780,7 +785,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
wchar_t newBase[_MAX_PATH];
getUserFile(newBase, base.c_str());
if (!fileExists(newBase))
- oe->save(newBase);
+ oe->save(newBase, false);
loadConnectionPage(gdi);
}
@@ -911,7 +916,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
oEvent nextStage(gdi);
if (!file.empty())
- success = nextStage.open(file.c_str(), false, false);
+ success = nextStage.open(file.c_str(), false, false, false);
if (success)
success = nextStage.getNameId(0) == oe->getDCI().getString("PostEvent");
@@ -1138,7 +1143,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
wstring startlist = getTempFile();
bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0;
oe->exportIOFStartlist(oEvent::IOF30, startlist.c_str(), eventorUTC,
- set(), false, false, true);
+ set(), false, false, true, true);
vector fileList;
fileList.push_back(startlist);
@@ -1232,7 +1237,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0;
oe->exportIOFSplits(oEvent::IOF30, resultlist.c_str(), false,
eventorUTC, classes, -1, false, true,
- false, true);
+ false, true, true);
vector fileList;
fileList.push_back(resultlist);
@@ -1332,6 +1337,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(3);
gdi.popX();
gdi.addCheckbox("EventorDb", "Uppdatera löpardatabasen", CompetitionCB, true);
+ gdi.addCheckbox("IncludeWithoutClub", "Inkludera klubblösa");
+
gdi.dropLine(3);
gdi.popX();
gdi.addButton("Cancel", "Avbryt", CompetitionCB);
@@ -1339,14 +1346,16 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "EventorCmp") {
gdi.setInputStatus("EventorSel", gdi.isChecked(bi.id));
- gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorDb"));
+ gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) || gdi.isChecked("EventorDb"));
}
else if (bi.id == "EventorDb") {
- gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorCmp"));
+ gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) || gdi.isChecked("EventorCmp"));
}
else if (bi.id == "EventorNext") {
bool cmp = gdi.isChecked("EventorCmp");
bool db = gdi.isChecked("EventorDb");
+ bool withNoClub = gdi.isChecked("IncludeWithoutClub");
+
ListBoxInfo lbi;
gdi.getSelectedItem("EventorSel", lbi);
const CompetitionInfo *ci = 0;
@@ -1355,6 +1364,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.clearPage(true);
gdi.setData("UpdateDB", db);
+ gdi.setData("IncludeWithoutClub", withNoClub);
+
gdi.pushX();
if (cmp && ci) {
gdi.setData("EventIndex", lbi.data);
@@ -1412,11 +1423,14 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.popX();
}
else if (bi.id == "EventorImport") {
- const int diffZeroTime = 3600;
+ const int diffZeroTime = timeConstHour;
DWORD id;
DWORD db;
+ DWORD withNoClub;
+
gdi.getData("EventorId", id);
gdi.getData("UpdateDB", db);
+ gdi.getData("IncludeWithoutClub", withNoClub);
DWORD eventIndex;
gdi.getData("EventIndex", eventIndex);
@@ -1444,7 +1458,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
firstStart = t;
zeroTime = t - diffZeroTime;
if (zeroTime<0)
- zeroTime += 3600*24;
+ zeroTime += timeConstHour * 24;
startType = gdi.getSelectedItem("StartType").first;
lastEntry = gdi.getText("LastEntryDate");
@@ -1509,8 +1523,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
else
tRunnerDB = extractedFiles[0];
}
-
- oe->importXML_IOF_Data(tClubs, tRunnerDB, true);
+
+ oe->importXML_IOF_Data(tClubs, tRunnerDB, withNoClub == 0, true);
removeTempFile(tClubs);
if (id > 0) {
@@ -1522,6 +1536,12 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (createNew && id>0) {
gdi.addString("", 1, "Skapar ny tävling");
oe->newCompetition(L"New");
+ oe->loadDefaults();
+
+ bool importHiredCard = true;
+ if (importHiredCard)
+ importDefaultHiredCards(gdi);
+
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter, noType);
oe->setZeroTime(formatTimeHMS(zeroTime), false);
oe->getDI().setDate("OrdinaryEntry", lastEntry);
@@ -1546,7 +1566,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (!course.empty()) {
gdi.dropLine();
- TabCourse::runCourseImport(gdi, course, oe, true);
+ TabCourse::runCourseImport(gdi, course, oe, true, false);
}
set clsWithRef;
@@ -1563,7 +1583,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
switch (startType) {
case SMCommon:
- oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0",
+ oe->automaticDrawAll(gdi, formatTimeHMS(firstStart, SubSecond::Off), L"0",
L"0", oEvent::VacantPosition::Mixed,
false, false, oEvent::DrawMethod::Random, 1);
break;
@@ -1589,7 +1609,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
}
if (!skip)
- oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00",
+ oe->automaticDrawAll(gdi, formatTimeHMS(firstStart, SubSecond::Off), L"2:00",
L"2", oEvent::VacantPosition::Mixed,
true, false, oEvent::DrawMethod::MeOS, 1);
break;
@@ -1780,7 +1800,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (filterIndex == ImportFormats::IOF30 || filterIndex == ImportFormats::IOF203) {
bool useUTC = oe->getDCI().getInt("UTC") != 0;
oe->exportIOFStartlist(filterIndex == ImportFormats::IOF30 ? oEvent::IOF30 : oEvent::IOF20,
- save.c_str(), useUTC, allTransfer, individual, includeStage, false);
+ save.c_str(), useUTC, allTransfer, individual, includeStage, false, false);
}
else if (filterIndex == ImportFormats::OE) {
oe->exportOECSV(save.c_str(), cSVLanguageHeaderIndex, false);
@@ -1838,7 +1858,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (!gdi.hasWidget("LegType")) {
oe->exportIOFSplits(ver, save.c_str(), true, useUTC,
- allTransfer, -1, false, unroll, includeStage, false);
+ allTransfer, -1, false, unroll, includeStage, false, false);
}
else {
ListBoxInfo leglbi;
@@ -1860,17 +1880,17 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
for (int leg = 0; legexportIOFSplits(ver, file.c_str(), true, useUTC,
- allTransfer, leg, false, unroll, includeStage, false);
+ allTransfer, leg, false, unroll, includeStage, false, false);
}
}
else if (leglbi.data == 3) {
oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer,
- -1, true, unroll, includeStage, false);
+ -1, true, unroll, includeStage, false, false);
}
else {
int leg = leglbi.data == 1 ? -1 : leglbi.data - 10;
oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer,
- leg, false, unroll, includeStage, false);
+ leg, false, unroll, includeStage, false, false);
}
}
}
@@ -1951,6 +1971,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
oe->newCompetition(lang.tl(L"Ny tävling"));
+ oe->loadDefaults();
gdi.setWindowTitle(L"");
if (useEventor()) {
@@ -2077,15 +2098,18 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.disableInput("Cancel");
gdi.disableInput("BrowseCourse");
gdi.disableInput("AddClasses");
+ gdi.disableInput("CreateClasses");
try {
- TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"));
+ TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"),
+ gdi.isChecked("CreateClasses"));
}
- catch (std::exception &) {
+ catch (const std::exception &) {
gdi.enableInput("DoImportCourse");
gdi.enableInput("Cancel");
gdi.enableInput("BrowseCourse");
gdi.enableInput("AddClasses");
+ gdi.enableInput("CreateClasses");
throw;
}
gdi.dropLine();
@@ -2136,7 +2160,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setWaitCursor(true);
xml.openOutput(fileName.c_str(), false);
- IOF30Interface writer(oe, false);
+ IOF30Interface writer(oe, false, false);
writer.writeRunnerDB(oe->getRunnerDatabase(), xml);
gdi.setWaitCursor(false);
}
@@ -2151,7 +2175,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setWaitCursor(true);
xml.openOutput(fileName.c_str(), false);
- IOF30Interface writer(oe, false);
+ IOF30Interface writer(oe, false, false);
writer.writeClubDB(oe->getRunnerDatabase(), xml);
gdi.setWaitCursor(false);
}
@@ -2242,6 +2266,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setInputStatus(gdi.narrow(fn).c_str(), !ii.text.empty());
}
}
+ else if (ii.id == "Name") {
+ updateWarning(gdi);
+ }
}
else if (type==GUI_EVENT) {
EventInfo ei=*(EventInfo *)data;
@@ -2277,16 +2304,16 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setData("RunnerIx", ix);
gdi.dropLine();
gdi.addSelection("Classes", 200, 300, 0, L"Klasser:");
- oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone);
+ oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterOnlySingle);
- if (lastSelectedClass != -1)
- gdi.selectItemByData("Classes", lastSelectedClass);
- else
+ if (lastSelectedClass == -1 || !gdi.selectItemByData("Classes", lastSelectedClass))
gdi.selectFirstItem("Classes");
gdi.dropLine();
gdi.fillRight();
gdi.addButton("DBEntry", "Anmäl", CompetitionCB).setDefault();
+ gdi.setInputStatus("DBEntry", gdi.getSelectedItem("Classes").first > 0); // Cannot change
+
gdi.addButton("CancelEntry", "Avbryt", CompetitionCB).setCancel();
gdi.refresh();
}
@@ -2339,7 +2366,7 @@ int TabCompetition::restoreCB(gdioutput &gdi, int type, void *data) {
if (ti.id == "") {
wstring fi(bi.FullPath);
- if (!oe->open(fi, false, false)) {
+ if (!oe->open(fi, false, false, false)) {
gdi.alert("Kunde inte öppna tävlingen.");
}
else {
@@ -2392,7 +2419,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
gdi.dropLine(0.4);
gdi.fillDown();
- gdi.addString("", 0, makeDash(L"#Copyright © 2007-2022 Melin Software HB"));
+ gdi.addString("", 0, makeDash(L"#Copyright © 2007-2023 Melin Software HB"));
gdi.dropLine(1);
gdi.popX();
@@ -2422,7 +2449,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.dropLine(1.5);
gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
- gdi.addStringUT(1, makeDash(L"Copyright © 2007-2022 Melin Software HB"));
+ gdi.addStringUT(1, makeDash(L"Copyright © 2007-2023 Melin Software HB"));
gdi.dropLine();
gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright "
"(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB,"
@@ -2463,6 +2490,20 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.refresh();
}
+void TabCompetition::updateWarning(gdioutput &gdi) const {
+ const wstring &n = gdi.getText("Name");
+ const wstring &w = gdi.getText("cmpwarning");
+ constexpr int limit = 32;
+ if (n.length() < limit && !w.empty()) {
+ gdi.setText("warningicon", L"", true);
+ gdi.setText("cmpwarning", L"", true);
+ }
+ else if (n.length() >= limit && w.empty()) {
+ gdi.setText("warningicon", L"514", true);
+ gdi.setText("cmpwarning", L"Ett långt tävlingsnamn kan ge oväntad nerskalning av utskrifter.", true);
+ }
+}
+
bool TabCompetition::useEventor() const {
return oe->getPropertyInt("UseEventor", 0) == 1;
}
@@ -2566,7 +2607,7 @@ bool TabCompetition::loadPage(gdioutput &gdi)
gdi.pushX();
gdi.fillRight();
- gdi.addInput("Name", oe->getName(), 24, 0, L"Tävlingsnamn:");
+ gdi.addInput("Name", oe->getName(), 24, CompetitionCB, L"Tävlingsnamn:");
gdi.fillDown();
gdi.addInput("Annotation", oe->getAnnotation(), 20, 0, L"Kommentar / version:")
@@ -2579,12 +2620,16 @@ bool TabCompetition::loadPage(gdioutput &gdi)
gdi.fillDown();
gdi.dropLine(1.2);
+ //int ccx = gdi.getCX();
gdi.addCheckbox("LongTimes", "Aktivera stöd för tider över 24 timmar", CompetitionCB, oe->useLongTimes());
-
+ gdi.addCheckbox("SubSecond", "Aktivera stöd för tiondels sekunder", CompetitionCB, oe->supportSubSeconds());
+
+ gdi.dropLine(0.3);
if (false && oe->isClient()) {
gdi.popX();
gdi.disableInput("ZeroTime");
gdi.disableInput("LongTimes");
+ gdi.disableInput("SubSecond");
if (oe->useLongTimes())
gdi.disableInput("Date");
}
@@ -2651,6 +2696,14 @@ bool TabCompetition::loadPage(gdioutput &gdi)
gdi.fillDown();
gdi.popX();
+ gdi.fillRight();
+ gdi.addString("warningicon", textImage, "S25");
+ gdi.dropLine(0.2);
+ gdi.fillDown();
+ gdi.addString("cmpwarning", 0, "");
+ updateWarning(gdi);
+ gdi.popX();
+
gdi.newColumn();
gdi.dropLine(3);
gdi.setCX(gdi.getCX()+gdi.scaleLength(60));
@@ -2908,26 +2961,26 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
date.getObjectString("Clock", ci.firstStart);
if (useEventorUTC()) {
- int offset = getTimeZoneInfo(ci.Date);
+ int offset = getTimeZoneInfo(ci.Date) * timeConstSecond;
int t = convertAbsoluteTimeISO(ci.firstStart);
int nt = t - offset;
int dayOffset = 0;
if (nt < 0) {
- nt += 24*3600;
+ nt += 24 * timeConstHour;
dayOffset = -1;
}
- else if (nt > 24*3600) {
- nt -= 24*3600;
+ else if (nt > 24* timeConstHour) {
+ nt -= 24* timeConstHour;
dayOffset = 1;
}
- ci.firstStart = formatTimeHMS(nt);
+ ci.firstStart = formatTimeHMS(nt, SubSecond::Off);
//TODO: Take dayoffset into account
}
xmlEvents[k].getObjectString("WebURL", ci.url);
xmlobject aco = xmlEvents[k].getObject("Account");
if (aco) {
- string type = aco.getAttrib("type").get();
+ string type = aco.getAttrib("type").getStr();
wstring no;
aco.getObjectString("AccountNo", no);
@@ -2960,8 +3013,8 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
SYSTEMTIME st;
convertDateYMS(breakDate, st, false);
- __int64 time = SystemTimeToInt64Second(st) - 1;
- breakDate = convertSystemDate(Int64SecondToSystemTime(time));
+ __int64 time = SystemTimeToInt64TenthSecond(st) - 10;
+ breakDate = convertSystemDate(Int64TenthSecondToSystemTime(time));
if (ci.lastNormalEntryDate.empty() || ci.lastNormalEntryDate >= breakDate)
ci.lastNormalEntryDate = breakDate;
@@ -3080,7 +3133,9 @@ void TabCompetition::getEventorCmpData(gdioutput &gdi, int id,
if (dbFile.length() > 0) {
gdi.addString("", 0, "Hämtar löpardatabasen...");
gdi.refreshFast();
- dwl.downloadFile(eventorBase + L"export/cachedcompetitors?organisationIds=1&includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
+ //dwl.downloadFile(eventorBase + L"export/cachedcompetitors?organisationIds=1&includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
+ dwl.downloadFile(eventorBase + L"export/cachedcompetitors?includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
+
dwl.createDownloadThread();
while (dwl.isWorking()) {
Sleep(100);
@@ -3640,7 +3695,7 @@ FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
xml.read(fname);
xmlobject xo = xml.getObject("EntryList");
set scanFilter;
- IOF30Interface reader(oe, false);
+ IOF30Interface reader(oe, false, false);
vector idProviders;
if (xo) {
if (xo.getAttrib("iofVersion")) {
@@ -3967,9 +4022,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
gdi.addString("", 1, "Tidszon");
gdi.dropLine(0.3);
- gdi.addCheckbox("UTC", "Exportera tider i UTC", 0,
- oe->getDCI().getInt("UTC") == 1);
-
+ gdi.addCheckbox("UTC", "Exportera tider i UTC", nullptr, oe->getDCI().getInt("UTC") != 0);
gdi.newColumn();
gdi.popY();
@@ -3999,16 +4052,60 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
gdi.dropLine(3);
gdi.addString("", 1, "Åldersgränser, reducerad anmälningsavgift");
- fields.clear();
- fields.push_back("YouthAge");
- fields.push_back("SeniorAge");
+ gdi.addString("", 0, "Ungdomar och äldre kan få reducerad avgift");
+ gdi.dropLine(0.5);
+
gdi.fillRight();
- oe->getDI().buildDataFields(gdi, fields, 10);
+ auto yfields = oe->getDI().buildDataFields(gdi, { "YouthAge" , "SeniorAge" }, 10);
+
+ class HandleAge : public GuiHandler {
+ public:
+ void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) final {
+ if (type == GuiEventType::GUI_INPUT)
+ update(gdi, true);
+ }
+
+ void update(gdioutput &gdi, bool update) {
+ int youth = gdi.getTextNo("YouthAge_odc");
+ int senior = gdi.getTextNo("SeniorAge_odc");
+
+ InputInfo &ii = dynamic_cast(gdi.getBaseInfo("SeniorAge_odc"));
+ bool warn = senior > 1 && senior <= youth + 1;
+ ii.setBgColor(warn ? colorLightRed : colorDefault);
+
+ string i1, i2, i3;
+ if (youth <= 0 && senior <= 0) {
+ i1 = "Ingen reducerad avgift";
+ }
+ else {
+ i1 = "Reducerad avgift för:";
+
+ if (youth > 0)
+ i2 = "Unga, till och med X år#" + itos(youth);
+ else
+ i2 = "Äldre, från och med X år#" + itos(senior);
+
+ if (youth > 0 && senior > 0)
+ i3 = "Äldre, från och med X år#" + itos(senior);
+ }
+ gdi.setText("ReduceInfo", lang.tl(i1), update);
+ gdi.setText("ReduceInfoL1", i2.empty() ? L"" : L"\u25AA " + lang.tl(i2), update);
+ gdi.setText("ReduceInfoL2", i3.empty() ? L"" : L"\u25AA " + lang.tl(i3), update);
+ }
+ };
gdi.fillDown();
gdi.popX();
- gdi.dropLine(3);
+ gdi.dropLine(2.8);
+ gdi.addString("ReduceInfo", 0, "Ingen reducerad avgift");
+ gdi.addString("ReduceInfoL1", 0, "-");
+ gdi.addString("ReduceInfoL2", 0, "-");
+ auto handler = make_shared();
+ yfields[0]->setHandler(handler);
+ yfields[1]->setHandler(handler);
+
+ gdi.dropLine(0.3);
gdi.addString("", 1, "Valuta");
fields.clear();
@@ -4053,6 +4150,8 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
oe->getDI().buildDataFields(gdi, fields, 10);
oe->getDI().fillDataFields(gdi);
+ handler->update(gdi, false);
+
gdi.dropLine(1);
int bottom = gdi.getCY();
@@ -4097,17 +4196,16 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
}
void TabCompetition::saveSettings(gdioutput &gdi) {
- vector fields;
+ vector fields = { "CardFee" ,"EliteFee" ,"EntryFee","YouthFee" };
vector fees(4);
- fields.push_back("CardFee");
- fields.push_back("EliteFee");
- fields.push_back("EntryFee");
- fields.push_back("YouthFee");
-
+
for (int k = 0; k<4; k++)
fees[k] = oe->getDCI().getInt(fields[k]);
+
wstring factor = oe->getDCI().getString("LateEntryFactor");
- oe->getDI().saveDataFields(gdi);
+ set modified;
+
+ oe->getDI().saveDataFields(gdi, modified);
bool changedFee = false;
bool changedCardFee = false;
@@ -4119,33 +4217,60 @@ void TabCompetition::saveSettings(gdioutput &gdi) {
else {
changedCardFee = true;
if (oe->getDCI().getInt(fields[k]) == 0)
- oe->getDI().setInt(fields[k].c_str(), -1); // Disallow zero card fee. -1 means no fee.
+ oe->getDI().setInt(fields[k], -1); // Disallow zero card fee. -1 means no fee.
}
}
}
if (factor != oe->getDCI().getString("LateEntryFactor"))
changedFee = true;
- oe->getDI().setInt("UTC", gdi.isChecked("UTC") ? 1 : 0);
+ if (oe->getDI().setInt("UTC", gdi.isChecked("UTC") ? 1 : 0))
+ setEventorUTC(gdi.isChecked("UTC"));
+
+ if (oe->getDI().setInt("CurrencyFactor", gdi.isChecked("UseFraction") ? 100 : 1))
+ modified.insert("CurrencyFactor");
+
+ if (oe->getDI().setInt("CurrencyPreSymbol", gdi.isChecked("PreSymbol") ? 1 : 0))
+ modified.insert("CurrencyPreSymbol");
- oe->getDI().setInt("CurrencyFactor", gdi.isChecked("UseFraction") ? 100 : 1);
- oe->getDI().setInt("CurrencyPreSymbol", gdi.isChecked("PreSymbol") ? 1 : 0);
oe->setCurrency(-1, L"", L"", false);
- vector< pair > modes;
+ wstring pm = oe->getDCI().getString("PayModes");
+ vector> modes;
oe->getPayModes(modes);
for (size_t k = 0; k < modes.size(); k++) {
string field = "M"+itos(k);
if (gdi.hasWidget(field)) {
wstring mode = gdi.getText("M"+itos(k));
- int id = gdi.getBaseInfo(field.c_str()).getExtraInt();
+ int id = gdi.getBaseInfo(field).getExtraInt();
oe->setPayMode(id, mode);
}
}
+ if (pm != oe->getDCI().getString("PayModes"))
+ modified.insert("PayModes");
// Read from model
if (oe->isChanged()) {
- oe->setProperty("Organizer", oe->getDCI().getString("Organizer"));
+ vector props = { "Organizer" ,"Street" ,"Address" ,"EMail" ,"Homepage" ,
+ "YouthAge","SeniorAge","Account", "LateEntryFactor","CurrencySymbol",
+ "CurrencyFactor","CurrencyPreSymbol","CurrencySeparator",
+ "CardFee","EliteFee","EntryFee","YouthFee", "PayModes" };
+
+ auto dci = oe->getDCI();
+ for (const string &p : props) {
+ if (modified.count(p)) {
+ if (dci.isString(p))
+ oe->setProperty(p.c_str(), dci.getString(p));
+ else if (dci.isInt(p))
+ oe->setProperty(p.c_str(), dci.getInt(p));
+ else
+ throw std::exception();
+ }
+ }
+
+ //oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
+
+ /*oe->setProperty("Organizer", oe->getDCI().getString("Organizer"));
oe->setProperty("Street", oe->getDCI().getString("Street"));
oe->setProperty("Address", oe->getDCI().getString("Address"));
oe->setProperty("EMail", oe->getDCI().getString("EMail"));
@@ -4166,8 +4291,8 @@ void TabCompetition::saveSettings(gdioutput &gdi) {
oe->setProperty("CurrencyFactor", oe->getDCI().getInt("CurrencyFactor"));
oe->setProperty("CurrencyPreSymbol", oe->getDCI().getInt("CurrencyPreSymbol"));
oe->setProperty("CurrencySeparator", oe->getDCI().getString("CurrencySeparator"));
-
- oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
+ */
+ //oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
}
oe->synchronize(true);
set dummy;
@@ -4260,7 +4385,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
if (!thisFile.empty()) {
wchar_t newBase[_MAX_PATH];
getUserFile(newBase, thisFile.c_str());
- mergeEvent->save(newBase);
+ mergeEvent->save(newBase, false);
}
tc->oe->merge(*mergeEvent, baseEvent.get(), allowRemove, numAdd, numRemove, numUpdate);
@@ -4285,7 +4410,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
gdi.refresh();
}
else if (bi.id == "Browse") {
- wstring fn = gdi.browseForOpen({ make_pair(L"xml", L"*.xml") }, L"xml");
+ wstring fn = gdi.browseForOpen({ make_pair(L"MeOS-data", L"*.meosxml;*.xml;*.bu?") }, L"meosxml");
if (fn.empty())
return;
@@ -4296,7 +4421,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
else if (bi.id == "Read") {
mergeEvent = make_shared(gdi);
- if (!mergeEvent->open(tc->mergeFile, true, true))
+ if (!mergeEvent->open(tc->mergeFile, true, true, false))
return;
gdi.restore("merge", false);
@@ -4384,7 +4509,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
baseEvent = make_shared(gdi);
bool ok = false;
try {
- ok = baseEvent->open(base, true, true);
+ ok = baseEvent->open(base, true, true, false);
ok = true;
}
catch (...) {
diff --git a/code/TabCompetition.h b/code/TabCompetition.h
index 8d7b3ca..69a89bf 100644
--- a/code/TabCompetition.h
+++ b/code/TabCompetition.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -60,6 +60,8 @@ class TabCompetition :
void copyrightLine(gdioutput &gdi) const;
void loadAboutPage(gdioutput &gdi) const;
+ void updateWarning(gdioutput &gdi) const;
+
int organizorId;
int lastChangeClassType;
@@ -118,6 +120,7 @@ class TabCompetition :
void meosFeatures(gdioutput &gdi, bool newGuide);
void newCompetitionGuide(gdioutput &gdi, int step);
+ void createNewCmp(gdioutput &gdi, bool useExisting);
void entryForm(gdioutput &gdi, bool isGuide);
FlowOperation saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide);
@@ -132,6 +135,8 @@ class TabCompetition :
void entryChoice(gdioutput &gdi);
void createCompetition(gdioutput &gdi);
+ void importDefaultHiredCards(gdioutput& gdi);
+
void listBackups(gdioutput &gdi);
shared_ptr mergeHandler;
diff --git a/code/TabControl.cpp b/code/TabControl.cpp
index c80133b..d2f94d2 100644
--- a/code/TabControl.cpp
+++ b/code/TabControl.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,35 +55,46 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
if (pc) {
pc->synchronize();
- if (pc->getStatus() == oControl::StatusStart ||
- pc->getStatus() == oControl::StatusFinish) {
+ if (oControl::isSpecialControl(pc->getStatus())) {
gdi.selectItemByData("Controls", pc->getId());
- gdi.selectItemByData("Status", oControl::StatusOK);
+ gdi.selectItemByData("Status", int(oControl::ControlStatus::StatusOK));
gdi.setText("ControlID", makeDash(L"-"), true);
gdi.setText("Code", L"");
gdi.setText("Name", pc->getName());
- gdi.setText("TimeAdjust", L"00:00");
+ gdi.setText("TimeAdjust", pc->getTimeAdjustS());
gdi.setText("MinTime", makeDash(L"-"));
gdi.setText("Point", L"");
+ gdi.disableInput("Visitors");
+ gdi.disableInput("Courses");
+
controlId = pc->getId();
gdi.enableInput("Remove");
gdi.enableInput("Save");
gdi.enableEditControls(false);
gdi.enableInput("Name");
+
+ if (pc->getUnitCode() > 0) {
+ gdi.setText("Code", itow(pc->getUnitCode()));
+ gdi.enableInput("TimeAdjust");
+ gdi.setText("Info", lang.tl("Du kan justera tiden för en viss enhet"), true);
+ }
+ else {
+ gdi.setText("Info", L"", true);
+ }
}
else {
gdi.selectItemByData("Controls", pc->getId());
- gdi.selectItemByData("Status", pc->getStatus());
+ gdi.selectItemByData("Status", int(pc->getStatus()));
const int numVisit = pc->getNumVisitors(true);
const int numVisitExp = pc->getNumVisitors(false);
wstring info;
if (numVisit > 0) {
info = L"Antal besökare X, genomsnittlig bomtid Y, största bomtid Z#" +
- itow(numVisit) + L" (" + itow(numVisitExp) + L")#" + getTimeMS(pc->getMissedTimeTotal() / numVisit) +
- L"#" + getTimeMS(pc->getMissedTimeMax());
+ itow(numVisit) + L" (" + itow(numVisitExp) + L")#" + formatTimeMS(pc->getMissedTimeTotal() / numVisit, false, SubSecond::Off) +
+ L"#" + formatTimeMS(pc->getMissedTimeMax(), false, SubSecond::Off);
}
else if (numVisitExp > 0) {
info = L"Förväntat antal besökare: X#" + itow(numVisitExp);
@@ -108,19 +119,20 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
gdi.enableEditControls(true);
oControl::ControlStatus st = pc->getStatus();
- if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
+ if (st == oControl::ControlStatus::StatusRogaining || st == oControl::ControlStatus::StatusRogainingRequired ||
+ st == oControl::ControlStatus::StatusNoTiming || st == oControl::ControlStatus::StatusBadNoTiming)
gdi.disableInput("MinTime");
- if (st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
+ if (st == oControl::ControlStatus::StatusNoTiming || st == oControl::ControlStatus::StatusBadNoTiming)
gdi.disableInput("TimeAdjust");
- if (gdi.hasWidget("Point") && st != oControl::StatusRogaining)
+ if (gdi.hasWidget("Point") && st != oControl::ControlStatus::StatusRogaining && st != oControl::ControlStatus::StatusRogainingRequired)
gdi.disableInput("Point");
}
}
else {
gdi.selectItemByData("Controls", -1);
- gdi.selectItemByData("Status", oControl::StatusOK);
+ gdi.selectItemByData("Status", int(oControl::ControlStatus::StatusOK));
gdi.setText("Code", L"");
gdi.setText("Name", L"");
controlId = 0;
@@ -145,26 +157,58 @@ int ControlsCB(gdioutput *gdi, int type, void *data)
return tc.controlCB(*gdi, type, data);
}
-void TabControl::save(gdioutput &gdi)
-{
+void TabControl::save(gdioutput &gdi) {
if (controlId==0)
return;
- DWORD pcid = controlId;
-
- pControl pc;
- pc = oe->getControl(pcid, false);
+ pControl pc = oe->getControl(controlId, false, true);
if (!pc)
throw std::exception("Internal error");
- if (pc->getStatus() != oControl::StatusFinish && pc->getStatus() != oControl::StatusStart) {
+
+ if (!pc->isAddedToEvent()) {
+ if (gdi.getText("TimeAdjust") == pc->getTimeAdjustS()
+ && gdi.getText("Name") == pc->getName())
+ return; // Virtual control with no change.
+
+ oe->synchronizeList(oListId::oLControlId);
+ pc = oe->getControl(controlId, false, true);
+
+ if (!pc->isAddedToEvent())
+ pc = oe->addControl(*pc);
+
+ if (!pc)
+ throw std::exception("Internal error");
+ }
+
+ bool defaultName = false;
+
+ if (!oControl::isSpecialControl(pc->getStatus())) {
+ int oldFirst = pc->getFirstNumber();
+
if (!pc->setNumbers(gdi.getText("Code")))
gdi.alert("Kodsiffran måste vara ett heltal. Flera kodsiffror måste separeras med komma.");
+ int newFirst = pc->getFirstNumber();
+ if (oldFirst != newFirst && pc->getId() == oldFirst) {
+ // Update id if possible (make new control and remove old)
+ if (!oe->isControlUsed(pc->getId()) && oe->getControl(newFirst) == nullptr) {
+ pc->setName(gdi.getText("Name"));
+ if (!pc->hasName())
+ defaultName = true;
+
+ pc = oe->addControl(newFirst, newFirst, L"");
+ pc->synchronize();
+ controlId = pc->getId();
+ pc->setNumbers(gdi.getText("Code"));
+ oe->removeControl(oldFirst);
+ }
+ }
+
pc->setStatus(oControl::ControlStatus(gdi.getSelectedItem("Status").first));
pc->setTimeAdjust(gdi.getText("TimeAdjust"));
- if (pc->getStatus() != oControl::StatusRogaining) {
- if (pc->getStatus() != oControl::StatusNoTiming && pc->getStatus() != oControl::StatusBadNoTiming)
+ if (pc->getStatus() != oControl::ControlStatus::StatusRogaining && pc->getStatus() != oControl::ControlStatus::StatusRogainingRequired) {
+ if (pc->getStatus() != oControl::ControlStatus::StatusNoTiming && pc->getStatus() != oControl::ControlStatus::StatusBadNoTiming)
pc->setMinTime(gdi.getText("MinTime"));
pc->setRogainingPoints(0);
}
@@ -175,12 +219,65 @@ void TabControl::save(gdioutput &gdi)
}
}
}
+ else if (pc->isUnit()) {
+ // Ensure cache is up-to-date
+ auto type = pc->getUnitType();
+ int oldAdjust = oe->getUnitAdjustment(type, pc->getUnitCode());
- pc->setName(gdi.getText("Name"));
+ if (pc->setTimeAdjust(gdi.getText("TimeAdjust"))) {
+
+ // Cache is not updated. No new adjustment applied
+ assert(oldAdjust == oe->getUnitAdjustment(type, pc->getUnitCode()));
+
+ vector> adjustList;
+
+ if (type == oPunch::SpecialPunch::PunchStart) {
+ auto pList = oe->getPunchesByType(type, pc->getUnitCode());
+ for (auto p : pList) {
+ pRunner r = oe->getRunnerByCardNo(p->getCardNo(), p->getTimeInt(), oEvent::CardLookupProperty::Any);
+ if (r && !r->getCard() && r->getStartTime() == p->getTimeInt()) {
+ // Need not adjust runners with card.
+ adjustList.emplace_back(r, p);
+ }
+ }
+ }
+ else if (type == oPunch::SpecialPunch::PunchFinish) {
+ auto pList = oe->getPunchesByType(type, pc->getUnitCode());
+ for (auto p : pList) {
+ pRunner r = oe->getRunnerByCardNo(p->getCardNo(), p->getTimeInt(), oEvent::CardLookupProperty::Any);
+ if (r && !r->getCard() && r->getFinishTime() == p->getTimeInt()) {
+ // Need not adjust runners with card.
+ adjustList.emplace_back(r, p);
+ }
+ }
+ }
+
+ // Clear cache to make sure adjustment takes effect
+ pc->clearCache();
+ oe->clearUnitAdjustmentCache();
+
+ // With new adjustment applied
+ assert(oldAdjust != oe->getUnitAdjustment(type, pc->getUnitCode()));
+
+ for (auto& rp : adjustList) {
+ if (type == oPunch::SpecialPunch::PunchStart) {
+ rp.first->setStartTime(rp.second->getTimeInt(), true, oBase::ChangeType::Update, true);
+ }
+ else if (type == oPunch::SpecialPunch::PunchFinish) {
+ rp.first->setFinishTime(rp.second->getTimeInt());
+ }
+ rp.first->synchronize(true);
+ }
+ }
+ }
+
+ if (!defaultName)
+ pc->setName(gdi.getText("Name"));
pc->synchronize();
- vector< pair > d;
- oe->fillControls(d, oEvent::CTAll);
+
+ vector> d;
+ oe->fillControls(d, oEvent::ControlType::All);
gdi.addItem("Controls", d);
oe->reEvaluateAll(set(), true);
@@ -239,8 +336,8 @@ void TabControl::courseTable(Table &table) const {
void TabControl::visitorTable(Table &table) const {
vector c;
- oe->getCards(c);
- pControl pc = oe->getControl(controlId, false);
+ oe->getCards(c, true, false);
+ pControl pc = oe->getControl(controlId, false, true);
if (!pc)
return;
@@ -297,7 +394,7 @@ void TabControl::visitorTable(Table &table) const {
lang.tl("Ja") : lang.tl("Nej"), false);
table.set(row++, it, TID_CARD, it.getCardNoString(), false);
- table.set(row++, it, TID_STATUS, punch->getTime(), false);
+ table.set(row++, it, TID_STATUS, punch->getTime(false, SubSecond::Auto), false);
table.set(row++, it, TID_CONTROL, punch->getType(), false);
table.set(row++, it, TID_CODES, j>0 ? p[j-1]->getType() : L"-", true);
}
@@ -316,15 +413,24 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
bool rogaining = false;
if (controlId>0) {
save(gdi);
- pControl pc = oe->getControl(controlId, false);
- rogaining = pc && pc->getStatus() == oControl::StatusRogaining;
+ pControl pc = oe->getControl(controlId, false, true);
+ rogaining = pc && (pc->getStatus() == oControl::ControlStatus::StatusRogaining || pc->getStatus() == oControl::ControlStatus::StatusRogainingRequired);
}
- pControl pc = oe->addControl(0,oe->getNextControlNumber(), L"");
+ int nextCtrl = oe->getNextControlNumber();
+ int nextId = nextCtrl;
+ if (oe->getControl(nextId)) {
+ nextId += 1000;
+ if (oe->getControl(nextId))
+ nextId = 0; // Use default
+ }
+ pControl pc = oe->addControl(nextId, nextCtrl, L"");
if (rogaining)
- pc->setStatus(oControl::StatusRogaining);
+ pc->setStatus(oControl::ControlStatus::StatusRogaining);
+
+ pc->synchronize();
vector< pair > d;
- oe->fillControls(d, oEvent::CTAll);
+ oe->fillControls(d, oEvent::ControlType::All);
gdi.addItem("Controls", d);
selectControl(gdi, pc);
}
@@ -342,7 +448,7 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
oe->removeControl(cid);
vector< pair > d;
- oe->fillControls(d, oEvent::CTAll);
+ oe->fillControls(d, oEvent::ControlType::All);
gdi.addItem("Controls", d);
selectControl(gdi, 0);
}
@@ -409,16 +515,17 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
if (gdi.isInputChanged(""))
save(gdi);
- pControl pc=oe->getControl(bi.data, false);
+ pControl pc=oe->getControl(bi.data, false, true);
if (!pc)
throw std::exception("Internal error");
selectControl(gdi, pc);
}
else if (bi.id == "Status" ) {
- gdi.setInputStatus("MinTime", bi.data != oControl::StatusRogaining && bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
- gdi.setInputStatus("Point", bi.data == oControl::StatusRogaining, true);
- gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
+ oControl::ControlStatus st = (oControl::ControlStatus)bi.data;
+ gdi.setInputStatus("MinTime", st != oControl::ControlStatus::StatusRogaining && st != oControl::ControlStatus::StatusRogainingRequired && st != oControl::ControlStatus::StatusNoTiming && st != oControl::ControlStatus::StatusBadNoTiming, true);
+ gdi.setInputStatus("Point", st == oControl::ControlStatus::StatusRogaining || st != oControl::ControlStatus::StatusRogainingRequired, true);
+ gdi.setInputStatus("TimeAdjust", st != oControl::ControlStatus::StatusNoTiming && st != oControl::ControlStatus::StatusBadNoTiming, true);
}
}
else if (type==GUI_CLEAR) {
@@ -454,10 +561,10 @@ bool TabControl::loadPage(gdioutput &gdi)
gdi.pushY();
gdi.addListBox("Controls", 250, 530, ControlsCB).isEdit(false).ignore(true);
- gdi.setTabStops("Controls", 40, 160);
+ gdi.setTabStops("Controls", 44, 160);
vector< pair > d;
- oe->fillControls(d, oEvent::CTAll);
+ oe->fillControls(d, oEvent::ControlType::All);
gdi.addItem("Controls", d);
gdi.newColumn();
@@ -515,7 +622,7 @@ bool TabControl::loadPage(gdioutput &gdi)
gdi.dropLine(1.5);
gdi.addString("", 10, "help:89064");
- selectControl(gdi, oe->getControl(controlId, false));
+ selectControl(gdi, oe->getControl(controlId, false, true));
gdi.setOnClearCb(ControlsCB);
diff --git a/code/TabControl.h b/code/TabControl.h
index f8153f7..bad7b07 100644
--- a/code/TabControl.h
+++ b/code/TabControl.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabCourse.cpp b/code/TabCourse.cpp
index 4210314..d468ebd 100644
--- a/code/TabCourse.cpp
+++ b/code/TabCourse.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -459,7 +459,7 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
ext.push_back(make_pair(L"IOF CourseData, version 3.0 (xml)", L"*.xml"));
wstring save = gdi.browseForSave(ext, L"xml", FilterIndex);
if (save.length()>0) {
- IOF30Interface iof30(oe, false);
+ IOF30Interface iof30(oe, false, false);
xmlparser xml;
xml.openOutput(save.c_str(), false);
iof30.writeCourses(xml);
@@ -477,15 +477,19 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
gdi.disableInput("Cancel");
gdi.disableInput("BrowseCourse");
gdi.disableInput("AddClasses");
+ gdi.disableInput("CreateClasses");
try {
- TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"));
+ TabCourse::runCourseImport(gdi, filename, oe,
+ gdi.isChecked("AddClasses"),
+ gdi.isChecked("CreateClasses"));
}
- catch (std::exception &) {
+ catch (const std::exception &) {
gdi.enableInput("DoImportCourse");
gdi.enableInput("Cancel");
gdi.enableInput("BrowseCourse");
gdi.enableInput("AddClasses");
+ gdi.enableInput("CreateClasses");
throw;
}
gdi.addButton("Cancel", "OK", CourseCB);
@@ -525,8 +529,8 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
gdi.pushX();
gdi.fillRight();
- int firstStart = 3600;
- int interval = 2*60;
+ int firstStart = timeConstHour;
+ int interval = 2*timeConstMinute;
int vac = 1;
gdi.addInput("FirstStart", oe->getAbsTime(firstStart), 10, 0, L"Första start:");
gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):");
@@ -891,14 +895,14 @@ bool TabCourse::loadPage(gdioutput &gdi) {
}
void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
- oEvent *oe, bool addClasses) {
+ oEvent *oe, bool addToClasses, bool createClasses) {
if (csvparser::iscsv(filename) != csvparser::CSV::NoCSV) {
gdi.fillRight();
gdi.pushX();
gdi.addString("", 0, "Importerar OCAD csv-fil...");
gdi.refreshFast();
csvparser csv;
- if (csv.importOCAD_CSV(*oe, filename, addClasses)) {
+ if (csv.importOCAD_CSV(*oe, filename, addToClasses)) {
gdi.addString("", 1, "Klart.").setColor(colorGreen);
}
else gdi.addString("", 0, "Operationen misslyckades.").setColor(colorRed);
@@ -906,12 +910,64 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
gdi.dropLine(2.5);
gdi.fillDown();
}
+ else if (filename.find(L".txt") != wstring::npos || filename.find(L".TXT") != wstring::npos) {
+ ifstream fin(filename);
+
+ if (!fin.good())
+ throw meosException(L"Cannot read " + filename);
+
+ char bf[2048];
+ vector sw;
+ int importedC = oe->getNumCourses() + 1;
+ int line = 0;
+ while (fin.good()) {
+ fin.getline(bf, 2048);
+ if (strlen(bf) < 2)
+ continue;
+
+ if (0 == line && uint8_t(bf[0]) == 0xEF && uint8_t(bf[1]) == 0xBB && uint8_t(bf[2]) == 0xBF)
+ split(bf+3, " ;,", sw);
+ else
+ split(bf, " ;,", sw);
+ line++;
+
+ if (sw.size() <= 1)
+ continue;
+
+ wstring name;
+ int first = 0;
+ if (atoi(sw[0].c_str()) < 30 && trim(sw[0]).length() > 2) {
+ name = gdioutput::fromUTF8(trim(sw[0]));
+ first = 1;
+ }
+ if (name.empty())
+ name = lang.tl("Bana X#" + itos(importedC++));
+
+ string cs;
+ for (int i = first; i < sw.size(); i++) {
+ if (trim(sw[i]).empty())
+ continue;
+ int c = atoi(sw[i].c_str());
+ if (c >= 30 && c < 1000)
+ cs += itos(c) + " ";
+ else {
+ throw meosException("Kan inte tolka 'X' som en bana#" + string(bf));
+ }
+ }
+
+ pCourse pc = oe->addCourse(name);
+ pc->importControls(cs, true, false);
+ pc->synchronize();
+ }
+
+ fin.close();
+ }
else {
set noFilter;
string noType;
- oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter, noType);
+ oe->importXML_EntryData(gdi, filename.c_str(), addToClasses, false, noFilter, noType);
}
- if (addClasses) {
+ if (addToClasses) {
// There is specific course-class matching inside the import of each format,
// that uses additional information. Here we try to match based on a generic approach.
vector cls;
@@ -1012,6 +1068,34 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
gdi.dropLine();
}
+ if (createClasses) {
+ vector cls;
+ vector crs;
+ oe->getClasses(cls, false);
+ oe->getCourses(crs);
+ unordered_set usedCourseId;
+ vector usedCrs;
+ for (size_t k = 0; k < cls.size(); k++) {
+ cls[k]->getCourses(-1, usedCrs);
+ for (pCourse pc : usedCrs)
+ usedCourseId.insert(pc->getId());
+ }
+
+ set usedNames;
+ for (pCourse pc : crs) {
+ if (usedCourseId.count(pc->getId()))
+ continue;
+
+ pClass matchCls = oe->getClassCreate(-1, pc->getName(), usedNames);
+ if (!matchCls || matchCls->getCourse(false)) {
+ oe->addClass(pc->getName() + lang.tl(" Bana"), pc->getId());
+ }
+ else {
+ matchCls->setCourse(pc);
+ }
+ }
+ }
+
gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(baseButtonWidth),
"Print", "Skriv ut...", CourseCB,
"Skriv ut listan.", true, false);
@@ -1043,6 +1127,7 @@ void TabCourse::setupCourseImport(gdioutput& gdi, GUICALLBACK cb) {
gdi.fillDown();
gdi.addCheckbox("AddClasses", "Lägg till klasser", 0, true);
+ gdi.addCheckbox("CreateClasses", "Skapa en klass för varje bana", 0, false);
gdi.dropLine();
gdi.fillRight();
@@ -1060,9 +1145,9 @@ void TabCourse::fillCourseControls(gdioutput &gdi, const wstring &ctrl) {
vector< pair > item;
map used;
for (size_t k = 0; k < nr.size(); k++) {
- pControl pc = oe->getControl(nr[k], false);
+ pControl pc = oe->getControl(nr[k], false, false);
if (pc) {
- if (pc->getStatus() == oControl::StatusOK)
+ if (pc->getStatus() == oControl::ControlStatus::StatusOK)
++used[pc->getFirstNumber()];
}
else
@@ -1085,7 +1170,7 @@ void TabCourse::fillCourseControls(gdioutput &gdi, const wstring &ctrl) {
void TabCourse::fillOtherCourses(gdioutput &gdi, oCourse &crs, bool withLoops) {
vector< pair > ac;
- oe->fillCourses(ac, true);
+ oe->getCourses(ac, L"", true);
set skipped;
skipped.insert(crs.getId());
pCourse longer = crs.getLongerVersion();
@@ -1223,7 +1308,7 @@ wstring TabCourse::encodeCourse(const wstring &in, bool rogaining, bool firstSta
}
const wstring &TabCourse::formatControl(int id, wstring &bf) const {
- pControl ctrl = oe->getControl(id, false);
+ pControl ctrl = oe->getControl(id, false, true);
if (ctrl) {
bf = ctrl->getString();
return bf;
@@ -1231,3 +1316,4 @@ const wstring &TabCourse::formatControl(int id, wstring &bf) const {
else
return itow(id);
}
+
diff --git a/code/TabCourse.h b/code/TabCourse.h
index 26355aa..64e2fb9 100644
--- a/code/TabCourse.h
+++ b/code/TabCourse.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -70,7 +70,7 @@ public:
~TabCourse(void);
static void runCourseImport(gdioutput& gdi, const wstring &filename,
- oEvent *oe, bool addClasses);
+ oEvent *oe, bool addToClasses, bool createClasses);
static void setupCourseImport(gdioutput& gdi, GUICALLBACK cb);
diff --git a/code/TabList.cpp b/code/TabList.cpp
index 2e1ef1c..a547c8a 100644
--- a/code/TabList.cpp
+++ b/code/TabList.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -341,7 +341,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id=="Copy") {
ostringstream fout;
- HTMLWriter::writeTableHTML(gdi, fout, L"MeOS", true, 0, 1.0);
+ HTMLWriter::writeTableHTML(gdi, fout, L"MeOS", false, L"", true, 0, 1.0);
string res = fout.str();
gdi.copyToClipboard(res, L"");
}
@@ -570,32 +570,44 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="CancelPS") {
gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi);
}
- else if (bi.id=="SavePS") {
+ else if (bi.id == "SavePS") {
string ctype;
gdi.getData("Type", ctype);
saveExtraLines(*oe, ctype.c_str(), gdi);
if (gdi.hasWidget("SplitAnalysis")) {
int aflag = (gdi.isChecked("SplitAnalysis") ? 0 : 1) + (gdi.isChecked("Speed") ? 0 : 2)
- + (gdi.isChecked("Results") ? 0 : 4);
+ + (gdi.isChecked("Results") ? 0 : 4);
oe->getDI().setInt("Analysis", aflag);
}
-
- if (gdi.hasWidget("WideFormat")) {
- bool wide = gdi.isChecked("WideFormat");
- oe->setProperty("WideSplitFormat", wide);
-
- if (wide && gdi.hasWidget("NumPerPage")) {
- pair res = gdi.getSelectedItem("NumPerPage");
- if (res.second)
- oe->setProperty("NumSplitsOnePage", res.first);
+ if (gdi.hasWidget("SplitPrintList")) {
+ auto res = gdi.getSelectedItem("SplitPrintList");
+ if (res.second) {
+ if (res.first == -10)
+ oe->getDI().setString("SplitPrint", L"");
+ else {
+ EStdListType type = oe->getListContainer().getType(res.first);
+ string id = oe->getListContainer().getUniqueId(type);
+ oe->getDI().setString("SplitPrint", gdioutput::widen(id));
+ }
+ }
+ }
+
+ if (gdi.hasWidget("WideFormat")) {
+ bool wide = gdi.isChecked("WideFormat");
+ oe->setProperty("WideSplitFormat", wide);
- int no = gdi.getTextNo("MaxWaitTime");
- if (no >= 0)
- oe->setProperty("SplitPrintMaxWait", no);
- }
- }
+ if (wide && gdi.hasWidget("NumPerPage")) {
+ pair res = gdi.getSelectedItem("NumPerPage");
+ if (res.second)
+ oe->setProperty("NumSplitsOnePage", res.first);
+
+ int no = gdi.getTextNo("MaxWaitTime");
+ if (no >= 0)
+ oe->setProperty("SplitPrintMaxWait", no);
+ }
+ }
gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi);
}
else if (bi.id == "PrinterSetup") {
@@ -1071,11 +1083,21 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
return listCB(gdi, GUI_BUTTON, &bi);
}
-
gdi.clearPage(false);
gdi.addString("", boldLarge, "Tillgängliga listor");
- int xx = gdi.getCX() + gdi.scaleLength(360);
int bx = gdi.getCX();
+ int xx = bx + gdi.scaleLength(360);
+ TextInfo ti;
+ for (size_t k = 0; k < installedLists.size(); k++) {
+ ti.text = installedLists[k].first;
+ gdi.calcStringSize(ti);
+ xx = max(xx, bx + ti.realWidth + 10);
+ }
+ for (size_t k = 0; k < lists.size(); k++) {
+ ti.text = lists[k].first;
+ gdi.calcStringSize(ti);
+ xx = max(xx, bx + ti.realWidth + 10);
+ }
if (!installedLists.empty()) {
gdi.dropLine();
gdi.addString("", 1, "Listor i tävlingen");
@@ -1141,8 +1163,13 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
xmlobject xlist = xml.getObject(0);
oe->synchronize();
oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false);
- oe->synchronize(true);
+
+ set imgUsed;
+ oe->getListContainer().getUsedImages(imgUsed);
+ for (uint64_t id : imgUsed)
+ oe->saveImage(id);
+ oe->synchronize(true);
loadPage(gdi);
}
}
@@ -1218,6 +1245,12 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oe->synchronize(false);
oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false);
+
+ set imgUsed;
+ oe->getListContainer().getUsedImages(imgUsed);
+ for (uint64_t id : imgUsed)
+ oe->saveImage(id);
+
oe->synchronize(true);
oe->loadGeneralResults(true, false);
}
@@ -1286,7 +1319,7 @@ pair TabList::makeOwnWindow(gdioutput &gdi) {
void TabList::enableFromTo(oEvent &oe, gdioutput &gdi, bool from, bool to) {
vector< pair > d;
- oe.fillControls(d, oEvent::CTCourseControl);
+ oe.fillControls(d, oEvent::ControlType::CourseControl);
if (from) {
gdi.enableInput("ResultSpecialFrom");
@@ -2216,7 +2249,7 @@ void TabList::settingsResultList(gdioutput &gdi)
vector< pair > lists;
vector< pair > dlists;
const MetaListContainer &lc = oe->getListContainer();
- lc.getLists(dlists, false, true, !oe->hasTeam());
+ lc.getLists(dlists, false, true, !oe->hasTeam(), false);
set usedListIx;
map tag2ListIx;
for (size_t k = 0; k < dlists.size(); k++) {
@@ -2725,31 +2758,72 @@ void TabList::splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter,
gdi.addString("", boldLarge, "Inställningar startbevis");
gdi.dropLine();
-
- gdi.fillRight();
gdi.pushX();
- if (setupPrinter) {
- gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
- gdi.dropLine(0.3);
- }
-
-
+
if (!oe.empty() && type == Splits) {
- bool withSplitAnalysis = (oe.getDCI().getInt("Analysis") & 1) == 0;
+ gdi.fillRight();
+ gdi.addSelection("SplitPrintList", 200, 200, nullptr, L"Sträcktidslista:");
+ if (setupPrinter) {
+ gdi.dropLine(0.9);
+ gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
+ gdi.dropLine(2.8);
+ }
+ else {
+ gdi.dropLine(3);
+ }
+
+ gdi.fillDown();
+ gdi.popX();
+ gdi.addString("", 10, "info:customsplitprint");
+ gdi.dropLine();
+ vector> lists;
+ oe.getListContainer().getLists(lists, false, false, false, true);
+ lists.insert(lists.begin(), make_pair(lang.tl("Standard"), -10));
+ gdi.addItem("SplitPrintList", lists);
+ wstring listId = oe.getDCI().getString("SplitPrint");
+ EStdListType type = oe.getListContainer().getCodeFromUnqiueId(gdioutput::narrow(listId));
+ if (type == EStdListType::EStdNone)
+ gdi.selectFirstItem("SplitPrintList");
+ else {
+ for (auto& t : lists) {
+ if (type == oe.getListContainer().getType(t.second))
+ gdi.selectItemByData("SplitPrintList", t.second);
+ }
+ }
+ //if ()
+ /* bool withSplitAnalysis = (oe.getDCI().getInt("Analysis") & 1) == 0;
bool withSpeed = (oe.getDCI().getInt("Analysis") & 2) == 0;
bool withResult = (oe.getDCI().getInt("Analysis") & 4) == 0;
gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", 0, withSplitAnalysis);
gdi.addCheckbox("Speed", "Med km-tid", 0, withSpeed);
- gdi.addCheckbox("Results", "Med resultat", 0, withResult);
-
+ gdi.addCheckbox("Results", "Med resultat", 0, withResult);*/
}
+ else if (setupPrinter) {
+ gdi.dropLine(0.2);
+ gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
+ }
+
gdi.popX();
- gdi.fillDown();
+
+ RECT rc;
+ rc.top = gdi.getCY();
+ rc.left = gdi.getCX();
+ gdi.setCX(gdi.getCX() + gdi.scaleLength(8));
+ gdi.dropLine();
+
const char *ctype = type == Splits ? "SPExtra" : "EntryExtra";
- customTextLines(oe, ctype, gdi);
+ customTextLines(oe, ctype, !oe.empty(), gdi);
+
+ gdi.dropLine();
+
+ rc.right = gdi.getWidth();
+ rc.bottom = gdi.getCY();
+
+ gdi.addRectangle(rc, colorLightCyan);
if (type == Splits) {
+ gdi.dropLine(1.5);
const bool wideFormat = oe.getPropertyInt("WideSplitFormat", 0) == 1;
gdi.addCheckbox("WideFormat", "Sträcktider i kolumner (för standardpapper)", ListsCB, wideFormat);
@@ -2769,7 +2843,7 @@ void TabList::splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter,
}
}
-
+ gdi.dropLine();
gdi.fillRight();
gdi.setData("Type", ctype);
gdi.addButton("SavePS", "OK", ListsCB).setDefault().setExtra(returnMode);
@@ -2791,11 +2865,12 @@ void TabList::saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi)
oe.setExtraLines(dataField, lines);
}
-void TabList::customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi) {
- gdi.dropLine(2.5);
+void TabList::customTextLines(oEvent &oe, const char *dataField, bool withSymbols, gdioutput &gdi) {
gdi.addString("", fontMediumPlus, "Egna textrader");
- gdi.dropLine(0.3);
- gdi.addString("", 10, "help:custom_text_lines");
+ if (withSymbols) {
+ gdi.dropLine(0.3);
+ gdi.addString("", 10, "help:custom_text_lines");
+ }
gdi.dropLine(0.8);
int yp = gdi.getCY();
@@ -2825,18 +2900,20 @@ void TabList::customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi)
gdi.fillDown();
gdi.dropLine(2);
}
- gdi.pushX();
- gdi.pushY();
+ if (withSymbols) {
+ gdi.pushX();
+ gdi.pushY();
- gdi.setCX(xp);
- gdi.setCY(yp);
- gdi.addListBox("Symbols", 500, 160);
- gdi.setTabStops("Symbols", 300);
- vector < pair> symb;
- MetaList::fillSymbols(symb);
- gdi.addItem("Symbols", symb);
- gdi.popX();
- gdi.popY();
+ gdi.setCX(xp);
+ gdi.setCY(yp);
+ gdi.addListBox("Symbols", 500, 160);
+ gdi.setTabStops("Symbols", 300);
+ vector < pair> symb;
+ MetaList::fillSymbols(symb);
+ gdi.addItem("Symbols", symb);
+ gdi.popX();
+ gdi.popY();
+ }
}
void TabList::liveResult(gdioutput &gdi, oListInfo &li) {
diff --git a/code/TabList.h b/code/TabList.h
index 6d36f0c..425653a 100644
--- a/code/TabList.h
+++ b/code/TabList.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -147,7 +147,7 @@ public:
};
static void splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter, TabType returnMode, PrintSettingsSelection type);
- static void customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi);
+ static void customTextLines(oEvent &oe, const char *dataField, bool withSymbols, gdioutput &gdi);
static void saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi);
static void enableWideFormat(gdioutput &gdi, bool wide);
diff --git a/code/TabMulti.cpp b/code/TabMulti.cpp
index 5b36c08..94b7280 100644
--- a/code/TabMulti.cpp
+++ b/code/TabMulti.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabMulti.h b/code/TabMulti.h
index 689e778..8e631bd 100644
--- a/code/TabMulti.h
+++ b/code/TabMulti.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/code/TabRunner.cpp b/code/TabRunner.cpp
index 48fee5c..3811781 100644
--- a/code/TabRunner.cpp
+++ b/code/TabRunner.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,6 +28,9 @@
#include
#include "oEvent.h"
+#include "metalist.h"
+#include "generalresult.h"
+
#include "xmlparser.h"
#include "gdioutput.h"
#include "gdiconstants.h"
@@ -197,7 +200,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.setText("Team", L"");
}
- gdi.setText("TimeAdjust", getTimeMS(r->getTimeAdjustment()));
+ gdi.setText("TimeAdjust", formatTimeMS(r->getTimeAdjustment(false), false));
gdi.setText("PointAdjust", -r->getPointAdjustment());
#ifdef _DEBUG
@@ -221,13 +224,13 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
out += L" (" + itow(placeAcc[k]) + L")";
if (after[k] > 0)
- out += L" +" + getTimeMS(after[k]);
+ out += L" +" + formatTimeMS(after[k], false);
if (k < afterAcc.size() && afterAcc[k]>0)
- out += L" (+" + getTimeMS(afterAcc[k]) + L")";
+ out += L" (+" + formatTimeMS(afterAcc[k], false) + L")";
if (delta[k] > 0)
- out += L" B: " + getTimeMS(delta[k]);
+ out += L" B: " + formatTimeMS(delta[k], false);
out += L" | ";
@@ -528,7 +531,7 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
else
classId = lbi.data;
- int year = 0;
+ const wstring year;
pRunner r;
bool cardNoChanged = false;
if (runnerId==0) {
@@ -926,11 +929,12 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (!r) return 0;
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
- if (bi.getExtraInt() == 0)
+ if (bi.getExtraInt() == 0)
r->printSplits(gdiprint);
else
r->printStartInfo(gdiprint);
- gdiprint.print(oe, 0, false, true);
+
+ gdiprint.print(oe, nullptr, false, true);
gdiprint.fetchPrinterSettings(splitPrinter);
}
else if (bi.id == "PrintSettings") {
@@ -961,7 +965,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
pRunner r = oe->getRunner(runnerId, 0);
if (!name.empty() && r && r->getName() != name && r->getNameRaw() != name) {
if (gdi.ask(L"Vill du lägga till deltagaren 'X'?#" + name)) {
- r = oe->addRunner(name, 0, 0, 0,0, false);
+ r = oe->addRunner(name, 0, 0, 0, L"", false);
runnerId = r->getId();
}
save(gdi, runnerId, false);
@@ -973,7 +977,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
ListBoxInfo lbi;
gdi.getSelectedItem("RClass", lbi);
- pRunner r = oe->addRunner(oe->getAutoRunnerName(), 0,0,0,0, false);
+ pRunner r = oe->addRunner(oe->getAutoRunnerName(), 0, 0, 0, L"", false);
int clsId = lbi.data;
if (clsId > 0) {
pClass tCls = oe->getClass(clsId);
@@ -1095,7 +1099,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
r->synchronize();
card->fillPunches(gdi, "Punches", r->getCourse(true));
- gdi.setText("Time", r->getRunningTimeS(true));
+ gdi.setText("Time", r->getRunningTimeS(true, SubSecond::Auto));
gdi.selectItemByData("Status", r->getStatus());
}
else if (bi.id=="Check") {
@@ -1123,8 +1127,46 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
gdi.clearAutoComplete(ii.id);
}
}
+ else if (ii.id == "CardNo") {
+ bool show = false;
+ if (ii.text.length() > 0) {
+ vector records;
+ getAutoCompleteUnpairedCards(gdi, ii.text, records);
+ if (!records.empty()) {
+ auto& ac = gdi.addAutoComplete(ii.id);
+ ac.setAutoCompleteHandler(this);
+ ac.setData(records);
+ ac.show();
+ show = true;
+ }
+ }
+ if (!show) {
+ gdi.clearAutoComplete(ii.id);
+ }
+ }
}
- else if (type==GUI_INPUT) {
+ else if (type == GUI_FOCUS) {
+ InputInfo ii = *(InputInfo*)data;
+ if (ii.id == "CardNo") {
+ pRunner r = runnerId > 0 ? oe->getRunner(runnerId, 0) : nullptr;
+ if (r && r->getCard() == nullptr) {
+ bool show = false;
+ vector records;
+ getAutoCompleteUnpairedCards(gdi, L"", records);
+ if (!records.empty()) {
+ auto& ac = gdi.addAutoComplete(ii.id);
+ ac.setAutoCompleteHandler(this);
+ ac.setData(records);
+ ac.show();
+ show = true;
+ }
+ if (!show) {
+ gdi.clearAutoComplete(ii.id);
+ }
+ }
+ }
+ }
+ else if (type == GUI_INPUT) {
InputInfo ii=*(InputInfo *)data;
if (ii.id=="CardNo") {
@@ -1311,7 +1353,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
ac.setAutoCompleteHandler(this);
vector items;
for (auto club : clubs)
- items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
+ items.emplace_back(club->getDisplayName(), -int(items.size()), club->getName(), club->getId());
ac.setData(items);
ac.show();
@@ -1650,12 +1692,12 @@ void TabRunner::showRunnerReport(gdioutput &gdi) {
}
wstring tInfo = t->getName();
- if (t->statusOK(true)) {
- tInfo += L", " + t->getRunningTimeS(true) + lang.tl(", Placering: ") + t->getPlaceS();
- if (t->getTimeAfter(-1) > 0)
- tInfo += L", +" + formatTime(t->getTimeAfter(-1));
+ if (t->statusOK(true, true)) {
+ tInfo += L", " + t->getRunningTimeS(true, SubSecond::Auto) + lang.tl(", Placering: ") + t->getPlaceS();
+ if (t->getTimeAfter(-1, true) > 0)
+ tInfo += L", +" + formatTime(t->getTimeAfter(-1, true));
}
- else if (t->getStatusComputed() != StatusUnknown) {
+ else if (t->getStatusComputed(true) != StatusUnknown) {
tInfo += L" " + t->getStatusS(true, true);
}
@@ -1719,7 +1761,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
gdi.dropLine(0.3);
- if (r->statusOK(true)) {
+ if (r->statusOK(true, true)) {
int total, finished, dns;
r->getClassRef(true)->getNumResults(r->getLegNumber(), total, finished, dns);
@@ -1736,7 +1778,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
}
}
}
- else if (r->getStatusComputed() != StatusUnknown) {
+ else if (r->getStatusComputed(true) != StatusUnknown) {
gdi.addStringUT(fontMediumPlus, str).setColor(colorRed);
}
@@ -1747,7 +1789,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
gdi.addString("", fontMedium, L"Starttid: X #" + r->getStartTimeCompact());
if (r->getFinishTime() > 0)
- gdi.addString("", fontMedium, L"MÃ¥ltid: X #" + r->getFinishTimeS());
+ gdi.addString("", fontMedium, L"MÃ¥ltid: X #" + r->getFinishTimeS(false, SubSecond::Auto));
const wstring &after = oe.formatListString(lRunnerTimeAfter, r);
if (!after.empty()) {
@@ -1811,7 +1853,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
GDICOLOR color = colorDefault;
if (k < int(after.size()) ) {
if (after[k] > 0)
- split += L" (" + itow(place[k]) + L", +" + getTimeMS(after[k]) + L")";
+ split += L" (" + itow(place[k]) + L", +" + formatTimeMS(after[k], false) + L")";
else if (place[k] == 1)
split += lang.tl(" (sträckseger)");
else if (place[k] > 0)
@@ -1823,11 +1865,11 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
gdi.addStringUT(yp + lh, cx, fontMedium, split, limit);
if (k>0 && k < int(placeAcc.size())) {
- split = r->getPunchTimeS(k, false);
+ split = r->getPunchTimeS(k, false, false, SubSecond::Auto);
wstring pl = placeAcc[k] > 0 ? itow(placeAcc[k]) : L"-";
if (k < int(afterAcc.size()) ) {
if (afterAcc[k] > 0)
- split += L" (" + pl + L", +" + getTimeMS(afterAcc[k]) + L")";
+ split += L" (" + pl + L", +" + formatTimeMS(afterAcc[k], false) + L")";
else if (placeAcc[k] == 1)
split += lang.tl(" (ledare)");
else if (placeAcc[k] > 0)
@@ -1837,7 +1879,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
}
if (k < int(delta.size()) && delta[k] > 0 ) {
- gdi.addString("", yp + 3*lh, cx, fontMedium, L"Bomtid: X#" + getTimeMS(delta[k]));
+ gdi.addString("", yp + 3*lh, cx, fontMedium, L"Bomtid: X#" + formatTimeMS(delta[k], false, SubSecond::Off));
color = (delta[k] > bestTime * 0.5 && delta[k]>60 ) ?
colorMediumDarkRed : colorMediumRed;
@@ -1897,7 +1939,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
if (st > 0 && t > st) {
wstring split = formatTimeHMS(t-st);
if (lastT>0 && st != lastT && lastT < t)
- split += L" (" + getTimeMS(t-lastT) + L")";
+ split += L" (" + formatTimeMS(t-lastT, false) + L")";
gdi.addStringUT(yp + 2*lh, cx, normalText, split, limit);
}
}
@@ -2267,8 +2309,8 @@ void TabRunner::updateStatus(gdioutput &gdi, pRunner r) {
if (!r) return;
gdi.setText("Start", r->getStartTimeS());
- gdi.setText("Finish", r->getFinishTimeS());
- gdi.setText("Time", r->getRunningTimeS(false));
+ gdi.setText("Finish", r->getFinishTimeS(false, SubSecond::Auto));
+ gdi.setText("Time", r->getRunningTimeS(false, SubSecond::Auto));
gdi.setText("Points", itow(r->getRogainingPoints(false, false)));
gdi.selectItemByData("Status", r->getStatus());
@@ -2321,7 +2363,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data) {
wstring ptime;
if (punch->getTimeInt() > 0)
- ptime = punch->getTime();
+ ptime = punch->getTime(false, SubSecond::Auto);
gdi.setText("PTime", ptime);
@@ -2386,7 +2428,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data) {
if (!oc) return 0;
vector nmp;
- if (oc->getStatus() == oControl::StatusRogaining) {
+ if (oc->getStatus() == oControl::ControlStatus::StatusRogaining || oc->getStatus() == oControl::ControlStatus::StatusRogainingRequired) {
r->evaluateCard(true, nmp, oc->getFirstNumber(), oBase::ChangeType::Update); //Add this punch
}
else {
@@ -2524,6 +2566,9 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.pushX();
gdi.dropLine(0.5);
+
+ const int hy = gdi.getCY();
+
gdi.addString("", boldLarge, "Deltagare");
gdi.fillRight();
gdi.registerEvent("SearchRunner", runnerSearchCB).setKeyCommand(KC_FIND);
@@ -2552,7 +2597,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.newColumn();
gdi.fillDown();
- gdi.dropLine(1);
+ gdi.setCY(hy);
gdi.fillRight();
gdi.pushX();
gdi.addInput("Name", L"", 16, RunnerCB, L"Namn:");
@@ -2736,11 +2781,11 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.fillDown();
gdi.newColumn();
+ gdi.setCY(hy);
int hx = gdi.getCX();
- int hy = gdi.getCY();
gdi.setCX(hx + gdi.scaleLength(5));
- gdi.dropLine(2.5);
+ gdi.dropLine(2.0);
gdi.addListBox("Punches", 150, 300, PunchesCB, L"Stämplingar:").ignore(true);
gdi.addButton("RemoveC", "Ta bort stämpling >>", RunnerCB);
@@ -2755,7 +2800,8 @@ bool TabRunner::loadPage(gdioutput &gdi)
int contY = gdi.getCY();
gdi.newColumn();
- gdi.dropLine(2.5);
+ gdi.setCY(hy);
+ gdi.dropLine(2.0);
gdi.fillDown();
gdi.addListBox("Course", 140, 300, PunchesCB, L"Banmall:").ignore(true);
gdi.addButton("AddC", "<< Lägg till stämpling", PunchesCB);
@@ -3136,7 +3182,7 @@ void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
- if (bi) {
+ if (bi->id == "Name") {
int ix = info.getCurrentInt();
bi->setExtra(ix);
if (info.getTarget() == "Name") {
@@ -3153,6 +3199,10 @@ void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
}
}
}
+ else if (bi->id == "CardNo") {
+
+ }
+
gdi.clearAutoComplete("");
gdi.TabFocus(1);
}
@@ -3173,3 +3223,81 @@ pClub TabRunner::extractClub(oEvent *oe, gdioutput &gdi) {
}
return dbClub;
}
+
+void TabRunner::getAutoCompleteUnpairedCards(gdioutput & gdi,
+ const wstring& w,
+ vector& records) {
+
+ pCourse matchCourse = nullptr;
+ ListBoxInfo lbi;
+ auto cls = gdi.getSelectedItem("RClass");
+ if (runnerId) {
+ pRunner r = oe->getRunner(runnerId, 0);
+ if (r && r->getClassId(true) == cls.first)
+ matchCourse = r->getCourse(false);
+ }
+ if (!matchCourse && cls.first) {
+ pClass cPtr = oe->getClass(cls.first);
+
+ matchCourse = cPtr ? cPtr->getCourse(true) : nullptr;
+ }
+
+ records.clear();
+ int nr = _wtoi(w.c_str());
+ char sIn[32];
+ char sComp[32];
+
+ vector cards;
+ oe->getCards(cards, false, true);
+ if (w.empty())
+ sIn[0] = 0;
+ else
+ sprintf_s(sIn, "%d", nr);
+
+ vector> matchedCards;
+
+ for (pCard c : cards) {
+ sprintf_s(sComp, "%d", c->getCardNo());
+ bool match = true;
+ int i = 0;
+ while (sIn[i]) {
+ if (sComp[i] != sIn[i]) {
+ match = false;
+ break;
+ }
+ i++;
+ }
+ if (match) {
+ int score = 0;
+ if (matchCourse) {
+ int d = matchCourse->distance(*c);
+ if (d < 0)
+ d = min(10 - d, 20);
+ else
+ d = max(d, 10);
+
+ int age = c->getAge();
+ if (age > 10000)
+ age = 10000;
+ if (age < 0)
+ age = 0;
+
+ score = d * 10000 + age;
+
+ matchedCards.emplace_back(score, c);
+ }
+ }
+ }
+
+ sort(matchedCards.begin(), matchedCards.end());
+
+ wstring star;
+ for (auto &mc : matchedCards) {
+ wstring m = mc.second->getModified().getUpdateTime();
+ const wstring& cno = mc.second->getCardNoString();
+ star = mc.first < 3 * 10000 ? L"*" : L""; // Star if contents matches course
+ records.emplace_back(cno + star + L", "
+ + lang.tl("X stämplingar#" + itos(mc.second->getNumControlPunches(-1, -1)))
+ + L" (" + m + L")", -int(records.size()), cno, mc.second->getCardNo());
+ }
+}
diff --git a/code/TabRunner.h b/code/TabRunner.h
index bb34f29..c65f8c8 100644
--- a/code/TabRunner.h
+++ b/code/TabRunner.h
@@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include "autocompletehandler.h"
class Table;
+struct AutoCompleteRecord;
class TabRunner :
public TabBase, AutoCompleteHandler
@@ -107,6 +108,8 @@ private:
shared_ptr ecoHandler;
EconomyHandler *getEconomyHandler(oRunner &r);
+ void getAutoCompleteUnpairedCards(gdioutput &gdi, const wstring& w, vector& records);
+
protected:
void clearCompetitionData();
public:
diff --git a/code/TabSI.cpp b/code/TabSI.cpp
index 3bfd93e..b69dd57 100644
--- a/code/TabSI.cpp
+++ b/code/TabSI.cpp
@@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
- Copyright (C) 2009-2022 Melin Software HB
+ Copyright (C) 2009-2023 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,6 +44,7 @@
#include "meos_util.h"
#include
#include "TabRunner.h"
+#include "onlineinput.h"
#include "meosexception.h"
#include "MeOSFeatures.h"
#include "RunnerDB.h"
@@ -52,25 +53,34 @@
constexpr bool addTestPort = false;
void tabForceSync(gdioutput& gdi, pEvent oe);
+wstring getHiredCardDefault();
-TabSI::TabSI(oEvent *poe):TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) {
+TabSI::TabSI(oEvent* poe) :TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) {
editCardData.tabSI = this;
directEntryGUI.tabSI = this;
- interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0;
- useDatabase = poe->getPropertyInt("Database", 1)!=0;
+ interactiveReadout = poe->getPropertyInt("Interactive", 1) != 0;
+ useDatabase = poe->getPropertyInt("Database", 1) != 0;
printSplits = false;
printStartInfo = false;
- savedCardUniqueId = 1;
-
+ savedCardUniqueId = 1;
+
manualInput = poe->getPropertyInt("ManualInput", 0) == 1;
- mode=ModeReadOut;
- currentAssignIndex=0;
+ mode = SIMode::ModeReadOut;
+
+ modeName[SIMode::ModeReadOut] = "Avläsning/radiotider";
+ modeName[SIMode::ModeAssignCards] = "Tilldela hyrbrickor";
+ modeName[SIMode::ModeCheckCards] = "Avstämning hyrbrickor";
+ modeName[SIMode::ModeRegisterCards] = "Registrera hyrbrickor";
+ modeName[SIMode::ModeEntry] = "Anmälningsläge";
+ modeName[SIMode::ModeCardData] = "Print card data";
+
+ currentAssignIndex = 0;
+
+ lastClubId = 0;
+ lastClassId = 0;
- lastClubId=0;
- lastClassId=0;
-
minRunnerId = 0;
inputId = 0;
printErrorShown = false;
@@ -83,7 +93,7 @@ TabSI::~TabSI(void)
}
-static void entryTips(gdioutput &gdi) {
+static void entryTips(gdioutput& gdi) {
gdi.fillDown();
gdi.addString("", 10, "help:21576");
gdi.dropLine(1);
@@ -91,14 +101,14 @@ static void entryTips(gdioutput &gdi) {
}
-void TabSI::logCard(gdioutput &gdi, const SICard &card)
+void TabSI::logCard(gdioutput& gdi, const SICard& card)
{
if (!logger) {
logger = make_shared();
wstring readlog = L"sireadlog_" + getLocalTimeFileName() + L".csv";
wchar_t file[260];
wstring subfolder = makeValidFileName(oe->getName(), true);
- const wchar_t *sf = subfolder.empty() ? 0 : subfolder.c_str();
+ const wchar_t* sf = subfolder.empty() ? 0 : subfolder.c_str();
getDesktopFile(file, readlog.c_str(), sf);
logger->openOutput(file);
vector head = SICard::logHeader();
@@ -110,11 +120,11 @@ void TabSI::logCard(gdioutput &gdi, const SICard &card)
logger->outputRow(log);
}
-extern SportIdent *gSI;
+extern SportIdent* gSI;
extern pEvent gEvent;
-int SportIdentCB(gdioutput *gdi, int type, void *data) {
- TabSI &tsi = dynamic_cast(*gdi->getTabs().get(TSITab));
+int SportIdentCB(gdioutput* gdi, int type, void* data) {
+ TabSI& tsi = dynamic_cast(*gdi->getTabs().get(TSITab));
return tsi.siCB(*gdi, type, data);
}
@@ -135,10 +145,10 @@ string TabSI::typeFromSndType(SND s) {
return "";
}
-int TabSI::siCB(gdioutput &gdi, int type, void *data)
+int TabSI::siCB(gdioutput& gdi, int type, void* data)
{
if (type == GUI_BUTTON) {
- ButtonInfo bi = *(ButtonInfo *)data;
+ ButtonInfo bi = *(ButtonInfo*)data;
if (bi.id == "LockFunction") {
lockedFunction = true;
@@ -148,12 +158,44 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
lockedFunction = false;
loadPage(gdi);
}
- else if (bi.id == "AllowStart")
+ else if (bi.id == "ChangeMapping") {
+ gdi.restore("Mapping", false);
+ gdi.dropLine(4);
+ gdi.popX();
+
+ changeMapping(gdi);
+
+ gdi.refresh();
+ }
+ else if (bi.id == "SaveMapping") {
+ int ctrl = gdi.getTextNo("Code");
+ if (ctrl < 1 || ctrl > 31)
+ throw meosException("Ogiltig kontrollkod");
+ ListBoxInfo lbi;
+ if (!gdi.getSelectedItem("Function", lbi))
+ throw meosException("Ogiltig funktion");
+ getSI(gdi).addSpecialMapping(ctrl, (oPunch::SpecialPunch)lbi.data);
+ fillMappings(gdi);
+ }
+ else if (bi.id == "RemoveMapping") {
+ set sel;
+ gdi.getSelection("Mappings", sel);
+ for (auto code : sel) {
+ getSI(gdi).removeSpecialMapping(code);
+ }
+ fillMappings(gdi);
+ }
+ else if (bi.id == "CloseMapping") {
+ gdi.restore("SIPageLoaded");
+ showReadoutMode(gdi);
+ gdi.refresh();
+ }
+ /*else if (bi.id == "AllowStart")
allowStart = gdi.isChecked(bi.id);
- else if (bi.id == "AllowControl")
+ else if (bi.id == "AllowControl")
allowControl = gdi.isChecked(bi.id);
- else if (bi.id == "AllowFinish")
- allowFinish = gdi.isChecked(bi.id);
+ else if (bi.id == "AllowFinish")
+ allowFinish = gdi.isChecked(bi.id);*/
else if (bi.id == "PlaySound") {
oe->setProperty("PlaySound", gdi.isChecked(bi.id) ? 1 : 0);
}
@@ -167,7 +209,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.pushX();
gdi.fillRight();
- auto addSoundWidget = [&gdi, this](const wchar_t *name, SND type, const wstring &label) {
+ auto addSoundWidget = [&gdi, this](const wchar_t* name, SND type, const wstring& label) {
int itype = int(type);
string nname = gdioutput::narrow(name);
wstring fn = oe->getPropertyString(nname.c_str(), L"");
@@ -184,13 +226,13 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(0.8);
gdi.addButton("BrowseSound", "Bläddra...", SportIdentCB).setExtra(itype);
gdi.addButton("TestSound", "Testa", SportIdentCB).setExtra(itype);
-
+
if (!doPlay) {
gdi.setInputStatus("SoundFile", false, false, itype);
gdi.setInputStatus("BrowseSound", false, false, itype);
gdi.setInputStatus("TestSound", false, false, itype);
}
-
+
gdi.dropLine(3);
gdi.popX();
};
@@ -273,8 +315,12 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
wstring port = gdi.getText("ComPortName");
if (gSI->openComListen(port.c_str(), gdi.getTextNo("BaudRate"))) {
gSI->startMonitorThread(port.c_str());
- loadPage(gdi);
+ //loadPage(gdi);
+ gdi.restore("", false);
gdi.addString("", 1, L"Lyssnar på X.#" + port).setColor(colorDarkGreen);
+ if (!gdi.hasData("ShowControlMapping") && gSI->isAnyOpenUnkownUnit()) {
+ changeMapping(gdi);
+ }
}
else
gdi.addString("", 1, "FEL: Porten kunde inte öppnas").setColor(colorRed);
@@ -292,6 +338,12 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(0.5);
refillComPorts(gdi);
+
+
+ if (!gdi.hasData("ShowControlMapping") && gSI->isAnyOpenUnkownUnit()) {
+ changeMapping(gdi);
+ }
+
gdi.refresh();
}
else if (bi.id == "StartSI") {
@@ -350,12 +402,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addStringUT(0, lang.tl(L"Startar SI på ") + port + L"...");
gdi.refresh();
+ bool askListen = false;
+
if (gSI->openCom(port.c_str())) {
gSI->startMonitorThread(port.c_str());
gdi.addStringUT(0, lang.tl(L"SI på ") + port + L": " + lang.tl(L"OK"));
printSIInfo(gdi, port);
- SI_StationInfo *si = gSI->findStation(port);
+ const SI_StationInfo* si = gSI->findStation(port);
if (si && !si->extended())
gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed);
}
@@ -367,7 +421,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addStringUT(0, lang.tl(L"SI på ") + port + L": " + lang.tl(L"OK"));
printSIInfo(gdi, port);
- SI_StationInfo *si = gSI->findStation(port);
+ const SI_StationInfo* si = gSI->findStation(port);
if (si && !si->extended())
gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed);
}
@@ -396,11 +450,17 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.fillDown();
gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel();
gdi.popX();
+ askListen = true;
}
}
}
gdi.popX();
gdi.dropLine();
+
+ if (!askListen && !gdi.hasData("ShowControlMapping") && gSI->isAnyOpenUnkownUnit()) {
+ changeMapping(gdi);
+ }
+
refillComPorts(gdi);
}
gdi.refresh();
@@ -448,7 +508,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addStringUT(0, lang.tl(L"SI på ") + wstring(bf) + L": " + lang.tl(L"OK"));
printSIInfo(gdi, bf);
- SI_StationInfo *si = gSI->findStation(bf);
+ const SI_StationInfo* si = gSI->findStation(bf);
if (si && !si->extended())
gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed);
}
@@ -457,7 +517,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addStringUT(0, lang.tl(L"SI på ") + wstring(bf) + L": " + lang.tl(L"OK"));
printSIInfo(gdi, bf);
- SI_StationInfo *si = gSI->findStation(bf);
+ const SI_StationInfo* si = gSI->findStation(bf);
if (si && !si->extended())
gdi.addString("", boldText, "warn:notextended").setColor(colorDarkRed);
}
@@ -470,7 +530,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (bi.id == "PrinterSetup") {
- if (mode == ModeEntry) {
+ if (mode == SIMode::ModeEntry) {
printStartInfo = true;
TabList::splitPrintSettings(*oe, gdi, true, TSITab, TabList::StartInfo);
}
@@ -480,7 +540,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (bi.id == "AutoTie") {
- gEvent->setProperty("AutoTie", gdi.isChecked("AutoTie"));
+ gEvent->setProperty("AutoTie", gdi.isChecked(bi.id));
+ }
+ else if (bi.id == "AutoTieRent") {
+ gEvent->setProperty("AutoTieRent", gdi.isChecked(bi.id));
}
else if (bi.id == "RentCardTie") {
gEvent->setProperty("RentCard", gdi.isChecked(bi.id));
@@ -492,11 +555,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
interactiveReadout = gdi.isChecked(bi.id);
gEvent->setProperty("Interactive", interactiveReadout);
- if (mode == ModeAssignCards) {
- gdi.restore("ManualTie", false);
- showAssignCard(gdi, false);
+ if (mode == SIMode::ModeAssignCards) {
+ gdi.restore("SIPageLoaded");
+ showAssignCard(gdi, true);
}
}
+ else if (bi.id == "MultipleStarts") {
+ multipleStarts = gdi.isChecked(bi.id);
+ }
else if (bi.id == "Database") {
useDatabase = gdi.isChecked(bi.id);
gEvent->setProperty("Database", useDatabase);
@@ -515,7 +581,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
showManualInput(gdi);
}
else if (bi.id == "ReadoutWindow") {
- gdioutput *gdi_settings = getExtraWindow("readout_view", true);
+ gdioutput* gdi_settings = getExtraWindow("readout_view", true);
if (!gdi_settings) {
gdi_settings = createExtraWindow("readout_view", lang.tl("Brickavläsning"), gdi.scaleLength(800), gdi.scaleLength(600), false);
}
@@ -610,11 +676,11 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
for (size_t k = 0; k < punches.size(); k++) {
if (dofilter && filter != punches[k].date)
continue;
- oe->addFreePunch(punches[k].time, type, punches[k].card, true);
+ oe->addFreePunch(punches[k].time, type, 0, punches[k].card, true);
}
punches.clear();
if (origin == 1) {
- TabRunner &tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab));
+ TabRunner& tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab));
tc.showInForestList(gdi);
}
}
@@ -628,7 +694,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
oe->reEvaluateAll(set(), true);
cards.clear();
if (origin == 1) {
- TabRunner &tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab));
+ TabRunner& tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab));
tc.showInForestList(gdi);
}
}
@@ -639,10 +705,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum());
int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum());
if (f < s) {
- f += 24 * 3600;
+ f += 24 * timeConstHour;
}
- sic.FinishPunch.Time = f % (24 * 3600);
- sic.StartPunch.Time = s % (24 * 3600);
+ sic.FinishPunch.Time = f % (24 * timeConstHour);
+ sic.StartPunch.Time = s % (24 * timeConstHour);
if (!gdi.isChecked("HasFinish")) {
sic.FinishPunch.Code = -1;
sic.FinishPunch.Time = 0;
@@ -655,8 +721,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
double t = 0.1;
for (sic.nPunch = 0; sic.nPunch(*gdi.getTabs().get(TRunnerTab));
+ TabRunner& tc = dynamic_cast(*gdi.getTabs().get(TRunnerTab));
tc.showInForestList(gdi);
return 0;
}
@@ -727,6 +793,12 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
checkMoreCardsInQueue(gdi);
return 0;
}
+ else if (bi.id == "SaveUnpaired") {
+ gdi.restore();
+ processUnmatched(gdi, activeSIC, false);
+ activeSIC.clear(0);
+ return 0;
+ }
else if (bi.id == "OK1") {
wstring name = gdi.getText("Runners");
wstring club = gdi.getText("Club", true);
@@ -804,9 +876,9 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
club = lang.tl("Klubblös");
}
- int year = 0;
+ const wstring year;
pRunner r = gEvent->addRunner(gdi.getText("Runners"), club,
- classes[0]->getId(), activeSIC.CardNumber, year, true);
+ classes[0]->getId(), activeSIC.CardNumber, year, true);
if (oe->isHiredCard(activeSIC.CardNumber)) {
r->getDI().setInt("CardFee", oe->getBaseCardFee());
}
@@ -820,7 +892,6 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
return 0;
}
-
gdi.restore("restOK1", false);
gdi.popX();
gdi.dropLine(2);
@@ -835,16 +906,16 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.selectItemByData("Classes", classes[0]->getId());
gdi.dropLine();
-
gdi.setRestorePoint("restOK2");
- gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel();
if (oe->getNumClasses() > 0)
gdi.addButton("OK2", "OK", SportIdentCB).setDefault();
- gdi.fillDown();
-
+
gdi.addButton("NewClass", "Skapa ny klass", SportIdentCB);
+ gdi.fillDown();
+ gdi.addButton("Cancel", "Avbryt inläsning", SportIdentCB).setCancel();
+
gdi.popX();
if (classes.size() > 0)
gdi.addString("FindMatch", 0, "Press Enter to continue").setColor(colorGreen);
@@ -873,10 +944,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (club.empty() && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs))
club = lang.tl("Klubblös");
- int year = 0;
+ const wstring year;
pRunner r = gEvent->addRunner(gdi.getText("Runners"), club,
- lbi.data, activeSIC.CardNumber, year, true);
-
+ lbi.data, activeSIC.CardNumber, year, true);
+
if (activeSIC.CardNumber > 0 && oe->isHiredCard(activeSIC.CardNumber)) {
r->getDI().setInt("CardFee", oe->getBaseCardFee());
}
@@ -899,9 +970,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addInput("ClassName", gEvent->getAutoClassName(), 10, 0, L"Klassnamn:");
gdi.dropLine();
- gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel();
- gdi.fillDown();
gdi.addButton("OK3", "OK", SportIdentCB).setDefault();
+ gdi.fillDown();
+ gdi.addButton("Cancel", "Avbryt inläsning", SportIdentCB).setCancel();
+
gdi.setInputFocus("ClassName", true);
gdi.refresh();
gdi.popX();
@@ -911,8 +983,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
pClass pclass = 0;
if (oe->getNumClasses() == 1 && oe->getClass(1) != 0 &&
- oe->getClass(1)->getType() == L"tmp" &&
- oe->getClass(1)->getNumRunners(false, false, false) == 0) {
+ oe->getClass(1)->getType() == L"tmp" &&
+ oe->getClass(1)->getNumRunners(false, false, false) == 0) {
pclass = oe->getClass(1);
pclass->setType(L"");
pclass->setName(gdi.getText("ClassName"), true);
@@ -927,14 +999,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
pc->addControl(activeSIC.Punch[i].Code);
}
if (pclass == 0) {
- pclass = gEvent->addClass(gdi.getText("ClassName"), pc ? pc->getId(): 0);
+ pclass = gEvent->addClass(gdi.getText("ClassName"), pc ? pc->getId() : 0);
}
else if (pc)
pclass->setCourse(pc);
- int year = 0;
+ const wstring year;
pRunner r = gEvent->addRunner(gdi.getText("Runners"), gdi.getText("Club", true),
- pclass->getId(), activeSIC.CardNumber, year, true);
+ pclass->getId(), activeSIC.CardNumber, year, true);
if (activeSIC.CardNumber > 0 && oe->isHiredCard(activeSIC.CardNumber)) {
r->getDI().setInt("CardFee", oe->getBaseCardFee());
@@ -963,7 +1035,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (gdi.getData("RunnerId", rid) && rid > 0)
r = gEvent->getRunner(rid, 0);
- else r = gEvent->addRunner(lang.tl(L"Oparad bricka"), lang.tl("Okänd"), 0, 0, 0, false);
+ else r = gEvent->addRunner(lang.tl(L"Oparad bricka"), lang.tl("Okänd"), 0, 0, L"", false);
r->setClassId(lbi.data, true);
@@ -1006,7 +1078,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
clz->synchronize();
}
bool updated = false;
- int year = 0;
+ const wstring year;
bool warnClassFull = false;
if (!r || r->getClassRef(false) != clz) {
int numRemMaps = clz->getNumRemainingMaps(true);
@@ -1054,7 +1126,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
r->setCardNo(cardNo, true);//XXX
oDataInterface di = r->getDI();
-
+
int cardFee = gdi.isChecked("RentCard") ? oe->getBaseCardFee() : 0;
di.setInt("CardFee", cardFee);
@@ -1101,7 +1173,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (r->getClubId() != 0) {
swprintf_s(bf, L"%s%s, %s", cno.c_str(), r->getClub().c_str(),
- r->getClass(true).c_str());
+ r->getClass(true).c_str());
}
else {
swprintf_s(bf, L"%s%s", cno.c_str(), r->getClass(true).c_str());
@@ -1214,7 +1286,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
list> data;
csv.parse(fn, data);
set rentCards;
- for (auto &c : data) {
+ for (auto& c : data) {
for (wstring wc : c) {
int cn = _wtoi(wc.c_str());
if (cn > 0) {
@@ -1223,6 +1295,9 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
}
+
+ writeDefaultHiredCards();
+
gdi.scrollToBottom();
gdi.refresh();
vector runners;
@@ -1251,6 +1326,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
for (int c : hc)
csv.outputRow(itos(c));
csv.closeOutput();
+
+ writeDefaultHiredCards();
}
}
else if (bi.id == "RHCPrint") {
@@ -1317,10 +1394,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdiPrint.print(oe);
}
}
- else if (type==GUI_LISTBOX) {
- ListBoxInfo bi=*(ListBoxInfo *)data;
+ else if (type == GUI_LISTBOX) {
+ ListBoxInfo bi = *(ListBoxInfo*)data;
- if (bi.id=="Runners") {
+ if (bi.id == "Runners") {
pRunner r = gEvent->getRunner(bi.data, 0);
if (r) {
gdi.setData("RunnerId", bi.data);
@@ -1332,10 +1409,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
else if (bi.id == "PayMode") {
updateEntryInfo(gdi);
}
- else if (bi.id=="ComPort") {
+ else if (bi.id == "ComPort") {
wchar_t bf[64];
- if (bi.text.substr(0,3)!=L"TCP")
+ if (bi.text.substr(0, 3) != L"TCP")
swprintf_s(bf, 64, L"COM%d", bi.getDataInt());
else
wcscpy_s(bf, L"TCP");
@@ -1345,47 +1422,43 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
else
gdi.setText("StartSI", lang.tl("Aktivera"));
}
- else if (bi.id=="ReadType") {
+ else if (bi.id == "ReadType") {
gdi.restore("SIPageLoaded");
mode = SIMode(bi.data);
- gdi.setInputStatus("StartInfo", mode == ModeEntry);
-
- if (mode==ModeAssignCards || mode==ModeEntry) {
- if (mode==ModeAssignCards) {
- gdi.dropLine(1);
+ //gdi.setInputStatus("StartInfo", mode == ModeEntry);
+
+ if (mode == SIMode::ModeAssignCards || mode == SIMode::ModeEntry) {
+ if (mode == SIMode::ModeAssignCards) {
showAssignCard(gdi, true);
}
else {
+ checkBoxToolBar(gdi, { CheckBox::UseDB, CheckBox::PrintStart });
entryTips(gdi);
generateEntryLine(gdi, 0);
}
- gdi.setInputStatus("Interactive", mode == ModeAssignCards);
+ /*gdi.setInputStatus("Interactive", mode == ModeAssignCards);
gdi.setInputStatus("Database", mode != ModeAssignCards, true);
gdi.disableInput("PrintSplits");
-
- gdi.disableInput("UseManualInput");
+
+ gdi.disableInput("UseManualInput");*/
}
- else if (mode==ModeReadOut) {
- gdi.enableInput("Interactive");
- gdi.enableInput("Database", true);
- gdi.enableInput("PrintSplits");
- gdi.enableInput("UseManualInput");
+ else if (mode == SIMode::ModeReadOut) {
showReadoutMode(gdi);
}
- else if (mode == ModeCardData) {
+ else if (mode == SIMode::ModeCardData) {
numSavedCardsOnCmpOpen = savedCards.size();
showModeCardData(gdi);
}
- else if (mode == ModeCheckCards) {
+ else if (mode == SIMode::ModeCheckCards) {
showCheckCardStatus(gdi, "init");
}
- else if (mode == ModeRegisterCards) {
+ else if (mode == SIMode::ModeRegisterCards) {
showRegisterHiredCards(gdi);
}
updateReadoutFunction(gdi);
gdi.refresh();
}
- else if (bi.id=="Fee") {
+ else if (bi.id == "Fee") {
updateEntryInfo(gdi);
}
else if (bi.id == "NC") {
@@ -1394,7 +1467,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_LINK) {
- TextInfo ti = *(TextInfo *)data;
+ TextInfo ti = *(TextInfo*)data;
if (ti.id == "ChRunner") {
pRunner r = oe->getRunner(ti.getExtraInt(), 0);
generateEntryLine(gdi, r);
@@ -1411,14 +1484,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_COMBO) {
- ListBoxInfo bi=*(ListBoxInfo *)data;
+ ListBoxInfo bi = *(ListBoxInfo*)data;
- if (bi.id=="Fee") {
+ if (bi.id == "Fee") {
updateEntryInfo(gdi);
}
else if (bi.id == "Runners") {
DWORD rid;
- if ((gdi.getData("RunnerId", rid) && rid>0) || !gdi.getText("Club", true).empty())
+ if ((gdi.getData("RunnerId", rid) && rid > 0) || !gdi.getText("Club", true).empty())
return 0; // Selected from list
if (!bi.text.empty() && showDatabase()) {
@@ -1435,9 +1508,9 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_COMBOCHANGE) {
- ListBoxInfo bi=*(ListBoxInfo *)data;
+ ListBoxInfo bi = *(ListBoxInfo*)data;
if (bi.id == "Runners") {
-
+
if (!showDatabase()) {
inputId++;
gdi.addTimeoutMilli(300, "AddRunnerInteractive", SportIdentCB).setExtra(inputId);
@@ -1447,7 +1520,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (showDatabase() && bi.text.length() > 1) {
auto rw = oe->getRunnerDatabase().getRunnerSuggestions(bi.text, 0, 20);
if (!rw.empty()) {
- auto &ac = gdi.addAutoComplete(bi.id);
+ auto& ac = gdi.addAutoComplete(bi.id);
ac.setAutoCompleteHandler(this);
vector items = getRunnerAutoCompelete(oe->getRunnerDatabase(), rw, 0);
ac.setData(items);
@@ -1461,7 +1534,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_EVENT) {
- EventInfo ev = *(EventInfo *)data;
+ EventInfo ev = *(EventInfo*)data;
if (ev.id == "AutoComplete") {
pRunner r = oe->getRunner(runnerMatchedId, 0);
if (r) {
@@ -1478,7 +1551,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_FOCUS) {
- InputInfo &ii=*(InputInfo *)data;
+ InputInfo& ii = *(InputInfo*)data;
if (ii.id == "FinishTime") {
if (ii.getExtraInt() == 1) {
@@ -1490,7 +1563,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (type == GUI_TIMER) {
- TimerInfo &ti = *(TimerInfo *)(data);
+ TimerInfo& ti = *(TimerInfo*)(data);
if (ti.id == "TieCard") {
runnerMatchedId = ti.getExtraInt();
@@ -1502,7 +1575,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
return 0;
if (ti.id == "RunnerId") {
- const wstring &text = gdi.getText(ti.id);
+ const wstring& text = gdi.getText(ti.id);
int nr = _wtoi(text.c_str());
pRunner r = 0;
@@ -1536,7 +1609,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
tieCard(gdi);
}
else if (ti.id == "Manual") {
- const wstring &text = gdi.getText(ti.id);
+ const wstring& text = gdi.getText(ti.id);
int nr = _wtoi(text.c_str());
pRunner r = 0;
@@ -1560,7 +1633,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
else if (ti.id == "AddRunnerInteractive") {
- const wstring &text = gdi.getText("Runners");
+ const wstring& text = gdi.getText("Runners");
int nr = _wtoi(text.c_str());
pRunner r = 0;
@@ -1582,9 +1655,9 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
}
- else if (type==GUI_INPUTCHANGE) {
+ else if (type == GUI_INPUTCHANGE) {
- InputInfo ii=*(InputInfo *)data;
+ InputInfo ii = *(InputInfo*)data;
if (ii.id == "RunnerId") {
inputId++;
gdi.addTimeoutMilli(300, ii.id, SportIdentCB).setExtra(inputId);
@@ -1593,7 +1666,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
inputId++;
gdi.addTimeoutMilli(300, ii.id, SportIdentCB).setExtra(inputId);
}
- else if (ii.id == "CardNo" && mode == ModeAssignCards) {
+ else if (ii.id == "CardNo" && mode == SIMode::ModeAssignCards) {
gdi.setInputStatus("TieOK", runnerMatchedId != -1);
}
else if (ii.id == "SI") {
@@ -1601,36 +1674,42 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (r && r->getStartTime() > 0) {
gdi.setText("Start", r->getStartTimeS());
gdi.check("HasStart", false);
- int f = r->getStartTime() + 2800 + rand()%1200;
+ int f = r->getStartTime() + (2800 + rand() % 1200) * timeConstSecond;
gdi.setText("Finish", oe->getAbsTime(f));
pCourse pc = r->getCourse(false);
if (pc) {
for (int n = 0; n < pc->getNumControls(); n++) {
if (pc->getControl(n) && n < NC) {
- gdi.setText("C" + itos(n+1), pc->getControl(n)->getFirstNumber());
+ gdi.setText("C" + itos(n + 1), pc->getControl(n)->getFirstNumber());
}
}
}
}
}
}
- else if (type==GUI_INPUT) {
- InputInfo &ii=*(InputInfo *)data;
+ else if (type == GUI_INPUT) {
+ InputInfo& ii = *(InputInfo*)data;
if (ii.id == "FinishTime") {
if (ii.text.empty()) {
ii.setExtra(1);
ii.setFgColor(colorGreyBlue);
gdi.setText(ii.id, lang.tl("Aktuell tid"), true);
}
+ else if (oe->getRelativeTime(ii.text) > 0) {
+ ii.setExtra(0);
+ }
}
- else if (ii.id=="CardNo") {
+ else if (ii.id == "CardNo") {
int cardNo = gdi.getTextNo("CardNo");
- if (mode == ModeAssignCards) {
- if (runnerMatchedId != -1 && gdi.isChecked("AutoTie") && cardNo>0)
+ if (mode == SIMode::ModeAssignCards) {
+ if (gdi.hasWidget("AutoTieRent") && gdi.isChecked("AutoTieRent")) {
+ gdi.check("RentCardTie", oe->isHiredCard(gdi.getTextNo("CardNo")));
+ }
+ if (runnerMatchedId != -1 && gdi.isChecked("AutoTie") && cardNo > 0)
gdi.addTimeoutMilli(50, "TieCard", SportIdentCB).setExtra(runnerMatchedId);
}
- else if (cardNo>0) {
+ else if (cardNo > 0) {
if (ii.changedInput() && oe->hasHiredCardData())
gdi.check("RentCard", oe->isHiredCard(cardNo));
@@ -1643,10 +1722,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
}
}
- else if (ii.id[0]=='*') {
- int si=_wtoi(ii.text.c_str());
+ else if (ii.id[0] == '*') {
+ int si = _wtoi(ii.text.c_str());
- pRunner r=oe->getRunner(ii.getExtraInt(), 0);
+ pRunner r = oe->getRunner(ii.getExtraInt(), 0);
r->synchronize();
if (r && r->getCardNo() != si) {
@@ -1669,13 +1748,13 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
oe->setProperty(name.c_str(), ii.text);
}
}
- else if (type==GUI_INFOBOX) {
+ else if (type == GUI_INFOBOX) {
DWORD loaded;
if (!gdi.getData("SIPageLoaded", loaded))
loadPage(gdi);
}
else if (type == GUI_CLEAR) {
- if (mode == ModeEntry) {
+ if (mode == SIMode::ModeEntry) {
storedInfo.clear();
storedInfo.storedName = gdi.getText("Name");
storedInfo.storedCardNo = gdi.getText("CardNo");
@@ -1687,20 +1766,40 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
storedInfo.storedClassId = lbi.data;
storedInfo.storedPhone = gdi.getText("Phone");
storedInfo.storedStartTime = gdi.getText("StartTime");
-
+
storedInfo.allStages = gdi.isChecked("AllStages");
storedInfo.rentState = gdi.isChecked("RentCard");
storedInfo.hasPaid = gdi.isChecked("Paid");
storedInfo.payMode = gdi.hasWidget("PayMode") ? gdi.getSelectedItem("PayMode").first : 0;
}
+ else if (mode == SIMode::ModeReadOut && interactiveReadout && !activeSIC.empty()) {
+ CardQueue.push_back(activeSIC);
+ activeSIC.clear(nullptr);
+ }
return 1;
}
return 0;
}
+void TabSI::writeDefaultHiredCards() {
+ csvparser csv;
+ try {
+ oe->synchronizeList(oListId::oLPunchId);
+ wstring def = getHiredCardDefault();
+ auto hc = oe->getHiredCards();
+ csvparser csv;
+ csv.openOutput(def);
+ for (int c : hc)
+ csv.outputRow(itos(c));
+ csv.closeOutput();
+ }
+ catch (std::exception&) {
-void TabSI::refillComPorts(gdioutput &gdi)
+ }
+}
+
+void TabSI::refillComPorts(gdioutput& gdi)
{
if (!gSI) return;
@@ -1710,103 +1809,104 @@ void TabSI::refillComPorts(gdioutput &gdi)
gdi.clearList("ComPort");
ports.sort();
wchar_t bf[256];
- int active=0;
- int inactive=0;
- while(!ports.empty())
- {
- int p=ports.front();
+ int active = 0;
+ int inactive = 0;
+ while (!ports.empty()) {
+ int p = ports.front();
swprintf_s(bf, 256, L"COM%d", p);
- if (gSI->isPortOpen(bf)){
- gdi.addItem("ComPort", wstring(bf)+L" [OK]", p);
- active=p;
+ if (gSI->isPortOpen(bf)) {
+ gdi.addItem("ComPort", wstring(bf) + L" [OK]", p);
+ active = p;
}
- else{
+ else {
gdi.addItem("ComPort", bf, p);
- inactive=p;
+ inactive = p;
}
ports.pop_front();
}
- if (gSI->isPortOpen(L"TCP"))
- gdi.addItem("ComPort", L"TCP [OK]");
+ if (gSI->isPortOpen(L"TCP")) {
+ active = 10000;
+ gdi.addItem("ComPort", L"TCP [OK]", active);
+ }
else
gdi.addItem("ComPort", L"TCP");
if (addTestPort)
gdi.addItem("ComPort", L"TEST");
- if (active){
+ if (active) {
gdi.selectItemByData("ComPort", active);
gdi.setText("StartSI", lang.tl("Koppla ifrån"));
}
- else{
+ else {
gdi.selectItemByData("ComPort", inactive);
gdi.setText("StartSI", lang.tl("Aktivera"));
}
}
-void TabSI::showReadPunches(gdioutput &gdi, vector &punches, set &dates)
+void TabSI::showReadPunches(gdioutput& gdi, vector& punches, set& dates)
{
char bf[64];
int yp = gdi.getCY();
int xp = gdi.getCX();
dates.clear();
- for (size_t k=0;kgetRunnerByCardNo(punches[k].card, punches[k].time, oEvent::CardLookupProperty::Any);
sprintf_s(bf, "%d", punches[k].card);
- gdi.addStringUT(yp, xp+40, 0, bf, 240);
+ gdi.addStringUT(yp, xp + 40, 0, bf, 240);
- if (r!=0)
- gdi.addStringUT(yp, xp+100, 0, r->getName(), 170);
+ if (r != 0)
+ gdi.addStringUT(yp, xp + 100, 0, r->getName(), 170);
if (punches[k].date[0] != 0) {
- gdi.addStringUT(yp, xp+280, 0, punches[k].date, 75);
+ gdi.addStringUT(yp, xp + 280, 0, punches[k].date, 75);
dates.insert(punches[k].date);
}
- if (punches[k].time>0)
- gdi.addStringUT(yp, xp+360, 0, oe->getAbsTime(punches[k].time));
+ if (punches[k].time > 0)
+ gdi.addStringUT(yp, xp + 360, 0, oe->getAbsTime(punches[k].time));
else
- gdi.addStringUT(yp, xp+360, 0, makeDash(L"-"));
+ gdi.addStringUT(yp, xp + 360, 0, makeDash(L"-"));
yp += gdi.getLineHeight();
}
}
-void TabSI::showReadCards(gdioutput &gdi, vector &cards)
+void TabSI::showReadCards(gdioutput& gdi, vector& cards)
{
char bf[64];
int yp = gdi.getCY();
int xp = gdi.getCX();
- for (size_t k=0;kgetRunnerByCardNo(cards[k].CardNumber, 0, oEvent::CardLookupProperty::Any);
sprintf_s(bf, "%d", cards[k].CardNumber);
- gdi.addStringUT(yp, xp+40, 0, bf, 240);
+ gdi.addStringUT(yp, xp + 40, 0, bf, 240);
- if (r!=0)
- gdi.addStringUT(yp, xp+100, 0, r->getName(), 240);
+ if (r != 0)
+ gdi.addStringUT(yp, xp + 100, 0, r->getName(), 240);
- gdi.addStringUT(yp, xp+300, 0, oe->getAbsTime(cards[k].FinishPunch.Time));
+ gdi.addStringUT(yp, xp + 300, 0, oe->getAbsTime(cards[k].FinishPunch.Time));
yp += gdi.getLineHeight();
}
}
-SportIdent &TabSI::getSI(const gdioutput &gdi) {
+SportIdent& TabSI::getSI(const gdioutput& gdi) {
if (!gSI) {
- HWND hWnd=gdi.getHWNDMain();
+ HWND hWnd = gdi.getHWNDMain();
gSI = new SportIdent(hWnd, 0, true);
}
return *gSI;
}
-bool TabSI::loadPage(gdioutput &gdi) {
+bool TabSI::loadPage(gdioutput& gdi) {
gdi.clearPage(true);
printErrorShown = false;
gdi.pushX();
@@ -1823,48 +1923,48 @@ bool TabSI::loadPage(gdioutput &gdi) {
gdi.fillRight();
gdi.pushX();
gdi.addInput("SI", L"", 10, SportIdentCB, L"SI");
- int s = 3600+(rand()%60)*60;
- int f = s + 1800 + rand()%900;
-
- gdi.setCX(gdi.getCX()+gdi.getLineHeight());
-
+ int s = timeConstHour + (rand() % 60) * timeConstMinute;
+ int f = s + timeConstHour / 2 + ((rand() % 3600) / 3) * timeConstSecond;
+
+ gdi.setCX(gdi.getCX() + gdi.getLineHeight());
+
gdi.dropLine(1.4);
gdi.addCheckbox("HasStart", "");
gdi.dropLine(-1.4);
- gdi.setCX(gdi.getCX()-gdi.getLineHeight());
+ gdi.setCX(gdi.getCX() - gdi.getLineHeight());
gdi.addInput("Start", oe->getAbsTime(s), 6, 0, L"Start");
-
+
gdi.dropLine(1.4);
gdi.addCheckbox("HasFinish", "");
gdi.dropLine(-1.4);
- gdi.setCX(gdi.getCX()-gdi.getLineHeight());
+ gdi.setCX(gdi.getCX() - gdi.getLineHeight());
gdi.addInput("Finish", oe->getAbsTime(f), 6, 0, L"MÃ¥l");
gdi.addSelection("NC", 45, 200, SportIdentCB, L"NC");
- const int src[11] = {33, 34, 45, 50, 36, 38, 59, 61, 62, 67, 100};
-
+ const int src[11] = { 33, 34, 45, 50, 36, 38, 59, 61, 62, 67, 100 };
+
for (int i = 0; i < 32; i++)
gdi.addItem("NC", itow(i), i);
gdi.selectItemByData("NC", NC);
for (int i = 0; i < NC; i++) {
- int level = min(i, NC-i)/5;
+ int level = min(i, NC - i) / 5;
int c;
- if (i < NC /2) {
- int ix = i%6;
+ if (i < NC / 2) {
+ int ix = i % 6;
c = src[ix] + level * 10;
if (c == 100)
c = 183;
}
else {
- int ix = 10-(NC-i-1)%5;
+ int ix = 10 - (NC - i - 1) % 5;
c = src[ix] + level * 10;
}
- gdi.addInput("C" + itos(i+1), itow(c), 3, 0, L"#C" + itow(i+1));
+ gdi.addInput("C" + itos(i + 1), itow(c), 3, 0, L"#C" + itow(i + 1));
}
-
+
gdi.dropLine();
gdi.addButton("Save", "Bricka", SportIdentCB);
gdi.fillDown();
@@ -1893,21 +1993,31 @@ bool TabSI::loadPage(gdioutput &gdi) {
int xb = gdi.getCX();
int yb = gdi.getCY();
- gdi.fillRight();
if (!oe->empty()) {
gdi.setCX(xb + gdi.scaleLength(10));
gdi.setCY(yb + gdi.scaleLength(10));
-
+
if (!lockedFunction) {
+ gdi.fillRight();
gdi.addString("", fontMediumPlus, "Funktion:");
gdi.addSelection("ReadType", 200, 200, SportIdentCB);
- gdi.addItem("ReadType", lang.tl("Avläsning/radiotider"), ModeReadOut);
+ auto addItem = [this, &gdi](SIMode mode) {
+ gdi.addItem("ReadType", lang.tl(modeName[mode]), int(mode));
+ };
+ addItem(SIMode::ModeReadOut);
+ addItem(SIMode::ModeEntry);
+ addItem(SIMode::ModeAssignCards);
+ addItem(SIMode::ModeCheckCards);
+ addItem(SIMode::ModeRegisterCards);
+ addItem(SIMode::ModeCardData);
+ /*
+ gdi.addItem("ReadType", lang.tl(modeName[SIMode::ModeReadOut]), SIMode::ModeReadOut);
gdi.addItem("ReadType", lang.tl("Tilldela hyrbrickor"), ModeAssignCards);
gdi.addItem("ReadType", lang.tl("Avstämning hyrbrickor"), ModeCheckCards);
gdi.addItem("ReadType", lang.tl("Registrera hyrbrickor"), ModeRegisterCards);
gdi.addItem("ReadType", lang.tl("Anmälningsläge"), ModeEntry);
- gdi.addItem("ReadType", lang.tl("Print card data"), ModeCardData);
- gdi.selectItemByData("ReadType", mode);
+ gdi.addItem("ReadType", lang.tl("Print card data"), ModeCardData);*/
+ gdi.selectItemByData("ReadType", int(mode));
gdi.dropLine(-0.1);
gdi.addButton("LockFunction", "LÃ¥s funktion", SportIdentCB);
@@ -1915,82 +2025,56 @@ bool TabSI::loadPage(gdioutput &gdi) {
readoutFunctionY = gdi.getCY();
gdi.dropLine(0.3);
- gdi.addCheckbox("PlaySound", "Ljud", SportIdentCB, oe->getPropertyInt("PlaySound", 1) != 0,
- "Spela upp ett ljud för att indikera resultatet av brickavläsningen.");
+ gdi.addCheckbox("PlaySound", "Ljud", SportIdentCB, oe->getPropertyInt("PlaySound", 1) != 0,
+ "Spela upp ett ljud för att indikera resultatet av brickavläsningen.");
gdi.dropLine(-0.3);
gdi.addButton("SoundChoice", "Ljudval...", SportIdentCB);
gdi.dropLine(0.3);
- gdi.addString("Allow", 0, "Tillåt:");
- gdi.addCheckbox("AllowStart", "Start", SportIdentCB, allowStart);
- gdi.addCheckbox("AllowControl", "Radio", SportIdentCB, allowControl);
- gdi.addCheckbox("AllowFinish", "MÃ¥l", SportIdentCB, allowFinish);
-
updateReadoutFunction(gdi);
- gdi.dropLine(2.5);
+ gdi.dropLine(2);
gdi.setCX(xb + gdi.scaleLength(10));
}
else {
+ gdi.addString("", fontMediumPlus, lang.tl(modeName[mode]));
+ gdi.fillRight();
gdi.addButton("UnlockFunction", "LÃ¥s upp", SportIdentCB);
gdi.dropLine(0.2);
}
}
else {
- mode = ModeCardData;
+ mode = SIMode::ModeCardData;
}
- if (!oe->empty())
- gdi.addCheckbox("Interactive", "Interaktiv inläsning", SportIdentCB, interactiveReadout);
+ optionBarPosY = gdi.getCY();
+ optionBarPosX = gdi.getCX();
+ check_toolbar_xb = xb;
+ check_toolbar_yb = yb;
- if (oe->empty() || oe->useRunnerDb())
- gdi.addCheckbox("Database", "Använd löpardatabasen", SportIdentCB, useDatabase);
-
- gdi.addCheckbox("PrintSplits", "Sträcktidsutskrift[check]", SportIdentCB, printSplits);
-
- if (!oe->empty()) {
- gdi.addCheckbox("StartInfo", "Startbevis", SportIdentCB, printStartInfo, "Skriv ut startbevis för deltagaren");
- if (mode != ModeEntry)
- gdi.disableInput("StartInfo");
- }
- if (!oe->empty())
- gdi.addCheckbox("UseManualInput", "Manuell inmatning", SportIdentCB, manualInput);
-
- gdi.fillDown();
-
- if (!oe->empty()) {
- RECT rc = {xb, yb, gdi.getWidth(), gdi.getHeight()};
- gdi.addRectangle(rc, colorLightBlue);
- }
gdi.popX();
- gdi.dropLine(2);
gdi.setRestorePoint("SIPageLoaded");
- if (mode == ModeReadOut) {
+ if (mode == SIMode::ModeReadOut) {
showReadoutMode(gdi);
-
- gdi.dropLine();
}
- else if (mode == ModeAssignCards) {
- gdi.dropLine(1);
+ else if (mode == SIMode::ModeAssignCards) {
showAssignCard(gdi, true);
}
- else if (mode == ModeEntry) {
+ else if (mode == SIMode::ModeEntry) {
+ checkBoxToolBar(gdi, { CheckBox::UseDB, CheckBox::PrintStart });
entryTips(gdi);
generateEntryLine(gdi, 0);
- gdi.disableInput("Interactive");
- gdi.disableInput("PrintSplits");
- gdi.disableInput("UseManualInput");
}
- else if (mode == ModeCardData) {
+ else if (mode == SIMode::ModeCardData) {
showModeCardData(gdi);
}
- else if (mode == ModeCheckCards) {
+ else if (mode == SIMode::ModeCheckCards) {
showCheckCardStatus(gdi, "init");
}
- else if (mode == ModeRegisterCards) {
+ else if (mode == SIMode::ModeRegisterCards) {
showRegisterHiredCards(gdi);
}
@@ -2002,63 +2086,192 @@ bool TabSI::loadPage(gdioutput &gdi) {
return true;
}
-void TabSI::showReadoutMode(gdioutput & gdi) {
- gdi.dropLine(0.5);
- gdi.fillDown();
+void TabSI::checkBoxToolBar(gdioutput& gdi, const set& items) const {
+ gdi.pushX();
+ gdi.setCY(optionBarPosY);
+ gdi.setCX(optionBarPosX);
+ gdi.fillRight();
+
+ if (!items.empty())
+ gdi.dropLine(0.2);
+
+ if (items.count(CheckBox::Interactive))
+ gdi.addCheckbox("Interactive", "Interaktiv inläsning", SportIdentCB, interactiveReadout);
+
+ if (items.count(CheckBox::UseDB) && (oe->empty() || oe->useRunnerDb()))
+ gdi.addCheckbox("Database", "Använd löpardatabasen", SportIdentCB, useDatabase);
+
+ if (items.count(CheckBox::PrintSplits))
+ gdi.addCheckbox("PrintSplits", "Sträcktidsutskrift[check]", SportIdentCB, printSplits);
+
+ if (items.count(CheckBox::PrintStart))
+ gdi.addCheckbox("StartInfo", "Startbevis", SportIdentCB, printStartInfo, "Skriv ut startbevis för deltagaren");
+
+ if (items.count(CheckBox::Manual))
+ gdi.addCheckbox("UseManualInput", "Manuell inmatning", SportIdentCB, manualInput);
+
+ if (items.count(CheckBox::SeveralTurns))
+ gdi.addCheckbox("MultipleStarts", "Flera starter per deltagare", SportIdentCB, multipleStarts,
+ "info:multiple_start");
+
+ if (items.count(CheckBox::AutoTie))
+ gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0);
+
+ if (items.count(CheckBox::AutoTieRent) && oe->hasHiredCardData()) {
+ gdi.addCheckbox("AutoTieRent", "Automatisk hyrbrickshantering genom registrerade hyrbrickor", SportIdentCB, oe->getPropertyInt("AutoTieRent", 1) != 0);
+ }
+
+ if (!items.empty())
+ gdi.dropLine(2);
+
+ gdi.fillDown();
+
+ if (!oe->empty()) {
+ RECT rc = { check_toolbar_xb, check_toolbar_yb, gdi.getWidth(), gdi.getHeight() };
+ gdi.addRectangle(rc, colorLightBlue);
+ }
+ gdi.popX();
+ gdi.dropLine(1.5);
+
+ gdi.fillDown();
+ // gdi.popY();
+ gdi.popX();
+}
+
+void TabSI::showReadoutMode(gdioutput& gdi) {
+ if (!oe->empty())
+ checkBoxToolBar(gdi, { CheckBox::Interactive, CheckBox::UseDB, CheckBox::PrintSplits,
+ CheckBox::SeveralTurns, CheckBox::Manual });
+ else {
+ checkBoxToolBar(gdi, { CheckBox::UseDB, CheckBox::PrintSplits });
+ }
+
+ gdi.dropLine(0.5);
gdi.pushX();
- gdi.addString("", boldLarge, "Avläsning/radiotider");
- gdi.dropLine(0.2);
-
gdi.fillRight();
gdi.addButton("Import", "Importera från fil...", SportIdentCB);
- gdi.fillDown();
- gdi.addButton("ReadoutWindow", "Eget fönster", SportIdentCB);
+ gdi.addButton("ReadoutWindow", "Öppna avläsningsfönster", SportIdentCB, "info:readoutwindow");
+
+ if (oe->empty() || !getSI(gdi).isAnyOpenUnkownUnit())
+ gdi.dropLine(3);
+ else {
+ gdi.setRestorePoint("Mapping");
+ gdi.setData("ShowControlMapping", 1);
+ gdi.fillRight();
+ int cx = gdi.getCX() + gdi.scaleLength(10);
+ int cy = gdi.getCY();
+ gdi.setCX(cx);
+ gdi.setCY(cy);
+ gdi.addString("", boldText, "Tolkning av radiostämplingar med okänd typ");
+ int maxX = gdi.getCX();
+
+ gdi.setCX(cx);
+ gdi.dropLine(1.1);
+ auto mappings = getSI(gdi).getSpecialMappings();
+ wstring check, start, finish;
+ auto add = [](int code, wstring& dst) {
+ if (!dst.empty())
+ dst += L", ";
+ dst += itow(code);
+ };
+
+ auto complete = [](wstring& dst) {
+ if (dst.empty())
+ dst = makeDash(L"-");
+ };
+
+ for (auto& v : mappings) {
+ if (v.second == oPunch::SpecialPunch::PunchFinish)
+ add(v.first, finish);
+ else if (v.second == oPunch::SpecialPunch::PunchStart)
+ add(v.first, start);
+ else if (v.second == oPunch::SpecialPunch::PunchCheck)
+ add(v.first, check);
+ }
+ complete(finish);
+ complete(start);
+ complete(check);
+ gdi.addString("", 1, "Enhetskod:");
+
+ if (!check.empty()) {
+ gdi.addString("", 0, "Check:");
+ gdi.setCX(gdi.getCX() - gdi.scaleLength(2));
+ gdi.addStringUT(0, check);
+ }
+ if (!start.empty()) {
+ gdi.addString("", 0, "Start:");
+ gdi.setCX(gdi.getCX() - gdi.scaleLength(2));
+ gdi.addStringUT(0, start);
+ }
+ if (!finish.empty()) {
+ gdi.addString("", 0, "MÃ¥l:");
+ gdi.setCX(gdi.getCX() - gdi.scaleLength(2));
+ gdi.addStringUT(0, finish);
+ }
+ maxX = max(maxX, gdi.getCX());
+ gdi.setCX(maxX);
+ gdi.setCY(cy);
+
+ gdi.addButton("ChangeMapping", "Ändra", SportIdentCB);
+ maxX = max(maxX, gdi.getCX()) + gdi.scaleLength(10);
+
+ RECT rc;
+ rc.left = cx - gdi.scaleLength(5);
+ rc.top = cy - gdi.scaleLength(10);
+ rc.right = maxX;
+ rc.bottom = gdi.getHeight() + gdi.scaleLength(4);//gdi.getCY() + gdi.scaleLength(5);
+ gdi.fillDown();
+ gdi.addRectangle(rc, GDICOLOR::colorLightCyan);
+ gdi.dropLine(1);
+ }
- gdi.dropLine();
- gdi.popX();
- gdi.setRestorePoint("Help");
gdi.fillDown();
+ gdi.popX();
+
+ gdi.setRestorePoint("Help");
+ gdi.fillRight();
gdi.addString("", 10, "info:readoutbase");
+ gdi.fillDown();
+ gdi.addString("", 10, "info:readoutmore");
gdi.popX();
gdi.setCY(gdi.getHeight());
+ gdi.dropLine(0.5);
+
+ renderReadCard(gdi, 100);
if (gdi.isChecked("UseManualInput"))
showManualInput(gdi);
}
-void TabSI::updateReadoutFunction(gdioutput &gdi) {
+void TabSI::updateReadoutFunction(gdioutput& gdi) {
bool hide = mode != SIMode::ModeReadOut;
- gdi.hideWidget("Allow", hide);
- gdi.hideWidget("AllowStart", hide);
- gdi.hideWidget("AllowControl", hide);
- gdi.hideWidget("AllowFinish", hide);
gdi.hideWidget("SoundChoice", hide);
gdi.hideWidget("PlaySound", hide);
}
-void InsertSICard(gdioutput &gdi, SICard &sic)
+void InsertSICard(gdioutput& gdi, SICard& sic)
{
- TabSI &tsi = dynamic_cast(*gdi.getTabs().get(TSITab));
+ TabSI& tsi = dynamic_cast(*gdi.getTabs().get(TSITab));
tsi.insertSICard(gdi, sic);
}
-pRunner TabSI::autoMatch(const SICard &sic, pRunner db_r)
+pRunner TabSI::autoMatch(const SICard& sic, pRunner db_r)
{
assert(useDatabase);
//Look up in database.
if (!db_r)
db_r = gEvent->dbLookUpByCard(sic.CardNumber);
- pRunner r=0;
+ pRunner r = 0;
if (db_r) {
r = gEvent->getRunnerByName(db_r->getName(), db_r->getClub());
- if ( !r ) {
+ if (!r) {
vector classes;
int dist = gEvent->findBestClass(sic, classes);
- if (classes.size()==1 && dist>=-1 && dist<=1) { //Almost perfect match found. Assume it is it!
+ if (classes.size() == 1 && dist >= -1 && dist <= 1) { //Almost perfect match found. Assume it is it!
r = gEvent->addRunnerFromDB(db_r, classes[0]->getId(), true);
r->setCardNo(sic.CardNumber, false);
@@ -2066,27 +2279,27 @@ pRunner TabSI::autoMatch(const SICard &sic, pRunner db_r)
r->getDI().setInt("CardFee", oe->getBaseCardFee());
}
}
- else r=0; //Do not assume too much...
+ else r = 0; //Do not assume too much...
}
}
- if (r && r->getCard()==0)
+ if (r && r->getCard() == 0)
return r;
else return 0;
}
-void TabSI::insertSICard(gdioutput &gdi, SICard &sic)
+void TabSI::insertSICard(gdioutput& gdi, SICard& sic)
{
wstring msg;
try {
insertSICardAux(gdi, sic);
}
- catch (meosException &ex) {
+ catch (meosException& ex) {
msg = ex.wwhat();
}
- catch(std::exception &ex) {
+ catch (std::exception& ex) {
msg = gdi.widen(ex.what());
}
- catch(...) {
+ catch (...) {
msg = L"Ett okänt fel inträffade.";
}
@@ -2094,7 +2307,7 @@ void TabSI::insertSICard(gdioutput &gdi, SICard &sic)
gdi.alert(msg);
}
-void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
+void TabSI::insertSICardAux(gdioutput& gdi, SICard& sic)
{
if (oe->isReadOnly()) {
gdi.makeEvent("ReadCard", "insertSICard", sic.CardNumber, 0, true);
@@ -2102,9 +2315,9 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
}
DWORD loaded;
- bool pageLoaded=gdi.getData("SIPageLoaded", loaded);
+ bool pageLoaded = gdi.getData("SIPageLoaded", loaded);
- if (pageLoaded && manualInput && mode == ModeReadOut)
+ if (pageLoaded && manualInput && mode == SIMode::ModeReadOut)
gdi.restore("ManualInput");
if (!pageLoaded && !insertCardNumberField.empty()) {
@@ -2112,7 +2325,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
return;
}
- if (mode==ModeAssignCards) {
+ if (mode == SIMode::ModeAssignCards) {
if (!pageLoaded) {
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"Inläst bricka ställd i kö");
@@ -2120,7 +2333,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
else assignCard(gdi, sic);
return;
}
- else if (mode==ModeEntry) {
+ else if (mode == SIMode::ModeEntry) {
if (!pageLoaded) {
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"Inläst bricka ställd i kö");
@@ -2128,16 +2341,16 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
else entryCard(gdi, sic);
return;
}
- if (mode==ModeCheckCards) {
+ if (mode == SIMode::ModeCheckCards) {
if (!pageLoaded) {
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"Inläst bricka ställd i kö");
}
- else
+ else
checkCard(gdi, sic, true);
return;
}
- else if (mode == ModeRegisterCards) {
+ else if (mode == SIMode::ModeRegisterCards) {
if (!pageLoaded) {
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"Inläst bricka ställd i kö");
@@ -2147,7 +2360,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
}
return;
}
- else if (mode == ModeCardData) {
+ else if (mode == SIMode::ModeCardData) {
if (sic.convertedTime == ConvertedTimeStatus::Hour12) {
int locTime = getLocalAbsTime();
int st = -1;
@@ -2155,22 +2368,22 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
st = sic.StartPunch.Time;
else if (sic.nPunch > 0 && sic.Punch[0].Code != -1)
st = sic.Punch[0].Time;
-
+
if (st == -1)
- st = (locTime + 3600 * 20) % (12 * 3600);
+ st = (locTime + timeConstHour * 20) % (12 * timeConstHour);
else {
// We got a start time. Calculate running time
if (sic.FinishPunch.Code != -1) {
- int rt = (sic.FinishPunch.Time - st + 12 * 3600) % (12 * 3600);
-
+ int rt = (sic.FinishPunch.Time - st + 12 * timeConstHour) % (12 * timeConstHour);
+
// Adjust to local time at start;
- locTime = (locTime - rt + (24 * 3600)) % (24 * 3600);
+ locTime = (locTime - rt + (24 * timeConstHour)) % (24 * timeConstHour);
}
}
- int zt1 = (st + 23 * 3600) % (24 * 3600);
- int zt2 = st + 11 * 3600;
- int d1 = min(abs(locTime - zt1), abs(locTime - zt1 + 3600 * 24));
- int d2 = min(abs(locTime - zt2), abs(locTime - zt2 + 3600 * 24));
+ int zt1 = (st + 23 * timeConstHour) % (24 * timeConstHour);
+ int zt2 = st + 11 * timeConstHour;
+ int d1 = min(abs(locTime - zt1), abs(locTime - zt1 + timeConstHour * 24));
+ int d2 = min(abs(locTime - zt2), abs(locTime - zt2 + timeConstHour * 24));
if (d1 < d2)
sic.analyseHour12Time(zt1);
@@ -2183,18 +2396,18 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
bool first = savedCards.size() == numSavedCardsOnCmpOpen;
savedCards.push_back(make_pair(savedCardUniqueId++, sic));
-
+
if (printSplits) {
generateSplits(savedCards.back().first, gdi);
}
- gdioutput *gdi_settings = getExtraWindow("readout_view", true);
+ gdioutput* gdi_settings = getExtraWindow("readout_view", true);
if (gdi_settings) {
showReadoutStatus(*gdi_settings, nullptr, nullptr, &savedCards.back().second, L"");
}
if (savedCards.size() > 1 && pageLoaded) {
- RECT rc = {30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3};
+ RECT rc = { 30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3 };
gdi.addRectangle(rc);
}
@@ -2219,8 +2432,46 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
return;
}
pRunner r;
- if (sic.runnerId == 0)
- r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, oEvent::CardLookupProperty::ForReadout);
+ if (sic.runnerId == 0) {
+ r = oe->getRunnerByCardNo(sic.CardNumber, 0, oEvent::CardLookupProperty::ForReadout);
+
+ if (!r && multipleStarts && !oe->isCardRead(sic)) {
+ // Convert punch times to relative times.
+ oe->convertTimes(nullptr, sic);
+ int time = sic.getFirstTime();
+ pRunner rOld = oe->getRunnerByCardNo(sic.CardNumber, time, oEvent::CardLookupProperty::Any);
+
+ if (rOld) {
+ // New entry
+ vector classes;
+ oe->findBestClass(sic, classes);
+ int classId = rOld->getClassId(false);
+ if (classes.size() == 1)
+ classId = classes[0]->getId();
+
+ wstring given = rOld->getGivenName();
+ wstring family = rOld->getFamilyName();
+ size_t ep = family.find_last_of(')');
+ size_t sp = family.find_last_of('(');
+
+ int num = 1;
+ if (ep != string::npos && sp != string::npos && sp + 1 < ep) {
+ num = _wtoi(family.data() + sp + 1);
+ if (num > 0) {
+ family = trim(family.substr(0, ep - 2));
+ }
+ }
+ if (classId == rOld->getClassId(false))
+ family += + L" (" + itow(num + 1) + L")";
+
+ r = oe->addRunner(L"tmp", rOld->getClub(),
+ classId, sic.CardNumber, rOld->getBirthDate(), false);
+
+ r->setName(family + L", " + given, true);
+ r->setFlag(oAbstractRunner::TransferFlags::FlagNoDatabase, true);
+ }
+ }
+ }
else {
r = gEvent->getRunner(sic.runnerId, 0);
sic.CardNumber = r->getCardNo();
@@ -2236,7 +2487,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
//SIPage not loaded...
if (!r && showDatabase())
- r=autoMatch(sic, 0);
+ r = autoMatch(sic, 0);
// Assign a class if not already done
autoAssignClass(r, sic);
@@ -2249,7 +2500,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
}
else {
CardQueue.push_back(sic);
- gdi.addInfoBox("SIREAD", L"info:readout_action#" + gEvent->getCurrentTimeS()+L"#"+itow(sic.CardNumber), 0, SportIdentCB);
+ gdi.addInfoBox("SIREAD", L"info:readout_action#" + gEvent->getCurrentTimeS() + L"#" + itow(sic.CardNumber), 0, SportIdentCB);
playReadoutSound(SND::ActionNeeded);
return;
}
@@ -2293,7 +2544,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
if (readBefore) {
//We stop processing of new cards, while working...
// Thus cannot be in interactive mode
- activeSIC=sic;
+ activeSIC = sic;
wchar_t bf[256];
if (interactiveReadout) {
@@ -2314,8 +2565,8 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
}
else {
if (printSplits) {
- pRunner runner = getRunnerForCardSplitPrint(sic);
-
+ pRunner runner = getRunnerForCardSplitPrint(sic);
+
if (runner)
generateSplits(runner, gdi);
}
@@ -2385,7 +2636,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
}
}
-pRunner TabSI::getRunnerForCardSplitPrint(const SICard &sic) const {
+pRunner TabSI::getRunnerForCardSplitPrint(const SICard& sic) const {
pRunner runner = 0;
vector out;
oe->getRunnersByCardNo(sic.CardNumber, false, oEvent::CardLookupProperty::SkipNoStart, out);
@@ -2407,7 +2658,7 @@ pRunner TabSI::getRunnerForCardSplitPrint(const SICard &sic) const {
return runner;
}
-void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunner db_r)
+void TabSI::startInteractive(gdioutput& gdi, const SICard& sic, pRunner r, pRunner db_r)
{
if (!r) {
gdi.setRestorePoint();
@@ -2425,11 +2676,11 @@ void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunn
gdi.addCombo("Runners", 300, 300, SportIdentCB, L"Namn:");
gEvent->fillRunners(gdi, "Runners", false, oEvent::RunnerFilterOnlyNoResult);
- if (db_r){
+ if (db_r) {
gdi.setText("Runners", db_r->getName()); //Data from DB
}
- else if (sic.firstName[0] || sic.lastName[0]){ //Data from SI-card
- gdi.setText("Runners", wstring(sic.lastName) + L", " + sic.firstName);
+ else if (sic.firstName[0] || sic.lastName[0]) { //Data from SI-card
+ gdi.setText("Runners", wstring(sic.lastName) + L", " + sic.firstName);
}
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
gdi.addCombo("Club", 200, 300, 0, L"Klubb:").setHandler(&directEntryGUI);
@@ -2444,29 +2695,31 @@ void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunn
gdi.setInputFocus("Club");
//Process this card.
- activeSIC=sic;
+ activeSIC = sic;
gdi.dropLine();
gdi.setRestorePoint("restOK1");
gdi.addButton("OK1", "OK", SportIdentCB).setDefault();
+ gdi.addButton("SaveUnpaired", "Spara oparad bricka", SportIdentCB);
gdi.fillDown();
- gdi.addButton("Cancel", "Avbryt", SportIdentCB).setCancel();
+ gdi.addButton("Cancel", "Avbryt inläsning", SportIdentCB).setCancel();
gdi.popX();
gdi.addString("FindMatch", 0, "").setColor(colorGreen);
gdi.registerEvent("AutoComplete", SportIdentCB).setKeyCommand(KC_AUTOCOMPLETE);
gdi.dropLine();
gdi.scrollToBottom();
+ gdi.setOnClearCb(SportIdentCB);
gdi.refresh();
}
else {
//Process this card.
- activeSIC=sic;
+ activeSIC = sic;
//No class. Select...
gdi.setRestorePoint();
wchar_t bf[256];
swprintf_s(bf, 256, L"SI X inläst. Brickan tillhör Y som saknar klass.#%d#%s",
- sic.CardNumber, r->getName().c_str());
+ sic.CardNumber, r->getName().c_str());
gdi.dropLine();
gdi.addString("", 1, bf);
@@ -2491,12 +2744,13 @@ void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunn
gdi.popX();
gdi.setData("RunnerId", r->getId());
gdi.scrollToBottom();
+ gdi.setOnClearCb(SportIdentCB);
gdi.refresh();
}
}
// Insert card without converting times and with/without runner
-void TabSI::processInsertCard(const SICard &sic)
+void TabSI::processInsertCard(const SICard& sic)
{
if (oe->isCardRead(sic))
return;
@@ -2507,17 +2761,17 @@ void TabSI::processInsertCard(const SICard &sic)
card->setCardNo(sic.CardNumber);
card->setMeasuredVoltage(sic.miliVolt);
- if (sic.CheckPunch.Code!=-1)
- card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0);
+ if (sic.CheckPunch.Code != -1)
+ card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0, sic.CheckPunch.Code);
- if (sic.StartPunch.Code!=-1)
- card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0);
+ if (sic.StartPunch.Code != -1)
+ card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0, sic.StartPunch.Code);
- for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0);
+ for (unsigned i = 0; i < sic.nPunch; i++)
+ card->addPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0, 0);
- if (sic.FinishPunch.Code!=-1)
- card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time,0 );
+ if (sic.FinishPunch.Code != -1)
+ card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time, 0, sic.FinishPunch.Code);
//Update to SQL-source
card->synchronize();
@@ -2528,16 +2782,16 @@ void TabSI::processInsertCard(const SICard &sic)
}
}
-bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent) {
+bool TabSI::processUnmatched(gdioutput& gdi, const SICard& csic, bool silent) {
SICard sic(csic);
- pCard card=gEvent->allocateCard(0);
+ StoredReadout rout;
+ pCard card = gEvent->allocateCard(0);
card->setReadId(csic);
card->setCardNo(csic.CardNumber);
card->setMeasuredVoltage(csic.miliVolt);
-
- wstring info=lang.tl(L"Okänd bricka ") + itow(sic.CardNumber) + L".";
- wstring warnings;
+
+ rout.info = lang.tl(L"Okänd bricka ") + itow(sic.CardNumber) + L".";
// Write read card to log
logCard(gdi, sic);
@@ -2545,67 +2799,49 @@ bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent) {
// Convert punch times to relative times.
gEvent->convertTimes(nullptr, sic);
- if (sic.CheckPunch.Code!=-1)
- card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0);
+ if (sic.CheckPunch.Code != -1)
+ card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0, sic.CheckPunch.Code);
- if (sic.StartPunch.Code!=-1)
- card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0);
+ if (sic.StartPunch.Code != -1)
+ card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0, sic.StartPunch.Code);
- for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0);
+ for (unsigned i = 0; i < sic.nPunch; i++)
+ card->addPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0, 0);
- if (sic.FinishPunch.Code!=-1)
- card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time, 0);
+ if (sic.FinishPunch.Code != -1)
+ card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time, 0, sic.FinishPunch.Code);
else
- warnings+=lang.tl("Målstämpling saknas.");
+ rout.warnings += lang.tl("Målstämpling saknas.");
//Update to SQL-source
card->synchronize();
- gdioutput *gdi_settings = getExtraWindow("readout_view", true);
+ gdioutput* gdi_settings = getExtraWindow("readout_view", true);
if (gdi_settings) {
showReadoutStatus(*gdi_settings, nullptr, card, nullptr, L"");
}
- RECT rc;
- rc.left=15;
- rc.right=gdi.getWidth()-10;
- rc.top=gdi.getCY()+gdi.getLineHeight()-5;
- rc.bottom=rc.top+gdi.getLineHeight()*2+14;
+ rout.color = colorLightRed;
if (!silent) {
- gdi.fillDown();
- //gdi.dropLine();
- gdi.addRectangle(rc, colorLightRed, true);
- gdi.addStringUT(rc.top+6, rc.left+20, 1, info);
- //gdi.dropLine();
+ rout.render(gdi, rout.computeRC(gdi));
+
if (gdi.isChecked("UseManualInput"))
showManualInput(gdi);
gdi.scrollToBottom();
}
else {
- gdi.addInfoBox("SIINFO", L"#" + info, 10000);
+ gdi.addInfoBox("SIINFO", L"#" + rout.info, 10000);
}
+ readCards.push_back(std::move(rout));
gdi.makeEvent("DataUpdate", "sireadout", 0, 0, true);
playReadoutSound(SND::ActionNeeded);
checkMoreCardsInQueue(gdi);
return true;
}
-void TabSI::rentCardInfo(gdioutput &gdi, int width)
-{
- RECT rc;
- rc.left=15;
- rc.right=rc.left+width;
- rc.top=gdi.getCY()-7;
- rc.bottom=rc.top+gdi.getLineHeight()+5;
-
- gdi.addRectangle(rc, colorYellow, true);
- gdi.addString("", rc.top+2, rc.left+width/2, 1|textCenter, "Vänligen återlämna hyrbrickan.");
-}
-
-bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool silent)
+bool TabSI::processCard(gdioutput& gdi, pRunner runner, const SICard& csic, bool silent)
{
if (!runner)
return false;
@@ -2614,7 +2850,7 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
runner = runner->getMatchedRunner(csic);
- int lh=gdi.getLineHeight();
+ int lh = gdi.getLineHeight();
//Update from SQL-source
runner->synchronize();
@@ -2625,9 +2861,9 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
pClass cls = runner->getClassRef(false);
pClass pclass = runner->getClassRef(true);
if (cls && cls->hasCoursePool()) {
- unsigned leg=runner->legToRun();
+ unsigned leg = runner->legToRun();
- if (leggetNumStages()) {
+ if (leg < cls->getNumStages()) {
pCourse c = cls->selectCourseFromPool(leg, csic);
if (c)
runner->setCourseId(c->getId());
@@ -2650,16 +2886,16 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
if (!runner->getCourse(false) && !csic.isManualInput() && !oe->getMeOSFeatures().hasFeature(MeOSFeatures::NoCourses)) {
if (pclass && !pclass->hasMultiCourse() && !pclass->hasDirectResult()) {
- pCourse pcourse=gEvent->addCourse(pclass->getName());
+ pCourse pcourse = gEvent->addCourse(pclass->getName());
pclass->setCourse(pcourse);
- for(unsigned i=0;iaddControl(csic.Punch[i].Code);
wchar_t msg[256];
swprintf_s(msg, lang.tl(L"Skapade en bana för klassen %s med %d kontroller från brickdata (SI-%d)").c_str(),
- pclass->getName().c_str(), csic.nPunch, csic.CardNumber);
+ pclass->getName().c_str(), csic.nPunch, csic.CardNumber);
if (silent)
gdi.addInfoBox("SIINFO", wstring(L"#") + msg, 15000);
@@ -2668,7 +2904,7 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
}
else {
if (!(pclass && pclass->hasDirectResult())) {
- const wchar_t *msg=L"Löpare saknar klass eller bana";
+ const wchar_t* msg = L"Löpare saknar klass eller bana";
if (silent)
gdi.addInfoBox("SIINFO", msg, 15000);
@@ -2678,30 +2914,28 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
}
}
- pCourse pcourse=runner->getCourse(false);
+ pCourse pcourse = runner->getCourse(false);
if (pcourse)
pcourse->synchronize();
else if (pclass && pclass->hasDirectResult())
runner->setStatus(StatusOK, true, oBase::ChangeType::Update, false);
- //silent=true;
SICard sic(csic);
- wstring info, warnings, cardno;
- vector MP;
+ StoredReadout rout;
if (!csic.isManualInput()) {
- pCard card=gEvent->allocateCard(runner);
+ pCard card = gEvent->allocateCard(runner);
card->setReadId(csic);
card->setCardNo(sic.CardNumber);
card->setMeasuredVoltage(sic.miliVolt);
- cardno = itow(sic.CardNumber);
+ rout.cardno = itow(sic.CardNumber);
- info = runner->getName() + L" (" + cardno + L"), ";
+ rout.info = runner->getName() + L" (" + rout.cardno + L"), ";
if (!runner->getClub().empty())
- info += runner->getClub() + +L", ";
- info += runner->getClass(true);
+ rout.info += runner->getClub() + +L", ";
+ rout.info += runner->getClass(true);
// Write read card to log
logCard(gdi, sic);
@@ -2712,33 +2946,34 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
const int finishPT = prelCourse ? prelCourse->getFinishPunchType() : oPunch::PunchFinish;
bool hasFinish = false;
- if (sic.CheckPunch.Code!=-1)
- card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time,0);
+ if (sic.CheckPunch.Code != -1)
+ card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0, sic.CheckPunch.Code);
- if (sic.StartPunch.Code!=-1)
- card->addPunch(oPunch::PunchStart, sic.StartPunch.Time,0);
+ if (sic.StartPunch.Code != -1)
+ card->addPunch(oPunch::PunchStart, sic.StartPunch.Time, 0, sic.StartPunch.Code);
- for(unsigned i=0;iaddPunch(sic.Punch[i].Code, sic.Punch[i].Time,0);
+ card->addPunch(sic.Punch[i].Code, sic.Punch[i].Time, 0, 0);
}
- if (sic.FinishPunch.Code!=-1) {
- card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time,0);
+ if (sic.FinishPunch.Code != -1) {
+ card->addPunch(oPunch::PunchFinish, sic.FinishPunch.Time, 0, sic.FinishPunch.Code);
if (finishPT == oPunch::PunchFinish)
hasFinish = true;
}
if (!hasFinish)
- warnings+=lang.tl(L"Målstämpling saknas.");
+ rout.warnings += lang.tl(L"Målstämpling saknas.");
card->synchronize();
- runner->addPunches(card, MP);
+ runner->addPunches(card, rout.MP);
+ runner->synchronize(true);
runner->hasManuallyUpdatedTimeStatus();
}
else {
//Manual input
- info = runner->getName() + L", " + runner->getClub() + L", " + runner->getClass(true);
+ rout.info = runner->getName() + L", " + runner->getClub() + L", " + runner->getClass(true);
runner->setCard(0);
if (csic.statusOK) {
@@ -2754,8 +2989,8 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
runner->setFinishTime(csic.relativeFinishTime);
}
- cardno = makeDash(L"-");
- runner->evaluateCard(true, MP, 0, oBase::ChangeType::Update);
+ rout.cardno = makeDash(L"-");
+ runner->evaluateCard(true, rout.MP, 0, oBase::ChangeType::Update);
runner->synchronizeAll(true);
runner->hasManuallyUpdatedTimeStatus();
}
@@ -2763,15 +2998,6 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
//Update to SQL-source
runner->synchronize();
- RECT rc;
- rc.left=15;
- rc.right=gdi.getWidth()-10;
- rc.top=gdi.getCY()+gdi.getLineHeight()-5;
- rc.bottom=rc.top+gdi.getLineHeight()*2+14;
-
- if (!warnings.empty())
- rc.bottom+=gdi.getLineHeight();
-
set clsSet;
wstring mpList;
@@ -2781,50 +3007,41 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
if (runner->getTeam())
gEvent->calculateTeamResults(clsSet, oEvent::ResultType::ClassResult);
- if (runner->getStatusComputed()==StatusOK || isPossibleResultStatus(runner->getStatusComputed())) {
+ if (runner->getStatusComputed(true) == StatusOK || isPossibleResultStatus(runner->getStatusComputed(true))) {
wstring placeS = getPlace(runner);
- if (placeS == L"1")
+ if (placeS == L"1")
playReadoutSound(SND::Leader);
else
playReadoutSound(SND::OK);
+ rout.color = colorLightGreen;
+ rout.statusline = lang.tl(L"Status OK, ") +
+ lang.tl(L"Tid: ") + getTimeString(runner);
+ if (!placeS.empty())
+ rout.statusline += lang.tl(L", Prel. placering: ") + placeS;
+ rout.statusline += lang.tl(L", Prel. bomtid: ") + runner->getMissedTimeS();
+
+ rout.rentCard = runner->isHiredCard() || oe->isHiredCard(sic.CardNumber);
+
if (!silent) {
- gdi.fillDown();
- //gdi.dropLine();
- gdi.addRectangle(rc, colorLightGreen, true);
-
- gdi.addStringUT(rc.top+6, rc.left+20, 1, info);
- if (!warnings.empty())
- gdi.addStringUT(rc.top+6+2*lh, rc.left+20, 0, warnings);
-
- wstring statusline = lang.tl(L"Status OK, ") +
- lang.tl(L"Tid: ") + getTimeString(runner);
-
- if (!placeS.empty())
- statusline += lang.tl(L", Prel. placering: ") + placeS;
-
- statusline += lang.tl(L", Prel. bomtid: ") + runner->getMissedTimeS();
- gdi.addStringUT(rc.top+6+lh, rc.left+20, 0, statusline);
-
- if (runner->isHiredCard() || oe->isHiredCard(sic.CardNumber))
- rentCardInfo(gdi, rc.right-rc.left);
+ rout.render(gdi, rout.computeRC(gdi));
gdi.scrollToBottom();
}
else {
- wstring msg = L"#" + runner->getName() + L" (" + cardno + L")\n"+
- runner->getClub() + L". " + runner->getClass(true) +
- L"\n" + lang.tl("Tid: ") + runner->getRunningTimeS(true) + lang.tl(L", Plats ") + placeS;
+ wstring msg = L"#" + runner->getName() + L" (" + rout.cardno + L")\n" +
+ runner->getClub() + L". " + runner->getClass(true) +
+ L"\n" + lang.tl("Tid: ") + runner->getRunningTimeS(true, SubSecond::Auto) + lang.tl(L", Plats ") + placeS;
gdi.addInfoBox("SIINFO", msg, 10000);
}
}
else {
- wstring msg=lang.tl(L"Status: ") + runner->getStatusS(true, true);
+ rout.statusline = lang.tl(L"Status: ") + runner->getStatusS(true, true);
playReadoutSound(SND::NotOK);
- if (!MP.empty()) {
- for (int c : MP) {
+ if (!rout.MP.empty()) {
+ for (int c : rout.MP) {
if (!mpList.empty())
mpList += L", ";
mpList = mpList + itow(c);
@@ -2832,35 +3049,26 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
mpList += lang.tl(" saknas.");
}
- if (!mpList.empty())
- msg += L", (" + mpList + + L")";
+ if (!mpList.empty())
+ rout.statusline += L", (" + mpList + +L")";
+
+ rout.color = colorLightRed;
+ rout.rentCard = runner->isHiredCard() || oe->isHiredCard(sic.CardNumber);
if (!silent) {
- gdi.fillDown();
- gdi.dropLine();
- gdi.addRectangle(rc, colorLightRed, true);
-
- gdi.addStringUT(rc.top+6, rc.left+20, 1, info);
- if (!warnings.empty())
- gdi.addStringUT(rc.top+6+lh*2, rc.left+20, 1, warnings);
-
- gdi.addStringUT(rc.top+6+lh, rc.left+20, 0, msg);
-
- if (runner->isHiredCard())
- rentCardInfo(gdi, rc.right-rc.left);
-
+ rout.render(gdi, rout.computeRC(gdi));
gdi.scrollToBottom();
}
else {
- wstring statusmsg = L"#" + runner->getName() + L" (" + cardno + L")\n"+
- runner->getClub() + L". "+ runner->getClass(true) +
- L"\n" + msg;
+ wstring statusmsg = L"#" + runner->getName() + L" (" + rout.cardno + L")\n" +
+ runner->getClub() + L". " + runner->getClass(true) +
+ L"\n" + rout.statusline;
gdi.addInfoBox("SIINFO", statusmsg, 10000);
}
}
- gdioutput *gdi_settings = getExtraWindow("readout_view", true);
+ gdioutput* gdi_settings = getExtraWindow("readout_view", true);
if (gdi_settings) {
showReadoutStatus(*gdi_settings, runner, nullptr, nullptr, mpList);
}
@@ -2874,11 +3082,70 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
activeSIC.clear(&csic);
+ readCards.push_back(std::move(rout));
checkMoreCardsInQueue(gdi);
return true;
}
-wstring TabSI::getPlace(const oRunner *runner) {
+RECT TabSI::StoredReadout::computeRC(gdioutput& gdi) const {
+ RECT rc;
+ rc.left = gdi.scaleLength(15);
+ rc.right = gdi.getWidth() - gdi.scaleLength(10);
+ rc.top = gdi.getCY() + gdi.getLineHeight() - gdi.scaleLength(5);
+ rc.bottom = rc.top + gdi.getLineHeight() * 2 + gdi.scaleLength(14);
+
+ if (!warnings.empty())
+ rc.bottom += gdi.getLineHeight();
+
+ return rc;
+}
+
+void TabSI::StoredReadout::render(gdioutput& gdi, const RECT& rc) const {
+ gdi.fillDown();
+ gdi.addRectangle(rc, color, true);
+ int lh = gdi.getLineHeight();
+ int marg = gdi.scaleLength(20);
+ int tmarg = gdi.scaleLength(6);
+ gdi.addStringUT(rc.top + 6, rc.left + marg, 1, info);
+ if (!warnings.empty())
+ gdi.addStringUT(rc.top + tmarg + 2 * lh, rc.left + marg, 0, warnings);
+
+ gdi.addStringUT(rc.top + tmarg + lh, rc.left + marg, 0, statusline);
+
+ if (rentCard)
+ rentCardInfo(gdi, rc);
+}
+
+void TabSI::StoredReadout::rentCardInfo(gdioutput& gdi, const RECT& rcIn) {
+ RECT rc;
+ rc.left = rcIn.left;
+ rc.right = rcIn.right;
+ rc.top = rcIn.bottom;
+ rc.bottom = rc.top + gdi.getLineHeight() + gdi.scaleLength(5);
+
+ gdi.addRectangle(rc, colorYellow, true);
+ gdi.addString("", rc.top + gdi.scaleLength(2), (rc.left + rc.right) / 2, 1 | textCenter, "Vänligen återlämna hyrbrickan.");
+}
+
+void TabSI::renderReadCard(gdioutput& gdi, int maxNumber) {
+ if (readCards.empty())
+ return;
+
+ auto it = readCards.begin();
+ int N = readCards.size();
+ if (N > maxNumber)
+ it = std::next(it, N - maxNumber);
+
+ while (it != readCards.end()) {
+ it->render(gdi, it->computeRC(gdi));
+ ++it;
+ }
+
+ gdi.scrollToBottom();
+}
+
+
+wstring TabSI::getPlace(const oRunner* runner) {
bool qfClass = runner->getClassId(false) != runner->getClassId(true);
wstring placeS = (runner->getTeam() && !qfClass) ?
runner->getTeam()->getLegPlaceS(runner->getLegNumber(), false) :
@@ -2887,36 +3154,36 @@ wstring TabSI::getPlace(const oRunner *runner) {
return placeS;
}
-wstring TabSI::getTimeString(const oRunner *runner) {
+wstring TabSI::getTimeString(const oRunner* runner) {
bool qfClass = runner->getClassId(false) != runner->getClassId(true);
- wstring ts = runner->getRunningTimeS(true);
+ wstring ts = runner->getRunningTimeS(true, SubSecond::Auto);
if (!qfClass && runner->getTeam()) {
cTeam t = runner->getTeam();
if (t->getLegStatus(runner->getLegNumber(), true, false) == StatusOK) {
- ts += L" (" + t->getLegRunningTimeS(runner->getLegNumber(), true, false) + L")";
+ ts += L" (" + t->getLegRunningTimeS(runner->getLegNumber(), true, false, SubSecond::Auto) + L")";
}
}
return ts;
}
-wstring TabSI::getTimeAfterString(const oRunner *runner) {
+wstring TabSI::getTimeAfterString(const oRunner* runner) {
bool qfClass = runner->getClassId(false) != runner->getClassId(true);
int ta = runner->getTimeAfter();
-
+
wstring ts;
if (ta > 0)
ts = L"+" + formatTime(ta);
-
+
if (!qfClass && runner->getTeam()) {
cTeam t = runner->getTeam();
if (t->getLegStatus(runner->getLegNumber(), true, false) == StatusOK) {
- int tat = t->getTimeAfter(runner->getLegNumber());
+ int tat = t->getTimeAfter(runner->getLegNumber(), true);
if (tat > 0) {
- /* if (ta == 0)
- ts = L"0:00";
+ /* if (ta == 0)
+ ts = L"0:00";
- ts += L" (+" + formatTime(tat) + L")";
- */
+ ts += L" (+" + formatTime(tat) + L")";
+ */
ts = L"+" + formatTime(tat);
}
}
@@ -2924,37 +3191,28 @@ wstring TabSI::getTimeAfterString(const oRunner *runner) {
return ts;
}
-void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic)
+void TabSI::processPunchOnly(gdioutput& gdi, const SICard& csic)
{
SICard sic = csic;
DWORD loaded;
gEvent->convertTimes(nullptr, sic);
- oFreePunch *ofp = 0;
+ oFreePunch* ofp = 0;
wstring accessError;
if (sic.nPunch == 1) {
- if (allowControl)
- ofp = gEvent->addFreePunch(sic.Punch[0].Time, sic.Punch[0].Code, sic.CardNumber, true);
- else
- accessError = L"Radio tillåts inte (X)#" + itow(sic.CardNumber);
+ ofp = gEvent->addFreePunch(sic.Punch[0].Time, sic.Punch[0].Code, 0, sic.CardNumber, true);
}
else if (sic.FinishPunch.Time > 0) {
- if (allowFinish)
- ofp = gEvent->addFreePunch(sic.FinishPunch.Time, oPunch::PunchFinish, sic.CardNumber, true);
- else
- accessError = L"Målstämpling tillåts inte (X)#" + itow(sic.CardNumber);
+ ofp = gEvent->addFreePunch(sic.FinishPunch.Time, oPunch::PunchFinish, sic.FinishPunch.Code, sic.CardNumber, true);
}
else if (sic.StartPunch.Time > 0) {
- if (allowStart)
- ofp = gEvent->addFreePunch(sic.StartPunch.Time, oPunch::PunchStart, sic.CardNumber, true);
- else
- accessError = L"Startstämpling tillåts inte (X)#" + itow(sic.CardNumber);
+ ofp = gEvent->addFreePunch(sic.StartPunch.Time, oPunch::PunchStart, sic.StartPunch.Code, sic.CardNumber, true);
}
else {
- ofp = gEvent->addFreePunch(sic.CheckPunch.Time, oPunch::PunchCheck, sic.CardNumber, true);
+ ofp = gEvent->addFreePunch(sic.CheckPunch.Time, oPunch::PunchCheck, sic.CheckPunch.Code, sic.CardNumber, true);
}
if (ofp) {
pRunner r = ofp->getTiedRunner();
- if (gdi.getData("SIPageLoaded", loaded)){
+ if (gdi.getData("SIPageLoaded", loaded)) {
//gEvent->getRunnerByCard(sic.CardNumber);
if (r) {
@@ -2963,7 +3221,7 @@ void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic)
gdi.dropLine();
}
else {
- wstring str= itow(sic.CardNumber) + lang.tl(" (okänd) stämplade vid ") + ofp->getSimpleString();
+ wstring str = itow(sic.CardNumber) + lang.tl(" (okänd) stämplade vid ") + ofp->getSimpleString();
gdi.addStringUT(0, str);
gdi.dropLine(0.3);
}
@@ -2974,8 +3232,9 @@ void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic)
gdi.makeEvent("DataUpdate", "sireadout", r ? r->getId() : 0, 0, true);
}
else if (!accessError.empty()) {
+ playReadoutSound(SND::ActionNeeded);
if (gdi.getData("SIPageLoaded", loaded)) {
- gdi.addString("", 0, accessError).setColor(colorDarkRed);
+ gdi.addString("", fontLarge, accessError).setColor(colorDarkRed);
gdi.dropLine(0.3);
gdi.scrollToBottom();
}
@@ -2987,7 +3246,7 @@ void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic)
return;
}
-void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
+void TabSI::entryCard(gdioutput& gdi, const SICard& sic)
{
gdi.setText("CardNo", sic.CardNumber);
@@ -2998,18 +3257,18 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
wstring club;
int age = 0;
if (showDatabase()) {
- pRunner db_r=oe->dbLookUpByCard(sic.CardNumber);
+ pRunner db_r = oe->dbLookUpByCard(sic.CardNumber);
if (db_r) {
- name=db_r->getNameRaw();
- club=db_r->getClub();
+ name = db_r->getNameRaw();
+ club = db_r->getClub();
age = db_r->getBirthAge();
}
}
//Else get name from card
if (name.empty() && (sic.firstName[0] || sic.lastName[0]))
- name=wstring(sic.lastName) + L", " + wstring(sic.firstName);
+ name = wstring(sic.lastName) + L", " + wstring(sic.firstName);
gdi.setText("Name", name);
if (gdi.hasWidget("Club") && !club.empty())
@@ -3032,7 +3291,7 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
}
}
-void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
+void TabSI::assignCard(gdioutput& gdi, const SICard& sic)
{
if (interactiveReadout) {
@@ -3049,34 +3308,34 @@ void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
int storedAssigneIndex = currentAssignIndex;
//Try first current focus
- BaseInfo *ii=gdi.getInputFocus();
+ BaseInfo* ii = gdi.getInputFocus();
wstring sicode = itow(sic.CardNumber);
- if (ii && ii->id[0]=='*') {
- currentAssignIndex=atoi(ii->id.c_str()+1);
+ if (ii && ii->id[0] == '*') {
+ currentAssignIndex = atoi(ii->id.c_str() + 1);
}
else { //If not correct focus, use internal counter
char id[32];
sprintf_s(id, "*%d", currentAssignIndex++);
- ii=gdi.setInputFocus(id);
+ ii = gdi.setInputFocus(id);
if (!ii) {
- currentAssignIndex=0;
+ currentAssignIndex = 0;
sprintf_s(id, "*%d", currentAssignIndex++);
- ii=gdi.setInputFocus(id);
+ ii = gdi.setInputFocus(id);
}
}
if (ii && ii->getExtraInt()) {
- pRunner r=oe->getRunner(ii->getExtraInt(), 0);
+ pRunner r = oe->getRunner(ii->getExtraInt(), 0);
if (r) {
if (oe->checkCardUsed(gdi, *r, sic.CardNumber)) {
currentAssignIndex = storedAssigneIndex;
return;
}
if (r->getCardNo() == 0 ||
- gdi.ask(L"Skriv över existerande bricknummer?")) {
+ gdi.ask(L"Skriv över existerande bricknummer?")) {
r->setCardNo(sic.CardNumber, false);
r->getDI().setInt("CardFee", oe->getBaseCardFee());
@@ -3090,7 +3349,7 @@ void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
checkMoreCardsInQueue(gdi);
}
-void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
+void TabSI::generateEntryLine(gdioutput& gdi, pRunner r) {
oe->synchronizeList({ oListId::oLRunnerId, oListId::oLCardId });
gdi.restore("EntryLine", false);
@@ -3108,7 +3367,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, L"Bricka:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
- gdi.addCombo("Club", 180, 200, 0, L"Klubb:",
+ gdi.addCombo("Club", 180, 200, 0, L"Klubb:",
L"Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben")
.setHandler(&directEntryGUI);
oe->fillClubs(gdi, "Club");
@@ -3129,7 +3388,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
}
gdi.addItem("Class", d);
}
-
+
if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) {
}
else if (!gdi.selectItemByData("Class", lastClassId)) {
@@ -3139,7 +3398,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
gdi.addCombo("Fee", 60, 150, SportIdentCB, L"Anm. avgift:");
oe->fillFees(gdi, "Fee", true, false);
-
+
if (!storedInfo.storedFee.empty() && storedInfo.storedFee != L"@")
gdi.setText("Fee", storedInfo.storedFee);
else
@@ -3153,7 +3412,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
gdi.popX();
gdi.dropLine(3.1);
- gdi.addString("",0, "Starttid:");
+ gdi.addString("", 0, "Starttid:");
gdi.dropLine(-0.2);
gdi.addInput("StartTime", storedInfo.storedStartTime, 5, 0, L"");
@@ -3164,24 +3423,24 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
gdi.dropLine(-0.2);
gdi.addInput("Bib", L"", 5, 0, L"");
- gdi.setCX(gdi.getCX()+gdi.scaleLength(20));
+ gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
gdi.dropLine(0.2);
-
+
gdi.addString("", 0, "Telefon:");
gdi.dropLine(-0.2);
gdi.addInput("Phone", storedInfo.storedPhone, 12, 0, L"");
gdi.dropLine(0.2);
- gdi.setCX(gdi.getCX()+gdi.scaleLength(20));
+ gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
gdi.addCheckbox("RentCard", "Hyrbricka", SportIdentCB, storedInfo.rentState);
gdi.addCheckbox("NoTiming", "Utan tidtagning", nullptr, false);
if (oe->hasNextStage())
gdi.addCheckbox("AllStages", "Anmäl till efterföljande etapper", SportIdentCB, storedInfo.allStages);
-
- if (r!=0) {
- if (r->getCardNo()>0)
+
+ if (r != 0) {
+ if (r->getCardNo() > 0)
gdi.setText("CardNo", r->getCardNo());
gdi.setText("Name", r->getNameRaw());
@@ -3200,7 +3459,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
gdi.check("NoTiming", r->hasFlag(oAbstractRunner::TransferFlags::FlagNoTiming));
gdi.check("RentCard", dci.getInt("CardFee") != 0);
if (gdi.hasWidget("Paid"))
- gdi.check("Paid", dci.getInt("Paid")>0);
+ gdi.check("Paid", dci.getInt("Paid") > 0);
else if (gdi.hasWidget("PayMode")) {
int paidId = dci.getInt("Paid") > 0 ? r->getPaymentMode() : 1000;
gdi.selectItemByData("PayMode", paidId);
@@ -3220,15 +3479,15 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
updateEntryInfo(gdi);
gdi.setInputFocus("CardNo");
gdi.dropLine(2);
-
- RECT rc = {xb, yb, gdi.getWidth(), gdi.getHeight()};
+
+ RECT rc = { xb, yb, gdi.getWidth(), gdi.getHeight() };
gdi.addRectangle(rc, colorLightCyan);
gdi.scrollToBottom();
gdi.popX();
gdi.setOnClearCb(SportIdentCB);
}
-void TabSI::updateEntryInfo(gdioutput &gdi)
+void TabSI::updateEntryInfo(gdioutput& gdi)
{
int fee = oe->interpretCurrency(gdi.getText("Fee", true));
if (gdi.isChecked("RentCard")) {
@@ -3248,7 +3507,7 @@ void TabSI::updateEntryInfo(gdioutput &gdi)
wstring method;
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
- bool invoice = true;
+ bool invoice = true;
if (gdi.hasWidget("PayMode")) {
invoice = gdi.getSelectedItem("PayMode").first == 1000;
}
@@ -3261,7 +3520,7 @@ void TabSI::updateEntryInfo(gdioutput &gdi)
method = lang.tl(L"Faktureras");
gdi.setText("EntryInfo", lang.tl(L"X: Y. Tryck för att spara#" +
- method + L"#" + oe->formatCurrency(fee)), true);
+ method + L"#" + oe->formatCurrency(fee)), true);
}
else {
gdi.setText("EntryInfo", lang.tl("Press Enter to continue"), true);
@@ -3269,12 +3528,12 @@ void TabSI::updateEntryInfo(gdioutput &gdi)
}
}
-void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
+void TabSI::generateSplits(const pRunner r, gdioutput& gdi)
{
const bool wideFormat = oe->getPropertyInt("WideSplitFormat", 0) == 1;
if (wideFormat) {
addToPrintQueue(r);
- while(checkpPrintQueue(gdi));
+ while (checkpPrintQueue(gdi));
}
else {
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
@@ -3286,7 +3545,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
}
}
-void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) {
+void TabSI::generateStartInfo(gdioutput& gdi, const oRunner& r) {
if (printStartInfo) {
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
r.printStartInfo(gdiprint);
@@ -3295,15 +3554,15 @@ void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) {
}
}
-void TabSI::printerSetup(gdioutput &gdi)
+void TabSI::printerSetup(gdioutput& gdi)
{
gdi.printSetup(splitPrinter);
splitPrinter.onlyChanged = false;
}
-void TabSI::checkMoreCardsInQueue(gdioutput &gdi) {
+void TabSI::checkMoreCardsInQueue(gdioutput& gdi) {
// Create a local list to avoid stack overflow
- list cards = CardQueue;
+ list cards = std::move(CardQueue);
CardQueue.clear();
std::exception storedEx;
bool fail = false;
@@ -3315,7 +3574,7 @@ void TabSI::checkMoreCardsInQueue(gdioutput &gdi) {
gdi.RemoveFirstInfoBox("SIREAD");
insertSICard(gdi, c);
}
- catch (std::exception &ex) {
+ catch (std::exception& ex) {
fail = true;
storedEx = ex;
}
@@ -3325,19 +3584,19 @@ void TabSI::checkMoreCardsInQueue(gdioutput &gdi) {
throw storedEx;
}
-bool TabSI::autoAssignClass(pRunner r, const SICard &sic) {
- if (r && r->getClassId(false)==0) {
+bool TabSI::autoAssignClass(pRunner r, const SICard& sic) {
+ if (r && r->getClassId(false) == 0) {
vector classes;
int dist = oe->findBestClass(sic, classes);
- if (classes.size() == 1 && dist>=-1 && dist<=1) // Allow at most one wrong punch
+ if (classes.size() == 1 && dist >= -1 && dist <= 1) // Allow at most one wrong punch
r->setClassId(classes[0]->getId(), true);
}
return r && r->getClassId(false) != 0;
}
-void TabSI::showManualInput(gdioutput &gdi) {
+void TabSI::showManualInput(gdioutput& gdi) {
runnerMatchedId = -1;
gdi.setRestorePoint("ManualInput");
gdi.fillDown();
@@ -3346,7 +3605,7 @@ void TabSI::showManualInput(gdioutput &gdi) {
int x = gdi.getCX();
int y = gdi.getCY();
- gdi.setCX(x+gdi.scaleLength(15));
+ gdi.setCX(x + gdi.scaleLength(15));
gdi.dropLine();
gdi.addString("", 1, "Manuell inmatning");
gdi.fillRight();
@@ -3366,17 +3625,16 @@ void TabSI::showManualInput(gdioutput &gdi) {
gdi.dropLine();
RECT rc;
- rc.left=x;
- rc.right=gdi.getWidth()-10;
- rc.top=y;
- rc.bottom=gdi.getCY()+gdi.scaleLength(5);
+ rc.left = x;
+ rc.right = gdi.getWidth() - 10;
+ rc.top = y;
+ rc.bottom = gdi.getCY() + gdi.scaleLength(5);
gdi.dropLine();
gdi.addRectangle(rc, colorLightBlue);
- //gdi.refresh();
gdi.scrollToBottom();
}
-void TabSI::tieCard(gdioutput &gdi) {
+void TabSI::tieCard(gdioutput& gdi) {
int card = gdi.getTextNo("CardNo");
pRunner r = oe->getRunner(runnerMatchedId, 0);
@@ -3391,9 +3649,14 @@ void TabSI::tieCard(gdioutput &gdi) {
return;
}
- bool rent = gdi.isChecked("RentCardTie");
+ bool rent = false;
+ if (!gdi.hasWidget("AutoTieRent") || !gdi.isChecked("AutoTieRent"))
+ rent = gdi.isChecked("RentCardTie");
+ else
+ rent = oe->isHiredCard(card);
+
+ r->synchronize();
r->setCardNo(card, true, false);
-
r->getDI().setInt("CardFee", rent ? oe->getBaseCardFee() : 0);
r->synchronize(true);
@@ -3411,6 +3674,9 @@ void TabSI::tieCard(gdioutput &gdi) {
gdi.addStringUT(0, L"(" + r->getClub() + L")", 0);
gdi.addStringUT(1, itos(r->getCardNo()), 0).setColor(colorDarkGreen);
+ if (rent)
+ gdi.addStringUT(0, L" (" + lang.tl("Hyrd") + L") ");
+
gdi.addString("EditAssign", 0, "Ändra", SportIdentCB).setExtra(r->getId());
gdi.dropLine(1.5);
gdi.popX();
@@ -3418,21 +3684,30 @@ void TabSI::tieCard(gdioutput &gdi) {
showAssignCard(gdi, false);
}
-void TabSI::showAssignCard(gdioutput &gdi, bool showHelp) {
- gdi.enableInput("Interactive");
- gdi.disableInput("Database", true);
- gdi.disableInput("PrintSplits");
- gdi.disableInput("StartInfo");
- gdi.disableInput("UseManualInput");
- gdi.setRestorePoint("ManualTie");
- gdi.fillDown();
+void TabSI::showAssignCard(gdioutput& gdi, bool showHelp) {
+ //gdi.fillDown();
+ //gdi.setRestorePoint("AssignCardBase");
if (interactiveReadout) {
- if (showHelp)
+ if (showHelp) {
+ checkBoxToolBar(gdi, { CheckBox::Interactive, CheckBox::AutoTie, CheckBox::AutoTieRent });
gdi.addString("", 10, L"Avmarkera 'X' för att hantera alla bricktildelningar samtidigt.#" + lang.tl("Interaktiv inläsning"));
+ /*gdi.dropLine(0.5);
+ gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0);
+ gdi.addCheckbox("AutoTieRent", "Automatisk hyrbrickshantering genom registrerade hyrbrickor", SportIdentCB, oe->getPropertyInt("AutoTieRent", 1) != 0);
+ if (!oe->hasHiredCardData()) {
+ gdi.disableInput("AutoTieRent");
+ gdi.check("AutoTieRent", false);
+ }*/
+ gdi.dropLine(0.5);
+ gdi.setRestorePoint("ManualTie");
+ }
}
else {
- if (showHelp)
+ if (showHelp) {
+ checkBoxToolBar(gdi, { CheckBox::Interactive });
gdi.addString("", 10, L"Markera 'X' för att hantera deltagarna en och en.#" + lang.tl("Interaktiv inläsning"));
+ }
+
gEvent->assignCardInteractive(gdi, SportIdentCB);
gdi.refresh();
return;
@@ -3445,7 +3720,7 @@ void TabSI::showAssignCard(gdioutput &gdi, bool showHelp) {
int x = gdi.getCX();
int y = gdi.getCY();
- gdi.setCX(x+gdi.scaleLength(15));
+ gdi.setCX(x + gdi.scaleLength(15));
gdi.dropLine();
gdi.addString("", 1, "Knyt bricka / deltagare");
gdi.fillRight();
@@ -3454,7 +3729,7 @@ void TabSI::showAssignCard(gdioutput &gdi, bool showHelp) {
gdi.addInput("RunnerId", L"", 20, SportIdentCB, L"Nummerlapp, lopp-id eller namn:");
gdi.addInput("CardNo", L"", 8, SportIdentCB, L"Bricknr:");
gdi.dropLine(1.2);
- gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0);
+ //gdi.addCheckbox("AutoTie", "Knyt automatiskt efter inläsning", SportIdentCB, oe->getPropertyInt("AutoTie", 1) != 0);
gdi.addCheckbox("RentCardTie", "Hyrd", SportIdentCB, oe->getPropertyInt("RentCard", 0) != 0);
gdi.dropLine(-0.3);
@@ -3468,10 +3743,10 @@ void TabSI::showAssignCard(gdioutput &gdi, bool showHelp) {
gdi.dropLine();
RECT rc;
- rc.left=x;
- rc.right=gdi.getWidth()+gdi.scaleLength(5);
- rc.top=y;
- rc.bottom=gdi.getCY()+gdi.scaleLength(5);
+ rc.left = x;
+ rc.right = gdi.getWidth() + gdi.scaleLength(5);
+ rc.top = y;
+ rc.bottom = gdi.getCY() + gdi.scaleLength(5);
gdi.dropLine();
gdi.addRectangle(rc, colorLightBlue);
gdi.scrollToBottom();
@@ -3497,7 +3772,7 @@ pRunner TabSI::getRunnerByIdentifier(int identifier) const {
vector runners;
oe->autoSynchronizeLists(false);
oe->getRunners(0, 0, runners, false);
- for ( size_t k = 0; k< runners.size(); k++) {
+ for (size_t k = 0; k < runners.size(); k++) {
if (runners[k]->getRaceNo() == 0) {
int i = runners[k]->getRaceIdentifier();
identifierToRunnerId.insert(i, runners[k]->getId());
@@ -3509,22 +3784,23 @@ pRunner TabSI::getRunnerByIdentifier(int identifier) const {
return ret;
}
-bool TabSI::askOverwriteCard(gdioutput &gdi, pRunner r) const {
+bool TabSI::askOverwriteCard(gdioutput& gdi, pRunner r) const {
return gdi.ask(L"ask:overwriteresult#" + r->getCompleteIdentification());
}
-void TabSI::showModeCardData(gdioutput &gdi) {
- gdi.disableInput("Interactive", true);
- gdi.enableInput("Database", true);
- gdi.enableInput("PrintSplits");
- gdi.disableInput("StartInfo", true);
- gdi.disableInput("UseManualInput", true);
+void TabSI::showModeCardData(gdioutput& gdi) {
+ // gdi.disableInput("Interactive", true);
+ // gdi.enableInput("Database", true);
+ // gdi.enableInput("PrintSplits");
+ // gdi.disableInput("StartInfo", true);
+ // gdi.disableInput("UseManualInput", true);
+ checkBoxToolBar(gdi, { CheckBox::UseDB, CheckBox::PrintSplits });
gdi.dropLine(0.5);
- gdi.fillDown();
+ //gdi.fillDown();
gdi.pushX();
- gdi.addStringUT(boldLarge, lang.tl(L"Print card data", true));
- gdi.dropLine(0.2);
+ //gdi.addStringUT(boldLarge, lang.tl(L"Print card data", true));
+ //gdi.dropLine(0.2);
gdi.fillRight();
gdi.addButton("ClearMemory", "Clear Memory", SportIdentCB);
gdi.addButton("SaveMemory", "Spara...", SportIdentCB);
@@ -3543,14 +3819,14 @@ void TabSI::showModeCardData(gdioutput &gdi) {
gdi.dropLine();
gdi.popX();
gdi.addString("", 10, "help:analyzecard");
-
+
gdi.dropLine(3);
gdi.popX();
bool first = true;
for (auto it = savedCards.begin(); it != savedCards.end(); ++it) {
gdi.dropLine(0.5);
if (!first) {
- RECT rc = {30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3};
+ RECT rc = { 30, gdi.getCY(), gdi.scaleLength(250), gdi.getCY() + 3 };
gdi.addRectangle(rc);
}
first = false;
@@ -3559,11 +3835,11 @@ void TabSI::showModeCardData(gdioutput &gdi) {
}
}
-void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+void TabSI::EditCardData::handle(gdioutput& gdi, BaseInfo& info, GuiEventType type) {
if (type == GUI_LINK) {
- TextInfo &ti = dynamic_cast(info);
+ TextInfo& ti = dynamic_cast(info);
int cardId = ti.getExtraInt();
- SICard &card = tabSI->getCard(cardId);
+ SICard& card = tabSI->getCard(cardId);
ti.id = "card" + itos(cardId);
gdi.removeWidget("CardName");
gdi.removeWidget("ClubName");
@@ -3581,24 +3857,24 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
if (noClub)
club = lang.tl("Klubb");
- InputInfo &ii = gdi.addInput(ti.xp-2, ti.yp-2, "CardName", name, 18, 0);
+ InputInfo& ii = gdi.addInput(ti.xp - 2, ti.yp - 2, "CardName", name, 18, 0);
ii.setHandler(this);
- InputInfo &ii2 = gdi.addInput(ti.xp + ii.getWidth(), ti.yp-2, "ClubName", club, 22, 0);
+ InputInfo& ii2 = gdi.addInput(ti.xp + ii.getWidth(), ti.yp - 2, "ClubName", club, 22, 0);
ii2.setExtra(noClub).setHandler(this);
- ButtonInfo &bi = gdi.addButton(ii2.getX() + 2 + ii2.getWidth(), ti.yp-4, "OKCard", "OK", 0);
+ ButtonInfo& bi = gdi.addButton(ii2.getX() + 2 + ii2.getWidth(), ti.yp - 4, "OKCard", "OK", 0);
bi.setExtra(cardId).setHandler(this);
bi.setDefault();
int w, h;
bi.getDimension(gdi, w, h);
- gdi.addButton(bi.xp + w + 4, ti.yp-4, "CancelCard", "Avbryt", 0).setCancel().setHandler(this);
+ gdi.addButton(bi.xp + w + 4, ti.yp - 4, "CancelCard", "Avbryt", 0).setCancel().setHandler(this);
gdi.setInputFocus(ii.id, noName);
}
else if (type == GUI_BUTTON) {
- ButtonInfo bi = dynamic_cast(info);
+ ButtonInfo bi = dynamic_cast(info);
//OKCard or CancelCard
if (bi.id == "OKCard") {
int cardId = bi.getExtraInt();
- SICard &card = tabSI->getCard(cardId);
+ SICard& card = tabSI->getCard(cardId);
wstring name = gdi.getText("CardName");
wstring club = gdi.getBaseInfo("ClubName").getExtra() ? L"" : gdi.getText("ClubName");
wstring given = getGivenName(name);
@@ -3606,7 +3882,7 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
wcsncpy_s(card.firstName, given.c_str(), 20);
wcsncpy_s(card.lastName, familty.c_str(), 20);
wcsncpy_s(card.club, club.c_str(), 40);
-
+
wstring s = name;
if (!club.empty())
s += L", " + club;
@@ -3619,7 +3895,7 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
gdi.removeWidget("CancelCard");
}
else if (type == GUI_FOCUS) {
- InputInfo &ii = dynamic_cast(info);
+ InputInfo& ii = dynamic_cast(info);
if (ii.getExtraInt()) {
ii.setExtra(0);
gdi.setInputFocus(ii.id, true);
@@ -3627,11 +3903,11 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
}
}
-void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef, bool forPrinter) const {
+void TabSI::printCard(gdioutput& gdi, int lineBreak, int cardId, SICard* crdRef, bool forPrinter) const {
if (crdRef == nullptr)
crdRef = &getCard(cardId);
-
- SICard &c = *crdRef;
+
+ SICard& c = *crdRef;
if (c.readOutTime[0] == 0)
strcpy_s(c.readOutTime, getLocalTimeN().c_str());
@@ -3643,10 +3919,10 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
clubName = c.club;
}
else if (useDatabase) {
- const RunnerWDBEntry *r = oe->getRunnerDatabase().getRunnerByCard(c.CardNumber);
+ const RunnerWDBEntry* r = oe->getRunnerDatabase().getRunnerByCard(c.CardNumber);
if (r) {
r->getName(name);
- const oClub *club = oe->getRunnerDatabase().getClub(r->dbe().clubNo);
+ const oClub* club = oe->getRunnerDatabase().getClub(r->dbe().clubNo);
if (club) {
clubName = club->getName();
wcsncpy_s(c.club, clubName.c_str(), 20);
@@ -3665,11 +3941,11 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
if (!name.empty()) {
if (!clubName.empty())
- name += L", " + clubName;
+ name += L", " + clubName;
gdi.fillDown();
- auto &res = gdi.addStringUT(0, name);
+ auto& res = gdi.addStringUT(0, name);
if (cardId >= 0)
- res.setExtra(cardId).setHandler(&editCardData);
+ res.setExtra(cardId).setHandler(&editCardData);
gdi.popX();
}
gdi.fillDown();
@@ -3710,7 +3986,7 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
int xp4 = xp3 + gdi.scaleLength(60);
int xp5 = xp4 + gdi.scaleLength(45);
const int off = xp5 - xp + gdi.scaleLength(80);
-
+
int baseCY = gdi.getCY();
int maxCY = baseCY;
int baseCX = gdi.getCX();
@@ -3724,21 +4000,21 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
for (unsigned k = 0; k < c.nPunch; k++) {
int cy = gdi.getCY();
- gdi.addStringUT(cy, xp, 0, itos(k+1) + ".");
+ gdi.addStringUT(cy, xp, 0, itos(k + 1) + ".");
gdi.addStringUT(cy, xp2, 0, itos(c.Punch[k].Code));
- gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.Punch[k].Time % (24*3600)));
+ gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.Punch[k].Time % (24 * timeConstHour)));
if (start != NOTIME) {
int legTime = analyzePunch(c.Punch[k], start, accTime, days);
if (legTime > 0)
- gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime));
+ gdi.addStringUT(cy, xp5 - gdi.scaleLength(10), textRight, formatTime(legTime));
- gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime));
+ gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days * timeConstHour * 24 + accTime));
}
else {
start = c.Punch[k].Time;
}
- if (lineBreak > 0 && (k%lineBreak) == lineBreak-1) {
+ if (lineBreak > 0 && (k % lineBreak) == lineBreak - 1) {
maxCY = max(maxCY, gdi.getCY());
RECT rcc;
rcc.top = baseCY;
@@ -3758,14 +4034,14 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
if (c.FinishPunch.Code != -1) {
int cy = gdi.getCY();
gdi.addString("", cy, xp, 0, "MÃ¥l");
- gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.FinishPunch.Time % (24*3600)));
+ gdi.addStringUT(cy, xp3, 0, formatTimeHMS(c.FinishPunch.Time % (24 * timeConstHour)));
if (start != NOTIME) {
int legTime = analyzePunch(c.FinishPunch, start, accTime, days);
if (legTime > 0)
- gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime));
+ gdi.addStringUT(cy, xp5 - gdi.scaleLength(10), textRight, formatTime(legTime));
- gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime));
+ gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days * timeConstHour * 24 + accTime));
}
maxCY = max(maxCY, gdi.getCY());
@@ -3775,7 +4051,7 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
gdi.setCX(baseCX);
}
- gdi.addString("", 1, L"Time: X#" + formatTime(days*3600*24 + accTime));
+ gdi.addString("", 1, L"Time: X#" + formatTime(days * timeConstHour * 24 + accTime));
}
maxCY = max(maxCY, gdi.getCY());
@@ -3789,27 +4065,27 @@ void TabSI::printCard(gdioutput &gdi, int lineBreak, int cardId, SICard *crdRef,
if (forPrinter) {
gdi.dropLine(1);
- vector< pair > lines;
+ vector> lines;
oe->getExtraLines("SPExtra", lines);
for (size_t k = 0; k < lines.size(); k++) {
gdi.addStringUT(lines[k].second, lines[k].first);
}
- if (lines.size()>0)
+ if (lines.size() > 0)
gdi.dropLine(0.5);
gdi.addString("", fontSmall, "Av MeOS: www.melin.nu/meos");
}
}
-int TabSI::analyzePunch(SIPunch &p, int &start, int &accTime, int &days) {
+int TabSI::analyzePunch(SIPunch& p, int& start, int& accTime, int& days) {
int newAccTime = p.Time - start;
if (newAccTime < 0) {
- newAccTime += 3600 * 24;
- if (accTime > 12 * 3600)
+ newAccTime += timeConstHour * 24;
+ if (accTime > 12 * timeConstHour)
days++;
}
- else if (newAccTime < accTime - 12 * 3600) {
+ else if (newAccTime < accTime - 12 * timeConstHour) {
days++;
}
int legTime = newAccTime - accTime;
@@ -3817,17 +4093,17 @@ int TabSI::analyzePunch(SIPunch &p, int &start, int &accTime, int &days) {
return legTime;
}
-void TabSI::generateSplits(int cardId, gdioutput &gdi) {
+void TabSI::generateSplits(int cardId, gdioutput& gdi) {
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
printCard(gdiprint, 0, cardId, nullptr, true);
printProtected(gdi, gdiprint);
}
-void TabSI::printProtected(gdioutput &gdi, gdioutput &gdiprint) {
+void TabSI::printProtected(gdioutput& gdi, gdioutput& gdiprint) {
try {
gdiprint.print(splitPrinter, oe, false, true);
}
- catch (meosException &ex) {
+ catch (meosException& ex) {
DWORD loaded;
if (gdi.getData("SIPageLoaded", loaded)) {
gdi.dropLine();
@@ -3846,23 +4122,24 @@ void TabSI::printProtected(gdioutput &gdi, gdioutput &gdiprint) {
}
}
-void TabSI::createCompetitionFromCards(gdioutput &gdi) {
+void TabSI::createCompetitionFromCards(gdioutput& gdi) {
oe->newCompetition(lang.tl(L"Ny tävling"));
+ oe->loadDefaults();
gdi.setWindowTitle(L"");
map hashCount;
- vector< pair > cards;
- int zeroTime = 3600 * 24;
+ vector< pair > cards;
+ int zeroTime = timeConstHour * 24;
for (list >::iterator it = savedCards.begin(); it != savedCards.end(); ++it) {
size_t hash = 0;
if (it->second.StartPunch.Code != -1 && it->second.StartPunch.Time > 0)
zeroTime = min(zeroTime, it->second.StartPunch.Time);
for (unsigned k = 0; k < it->second.nPunch; k++) {
- hash = 997 * hash + (it->second.Punch[k].Code-30);
+ hash = 997 * hash + (it->second.Punch[k].Code - 30);
if (it->second.Punch[k].Code != -1 && it->second.Punch[k].Time > 0)
zeroTime = min(zeroTime, it->second.Punch[k].Time);
}
- pair p(hash, &it->second);
+ pair p(hash, &it->second);
++hashCount[hash];
cards.push_back(p);
}
@@ -3872,7 +4149,7 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) {
if (!hashCount.count(cards[k].first))
continue;
int count = hashCount[cards[k].first];
- if (count < 5 && count < int(cards.size()) /2)
+ if (count < 5 && count < int(cards.size()) / 2)
continue;
pCourse pc = oe->addCourse(lang.tl("Bana ") + itow(++course));
@@ -3905,10 +4182,10 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) {
}
// Define a new zero time
- zeroTime -= 3600;
+ zeroTime -= timeConstHour;
if (zeroTime < 0)
- zeroTime += 3600 * 24;
- zeroTime -= zeroTime % 1800;
+ zeroTime += timeConstHour * 24;
+ zeroTime -= zeroTime % (timeConstHour / 2);
oe->setZeroTime(formatTime(zeroTime), false);
// Add competitors
@@ -3930,20 +4207,20 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) {
name = lang.tl(L"Bricka X#" + itow(cards[k].second->CardNumber));
oe->addRunner(name, wstring(cards[k].second->club), cls[0]->getId(),
- cards[k].second->CardNumber, 0, true);
+ cards[k].second->CardNumber, L"", true);
processInsertCard(*cards[k].second);
}
}
- TabList &tc = dynamic_cast(*gdi.getTabs().get(TListTab));
+ TabList& tc = dynamic_cast(*gdi.getTabs().get(TListTab));
tc.loadPage(gdi, "ResultIndividual");
}
void TabSI::StoredStartInfo::checkAge() {
DWORD t = GetTickCount();
const int minuteLimit = 3;
- if (t > age && (t - age) > (1000*60*minuteLimit)) {
+ if (t > age && (t - age) > (1000 * 60 * minuteLimit)) {
clear();
}
age = t;
@@ -3969,7 +4246,7 @@ void TabSI::clearCompetitionData() {
interactiveReadout = oe->getPropertyInt("Interactive", 1) != 0;
useDatabase = oe->getPropertyInt("Database", 1) != 0;
printSplits = false;
- printStartInfo = false;
+ printStartInfo = false;
manualInput = oe->getPropertyInt("ManualInput", 0) == 1;
savedCardUniqueId = 1;
@@ -3978,34 +4255,33 @@ void TabSI::clearCompetitionData() {
warnedClassOutOfMaps.clear();
lockedFunction = false;
- allowControl = true;
- allowFinish = true;
- allowStart = false;
- if (mode == ModeCardData)
+ if (mode == SIMode::ModeCardData)
mode = SIMode::ModeReadOut;
+ readCards.clear();
+
logger.reset();
numSavedCardsOnCmpOpen = savedCards.size();
}
-SICard &TabSI::getCard(int id) const {
+SICard& TabSI::getCard(int id) const {
if (id < int(savedCards.size() / 2)) {
- for (list< pair >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it){
- if (it->first==id)
- return const_cast(it->second);
+ for (list< pair >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) {
+ if (it->first == id)
+ return const_cast(it->second);
}
}
else {
- for (list< pair >::const_reverse_iterator it = savedCards.rbegin(); it != savedCards.rend(); ++it){
- if (it->first==id)
- return const_cast(it->second);
+ for (list< pair >::const_reverse_iterator it = savedCards.rbegin(); it != savedCards.rend(); ++it) {
+ if (it->first == id)
+ return const_cast(it->second);
}
}
throw meosException("Interal error");
}
-bool compareCardNo(const pRunner &r1, const pRunner &r2) {
+bool compareCardNo(const pRunner& r1, const pRunner& r2) {
int c1 = r1->getCardNo();
int c2 = r2->getCardNo();
if (c1 != c2)
@@ -4018,34 +4294,36 @@ bool compareCardNo(const pRunner &r1, const pRunner &r2) {
return false;
}
-wstring TabSI::getCardInfo(bool param, vector &count) const {
+wstring TabSI::getCardInfo(bool param, vector& count) const {
if (!param) {
assert(count.size() == 8);
- return L"Totalt antal unika avbockade brickor: X#" + itow(count[CNFCheckedAndUsed] +
- count[CNFChecked] +
- count[CNFCheckedNotRented] +
- count[CNFCheckedRentAndNotRent]);
+ return L"Totalt antal unika avbockade brickor: X#" + itow(count[CNFCheckedAndUsed] +
+ count[CNFChecked] +
+ count[CNFCheckedNotRented] +
+ count[CNFCheckedRentAndNotRent]);
}
count.clear();
count.resize(8);
- for (map::const_iterator it = checkedCardFlags.begin();
+ for (map::const_iterator it = checkedCardFlags.begin();
it != checkedCardFlags.end(); ++it) {
- ++count[it->second];
+ ++count[it->second];
}
- wstring msg = L"Uthyrda: X, Egna: Y, Avbockade uthyrda: Z#" + itow(count[CNFUsed] + count[CNFCheckedAndUsed]) +
- L"#" + itow(count[CNFNotRented] + count[CNFCheckedNotRented]) +
- L"#" + itow(count[CNFCheckedAndUsed]);
+ wstring msg = L"Uthyrda: X, Egna: Y, Avbockade uthyrda: Z#" + itow(count[CNFUsed] + count[CNFCheckedAndUsed]) +
+ L"#" + itow(count[CNFNotRented] + count[CNFCheckedNotRented]) +
+ L"#" + itow(count[CNFCheckedAndUsed]);
return msg;
}
-void TabSI::showRegisterHiredCards(gdioutput &gdi) {
- gdi.disableInput("Interactive");
+void TabSI::showRegisterHiredCards(gdioutput& gdi) {
+ checkBoxToolBar(gdi, { });
+
+ /*gdi.disableInput("Interactive");
gdi.disableInput("Database", true);
gdi.disableInput("PrintSplits");
gdi.disableInput("UseManualInput");
-
+ */
gdi.fillDown();
gdi.addString("", 10, "help:registerhiredcards");
@@ -4069,27 +4347,24 @@ void TabSI::showRegisterHiredCards(gdioutput &gdi) {
gdi.refresh();
}
-void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
+void TabSI::showCheckCardStatus(gdioutput& gdi, const string& cmd) {
vector r;
const int cx = gdi.getCX();
const int col1 = gdi.scaleLength(50);
const int col2 = gdi.scaleLength(200);
-
+
if (cmd == "init") {
- gdi.disableInput("Interactive");
- gdi.disableInput("Database");
- gdi.disableInput("PrintSplits");
- gdi.disableInput("UseManualInput");
-
- gdi.fillDown();
+ checkBoxToolBar(gdi, { });
+
+ gdi.fillDown();
gdi.addString("", 10, "help:checkcards");
gdi.dropLine();
gdi.fillRight();
gdi.pushX();
gdi.addButton("CCSReport", "Rapport", SportIdentCB);
- gdi.addButton("CCSClear", "Nollställ", SportIdentCB,
- "Nollställ minnet; markera alla brickor som icke avbockade");
+ gdi.addButton("CCSClear", "Nollställ", SportIdentCB,
+ "Nollställ minnet; markera alla brickor som icke avbockade");
gdi.addButton("CCSPrint", "Skriv ut...", SportIdentCB);
gdi.popX();
@@ -4129,10 +4404,10 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
for (size_t k = 0; k < r.size(); k++) {
int cno = r[k]->getCardNo();
if (cno == 0 || r[k]->getRaceNo() > 0)
- continue;
+ continue;
if (checkedCardFlags[cno] == CNFCheckedRentAndNotRent ||
- checkedCardFlags[cno] == CNFRentAndNotRent) {
+ checkedCardFlags[cno] == CNFRentAndNotRent) {
int yp = gdi.getCY();
wstring cp = r[k]->getCompleteIdentification();
bool hire = r[k]->isHiredCard();
@@ -4163,7 +4438,7 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
gdi.fillDown();
gdi.dropLine(0.5);
showHead = true;
- }
+ }
int yp = gdi.getCY();
gdi.addStringUT(yp, cx, 0, itos(++count));
gdi.addStringUT(yp, cx + col1, 0, itos(cno));
@@ -4176,9 +4451,9 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
int s = r[k]->getStartTime();
int f = r[k]->getFinishTime();
- if (s> 0 || f>0) {
- cp += L", " + (s>0 ? r[k]->getStartTimeS() : wstring(L"?")) + makeDash(L" - ")
- + (f>0 ? r[k]->getFinishTimeS() : wstring(L"?"));
+ if (s > 0 || f > 0) {
+ cp += L", " + (s > 0 ? r[k]->getStartTimeS() : wstring(L"?")) + makeDash(L" - ")
+ + (f > 0 ? r[k]->getFinishTimeS(false, SubSecond::Auto) : wstring(L"?"));
}
gdi.addStringUT(yp, cx + col2, 0, cp);
}
@@ -4192,8 +4467,8 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
}
else if (cmd == "tickoff") {
SICard sic(ConvertedTimeStatus::Hour24);
- for (map::const_iterator it = checkedCardFlags.begin();
- it != checkedCardFlags.end(); ++it) {
+ for (map::const_iterator it = checkedCardFlags.begin();
+ it != checkedCardFlags.end(); ++it) {
int stat = it->second;
if (stat & CNFChecked) {
sic.CardNumber = it->first;
@@ -4209,12 +4484,12 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
class ResetHiredCard : public GuiHandler {
- oEvent *oe;
-
+ oEvent* oe;
+
public:
- void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+ void handle(gdioutput& gdi, BaseInfo& info, GuiEventType type) {
if (type == GuiEventType::GUI_LINK) {
- TextInfo &ti = dynamic_cast(info);
+ TextInfo& ti = dynamic_cast(info);
int c = _wtoi(ti.text.c_str());
if (gdi.ask(L"Vill du ta bort brickan från hyrbrickslistan?")) {
oe->setHiredCard(c, false);
@@ -4225,17 +4500,17 @@ public:
}
}
- ResetHiredCard(oEvent *oe) : oe(oe) {}
+ ResetHiredCard(oEvent* oe) : oe(oe) {}
};
-GuiHandler *TabSI::getResetHiredCardHandler() {
+GuiHandler* TabSI::getResetHiredCardHandler() {
if (!resetHiredCardHandler)
resetHiredCardHandler = make_shared(oe);
-
- return resetHiredCardHandler.get();
+
+ return resetHiredCardHandler.get();
}
-void TabSI::registerHiredCard(gdioutput &gdi, const SICard &sic) {
+void TabSI::registerHiredCard(gdioutput& gdi, const SICard& sic) {
if (!oe->isHiredCard(sic.CardNumber))
oe->setHiredCard(sic.CardNumber, true);
gdi.addStringUT(0, itos(sic.CardNumber)).setHandler(getResetHiredCardHandler());
@@ -4243,7 +4518,7 @@ void TabSI::registerHiredCard(gdioutput &gdi, const SICard &sic) {
gdi.refresh();
}
-void TabSI::checkCard(gdioutput &gdi, const SICard &card, bool updateAll) {
+void TabSI::checkCard(gdioutput& gdi, const SICard& card, bool updateAll) {
bool wasChecked = (checkedCardFlags[card.CardNumber] & CNFChecked) != 0 && updateAll;
checkedCardFlags[card.CardNumber] = CardNumberFlags(checkedCardFlags[card.CardNumber] | CNFChecked);
@@ -4263,7 +4538,7 @@ void TabSI::checkCard(gdioutput &gdi, const SICard &card, bool updateAll) {
gdi.setTextTranslate("CardInfo", getCardInfo(true, count));
gdi.setTextTranslate("CardTicks", getCardInfo(false, count));
}
- TextInfo &ti = gdi.addStringUT(cardPosY, cardPosX + cardCurrentCol * cardOffsetX, 0, itos(card.CardNumber));
+ TextInfo& ti = gdi.addStringUT(cardPosY, cardPosX + cardCurrentCol * cardOffsetX, 0, itos(card.CardNumber));
if (wasChecked)
ti.setColor(colorRed);
if (++cardCurrentCol >= cardNumCol) {
@@ -4277,7 +4552,7 @@ void TabSI::checkCard(gdioutput &gdi, const SICard &card, bool updateAll) {
}
}
-void TabSI::generatePayModeWidget(gdioutput &gdi) const {
+void TabSI::generatePayModeWidget(gdioutput& gdi) const {
vector< pair > pm;
oe->getPayModes(pm);
assert(pm.size() > 0);
@@ -4294,10 +4569,10 @@ void TabSI::generatePayModeWidget(gdioutput &gdi) const {
}
}
-bool TabSI::writePayMode(gdioutput &gdi, int amount, oRunner &r) {
+bool TabSI::writePayMode(gdioutput& gdi, int amount, oRunner& r) {
int paid = 0;
bool hasPaid = false;
-
+
if (gdi.hasWidget("PayMode"))
hasPaid = gdi.getSelectedItem("PayMode").first != 1000;
@@ -4318,13 +4593,13 @@ void TabSI::addToPrintQueue(pRunner r) {
printPunchRunnerIdQueue.push_back(make_pair(t, r->getId()));
}
-bool TabSI::checkpPrintQueue(gdioutput &gdi) {
+bool TabSI::checkpPrintQueue(gdioutput& gdi) {
if (printPunchRunnerIdQueue.empty())
return false;
size_t printLen = oe->getPropertyInt("NumSplitsOnePage", 3);
if (printPunchRunnerIdQueue.size() < printLen) {
unsigned t = GetTickCount();
- unsigned diff = abs(int(t - printPunchRunnerIdQueue.front().first))/1000;
+ unsigned diff = abs(int(t - printPunchRunnerIdQueue.front().first)) / 1000;
if (diff < (unsigned)oe->getPropertyInt("SplitPrintMaxWait", 60))
return false; // Wait a little longer
@@ -4342,27 +4617,31 @@ bool TabSI::checkpPrintQueue(gdioutput &gdi) {
}
gdiprint.dropLine(4);
}
-
+
printProtected(gdi, gdiprint);
//gdiprint.print(splitPrinter, oe, false, true);
return true;
}
-void TabSI::printSIInfo(gdioutput &gdi, const wstring &port) const {
- vector info;
+void TabSI::printSIInfo(gdioutput& gdi, const wstring& port) const {
+ vector> info;
gdi.fillDown();
gSI->getInfoString(port, info);
- for (size_t j = 0; j < info.size(); j++)
- gdi.addStringUT(0, info[j]);
+ for (size_t j = 0; j < info.size(); j++) {
+ if (info[j].first)
+ gdi.addStringUT(1, info[j].second).setColor(colorDarkRed);
+ else
+ gdi.addStringUT(0, info[j].second);
+ }
}
-oClub *TabSI::extractClub(gdioutput &gdi) const {
- auto &db = oe->getRunnerDatabase();
- oClub *dbClub = nullptr;
+oClub* TabSI::extractClub(gdioutput& gdi) const {
+ auto& db = oe->getRunnerDatabase();
+ oClub* dbClub = nullptr;
if (gdi.hasWidget("Club")) {
int clubId = gdi.getExtraInt("Club");
if (clubId > 0) {
- dbClub = db.getClub(clubId-1);
+ dbClub = db.getClub(clubId - 1);
if (dbClub && !stringMatch(dbClub->getName(), gdi.getText("Club")))
dbClub = nullptr;
}
@@ -4373,14 +4652,14 @@ oClub *TabSI::extractClub(gdioutput &gdi) const {
return dbClub;
}
-RunnerWDBEntry *TabSI::extractRunner(gdioutput &gdi) const {
- auto &db = oe->getRunnerDatabase();
+RunnerWDBEntry* TabSI::extractRunner(gdioutput& gdi) const {
+ auto& db = oe->getRunnerDatabase();
int rId = gdi.getExtraInt("Name");
wstring name = gdi.getText("Name");
- RunnerWDBEntry *dbR = nullptr;
+ RunnerWDBEntry* dbR = nullptr;
if (rId > 0) {
- dbR = db.getRunnerByIndex(rId-1);
+ dbR = db.getRunnerByIndex(rId - 1);
if (dbR) {
wstring fname = dbR->getFamilyName();
wstring gname = dbR->getGivenName();
@@ -4390,13 +4669,13 @@ RunnerWDBEntry *TabSI::extractRunner(gdioutput &gdi) const {
}
}
if (dbR == nullptr) {
- oClub * dbClub = extractClub(gdi);
+ oClub* dbClub = extractClub(gdi);
dbR = db.getRunnerByName(name, dbClub ? dbClub->getId() : 0, 0);
}
return dbR;
}
-void TabSI::DirectEntryGUI::updateFees(gdioutput &gdi, const pClass cls, int age) {
+void TabSI::DirectEntryGUI::updateFees(gdioutput& gdi, const pClass cls, int age) {
int fee = cls->getEntryFee(getLocalDate(), age);
auto fees = cls->getAllFees();
gdi.addItem("Fee", fees);
@@ -4410,16 +4689,16 @@ void TabSI::DirectEntryGUI::updateFees(gdioutput &gdi, const pClass cls, int age
tabSI->updateEntryInfo(gdi);
}
-void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+void TabSI::DirectEntryGUI::handle(gdioutput& gdi, BaseInfo& info, GuiEventType type) {
if (type == GUI_FOCUS) {
- InputInfo &ii = dynamic_cast(info);
+ InputInfo& ii = dynamic_cast(info);
/*if (ii.getExtraInt()) {
ii.setExtra(0);
gdi.setInputFocus(ii.id, true);
}*/
}
else if (type == GUI_LISTBOX) {
- ListBoxInfo &lbi = dynamic_cast(info);
+ ListBoxInfo& lbi = dynamic_cast(info);
if (lbi.id == "Class") {
int clsId = lbi.data;
pClass cls = tabSI->oe->getClass(clsId);
@@ -4436,16 +4715,16 @@ void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType
}
}
else if (type == GUI_COMBOCHANGE) {
- ListBoxInfo &combo = dynamic_cast(info);
+ ListBoxInfo& combo = dynamic_cast(info);
bool show = false;
if (tabSI->useDatabase && combo.id == "Club" && combo.text.length() > 1) {
auto clubs = tabSI->oe->getRunnerDatabase().getClubSuggestions(combo.text, 20);
if (!clubs.empty()) {
- auto &ac = gdi.addAutoComplete(combo.id);
+ auto& ac = gdi.addAutoComplete(combo.id);
ac.setAutoCompleteHandler(this->tabSI);
vector items;
for (auto club : clubs)
- items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
+ items.emplace_back(club->getDisplayName(), -int(items.size()), club->getName(), club->getId());
ac.setData(items);
ac.show();
@@ -4457,17 +4736,17 @@ void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType
}
}
else if (type == GUI_INPUTCHANGE) {
- InputInfo &ii = dynamic_cast(info);
+ InputInfo& ii = dynamic_cast(info);
bool show = false;
if (tabSI->showDatabase() && ii.id == "Name") {
- auto &db = tabSI->oe->getRunnerDatabase();
+ auto& db = tabSI->oe->getRunnerDatabase();
if (ii.text.length() > 1) {
auto dbClub = tabSI->extractClub(gdi);
auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
if (!rw.empty()) {
- auto &ac = gdi.addAutoComplete(ii.id);
+ auto& ac = gdi.addAutoComplete(ii.id);
ac.setAutoCompleteHandler(this->tabSI);
-
+
ac.setData(getRunnerAutoCompelete(db, rw, dbClub));
ac.show();
show = true;
@@ -4480,7 +4759,7 @@ void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType
}
}
-vector TabSI::getRunnerAutoCompelete(RunnerDB &db, const vector< pair> &rw, pClub dbClub) {
+vector TabSI::getRunnerAutoCompelete(RunnerDB& db, const vector< pair