MeOS version 3.6.1086

This commit is contained in:
Erik Melin 2019-06-18 22:30:29 +02:00
parent 55d526c3e4
commit a4e2689418
43 changed files with 1142 additions and 492 deletions

View File

@ -135,9 +135,9 @@ void SportIdent::setCRC(BYTE *bf)
bf[len+3]=LOBYTE(crc); bf[len+3]=LOBYTE(crc);
} }
bool SportIdent::checkCRC(BYTE *bf) bool SportIdent::checkCRC(BYTE *bf, DWORD maxLen)
{ {
DWORD len=bf[1]; DWORD len=min(DWORD(bf[1]), maxLen);
WORD crc=calcCRC(bf, len+2); WORD crc=calcCRC(bf, len+2);
return bf[len+2]==HIBYTE(crc) && bf[len+3]==LOBYTE(crc); return bf[len+2]==HIBYTE(crc) && bf[len+3]==LOBYTE(crc);
@ -167,7 +167,7 @@ bool SportIdent::readSystemData(SI_StationInfo *si, int retry)
if (buff[0] == 0xFF && buff[1] == STX) if (buff[0] == 0xFF && buff[1] == STX)
offset++; offset++;
if (1){ if (1){
if (checkCRC(LPBYTE(buff+1 + offset))){ if (checkCRC(LPBYTE(buff+1 + offset), 100)){
si->data.resize(1); si->data.resize(1);
SI_StationData &da = si->data[0]; SI_StationData &da = si->data[0];
da.stationNumber=511 & MAKEWORD(buff[4 + offset], buff[3 + offset]); da.stationNumber=511 & MAKEWORD(buff[4 + offset], buff[3 + offset]);
@ -245,7 +245,7 @@ bool SportIdent::readSystemDataV2(SI_StationInfo &si)
int SportIdent::analyzeStation(BYTE *db, SI_StationData &si) { int SportIdent::analyzeStation(BYTE *db, SI_StationData &si) {
DWORD size = 0; DWORD size = 0;
DWORD addr = 0x70; DWORD addr = 0x70;
if (checkCRC(LPBYTE(db+1))) { if (checkCRC(LPBYTE(db+1), 256)) {
size = DWORD(db[2]) + 6; size = DWORD(db[2]) + 6;
bool dongle = db[0x11] == 0x6f && db[0x12] == 0x21; bool dongle = db[0x11] == 0x6f && db[0x12] == 0x21;
@ -385,6 +385,10 @@ bool SportIdent::openCom(const wchar_t *com)
si->data.clear(); si->data.clear();
if (si->ComPort == L"TEST") {
return true;
}
wstring comfile=wstring(L"//./")+com; wstring comfile=wstring(L"//./")+com;
si->hComm = CreateFile( comfile.c_str(), si->hComm = CreateFile( comfile.c_str(),
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
@ -510,6 +514,13 @@ bool SportIdent::openCom(const wchar_t *com)
SI_StationInfo *SportIdent::findStation(const wstring &com) SI_StationInfo *SportIdent::findStation(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;
n_SI_Info++;
}
}
for(int i=0;i<n_SI_Info; i++) for(int i=0;i<n_SI_Info; i++)
if (com == SI_Info[i].ComPort) if (com == SI_Info[i].ComPort)
return &SI_Info[i]; return &SI_Info[i];
@ -583,7 +594,7 @@ int SportIdent::readByte(BYTE &byte, HANDLE hComm)
#ifdef DEBUG_SI2 #ifdef DEBUG_SI2
char t[64]; char t[64];
sprintf_s(t, 64, "read=%02X\n", (int)byte); sprintf_s(t, 64, "read=%02X\n", (int)byte);
OutputDebugString(t); debugLog(t);
#endif #endif
if (dwRead) if (dwRead)
return 1; return 1;
@ -636,12 +647,12 @@ int SportIdent::readBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE h
#ifdef DEBUG_SI2 #ifdef DEBUG_SI2
char t[64]; char t[64];
sprintf_s(t, 64, "retry=%d\n", d); sprintf_s(t, 64, "retry=%d\n", d);
OutputDebugString(t); debugLog(t);
for (int k = 0; k < read; k++) { for (int k = 0; k < read; k++) {
char t[64]; char t[64];
sprintf_s(t, 64, "mreadd=%02X\n", (int)byte[k]); sprintf_s(t, 64, "mreadd=%02X\n", (int)byte[k]);
OutputDebugString(t); debugLog(t);
} }
#endif #endif
@ -661,7 +672,7 @@ int SportIdent::readBytes(BYTE *byte, DWORD len, HANDLE hComm)
for (int k = 0; k < dwRead; k++) { for (int k = 0; k < dwRead; k++) {
char t[64]; char t[64];
sprintf_s(t, 64, "mread=%02X\n", (int)byte[k]); sprintf_s(t, 64, "mread=%02X\n", (int)byte[k]);
OutputDebugString(t); debugLog(t);
} }
#endif #endif
return dwRead; return dwRead;
@ -693,7 +704,7 @@ int SportIdent::readBytesDLE_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDL
#ifdef DEBUG_SI2 #ifdef DEBUG_SI2
char t[64]; char t[64];
sprintf_s(t, 64, "retry=%d\n", d); sprintf_s(t, 64, "retry=%d\n", d);
OutputDebugString(t); debugLog(t);
#endif #endif
return read; return read;
@ -909,6 +920,45 @@ int SportIdent::MonitorTCPSI(WORD port, int localZeroTime)
return 1; return 1;
} }
bool SportIdent::MonitorTEST(SI_StationInfo &si)
{
int longSleepIter = 0;
while (true) {
if (testCards.empty())
return true;
TestCard tc = *testCards.begin();
testCards.erase(testCards.begin());
SICard card(ConvertedTimeStatus::Hour12);
card.StartPunch.Code = 1;
int t = card.StartPunch.Time = 3600*8 + rand()%1000;
card.FinishPunch.Code = 2;
card.FinishPunch.Time = card.StartPunch.Time + 1800 + rand() % 3600;
card.CardNumber = tc.cardNo;
for (size_t k = 0; k < tc.punches.size(); k++) {
card.Punch[k].Code = tc.punches[k];
int w = max<int>(1, tc.punches.size() - k - rand()%3);
t = card.Punch[k].Time = (card.FinishPunch.Time + t*w)/(w+1);
card.nPunch++;
}
addCard(card);
//Sleep(300 + rand()%600);
Sleep(0);
if (++longSleepIter > 20) {
Sleep(100 + rand() % 600);
longSleepIter = 0;
OutputDebugString(L"Long sleep\n");
}
}
OutputDebugString(L"--- Test Finished \n");
}
bool SportIdent::MonitorSI(SI_StationInfo &si) bool SportIdent::MonitorSI(SI_StationInfo &si)
{ {
HANDLE hComm=si.hComm; HANDLE hComm=si.hComm;
@ -942,7 +992,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
BYTE bf[32]; BYTE bf[32];
bf[0]=chRead; bf[0]=chRead;
readBytes(bf+1, 17, hComm); readBytes(bf+1, 17, hComm);
if (checkCRC(LPBYTE(bf))) if (checkCRC(LPBYTE(bf), 32))
{ {
WORD Station=MAKEWORD(bf[3], bf[2]); WORD Station=MAKEWORD(bf[3], bf[2]);
@ -1014,7 +1064,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
readBytes(bf+1, 10, hComm); readBytes(bf+1, 10, hComm);
//ReadByte(chRead); //ETX! //ReadByte(chRead); //ETX!
if (checkCRC(LPBYTE(bf))) if (checkCRC(LPBYTE(bf), 32))
getSI6DataExt(hComm); getSI6DataExt(hComm);
break; break;
@ -1024,7 +1074,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
bf[0]=0xE5; bf[0]=0xE5;
readBytes(bf+1, 10, hComm); readBytes(bf+1, 10, hComm);
if (checkCRC(LPBYTE(bf))) if (checkCRC(LPBYTE(bf), 32))
getSI5DataExt(hComm); getSI5DataExt(hComm);
break; break;
@ -1067,7 +1117,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
readBytes(bf+1, 10, hComm); readBytes(bf+1, 10, hComm);
//ReadByte(chRead); //ETX! //ReadByte(chRead); //ETX!
if (checkCRC(LPBYTE(bf))) if (checkCRC(LPBYTE(bf), 32))
getSI9DataExt(hComm); getSI9DataExt(hComm);
break; break;
@ -1163,7 +1213,7 @@ void SportIdent::getSI5DataExt(HANDLE hComm)
if (bf[0]==STX && bf[1]==0xB1) if (bf[0]==STX && bf[1]==0xB1)
{ {
if (checkCRC(bf+1)) if (checkCRC(bf+1, 254))
{ {
c[0]=ACK; c[0]=ACK;
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
@ -1186,7 +1236,7 @@ void SportIdent::getSI6DataExt(HANDLE hComm)
BYTE c[16]; BYTE c[16];
// STX, 0xE1, 0x01, BN, CRC1, // STX, 0xE1, 0x01, BN, CRC1,
//CRC0, ETX //CRC0, ETX
OutputDebugString(L"STARTREAD EXT-"); debugLog(L"STARTREAD EXT-");
int blocks[7]={0,6,7,2,3,4,5}; int blocks[7]={0,6,7,2,3,4,5};
DWORD written=0; DWORD written=0;
@ -1211,13 +1261,13 @@ void SportIdent::getSI6DataExt(HANDLE hComm)
int read=readBytes(bf, 128+9, hComm); int read=readBytes(bf, 128+9, hComm);
if (read==0) { if (read==0) {
OutputDebugString(L"TIMING"); debugLog(L"TIMING");
Sleep(300); Sleep(300);
read = readBytes(bf, 128+9, hComm); read = readBytes(bf, 128+9, hComm);
} }
if (bf[0]==STX && bf[1]==0xE1) { if (bf[0]==STX && bf[1]==0xE1) {
if (checkCRC(bf+1)) { if (checkCRC(bf+1, 250)) {
memcpy(b+k*128, bf+6, 128); memcpy(b+k*128, bf+6, 128);
LPDWORD ptr = LPDWORD(bf + 6); LPDWORD ptr = LPDWORD(bf + 6);
@ -1225,12 +1275,12 @@ void SportIdent::getSI6DataExt(HANDLE hComm)
break; //No need to read more break; //No need to read more
} }
else { else {
OutputDebugString(L"-FAIL-"); debugLog(L"-FAIL-");
return; return;
} }
} }
else { else {
OutputDebugString(L"-FAIL-"); debugLog(L"-FAIL-");
return; return;
} }
} }
@ -1239,7 +1289,7 @@ void SportIdent::getSI6DataExt(HANDLE hComm)
c[0]=ACK; c[0]=ACK;
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
OutputDebugString(L"-ACK-"); debugLog(L"-ACK-");
SICard card(ConvertedTimeStatus::Hour24); SICard card(ConvertedTimeStatus::Hour24);
getCard6Data(b, card); getCard6Data(b, card);
@ -1253,7 +1303,7 @@ void SportIdent::getSI9DataExt(HANDLE hComm)
BYTE c[16]; BYTE c[16];
// STX, 0xE1, 0x01, BN, CRC1, // STX, 0xE1, 0x01, BN, CRC1,
//CRC0, ETX //CRC0, ETX
OutputDebugString(L"STARTREAD9 EXT-"); debugLog(L"STARTREAD9 EXT-");
int blocks_8_9_p_t[2]={0,1}; int blocks_8_9_p_t[2]={0,1};
int blocks_10_11_SIAC[5]={0,4,5,6,7}; int blocks_10_11_SIAC[5]={0,4,5,6,7};
@ -1281,13 +1331,13 @@ void SportIdent::getSI9DataExt(HANDLE hComm)
int read=readBytes(bf, 128+9, hComm); int read=readBytes(bf, 128+9, hComm);
if (read==0) { if (read==0) {
OutputDebugString(L"TIMING"); debugLog(L"TIMING");
Sleep(300); Sleep(300);
read = readBytes(bf, 128+9, hComm); read = readBytes(bf, 128+9, hComm);
} }
if (bf[0]==STX && bf[1]==0xEf) { if (bf[0]==STX && bf[1]==0xEf) {
if (checkCRC(bf+1)) { if (checkCRC(bf+1, 200)) {
memcpy(b+k*128, bf+6, 128); memcpy(b+k*128, bf+6, 128);
if (k == 0) { if (k == 0) {
@ -1304,12 +1354,12 @@ void SportIdent::getSI9DataExt(HANDLE hComm)
} }
else { else {
OutputDebugString(L"-FAIL-"); debugLog(L"-FAIL-");
return; return;
} }
} }
else { else {
OutputDebugString(L"-FAIL-"); debugLog(L"-FAIL-");
return; return;
} }
} }
@ -1318,7 +1368,7 @@ void SportIdent::getSI9DataExt(HANDLE hComm)
c[0]=ACK; c[0]=ACK;
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
OutputDebugString(L"-ACK-"); debugLog(L"-ACK-");
SICard card(ConvertedTimeStatus::Hour24); SICard card(ConvertedTimeStatus::Hour24);
if (getCard9Data(b, card)) if (getCard9Data(b, card))
@ -1333,7 +1383,7 @@ bool SportIdent::readSI6Block(HANDLE hComm, BYTE *data)
int read=readBytesDLE(bf, 4, hComm); int read=readBytesDLE(bf, 4, hComm);
if (read==0){ if (read==0){
OutputDebugString(L"TIMING"); debugLog(L"TIMING");
Sleep(1000); Sleep(1000);
read=readBytesDLE(bf, 4, hComm); read=readBytesDLE(bf, 4, hComm);
} }
@ -1369,7 +1419,7 @@ void SportIdent::getSI6Data(HANDLE hComm)
BYTE c[16]; BYTE c[16];
// STX, 0xE1, 0x01, BN, CRC1, // STX, 0xE1, 0x01, BN, CRC1,
//CRC0, ETX //CRC0, ETX
OutputDebugString(L"STARTREAD-"); debugLog(L"STARTREAD-");
//int blocks[3]={0,6,7}; //int blocks[3]={0,6,7};
DWORD written=0; DWORD written=0;
@ -1390,7 +1440,7 @@ void SportIdent::getSI6Data(HANDLE hComm)
if (!readSI6Block(hComm, b+k*128)) { if (!readSI6Block(hComm, b+k*128)) {
if (k<=2) { if (k<=2) {
OutputDebugString(L"-FAIL-"); debugLog(L"-FAIL-");
return; return;
} }
else else
@ -1418,7 +1468,7 @@ void SportIdent::getSI6Data(HANDLE hComm)
c[0]=ACK; c[0]=ACK;
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
OutputDebugString(L"-ACK-"); debugLog(L"-ACK-");
SICard card(ConvertedTimeStatus::Hour24); SICard card(ConvertedTimeStatus::Hour24);
getCard6Data(b, card); getCard6Data(b, card);
@ -1688,7 +1738,8 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
} }
string2Wide(lastNameByte, lastName); string2Wide(lastNameByte, lastName);
wcsncpy_s(card.lastName, lastName.c_str(), 20); wcsncpy(card.lastName, lastName.c_str(), 20);
card.lastName[20] = 0;
memcpy(firstNameByte, data+32+20, 20); memcpy(firstNameByte, data+32+20, 20);
firstNameByte[20] = 0; firstNameByte[20] = 0;
@ -1698,7 +1749,8 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
} }
string2Wide(firstNameByte, firstName); string2Wide(firstNameByte, firstName);
wcsncpy_s(card.firstName, firstName.c_str(), 20); wcsncpy(card.firstName, firstName.c_str(), 20);
card.firstName[20] = 0;
data+=128-16; data+=128-16;
@ -1974,20 +2026,29 @@ void start_si_thread(void *ptr)
si->Current_SI_Info=0; si->Current_SI_Info=0;
LeaveCriticalSection(&si->SyncObj); LeaveCriticalSection(&si->SyncObj);
if (si_info.ComPort==L"TCP") { try {
if (si_info.ComPort == L"TCP") {
si->MonitorTCPSI(si_info.tcpPort, si_info.localZeroTime); si->MonitorTCPSI(si_info.tcpPort, si_info.localZeroTime);
} }
else if (si_info.ComPort == L"TEST") {
si->MonitorTEST(si_info);
}
else { else {
if (!si_info.hComm) MessageBox(NULL, L"ERROR", 0, MB_OK); if (!si_info.hComm) MessageBox(NULL, L"ERROR", 0, MB_OK);
si->MonitorSI(si_info); si->MonitorSI(si_info);
} }
}
catch (...) {
return;
}
} }
void SportIdent::startMonitorThread(const wchar_t *com) void SportIdent::startMonitorThread(const wchar_t *com)
{ {
SI_StationInfo *si = findStation(com); SI_StationInfo *si = findStation(com);
if (si && (si->hComm || si->ComPort==L"TCP")) if (si && (si->hComm || si->ComPort==L"TCP" || si->ComPort == L"TEST"))
{ {
if (si->ComPort==L"TCP") if (si->ComPort==L"TCP")
tcpPortOpen=0; tcpPortOpen=0;
@ -2366,3 +2427,11 @@ void SICard::deserializePunches(const string &arg) {
if (out.size() == 1) if (out.size() == 1)
punchOnly = true; punchOnly = true;
} }
void SportIdent::addTestCard(int cardNo, const vector<int> &punches) {
testCards.emplace(cardNo, punches);
}
void SportIdent::debugLog(const wchar_t *msg) {
}

View File

@ -9,6 +9,8 @@
#pragma once #pragma once
#endif // _MSC_VER > 1000 #endif // _MSC_VER > 1000
#include <set>
/************************************************************************ /************************************************************************
MeOS - Orienteering Software MeOS - Orienteering Software
Copyright (C) 2009-2019 Melin Software HB Copyright (C) 2009-2019 Melin Software HB
@ -176,7 +178,7 @@ protected:
SI_StationInfo *Current_SI_Info; //Current SI_Info in use (for thread startup); SI_StationInfo *Current_SI_Info; //Current SI_Info in use (for thread startup);
WORD calcCRC(BYTE *data, DWORD length); WORD calcCRC(BYTE *data, DWORD length);
bool checkCRC(BYTE *bf); bool checkCRC(BYTE *bf, DWORD maxLen);
void setCRC(BYTE *bf); void setCRC(BYTE *bf);
bool getCard5Data(BYTE *data, SICard &card); bool getCard5Data(BYTE *data, SICard &card);
@ -204,12 +206,31 @@ protected:
volatile int tcpPortOpen; volatile int tcpPortOpen;
volatile unsigned int serverSocket; volatile unsigned int serverSocket;
bool MonitorTEST(SI_StationInfo &si);
bool MonitorSI(SI_StationInfo &si); bool MonitorSI(SI_StationInfo &si);
int MonitorTCPSI(WORD port, int localZeroTime); int MonitorTCPSI(WORD port, int localZeroTime);
struct TestCard {
int cardNo;
vector<int> punches;
bool operator<(const TestCard &c) const {
return cardNo < c.cardNo;
}
TestCard(int cardNo, const vector<int> &punches) : cardNo(cardNo),
punches(punches) {
}
};
set<TestCard> testCards;
public: public:
SI_StationInfo *findStation(const wstring &com); SI_StationInfo *findStation(const wstring &com);
/** Log debug data. */
void debugLog(const wchar_t *ptr);
void getInfoString(const wstring &com, vector<wstring> &info); void getInfoString(const wstring &com, vector<wstring> &info);
bool isPortOpen(const wstring &com); bool isPortOpen(const wstring &com);
bool autoDetect(list<int> &ComPorts); bool autoDetect(list<int> &ComPorts);
@ -220,6 +241,7 @@ public:
void addCard(const SICard &sic); void addCard(const SICard &sic);
void addPunch(DWORD Time, int Station, int Card, int Mode=0); void addPunch(DWORD Time, int Station, int Card, int Mode=0);
void addTestCard(int cardNo, const vector<int> &punches);
void EnumrateSerialPorts(list<int> &ports); void EnumrateSerialPorts(list<int> &ports);

View File

@ -406,7 +406,7 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
throw std::exception("Klassen finns ej."); throw std::exception("Klassen finns ej.");
int total, finished, dns; int total, finished, dns;
oe->getNumClassRunners(pc->getId(), 0, total, finished, dns); pc->getNumResults(0, total, finished, dns);
oEvent::PredefinedTypes newType = oEvent::PredefinedTypes(gdi.getSelectedItem("Predefined").first); oEvent::PredefinedTypes newType = oEvent::PredefinedTypes(gdi.getSelectedItem("Predefined").first);
int nstages = gdi.getTextNo("NStage"); int nstages = gdi.getTextNo("NStage");
@ -1865,14 +1865,14 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.addString("", boldLarge, L"Dela klass: X#" + pc->getName()); gdi.addString("", boldLarge, L"Dela klass: X#" + pc->getName());
gdi.dropLine(); gdi.dropLine();
int tot, fin, dns; int tot, fin, dns;
oe->getNumClassRunners(pc->getId(), 0, tot, fin, dns); pc->getNumResults(0, tot, fin, dns);
if (pc->isQualificationFinalBaseClass()) { if (pc->isQualificationFinalBaseClass()) {
set<int> base; set<int> base;
pc->getQualificationFinal()->getBaseClassInstances(base); pc->getQualificationFinal()->getBaseClassInstances(base);
for (int i : base) { for (int i : base) {
if (pc->getVirtualClass(i)) { if (pc->getVirtualClass(i)) {
int tot2 = 0; int tot2 = 0;
oe->getNumClassRunners(pc->getVirtualClass(i)->getId(), 0, tot2, fin, dns); pc->getVirtualClass(i)->getNumResults(0, tot2, fin, dns);
tot += tot2; tot += tot2;
} }
} }
@ -2849,10 +2849,10 @@ void TabClass::multiCourse(gdioutput &gdi, int nLeg) {
} }
if (hasRelay) { if (hasRelay) {
headXPos[5]=gdi.getCX(); headXPos[5]=gdi.getCX();
gdi.addInput(string("RestartRope")+legno, L"", 5, MultiCB); gdi.addInput(string("RestartRope")+legno, L"", 7, MultiCB);
headXPos[6]=gdi.getCX(); headXPos[6]=gdi.getCX();
gdi.addInput(string("Restart")+legno, L"", 5, MultiCB); gdi.addInput(string("Restart")+legno, L"", 7, MultiCB);
} }
gdi.dropLine(-0.1); gdi.dropLine(-0.1);

View File

@ -2398,7 +2398,8 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
"\n\nRussian Translation by Paul A. Kazakov and Albert Salihov" "\n\nRussian Translation by Paul A. Kazakov and Albert Salihov"
"\n\nOriginal French Translation by Jerome Monclard" "\n\nOriginal French Translation by Jerome Monclard"
"\n\nAdaption to French conditions and extended translation by Pierre Gaufillet" "\n\nAdaption to French conditions and extended translation by Pierre Gaufillet"
"\n\nCzech Translation by Marek Kustka"); "\n\nCzech Translation by Marek Kustka"
"\n\nHelp with English documentation: Torbjörn Wikström");
gdi.dropLine(); gdi.dropLine();
gdi.addString("", 0, "Det här programmet levereras utan någon som helst garanti. Programmet är "); gdi.addString("", 0, "Det här programmet levereras utan någon som helst garanti. Programmet är ");

View File

@ -939,7 +939,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
gdi.registerEvent("DataUpdate", ListsEventCB); gdi.registerEvent("DataUpdate", ListsEventCB);
gdi.setData("DataSync", 1); gdi.setData("DataSync", 1);
gdi.registerEvent(bi.id, ListsCB); gdi.registerEvent(bi.id, ListsCB);
currentList.getParam().pageBreak = true;
oe->generateMinuteStartlist(gdi); oe->generateMinuteStartlist(gdi);
baseButtons(gdi, 0); baseButtons(gdi, 0);
gdi.refresh(); gdi.refresh();

View File

@ -1568,13 +1568,15 @@ void TabRunner::showRunnerReport(gdioutput &gdi) {
} }
void TabRunner::generateRunnerReport(oEvent &oe, gdioutput &gdi, vector<pair<int, bool>> &runnersToReport) { void TabRunner::generateRunnerReport(oEvent &oe, gdioutput &gdi, vector<pair<int, bool>> &runnersToReport) {
oe.synchronizeList({ oListId::oLRunnerId, oListId::oLTeamId, oListId::oLPunchId });
gdi.fillDown(); gdi.fillDown();
cTeam t = 0; cTeam t = 0;
set<int> clsSet; set<int> clsSet;
for (size_t k = 0; k < runnersToReport.size(); k++) { for (size_t k = 0; k < runnersToReport.size(); k++) {
pRunner r = oe.getRunner(runnersToReport[k].first, 0); pRunner r = oe.getRunner(runnersToReport[k].first, 0);
if (!r)
continue;
clsSet.insert(r->getClassId(true)); clsSet.insert(r->getClassId(true));
if (r && r->getTeam()) { if (r && r->getTeam()) {
pClass cls = r->getClassRef(true); pClass cls = r->getClassRef(true);
@ -1676,7 +1678,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
if (r->statusOK()) { if (r->statusOK()) {
int total, finished, dns; int total, finished, dns;
oe.getNumClassRunners(r->getClassId(true), r->getLegNumber(), total, finished, dns); r->getClassRef(true)->getNumResults(r->getLegNumber(), total, finished, dns);
if (r->getTeam() == 0) { if (r->getTeam() == 0) {
gdi.addString("", fontMediumPlus, L"Tid: X, nuvarande placering Y/Z.#" + str + L"#" + r->getPlaceS() + L"#" + itow(finished)); gdi.addString("", fontMediumPlus, L"Tid: X, nuvarande placering Y/Z.#" + str + L"#" + r->getPlaceS() + L"#" + itow(finished));

View File

@ -48,6 +48,8 @@
#include "recorder.h" #include "recorder.h"
#include "autocomplete.h" #include "autocomplete.h"
constexpr bool addTestPort = false;
TabSI::TabSI(oEvent *poe):TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) { TabSI::TabSI(oEvent *poe):TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) {
editCardData.tabSI = this; editCardData.tabSI = this;
directEntryGUI.tabSI = this; directEntryGUI.tabSI = this;
@ -184,6 +186,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (lbi.text.substr(0, 3) == L"TCP") if (lbi.text.substr(0, 3) == L"TCP")
port = L"TCP"; port = L"TCP";
else if (lbi.text == L"TEST")
port = L"TEST";
if (gSI->isPortOpen(port)) { if (gSI->isPortOpen(port)) {
gSI->closeCom(port.c_str()); gSI->closeCom(port.c_str());
@ -211,6 +215,20 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.refresh(); gdi.refresh();
return 0; return 0;
} }
else if (port == L"TEST") {
vector<pRunner> runners;
oe->getRunners(0, 0, runners, false);
for (pRunner r : runners) {
if (r->getCard() || r->getCardNo() == 0)
continue;
vector<int> pl;
auto c = r->getCourse(true);
if (c) {
pl = c->getControlNumbers();
gSI->addTestCard(r->getCardNo(), pl);
}
}
}
gdi.addStringUT(0, lang.tl(L"Startar SI på ") + port + L"..."); gdi.addStringUT(0, lang.tl(L"Startar SI på ") + port + L"...");
gdi.refresh(); gdi.refresh();
@ -1567,6 +1585,9 @@ void TabSI::refillComPorts(gdioutput &gdi)
else else
gdi.addItem("ComPort", L"TCP"); gdi.addItem("ComPort", L"TCP");
if (addTestPort)
gdi.addItem("ComPort", L"TEST");
if (active){ if (active){
gdi.selectItemByData("ComPort", active); gdi.selectItemByData("ComPort", active);
gdi.setText("StartSI", lang.tl("Koppla ifrån")); gdi.setText("StartSI", lang.tl("Koppla ifrån"));

View File

@ -83,17 +83,21 @@ int TimeStamp::getAge() const
return CTime-Time; return CTime-Time;
} }
string TimeStamp::getStamp() const const string &TimeStamp::getStamp() const
{ {
if (stampCodeTime == Time)
return stampCode;
stampCodeTime = Time;
__int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000; __int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000;
FILETIME &ft=*(FILETIME*)&ft64; FILETIME &ft=*(FILETIME*)&ft64;
SYSTEMTIME st; SYSTEMTIME st;
FileTimeToSystemTime(&ft, &st); FileTimeToSystemTime(&ft, &st);
char bf[64];
sprintf_s(bf, 32, "%d%02d%02d%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
stampCode = bf;
char bf[32]; return stampCode;
sprintf_s(bf, "%d%02d%02d%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
return bf;
} }
wstring TimeStamp::getStampString() const wstring TimeStamp::getStampString() const
@ -109,7 +113,7 @@ wstring TimeStamp::getStampString() const
return bf; return bf;
} }
void TimeStamp::setStamp(string s) void TimeStamp::setStamp(const string &s)
{ {
if (s.size()<14) if (s.size()<14)
return; return;

View File

@ -30,12 +30,14 @@
************************************************************************/ ************************************************************************/
class TimeStamp class TimeStamp {
{
unsigned int Time; unsigned int Time;
mutable string stampCode;
mutable int stampCodeTime = 0;
public: public:
void setStamp(string s); void setStamp(const string &s);
string getStamp() const; const string &getStamp() const;
wstring getStampString() const; wstring getStampString() const;
int getAge() const; int getAge() const;
unsigned int getModificationTime() const {return Time;} unsigned int getModificationTime() const {return Time;}

View File

@ -723,13 +723,13 @@ int csvparser::selectPunchIndex(const wstring &competitionDate, const vector<wst
for (size_t k = 0; k < sp.size(); k++) { for (size_t k = 0; k < sp.size(); k++) {
processGeneralTime(sp[k], pt, date); processGeneralTime(sp[k], pt, date);
if (!pt.empty()) { if (!pt.empty()) {
if (ti == -1) { //if (ti == -1) {
ti = k; ti = k;
pt.swap(processedTime); pt.swap(processedTime);
} // }
else { // else {
return -1; // Not a unique time // return -1; // Not a unique time
} // }
if (!date.empty()) { if (!date.empty()) {
date.swap(processedDate); date.swap(processedDate);
di = k; di = k;
@ -936,12 +936,12 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector<wstring> &sp, S
int np = wtoi(getSIC(sicNumPunch, sp)); int np = wtoi(getSIC(sicNumPunch, sp));
for (int k=0; k < np; k++) { for (int k = 0; k < np; k++) {
size_t ix = startIx + k*3; size_t ix = startIx + k * 3;
if (ix+2 >= sp.size()) if (ix + 2 >= sp.size())
return false; return false;
int code = wtoi(sp[ix]); int code = wtoi(sp[ix]);
int time = analyseSITime(sp[ix+1].c_str(), sp[ix+2].c_str(), is12Hour); int time = analyseSITime(sp[ix + 1].c_str(), sp[ix + 2].c_str(), is12Hour);
if (code > 0) { if (code > 0) {
punches.push_back(make_pair(code, time)); punches.push_back(make_pair(code, time));
} }

View File

@ -2428,3 +2428,7 @@ Lagändringblankett = Team Change Form
Mappa rootadresssen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function Mappa rootadresssen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function
ClassAvailableMaps = Available maps for class ClassAvailableMaps = Available maps for class
ClassTotalMaps = Total number of maps for class ClassTotalMaps = Total number of maps for class
Kunde inte öppna databasen (X) = Could not connect to database (X)
Kunde inte ladda upp löpardatabasen (X) = Could not upload runner database (X)
Runner check time = Runner check time
ClassNumEntries = Number of entries in class

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,7 @@ const int timeSeconds = 1<<14;
const int timerIgnoreSign = 1<<15; const int timerIgnoreSign = 1<<15;
const int Capitalize = 1<<16; const int Capitalize = 1<<16;
const int absolutePosition = 1 << 17; const int absolutePosition = 1 << 17;
const int skipBoundingBox = 1 << 18;
enum GDICOLOR {colorBlack = RGB(0,0,0), enum GDICOLOR {colorBlack = RGB(0,0,0),
colorRed = RGB(128,0,0), colorRed = RGB(128,0,0),

View File

@ -311,6 +311,7 @@ void gdioutput::initCommon(double _scale, const wstring &font)
Background=CreateSolidBrush(GetSysColor(COLOR_WINDOW)); Background=CreateSolidBrush(GetSysColor(COLOR_WINDOW));
fontHeightCache.clear();
fonts[currentFont].init(scale, currentFont, L""); fonts[currentFont].init(scale, currentFont, L"");
} }
@ -846,10 +847,37 @@ TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const string &text,
return addStringUT(yp, xp, format, widen(text), xlimit, cb, fontFace); return addStringUT(yp, xp, format, widen(text), xlimit, cb, fontFace);
} }
int gdioutput::getFontHeight(int format, const wstring &fontFace) const {
format = format & 0xFF;
auto res = fontHeightCache.find(make_pair(format, fontFace));
if (res != fontHeightCache.end())
return res->second;
TextInfo TI;
TI.format = format;
TI.xp = 0;
TI.yp = 0;
TI.text = L"M1y|";
TI.xlimit = 100;
TI.callBack = 0;
TI.font = fontFace;
calcStringSize(TI);
int h = TI.textRect.bottom - TI.textRect.top;
fontHeightCache.emplace(make_pair(format, fontFace), h);
return h;
}
TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const wstring &text, TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const wstring &text,
int xlimit, GUICALLBACK cb, const wchar_t *fontFace) int xlimit, GUICALLBACK cb, const wchar_t *fontFace)
{ {
TextInfo TI; bool skipBBCalc = (format & skipBoundingBox) == skipBoundingBox;
format &= ~skipBoundingBox;
TL.emplace_back();
TextInfo &TI = TL.back();
itTL = TL.begin();
TI.format=format; TI.format=format;
TI.xp=xp; TI.xp=xp;
TI.yp=yp; TI.yp=yp;
@ -859,23 +887,37 @@ TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const wstring &text
if (fontFace) if (fontFace)
TI.font = fontFace; TI.font = fontFace;
if (!skipTextRender(format)) { if (!skipTextRender(format)) {
HDC hDC=GetDC(hWndTarget);
if (skipBBCalc) {
assert(xlimit > 0);
int h = getFontHeight(format, fontFace);
TI.textRect.left = xp;
TI.textRect.top = yp;
TI.textRect.right = xp + xlimit;
TI.textRect.bottom = yp + h;
TI.realWidth = xlimit;
updatePos(TI.textRect.right + OffsetX, TI.yp, scaleLength(10),
TI.textRect.bottom - TI.textRect.top + scaleLength(2));
}
else {
HDC hDC = GetDC(hWndTarget);
if (hWndTarget && !manualUpdate) if (hWndTarget && !manualUpdate)
RenderString(TI, hDC); RenderString(TI, hDC);
else else
calcStringSize(TI, hDC); calcStringSize(TI, hDC);
if (xlimit == 0 || (format & (textRight|textCenter)) == 0) { if (xlimit == 0 || (format & (textRight | textCenter)) == 0) {
updatePos(TI.textRect.right+OffsetX, TI.yp, scaleLength(10), updatePos(TI.textRect.right + OffsetX, TI.yp, scaleLength(10),
TI.textRect.bottom - TI.textRect.top + scaleLength(2)); TI.textRect.bottom - TI.textRect.top + scaleLength(2));
} }
else { else {
updatePos(TI.xp, TI.yp, TI.realWidth + scaleLength(10), updatePos(TI.xp, TI.yp, TI.realWidth + scaleLength(10),
TI.textRect.bottom - TI.textRect.top + scaleLength(2)); TI.textRect.bottom - TI.textRect.top + scaleLength(2));
} }
ReleaseDC(hWndTarget, hDC); ReleaseDC(hWndTarget, hDC);
}
if (renderOptimize && !TL.empty()) { if (renderOptimize && !TL.empty()) {
if (TL.back().yp > TI.yp) if (TL.back().yp > TI.yp)
@ -889,9 +931,6 @@ TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const wstring &text
TI.textRect.top = yp; TI.textRect.top = yp;
} }
TL.push_back(TI);
itTL=TL.begin();
return TL.back(); return TL.back();
} }
@ -6076,15 +6115,13 @@ void gdioutput::liftCommandLock() const {
} }
int gdioutput::getLineHeight(gdiFonts font, const wchar_t *face) const { int gdioutput::getLineHeight(gdiFonts font, const wchar_t *face) const {
TextInfo ti; int h;
ti.xp = 0; if (face == nullptr)
ti.yp = 0; h = getFontHeight(font, _EmptyWString);
ti.format = font; else
ti.text = L"&abc_M|!I"; h = getFontHeight(font, face);
if (face)
ti.font = face; return (11*h)/10;
calcStringSize(ti);
return (11*(ti.textRect.bottom - ti.textRect.top))/10;
} }
GDIImplFontSet::GDIImplFontSet() { GDIImplFontSet::GDIImplFontSet() {

View File

@ -184,6 +184,8 @@ protected:
HBRUSH Background; HBRUSH Background;
mutable map<pair<int, wstring>, int> fontHeightCache;
map<wstring, GDIImplFontSet> fonts; map<wstring, GDIImplFontSet> fonts;
const GDIImplFontSet &getCurrentFont() const; const GDIImplFontSet &getCurrentFont() const;
const GDIImplFontSet &getFont(const wstring &font) const; const GDIImplFontSet &getFont(const wstring &font) const;
@ -596,9 +598,7 @@ public:
bool clearList(const string &id); bool clearList(const string &id);
bool hasField(const string &id) const; bool hasField(const string &id) const;
/*const wstring &getText(const wchar_t *id, bool acceptMissing = false) const {
return getText(toNarrow(id).c_str(), acceptMissing);
}*/
const wstring &getText(const char *id, bool acceptMissing = false) const; const wstring &getText(const char *id, bool acceptMissing = false) const;
BaseInfo &getBaseInfo(const char *id) const; BaseInfo &getBaseInfo(const char *id) const;
@ -616,6 +616,8 @@ public:
// Insert text and notify "focusList" // Insert text and notify "focusList"
bool insertText(const string &id, const wstring &text); bool insertText(const string &id, const wstring &text);
int getFontHeight(int format, const wstring &fontFace) const;
// The html version should be UTF-8. // The html version should be UTF-8.
void copyToClipboard(const string &html, void copyToClipboard(const string &html,
const wstring &txt) const; const wstring &txt) const;

View File

@ -963,6 +963,7 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
parser.declareSymbol("LegPlace", "Place on course leg", true); parser.declareSymbol("LegPlace", "Place on course leg", true);
parser.declareSymbol("Leg", "Leg number in team, zero indexed", false); parser.declareSymbol("Leg", "Leg number in team, zero indexed", false);
parser.declareSymbol("BirthYear", "Year of birth", false); parser.declareSymbol("BirthYear", "Year of birth", false);
parser.declareSymbol("CheckTime", "Runner check time", false);
} }
else { else {
parser.declareSymbol("RunnerStatus", "Status for each team member", true); parser.declareSymbol("RunnerStatus", "Status for each team member", true);
@ -1276,6 +1277,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
parser.addSymbol("LegPlace", place); parser.addSymbol("LegPlace", place);
parser.addSymbol("Leg", runner.getLegNumber()); parser.addSymbol("Leg", runner.getLegNumber());
parser.addSymbol("BirthYear", runner.getBirthYear()); parser.addSymbol("BirthYear", runner.getBirthYear());
parser.addSymbol("CheckTime", runner.getCheckTime());
} }
void DynamicResult::storeOutput(vector<int> &times, vector<int> &numbers) const { void DynamicResult::storeOutput(vector<int> &times, vector<int> &numbers) const {

View File

@ -812,6 +812,7 @@ void xmlbuffer::startXML(xmlparser &xml, const wstring &dest) {
} }
bool xmlbuffer::commit(xmlparser &xml, int count) { bool xmlbuffer::commit(xmlparser &xml, int count) {
vector<wstring> p2;
while (count>0 && !blocks.empty()) { while (count>0 && !blocks.empty()) {
block &block = blocks.front(); block &block = blocks.front();
@ -819,12 +820,20 @@ bool xmlbuffer::commit(xmlparser &xml, int count) {
xml.write(block.tag.c_str(), block.prop, block.value); xml.write(block.tag.c_str(), block.prop, block.value);
} }
else { else {
vector<wstring> p2; if (block.prop.size() > 1) {
for (size_t k = 0; k< block.prop.size(); k++) { p2.resize(block.prop.size() * 2);
p2.push_back(gdi_main->widen(block.prop[k].first)); for (size_t k = 0; k < block.prop.size(); k++) {
p2.push_back(block.prop[k].second); p2[k * 2] = gdi_main->widen(block.prop[k].first);
p2[k * 2 + 1] = std::move(block.prop[k].second);
} }
xml.startTag(block.tag.c_str(), p2); xml.startTag(block.tag.c_str(), p2);
}
else if (block.prop.size() == 1) {
xml.startTag(block.tag.c_str(), block.prop[0].first.c_str(), block.prop[0].second);
}
else if (block.prop.empty()) {
xml.startTag(block.tag.c_str());
}
for (size_t k = 0; k < block.subValues.size(); k++) for (size_t k = 0; k < block.subValues.size(); k++)
block.subValues[k].commit(xml, numeric_limits<int>::max()); block.subValues[k].commit(xml, numeric_limits<int>::max());

View File

@ -106,6 +106,13 @@ void IOF30Interface::readCourseData(gdioutput &gdi, const xmlobject &xo, bool up
failed++; failed++;
} }
vector<pCourse> allC;
oe.getCourses(allC);
for (pCourse pc : allC) {
if (!courses.count(pc->getName()))
courses[pc->getName()] = pc;
}
if (!updateClass) if (!updateClass)
return; return;
@ -399,6 +406,13 @@ void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
if (!bib.empty()) { if (!bib.empty()) {
teamText = bib; teamText = bib;
t = bib2Team[bib]; t = bib2Team[bib];
if (t == nullptr) {
int ibib = _wtoi(bib.c_str());
if (ibib > 0) {
wstring bib2 = itow(ibib);
t = bib2Team[bib2];
}
}
} }
if (t == 0) { if (t == 0) {
@ -2534,9 +2548,9 @@ void IOF30Interface::getLocalDateTime(const string &date, const string &time,
SystemTimeToTzSpecificLocalTime(0, &st, &localTime); SystemTimeToTzSpecificLocalTime(0, &st, &localTime);
char bf[64]; char bf[64];
sprintf(bf, "%02d:%02d:%02d", localTime.wHour, localTime.wMinute, localTime.wSecond); sprintf_s(bf, "%02d:%02d:%02d", localTime.wHour, localTime.wMinute, localTime.wSecond);
timeOut = bf; timeOut = bf;
sprintf(bf, "%d-%02d-%02d", localTime.wYear, localTime.wMonth, localTime.wDay); sprintf_s(bf, "%d-%02d-%02d", localTime.wYear, localTime.wMonth, localTime.wDay);
dateOut = bf; dateOut = bf;
} }
else { else {
@ -3529,7 +3543,8 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
return true; return true;
} }
void IOF30Interface::writeXMLCompetitorDB(xmlparser &xml, const RunnerWDBEntry &rde) const { void IOF30Interface::writeXMLCompetitorDB(xmlparser &xml, const RunnerDB &db,
const RunnerWDBEntry &rde) const {
wstring s = rde.getSex(); wstring s = rde.getSex();
xml.startTag("Competitor"); xml.startTag("Competitor");
@ -3566,10 +3581,19 @@ void IOF30Interface::writeXMLCompetitorDB(xmlparser &xml, const RunnerWDBEntry &
if (rde.dbe().clubNo > 0) { if (rde.dbe().clubNo > 0) {
pClub clb = db.getClub(rde.dbe().clubNo);
if (clb) {
uint64_t extId = clb->getExtIdentifier();
if (extId != 0) {
xml.startTag("Organisation"); xml.startTag("Organisation");
xml.write("Id", rde.dbe().clubNo); xml.write("Id", int(extId));
xml.endTag(); xml.endTag();
} }
else {
writeClub(xml, *clb, false);
}
}
}
xml.endTag(); // Competitor xml.endTag(); // Competitor
} }
@ -3926,7 +3950,7 @@ void IOF30Interface::writeRunnerDB(const RunnerDB &db, xmlparser &xml) const {
const vector<RunnerWDBEntry> &rdb = db.getRunnerDB(); const vector<RunnerWDBEntry> &rdb = db.getRunnerDB();
for (size_t k = 0; k < rdb.size(); k++) { for (size_t k = 0; k < rdb.size(); k++) {
if (!rdb[k].isRemoved()) if (!rdb[k].isRemoved())
writeXMLCompetitorDB(xml, rdb[k]); writeXMLCompetitorDB(xml, db, rdb[k]);
} }
xml.endTag(); xml.endTag();

View File

@ -232,7 +232,7 @@ class IOF30Interface {
int getStageNumber(); int getStageNumber();
bool readXMLCompetitorDB(const xmlobject &xCompetitor); bool readXMLCompetitorDB(const xmlobject &xCompetitor);
void writeXMLCompetitorDB(xmlparser &xml, const RunnerWDBEntry &rde) const; void writeXMLCompetitorDB(xmlparser &xml, const RunnerDB &db, const RunnerWDBEntry &rde) const;
int getStartIndex(const wstring &startId); int getStartIndex(const wstring &startId);

View File

@ -30,7 +30,7 @@
//V35: abcdef //V35: abcdef
//V36: abcdef //V36: abcdef
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 895 $"); string revision("$Rev: 912 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
@ -42,12 +42,12 @@ int getMeosBuild() {
//V33: abcdefghij //V33: abcdefghij
//V34: abcdfge //V34: abcdfge
wstring getMeosDate() { wstring getMeosDate() {
wstring date(L"$Date: 2019-05-11 07:26:35 +0200 (lö, 11 maj 2019) $"); wstring date(L"$Date: 2019-06-16 10:37:59 +0200 (sö, 16 jun 2019) $");
return date.substr(7,10); return date.substr(7,10);
} }
wstring getBuildType() { wstring getBuildType() {
return L""; // No parantheses (...) return L"Update 1"; // No parantheses (...)
} }
wstring getMajorVersion() { wstring getMajorVersion() {
@ -130,5 +130,8 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
supp.emplace_back(L"IP Skogen Göteborg"); supp.emplace_back(L"IP Skogen Göteborg");
supp.emplace_back(L"Smedjebackens Orientering"); supp.emplace_back(L"Smedjebackens Orientering");
supp.emplace_back(L"Gudhems IF"); supp.emplace_back(L"Gudhems IF");
supp.emplace_back(L"Kexholm SK");
supp.emplace_back(L"Utby IK");
supp.emplace_back(L"JWOC 2019");
reverse(supp.begin(), supp.end()); reverse(supp.begin(), supp.end());
} }

View File

@ -549,6 +549,8 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
oPrintPost *last = 0; oPrintPost *last = 0;
oPrintPost *base = 0; oPrintPost *base = 0;
auto indexPosToWidthSrc = indexPosToWidth;
int totalWidth = pos.getWidth(); int totalWidth = pos.getWidth();
for (map<pair<int, int>, int>::iterator it = linePostCount.begin(); it != linePostCount.end(); ++it) { for (map<pair<int, int>, int>::iterator it = linePostCount.begin(); it != linePostCount.end(); ++it) {
if (it->second == 1) { if (it->second == 1) {
@ -606,7 +608,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
added.resultModuleIndex = getResultModuleIndex(oe, li, mp); added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
setFixedWidth(added, indexPosToWidth, MLHead, j, k); setFixedWidth(added, indexPosToWidth, MLHead, j, k);
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLHead, j, k)];
added.color = mp.color; added.color = mp.color;
if (!mp.mergeWithPrevious) if (!mp.mergeWithPrevious)
base = &added; base = &added;
@ -657,7 +659,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
added.resultModuleIndex = getResultModuleIndex(oe, li, mp); added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
setFixedWidth(added, indexPosToWidth, MLSubHead, j, k); setFixedWidth(added, indexPosToWidth, MLSubHead, j, k);
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLSubHead, j, k)];
added.color = mp.color; added.color = mp.color;
if (!mp.mergeWithPrevious) if (!mp.mergeWithPrevious)
base = &added; base = &added;
@ -703,6 +705,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
added.resultModuleIndex = getResultModuleIndex(oe, li, mp); added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
setFixedWidth(added, indexPosToWidth, MLList, j, k); setFixedWidth(added, indexPosToWidth, MLList, j, k);
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLList, j, k)];
added.color = mp.color; added.color = mp.color;
if (!mp.mergeWithPrevious) if (!mp.mergeWithPrevious)
@ -756,6 +759,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
added.resultModuleIndex = getResultModuleIndex(oe, li, mp); added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
setFixedWidth(added, indexPosToWidth, MLSubList, j, k); setFixedWidth(added, indexPosToWidth, MLSubList, j, k);
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLSubList, j, k)];
if (last && mp.mergeWithPrevious) { if (last && mp.mergeWithPrevious) {
last->doMergeNext = true; last->doMergeNext = true;
@ -1656,6 +1660,7 @@ void MetaList::initSymbols() {
typeToSymbol[lClassResultFraction] = L"ClassResultFraction"; typeToSymbol[lClassResultFraction] = L"ClassResultFraction";
typeToSymbol[lClassAvailableMaps] = L"ClassAvailableMaps"; typeToSymbol[lClassAvailableMaps] = L"ClassAvailableMaps";
typeToSymbol[lClassTotalMaps] = L"ClassTotalMaps"; typeToSymbol[lClassTotalMaps] = L"ClassTotalMaps";
typeToSymbol[lClassNumEntries] = L"ClassNumEntries";
typeToSymbol[lCourseLength] = L"CourseLength"; typeToSymbol[lCourseLength] = L"CourseLength";
typeToSymbol[lCourseName] = L"CourseName"; typeToSymbol[lCourseName] = L"CourseName";
typeToSymbol[lCourseClimb] = L"CourseClimb"; typeToSymbol[lCourseClimb] = L"CourseClimb";

View File

@ -65,7 +65,6 @@ oCard::~oCard()
bool oCard::Write(xmlparser &xml) bool oCard::Write(xmlparser &xml)
{ {
if (Removed) return true; if (Removed) return true;
xml.startTag("Card"); xml.startTag("Card");
xml.write("CardNo", cardNo); xml.write("CardNo", cardNo);
xml.write("Punches", getPunchString()); xml.write("Punches", getPunchString());
@ -137,17 +136,13 @@ void oCard::addPunch(int type, int time, int matchControlId)
updateChanged(); updateChanged();
} }
string oCard::getPunchString() const string &oCard::getPunchString() const {
{ punchString.clear();
oPunchList::iterator it; punchString.reserve(punches.size() * 16);
for(auto &p : punches) {
string pstring; p.appendCodeString(punchString);
for(it=punches.begin(); it != punches.end(); ++it){
pstring += it->codeString();
} }
return punchString;
return pstring;
} }
void oCard::importPunches(const string &s) { void oCard::importPunches(const string &s) {

View File

@ -69,6 +69,8 @@ protected:
void changedObject(); void changedObject();
mutable string punchString;
public: public:
// Returns true if the card was constructed from punches. // Returns true if the card was constructed from punches.
@ -126,7 +128,7 @@ public:
const wstring &getCardNoString() const; const wstring &getCardNoString() const;
void setCardNo(int c); void setCardNo(int c);
void importPunches(const string &s); void importPunches(const string &s);
string getPunchString(); const string &getPunchString() const;
void Set(const xmlobject &xo); void Set(const xmlobject &xo);
bool Write(xmlparser &xml); bool Write(xmlparser &xml);

View File

@ -103,7 +103,6 @@ oClass::~oClass()
bool oClass::Write(xmlparser &xml) bool oClass::Write(xmlparser &xml)
{ {
if (Removed) return true; if (Removed) return true;
xml.startTag("Class"); xml.startTag("Class");
xml.write("Id", Id); xml.write("Id", Id);
@ -359,26 +358,145 @@ void oClass::importLegMethod(const string &legMethods)
apply(); apply();
} }
int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNotCompeting) const { string oClass::getCountTypeKey(int leg, CountKeyType type, bool countVacant) {
int nRunners=0; return itos(leg) + ":" + itos(type) + (countVacant ? "V" : "");
oRunnerList::iterator it;
for (it=oe->Runners.begin(); it != oe->Runners.end(); ++it) {
if (it->getClassId(true)==Id) {
if (it->skip())
continue;
if (checkFirstLeg && it->tLeg > 0)
continue;
if (noCountVacant && it->isVacant())
continue;
if (noCountNotCompeting && it->getStatus() == StatusNotCompetiting)
continue;
nRunners++;
}
}
return nRunners;
} }
int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNotCompeting) const {
if (tTypeKeyToRunnerCount.first != oe->dataRevision) {
for (auto &c : oe->Classes) {
c.tTypeKeyToRunnerCount.second.clear();
c.tTypeKeyToRunnerCount.first = oe->dataRevision;
}
}
string key = getCountTypeKey(checkFirstLeg ? 0 : -1,
noCountNotCompeting ? CountKeyType::All : CountKeyType::IncludeNotCompeting,
!noCountVacant);
auto res = tTypeKeyToRunnerCount.second.find(key);
if (res != tTypeKeyToRunnerCount.second.end())
return res->second;
unordered_map<int, int> nRunners;
for (auto &r : oe->Runners) {
if (r.isRemoved() || !r.Class)
continue;
if (checkFirstLeg && (r.tLeg > 0 && !r.Class->isQualificationFinalBaseClass()))
continue;
if (noCountVacant && r.isVacant())
continue;
if (noCountNotCompeting && r.getStatus() == StatusNotCompetiting)
continue;
int id = r.getClassId(true);
++nRunners[id];
}
for (auto &c : oe->Classes) {
if (!c.isRemoved())
c.tTypeKeyToRunnerCount.second[key] = nRunners[c.Id];
}
return nRunners[Id];
}
void oClass::getNumResults(int leg, int &total, int &finished, int &dns) const {
if (tTypeKeyToRunnerCount.first != oe->dataRevision) {
for (auto &c : oe->Classes) {
c.tTypeKeyToRunnerCount.second.clear();
c.tTypeKeyToRunnerCount.first = oe->dataRevision;
}
}
string keyTot = getCountTypeKey(leg, CountKeyType::ExpectedStarting, false);
string keyFinished = getCountTypeKey(leg, CountKeyType::Finished, false);
string keyDNS = getCountTypeKey(leg, CountKeyType::DNS, false);
auto rTot = tTypeKeyToRunnerCount.second.find(keyTot);
auto rFinished = tTypeKeyToRunnerCount.second.find(keyFinished);
auto rDNS = tTypeKeyToRunnerCount.second.find(keyDNS);
if (rTot != tTypeKeyToRunnerCount.second.end() &&
rFinished != tTypeKeyToRunnerCount.second.end() &&
rDNS != tTypeKeyToRunnerCount.second.end()) {
total = rTot->second;
finished = rFinished->second;
dns = rDNS->second;
return;
}
struct Cnt {
bool team = false;
bool singleClass = false;
int maxleg = 0;
int total = 0;
int finished = 0;
int dns = 0;
};
//Search runners
unordered_map<int, Cnt> cnt;
for (auto &c : oe->Classes) {
if (c.isRemoved())
continue;
ClassType ct = c.getClassType();
auto &cc = cnt[c.Id];
cc.maxleg = c.getLastStageIndex();
if (ct == oClassKnockout)
cc.singleClass = true || cc.maxleg == 1;
if (!(ct == oClassIndividual || ct == oClassIndividRelay || ct == oClassKnockout))
cnt[c.Id].team = true;
}
for (auto &r : oe->Runners) {
if (r.isRemoved() || !r.Class || r.tStatus == StatusNotCompetiting || r.tStatus == StatusCANCEL)
continue;
auto &c = cnt[r.getClassId(true)];
if (c.team)
continue;
int tleg = leg > 0 ? leg : c.maxleg;
if (r.tLeg == tleg || c.singleClass) {
c.total++;
if (r.tStatus != StatusUnknown)
c.finished++;
if (r.tStatus == StatusDNS)
c.dns++;
}
}
for (auto &t : oe->Teams) {
if (t.isRemoved() || !t.Class || t.tStatus == StatusNotCompetiting || t.tStatus == StatusCANCEL)
continue;
auto &c = cnt[t.getClassId(true)];
if (!c.team)
continue;
c.total++;
if (t.tStatus != StatusUnknown || t.getLegStatus(leg, false) != StatusUnknown)
c.finished++;
}
for (auto &c : oe->Classes) {
auto &cc = cnt[c.Id];
c.tTypeKeyToRunnerCount.second[keyDNS] = cc.dns;
c.tTypeKeyToRunnerCount.second[keyFinished] = cc.finished;
c.tTypeKeyToRunnerCount.second[keyTot] = cc.total;
}
auto &cc = cnt[Id];
dns = cc.dns;
total = cc.total;
finished = cc.finished;
}
void oClass::setCourse(pCourse c) void oClass::setCourse(pCourse c)
{ {
@ -1532,62 +1650,6 @@ ClassType oClass::getClassType() const
return oClassIndividual; return oClassIndividual;
} }
void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int &dns) const
{
total=0;
finished=0;
dns = 0;
//Search runners
const oClass *pc = getClass(id);
if (!pc)
return;
ClassType ct=pc->getClassType();
if (ct == oClassIndividual || ct == oClassIndividRelay || ct == oClassKnockout) {
oRunnerList::const_iterator it;
int maxleg = pc->getLastStageIndex();
for (it = Runners.begin(); it != Runners.end(); ++it) {
if (!it->skip() && it->getClassId(true) == id && it->getStatus() != StatusNotCompetiting) {
if (leg == 0) {
total++;
if (it->tStatus != StatusUnknown)
finished++;
else if (it->tStatus == StatusDNS || it->tStatus == StatusCANCEL)
dns++;
}
else {
int tleg = leg > 0 ? leg : maxleg;
const pRunner r = it->getMultiRunner(tleg);
if (r) {
total++;
if (r->tStatus != StatusUnknown)
finished++;
else if (it->tStatus == StatusDNS || it->tStatus == StatusCANCEL)
dns++;
}
}
}
}
}
else {
oTeamList::const_iterator it;
for (it=Teams.begin(); it != Teams.end(); ++it) {
if (it->getClassId(true)==id) {
total++;
if (it->tStatus!=StatusUnknown ||
it->getLegStatus(leg, false)!=StatusUnknown)
finished++;
}
}
}
}
int oClass::getNumMultiRunners(int leg) const int oClass::getNumMultiRunners(int leg) const
{ {
int ndup=0; int ndup=0;
@ -3130,6 +3192,20 @@ void oClass::calculateSplits() {
LegResult legRes; LegResult legRes;
LegResult legBestTime; LegResult legBestTime;
vector<pRunner> rCls;
if (isQualificationFinalBaseClass() || isQualificationFinalBaseClass()) {
for (auto &r : oe->Runners) {
if (!r.isRemoved() && r.getClassRef(true) == this)
rCls.push_back(&r);
}
}
else {
for (auto &r : oe->Runners) {
if (!r.isRemoved() && r.Class == this)
rCls.push_back(&r);
}
}
for (set<pCourse>::iterator cit = cSet.begin(); cit!= cSet.end(); ++cit) { for (set<pCourse>::iterator cit = cSet.begin(); cit!= cSet.end(); ++cit) {
pCourse pc = *cit; pCourse pc = *cit;
@ -3142,9 +3218,7 @@ void oClass::calculateSplits() {
vector< vector<int> > splitsAcc(nc+1); vector< vector<int> > splitsAcc(nc+1);
vector<bool> acceptMissingPunch(nc+1, true); vector<bool> acceptMissingPunch(nc+1, true);
for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { for (pRunner it : rCls) {
if (it->isRemoved() || it->getClassRef(true) != this)
continue;
pCourse tpc = it->getCourse(false); pCourse tpc = it->getCourse(false);
if (tpc != pc || tpc == 0) if (tpc != pc || tpc == 0)
continue; continue;
@ -3161,10 +3235,8 @@ void oClass::calculateSplits() {
} }
} }
} }
for (oRunnerList::iterator it = oe->Runners.begin(); it != oe->Runners.end(); ++it) {
if (it->isRemoved() || it->getClassRef(true) != this)
continue;
for (pRunner it : rCls) {
pCourse tpc = it->getCourse(false); pCourse tpc = it->getCourse(false);
if (tpc != pc) if (tpc != pc)

View File

@ -284,6 +284,19 @@ protected:
mutable int tMapsUsed; mutable int tMapsUsed;
mutable int tMapsUsedNoVacant; mutable int tMapsUsedNoVacant;
// First is data revision, second is key
mutable pair<int, map<string, int>> tTypeKeyToRunnerCount;
enum CountKeyType {
All,
Finished,
ExpectedStarting,
DNS,
IncludeNotCompeting
};
static string getCountTypeKey(int leg, CountKeyType type, bool countVacant);
void configureInstance(int instance, bool allowCreation) const; void configureInstance(int instance, bool allowCreation) const;
public: public:
@ -543,6 +556,7 @@ public:
// Get total number of runners running this class. // Get total number of runners running this class.
// Use checkFirstLeg to only check the number of runners running leg 1. // Use checkFirstLeg to only check the number of runners running leg 1.
int getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNotCompeting) const; int getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNotCompeting) const;
void getNumResults(int leg, int &total, int &finished, int &dns) const;
//Get remaining maps for class (or int::minvalue) //Get remaining maps for class (or int::minvalue)
int getNumRemainingMaps(bool forceRecalculate) const; int getNumRemainingMaps(bool forceRecalculate) const;

View File

@ -415,8 +415,7 @@ bool oCourse::fillCourse(gdioutput &gdi, const string &name)
return true; return true;
} }
void oCourse::getControls(vector<pControl> &pc) void oCourse::getControls(vector<pControl> &pc) const {
{
pc.clear(); pc.clear();
pc.reserve(nControls); pc.reserve(nControls);
for(int k=0;k<nControls;k++){ for(int k=0;k<nControls;k++){
@ -424,6 +423,14 @@ void oCourse::getControls(vector<pControl> &pc)
} }
} }
vector<int> oCourse::getControlNumbers() const {
vector<int> ret;
for (int k = 0; k<nControls; k++) {
ret.push_back(Controls[k]->getFirstNumber());
}
return ret;
}
int oCourse::distance(const SICard &card) int oCourse::distance(const SICard &card)
{ {
int matches=0; int matches=0;

View File

@ -211,7 +211,9 @@ public:
pControl addControl(int Id); pControl addControl(int Id);
void Set(const xmlobject *xo); void Set(const xmlobject *xo);
void getControls(vector<pControl> &pc); void getControls(vector<pControl> &pc) const;
vector<int> getControlNumbers() const;
string getControls() const; string getControls() const;
string getLegLengths() const; string getLegLengths() const;

View File

@ -1134,11 +1134,19 @@ bool oEvent::open(const xmlparser &xml) {
ZeroTime = 0; ZeroTime = 0;
xo = xml.getObject("Date"); xo = xml.getObject("Date");
if (xo) Date=xo.getw(); if (xo) {
wstring fDate = xo.getw();
if (convertDateYMS(fDate, true) > 0)
Date = fDate;
}
Name.clear();
xo = xml.getObject("Name"); xo = xml.getObject("Name");
if (xo) Name=xo.getw(); if (xo) Name=xo.getw();
if (Name.empty()) {
Name = lang.tl("Ny tävling");
}
xo = xml.getObject("Annotation"); xo = xml.getObject("Annotation");
if (xo) Annotation = xo.getw(); if (xo) Annotation = xo.getw();
@ -1719,6 +1727,7 @@ pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) {
Runners.push_back(r); Runners.push_back(r);
pRunner pr=&Runners.back(); pRunner pr=&Runners.back();
//cardToRunnerHash.reset();
if (cardToRunnerHash && r.getCardNo() != 0) { if (cardToRunnerHash && r.getCardNo() != 0) {
cardToRunnerHash->emplace(r.getCardNo(), pr); cardToRunnerHash->emplace(r.getCardNo(), pr);
} }
@ -2637,13 +2646,12 @@ void oEvent::removeRunner(const vector<int> &ids)
continue; //Already found. continue; //Already found.
//Remove a singe runner team //Remove a singe runner team
autoRemoveTeam(r); for (size_t k = 0; k < r->multiRunner.size(); k++) {
for (size_t k=0;k<r->multiRunner.size();k++)
if (r->multiRunner[k]) if (r->multiRunner[k])
toRemove.insert(r->multiRunner[k]->getId()); toRemove.insert(r->multiRunner[k]->getId());
}
toRemove.insert(Id); autoRemoveTeam(r);
toRemove.insert(r->Id);
} }
if (toRemove.empty()) if (toRemove.empty())
@ -4797,8 +4805,7 @@ wstring oEvent::getPropertyStringDecrypt(const char *name, const string &def)
return prop2; return prop2;
} }
void oEvent::setPropertyEncrypt(const char *name, const string &prop) void oEvent::setPropertyEncrypt(const char *name, const string &prop) {
{
wchar_t bf[MAX_COMPUTERNAME_LENGTH + 1]; wchar_t bf[MAX_COMPUTERNAME_LENGTH + 1];
DWORD len = MAX_COMPUTERNAME_LENGTH + 1; DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName(bf, &len); GetComputerName(bf, &len);
@ -4822,18 +4829,11 @@ void oEvent::setPropertyEncrypt(const char *name, const string &prop)
setProperty(name, gdibase.widen(prop2)); setProperty(name, gdibase.widen(prop2));
} }
void oEvent::setProperty(const char *name, int prop) void oEvent::setProperty(const char *name, int prop) {
{
eventProperties[name]=itow(prop); eventProperties[name]=itow(prop);
} }
/*
void oEvent::setProperty(const char *name, const string &prop)
{
eventProperties[name]=gdibase.toWide(prop);
}*/
void oEvent::setProperty(const char *name, const wstring &prop) void oEvent::setProperty(const char *name, const wstring &prop) {
{
eventProperties[name] = prop; eventProperties[name] = prop;
} }
@ -5762,10 +5762,11 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (!it->tInTeam) { if (!it->tInTeam) {
ClassType type = it->Class->getClassType(); ClassType type = it->Class->getClassType();
int cid = it->Class->getId();
if (type == oClassIndividRelay) { if (type == oClassIndividRelay) {
it->setClassId(0, true); it->setClassId(0, true);
it->setClassId(it->Class->getId(), true); it->setClassId(cid, true);
it->synchronize(); it->synchronizeAll();
} }
else if (type == oClassRelay) { else if (type == oClassRelay) {
if (!warnNoTeam) { if (!warnNoTeam) {

View File

@ -650,8 +650,6 @@ public:
void calculateSplitResults(int controlIdFrom, int controlIdTo); void calculateSplitResults(int controlIdFrom, int controlIdTo);
// Get total number of completed runner for given class and leg.
void getNumClassRunners(int id, int leg, int &total, int &finished, int &dns) const;
pTeam findTeam(const wstring &s, int lastId, unordered_set<int> &filter) const; pTeam findTeam(const wstring &s, int lastId, unordered_set<int> &filter) const;
pRunner findRunner(const wstring &s, int lastId, const unordered_set<int> &inputFilter, unordered_set<int> &filter) const; pRunner findRunner(const wstring &s, int lastId, const unordered_set<int> &inputFilter, unordered_set<int> &filter) const;
@ -826,7 +824,7 @@ protected:
mutable multimap<int, oAbstractRunner*> bibStartNoToRunnerTeam; mutable multimap<int, oAbstractRunner*> bibStartNoToRunnerTeam;
mutable shared_ptr<unordered_multimap<int, pRunner>> cardToRunnerHash; mutable shared_ptr<unordered_multimap<int, pRunner>> cardToRunnerHash;
unordered_multimap<int, pRunner> &getCardToRunner() const; vector<pRunner> getCardToRunner(int cardNo) const;
mutable set<int> hiredCardHash; mutable set<int> hiredCardHash;
mutable int tHiredCardHashDataRevision = -1; mutable int tHiredCardHashDataRevision = -1;

View File

@ -61,7 +61,6 @@ oFreePunch::~oFreePunch(void)
bool oFreePunch::Write(xmlparser &xml) bool oFreePunch::Write(xmlparser &xml)
{ {
if (Removed) return true; if (Removed) return true;
xml.startTag("Punch"); xml.startTag("Punch");
xml.write("CardNo", CardNo); xml.write("CardNo", CardNo);
xml.write("Time", Time); xml.write("Time", Time);

View File

@ -2255,7 +2255,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("ResultList"); xml.startTag("ResultList");
xml.write("IOFVersion", "version", L"2.0.3"); xml.write("IOFVersion", "version", L"2.0.3");
wstring hhmmss = L"HH:MM:SS";
exportIOFEvent(xml); exportIOFEvent(xml);
bool ClassStarted=false; bool ClassStarted=false;
@ -2304,13 +2304,13 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("Result"); xml.startTag("Result");
xml.startTag("StartTime"); xml.startTag("StartTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getStartTime(), ZeroTime));
xml.endTag(); xml.endTag();
xml.startTag("FinishTime"); xml.startTag("FinishTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getLegFinishTime(-1), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getLegFinishTime(-1), ZeroTime));
xml.endTag(); xml.endTag();
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(it->getLegRunningTime(-1, false), 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(it->getLegRunningTime(-1, false), 0));
xml.write("ResultPosition", it->getLegPlaceS(-1, false)); xml.write("ResultPosition", it->getLegPlaceS(-1, false));
xml.write("CompetitorStatus", "value", it->Runners[0]->getIOFStatusS()); xml.write("CompetitorStatus", "value", it->Runners[0]->getIOFStatusS());
@ -2333,7 +2333,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("SplitTime", "sequence", itos(no++)); xml.startTag("SplitTime", "sequence", itos(no++));
xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber());
if (unsigned(k)<sp.size() && sp[k].time>0) if (unsigned(k)<sp.size() && sp[k].time>0)
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(sp[k].time-it->tStartTime, 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(sp[k].time-it->tStartTime, 0));
else else
xml.write("Time", L"--:--:--"); xml.write("Time", L"--:--:--");
@ -2410,13 +2410,13 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.write("CCardId", it->getCardNo()); xml.write("CCardId", it->getCardNo());
xml.endTag(); xml.endTag();
xml.startTag("StartTime"); xml.startTag("StartTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getStartTime(), ZeroTime));
xml.endTag(); xml.endTag();
xml.startTag("FinishTime"); xml.startTag("FinishTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime));
xml.endTag(); xml.endTag();
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(it->getRunningTime(),0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(it->getRunningTime(),0));
xml.write("ResultPosition", it->getPlaceS()); xml.write("ResultPosition", it->getPlaceS());
xml.write("CompetitorStatus", "value", it->getIOFStatusS()); xml.write("CompetitorStatus", "value", it->getIOFStatusS());
@ -2438,7 +2438,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("SplitTime", "sequence", itos(no++)); xml.startTag("SplitTime", "sequence", itos(no++));
xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber());
if (unsigned(k)<sp.size() && sp[k].time>0) if (unsigned(k)<sp.size() && sp[k].time>0)
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(sp[k].time - it->tStartTime, 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(sp[k].time - it->tStartTime, 0));
else else
xml.write("Time", L"--:--:--"); xml.write("Time", L"--:--:--");
@ -2459,6 +2459,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldStylePatrol) void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldStylePatrol)
{ {
wstring hhmmss = L"HH:MM:SS";
vector<SplitData> dummy; vector<SplitData> dummy;
bool ClassStarted=false; bool ClassStarted=false;
int Id=-1; int Id=-1;
@ -2531,13 +2532,13 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
xml.write("BibNumber", it->getStartNo()); xml.write("BibNumber", it->getStartNo());
xml.startTag("StartTime"); xml.startTag("StartTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getStartTime(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getStartTime(), ZeroTime));
xml.endTag(); xml.endTag();
xml.startTag("FinishTime"); xml.startTag("FinishTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(it->getFinishTimeAdjusted(), ZeroTime));
xml.endTag(); xml.endTag();
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(it->getRunningTime(), 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(it->getRunningTime(), 0));
xml.write("ResultPosition", it->getPlaceS()); xml.write("ResultPosition", it->getPlaceS());
xml.write("TeamStatus", "value", it->getIOFStatusS()); xml.write("TeamStatus", "value", it->getIOFStatusS());
@ -2556,13 +2557,13 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
xml.startTag("Result"); { xml.startTag("Result"); {
xml.write("TeamSequence", k+1); xml.write("TeamSequence", k+1);
xml.startTag("StartTime"); xml.startTag("StartTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(r->getStartTime(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(r->getStartTime(), ZeroTime));
xml.endTag(); xml.endTag();
xml.startTag("FinishTime"); xml.startTag("FinishTime");
xml.write("Clock", "clockFormat", L"HH:MM:SS", formatTimeIOF(r->getFinishTimeAdjusted(), ZeroTime)); xml.write("Clock", "clockFormat", hhmmss, formatTimeIOF(r->getFinishTimeAdjusted(), ZeroTime));
xml.endTag(); xml.endTag();
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(r->getRunningTime(), 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(r->getRunningTime(), 0));
xml.write("ResultPosition", r->getPlaceS()); xml.write("ResultPosition", r->getPlaceS());
xml.write("CompetitorStatus", "value", r->getIOFStatusS()); xml.write("CompetitorStatus", "value", r->getIOFStatusS());
@ -2590,7 +2591,7 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
xml.startTag("SplitTime", "sequence", itos(no++)); xml.startTag("SplitTime", "sequence", itos(no++));
xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber()); xml.write("ControlCode", pcourse->Controls[k]->getFirstNumber());
if (unsigned(k)<sp.size() && sp[k].time>0) if (unsigned(k)<sp.size() && sp[k].time>0)
xml.write("Time", "timeFormat", L"HH:MM:SS", formatTimeIOF(sp[k].time - it->tStartTime, 0)); xml.write("Time", "timeFormat", hhmmss, formatTimeIOF(sp[k].time - it->tStartTime, 0));
else else
xml.write("Time", L"--:--:--"); xml.write("Time", L"--:--:--");

View File

@ -284,7 +284,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
const vector< pair<EPostType, wstring> > &typeFormats, const vector< pair<EPostType, wstring> > &typeFormats,
gdiFonts font, gdiFonts font,
const wchar_t *fontFace, const wchar_t *fontFace,
bool large, int minSize) { bool large, int minSize) const {
vector<oPrintPost> pps; vector<oPrintPost> pps;
for (size_t k = 0; k < typeFormats.size(); k++) { for (size_t k = 0; k < typeFormats.size(); k++) {
pps.push_back(oPrintPost()); pps.push_back(oPrintPost());
@ -1057,7 +1057,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
case lClassResultFraction: case lClassResultFraction:
if (pc && !invalidClass) { if (pc && !invalidClass) {
int total, finished, dns; int total, finished, dns;
oe->getNumClassRunners(pc->getId(), par.getLegNumber(pc), total, finished, dns); pc->getNumResults(par.getLegNumber(pc), total, finished, dns);
swprintf_s(wbf, L"(%d / %d)", finished, total); swprintf_s(wbf, L"(%d / %d)", finished, total);
} }
break; break;
@ -1091,6 +1091,13 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
} }
break; break;
case lClassNumEntries:
if (pc) {
int n = pc->getNumRunners(true, true, true);
wsptr = &itow(n);
}
break;
case lCourseClimb: case lCourseClimb:
if (r) { if (r) {
pCourse crs = r->getCourse(false); pCourse crs = r->getCourse(false);
@ -1658,7 +1665,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
case lRunnerUMMasterPoint: case lRunnerUMMasterPoint:
if (r) { if (r) {
int total, finished, dns; int total, finished, dns;
oe->getNumClassRunners(pc->getId(), par.getLegNumber(pc), total, finished, dns); pc->getNumResults(par.getLegNumber(pc), total, finished, dns);
int percent = int(floor(0.5+double((100*(total-dns-r->getPlace()))/double(total-dns)))); int percent = int(floor(0.5+double((100*(total-dns-r->getPlace()))/double(total-dns))));
if (r->getStatus()==StatusOK) if (r->getStatus()==StatusOK)
swprintf_s(wbf, L"%d", percent); swprintf_s(wbf, L"%d", percent);
@ -2296,7 +2303,7 @@ bool oEvent::formatPrintPost(const list<oPrintPost> &ppli, PrintPostInfo &ppi,
continue; continue;
} }
int limit = 0; int limit = ppit->xlimit;
bool keepNext = false; bool keepNext = false;
//Skip merged entities //Skip merged entities
@ -2337,20 +2344,20 @@ bool oEvent::formatPrintPost(const list<oPrintPost> &ppli, PrintPostInfo &ppi,
if ((pp.type == lRunnerName || pp.type == lRunnerCompleteName || if ((pp.type == lRunnerName || pp.type == lRunnerCompleteName ||
pp.type == lRunnerFamilyName || pp.type == lRunnerGivenName || pp.type == lRunnerFamilyName || pp.type == lRunnerGivenName ||
pp.type == lTeamRunner || (pp.type == lPatrolNameNames && !t)) && rr) { pp.type == lTeamRunner || (pp.type == lPatrolNameNames && !t)) && rr) {
ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format, text, ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format | skipBoundingBox, text,
ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str());
ti->setExtra(rr->getId()); ti->setExtra(rr->getId());
ti->id = "R"; ti->id = "R";
} }
else if ((pp.type == lTeamName || pp.type == lPatrolNameNames) && t) { else if ((pp.type == lTeamName || pp.type == lPatrolNameNames) && t) {
ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format, text, ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, pp.format | skipBoundingBox, text,
ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str()); ppi.gdi.scaleLength(limit), ppi.par.cb, pp.fontFace.c_str());
ti->setExtra(t->getId()); ti->setExtra(t->getId());
ti->id = "T"; ti->id = "T";
} }
else { else {
ti = &ppi.gdi.addStringUT(y + pdy, x + pdx, ti = &ppi.gdi.addStringUT(y + pdy, x + pdx,
pp.format, text, ppi.gdi.scaleLength(limit), 0, pp.fontFace.c_str()); pp.format | skipBoundingBox, text, ppi.gdi.scaleLength(limit), 0, pp.fontFace.c_str());
} }
if (ti && ppi.keepToghether) if (ti && ppi.keepToghether)
ti->lineBreakPrioity = -1; ti->lineBreakPrioity = -1;
@ -2733,11 +2740,26 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
PrintPostInfo printPostInfo(gdi, li.lp); PrintPostInfo printPostInfo(gdi, li.lp);
//oCounter counter; //oCounter counter;
//Render header //Render header
vector< pair<EPostType, wstring> > v;
for (auto &listPostList : { &li.Head, &li.subHead, &li.listPost, &li.subListPost }) {
for (auto &lp : *listPostList) {
if (lp.xlimit == 0) {
v.clear();
v.emplace_back(lp.type, lp.text);
gdiFonts font = lp.getFont();
lp.xlimit = li.getMaxCharWidth(this, gdi, li.getParam().selection, v, font, lp.fontFace.c_str());
}
}
}
if (formatHead && li.getParam().showHeader) { if (formatHead && li.getParam().showHeader) {
for (auto &h : li.Head) { for (auto &h : li.Head) {
if (h.type == lCmpName || h.type == lString) { if (h.type == lCmpName || h.type == lString) {
v.clear();
const_cast<wstring&>(h.text) = li.lp.getCustomTitle(h.text); const_cast<wstring&>(h.text) = li.lp.getCustomTitle(h.text);
v.emplace_back(h.type, h.text);
gdiFonts font = h.getFont();
h.xlimit = li.getMaxCharWidth(this, gdi, li.getParam().selection, v, font, h.fontFace.c_str());
break; break;
} }
} }

View File

@ -53,6 +53,7 @@ enum EPostType
lClassResultFraction, lClassResultFraction,
lClassAvailableMaps, lClassAvailableMaps,
lClassTotalMaps, lClassTotalMaps,
lClassNumEntries,
lCourseLength, lCourseLength,
lCourseName, lCourseName,
lCourseClimb, lCourseClimb,
@ -297,6 +298,7 @@ struct oPrintPost {
GDICOLOR color; GDICOLOR color;
int dx; int dx;
int dy; int dy;
mutable int xlimit = 0;
int legIndex; int legIndex;
bool linearLegIndex; bool linearLegIndex;
gdiFonts getFont() const {return gdiFonts(format & 0xFF);} gdiFonts getFont() const {return gdiFonts(format & 0xFF);}
@ -573,7 +575,7 @@ public:
gdiFonts font, gdiFonts font,
const wchar_t *fontFace = 0, const wchar_t *fontFace = 0,
bool large = false, bool large = false,
int minSize = 0); int minSize = 0) const;
int getMaxCharWidth(const oEvent *oe, int getMaxCharWidth(const oEvent *oe,
@ -583,7 +585,7 @@ public:
gdiFonts font, gdiFonts font,
const wchar_t *fontFace = 0, const wchar_t *fontFace = 0,
bool large = false, bool large = false,
int minSize = 0) { int minSize = 0) const {
vector< pair<EPostType, wstring> > typeFormats(1, make_pair(type, formats)); vector< pair<EPostType, wstring> > typeFormats(1, make_pair(type, formats));
return getMaxCharWidth(oe, oe->gdiBase(), clsSel, typeFormats, font, fontFace, largeSize, minSize); return getMaxCharWidth(oe, oe->gdiBase(), clsSel, typeFormats, font, fontFace, largeSize, minSize);
} }

View File

@ -63,6 +63,12 @@ string oPunch::codeString() const
return bf; return bf;
} }
void oPunch::appendCodeString(string &dst) const {
char bf[32];
sprintf_s(bf, 32, "%d-%d;", Type, Time);
dst.append(bf);
}
void oPunch::decodeString(const string &s) void oPunch::decodeString(const string &s)
{ {
Type=atoi(s.c_str()); Type=atoi(s.c_str());

View File

@ -97,6 +97,8 @@ public:
enum SpecialPunch {PunchStart=1, PunchFinish=2, PunchCheck=3, HiredCard=11111}; enum SpecialPunch {PunchStart=1, PunchFinish=2, PunchCheck=3, HiredCard=11111};
void decodeString(const string &s); void decodeString(const string &s);
string codeString() const; string codeString() const;
void appendCodeString(string &dst) const;
oPunch(oEvent *poe); oPunch(oEvent *poe);
virtual ~oPunch(); virtual ~oPunch();

View File

@ -1916,6 +1916,12 @@ bool oRunner::operator<(const oRunner &c) const {
return true; return true;
else if (tStartTime > c.tStartTime) else if (tStartTime > c.tStartTime)
return false; return false;
const wstring &b1 = getBib();
const wstring &b2 = c.getBib();
if (b1 != b2) {
return compareBib(b1, b2);
}
} }
else if (oe->CurrentSortOrder == SortByStartTimeClass) { else if (oe->CurrentSortOrder == SortByStartTimeClass) {
if (tStartTime < c.tStartTime) if (tStartTime < c.tStartTime)
@ -2558,7 +2564,7 @@ pRunner oRunner::nextNeedReadout() const {
return nullptr; return nullptr;
} }
unordered_multimap<int, pRunner> &oEvent::getCardToRunner() const { vector<pRunner> oEvent::getCardToRunner(int cardNo) const {
if (!cardToRunnerHash || cardToRunnerHash->size() > Runners.size() * 2) { if (!cardToRunnerHash || cardToRunnerHash->size() > Runners.size() * 2) {
cardToRunnerHash = make_shared<unordered_multimap<int, pRunner>>(); cardToRunnerHash = make_shared<unordered_multimap<int, pRunner>>();
for (auto &rc : Runners) { for (auto &rc : Runners) {
@ -2570,16 +2576,33 @@ unordered_multimap<int, pRunner> &oEvent::getCardToRunner() const {
cardToRunnerHash->emplace(cno, r); // The cache is "to large" -> filter is needed when looking into it. cardToRunnerHash->emplace(cno, r); // The cache is "to large" -> filter is needed when looking into it.
} }
} }
return *cardToRunnerHash; vector<pRunner> res;
set<int> ids;
auto rng = cardToRunnerHash->equal_range(cardNo);
for (auto it = rng.first; it != rng.second; ++it) {
pRunner r = it->second;
if (!r->isRemoved() && r->getCardNo() == cardNo) {
if (ids.insert(r->getId()).second)
res.push_back(r);
for (pRunner r2 : r->multiRunner) {
if (r2 && r2->getCardNo() == cardNo) {
if (ids.insert(r2->getId()).second)
res.push_back(r2);
}
}
}
}
return res;
} }
pRunner oEvent::getRunnerByCardNo(int cardNo, int time, CardLookupProperty prop) const { pRunner oEvent::getRunnerByCardNo(int cardNo, int time, CardLookupProperty prop) const {
auto range = getCardToRunner().equal_range(cardNo); auto range = getCardToRunner(cardNo);
bool skipDNS = (prop == CardLookupProperty::SkipNoStart || prop == CardLookupProperty::CardInUse); bool skipDNS = (prop == CardLookupProperty::SkipNoStart || prop == CardLookupProperty::CardInUse);
if (range.first != range.second && std::distance(range.first, range.second) == 1) { if (range.size() == 1) {
// Single hit // Single hit
pRunner r = range.first->second; pRunner r = range[0];
if (r->isRemoved() || r->getCardNo() != cardNo) if (r->isRemoved() || r->getCardNo() != cardNo)
return nullptr; return nullptr;
if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL)) if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
@ -2594,11 +2617,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, CardLookupProperty prop)
vector<pRunner> cand; vector<pRunner> cand;
bool forceRet = false; bool forceRet = false;
for (auto it = range.first; it != range.second; ++it) { for (auto r : range) {
pRunner r = it->second;
if (r->isRemoved() || r->getCardNo() != cardNo)
continue;
if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL)) if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
continue; continue;
@ -2700,11 +2719,8 @@ void oEvent::getRunnersByCardNo(int cardNo, bool sortUpdate, CardLookupProperty
const_cast<oEvent *>(this)->synchronizeList(oListId::oLRunnerId); const_cast<oEvent *>(this)->synchronizeList(oListId::oLRunnerId);
if (cardNo != 0) { if (cardNo != 0) {
auto range = getCardToRunner().equal_range(cardNo); auto range = getCardToRunner(cardNo);
for (auto it = range.first; it != range.second; ++it) { for (auto r : range) {
pRunner r = it->second;
if (r->isRemoved() || r->getCardNo() != cardNo)
continue;
if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL)) if (skipDNS && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
continue; continue;
if (prop == CardLookupProperty::OnlyMainInstance && r->getRaceNo() != 0) if (prop == CardLookupProperty::OnlyMainInstance && r->getRaceNo() != 0)
@ -4657,6 +4673,7 @@ bool oRunner::matchName(const wstring &pname) const
split(tRealName, L" ", myNames); split(tRealName, L" ", myNames);
split(pname, L" ", inNames); split(pname, L" ", inNames);
int numInNames = inNames.size();
for (size_t k = 0; k < myNames.size(); k++) for (size_t k = 0; k < myNames.size(); k++)
myNames[k] = canonizeName(myNames[k].c_str()); myNames[k] = canonizeName(myNames[k].c_str());
@ -4677,7 +4694,7 @@ bool oRunner::matchName(const wstring &pname) const
} }
} }
return nMatched >= min<int>(myNames.size(), 2); return nMatched >= min<int>(max<int>(numInNames, myNames.size()), 2);
} }
oRunner::BibAssignResult oRunner::autoAssignBib() { oRunner::BibAssignResult oRunner::autoAssignBib() {
@ -5999,3 +6016,17 @@ void oAbstractRunner::preventRestart(bool state) {
tPreventRestartCache.first = state; tPreventRestartCache.first = state;
tPreventRestartCache.second = oe->dataRevision; tPreventRestartCache.second = oe->dataRevision;
} }
int oRunner::getCheckTime() const {
oPunch *p = nullptr;
if (Card) {
p = Card->getPunchByType(oPunch::PunchCheck);
}
else {
p = oe->getPunch(Id, oPunch::PunchCheck, getCardNo());
}
if (p && p->Time > 0)
return p->Time;
return 0;
}

View File

@ -567,6 +567,9 @@ public:
// Returns true if there are radio control results, provided result calculation oEvent::ResultType::PreliminarySplitResults was invoked. // Returns true if there are radio control results, provided result calculation oEvent::ResultType::PreliminarySplitResults was invoked.
bool hasOnCourseResult() const { return !tOnCourseResults.empty() || getFinishTime() > 0 || getStatus() != RunnerStatus::StatusUnknown; } bool hasOnCourseResult() const { return !tOnCourseResults.empty() || getFinishTime() > 0 || getStatus() != RunnerStatus::StatusUnknown; }
/** Returns a check time (or zero for no time). */
int getCheckTime() const;
/** Get a runner reference (drawing) */ /** Get a runner reference (drawing) */
pRunner getReference() const; pRunner getReference() const;

View File

@ -205,18 +205,20 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
maxX *= scaleXFactor; maxX *= scaleXFactor;
float w = HPDF_Page_GetWidth(page); float w = HPDF_Page_GetWidth(page);
float h = HPDF_Page_GetHeight(page); float h = HPDF_Page_GetHeight(page);
float scale = (w / maxX) * 0.85f; float scale = (w / maxX) * 0.95f;
float fontScale = 1.5f;
vector<RenderedPage> pages; vector<RenderedPage> pages;
PageInfo pageInfo; PageInfo pageInfo;
pageInfo.topMargin = h * 0.05f; pageInfo.topMargin = h * 0.03f;
pageInfo.scaleX = scale * scaleXFactor; pageInfo.scaleX = scale * scaleXFactor;
pageInfo.scaleY = scale; pageInfo.scaleY = scale * 1.1f;
pageInfo.leftMargin = w * 0.07f; pageInfo.leftMargin = w * 0.03f;
pageInfo.bottomMargin = pageInfo.topMargin * 1.0f; pageInfo.bottomMargin = pageInfo.topMargin * 1.0f;
pageInfo.pageY = h; pageInfo.pageY = h;
pageInfo.printHeader = true; pageInfo.printHeader = true;
pageInfo.yMM2PrintC = pageInfo.xMM2PrintC = 1199.551f / 420.f; pageInfo.yMM2PrintC = pageInfo.xMM2PrintC = 1199.551f / 420.f;
pageInfo.yMM2PrintC *= fontScale;
pageInfo.xMM2PrintK = 0; pageInfo.xMM2PrintK = 0;
pageInfo.yMM2PrintK = 0; pageInfo.yMM2PrintK = 0;
@ -227,9 +229,11 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
if (!pinfo.empty()) { if (!pinfo.empty()) {
selectFont(page, fs, fontSmall, scale); selectFont(page, fs, fontSmall, scale);
HPDF_Page_BeginText (page); HPDF_Page_BeginText (page);
float df = min(w, h) * 0.02f; float df = min(w, h) * 0.04f;
float sw = HPDF_Page_TextWidth(page, gdi.toUTF8(pinfo).c_str()); float sw = HPDF_Page_TextWidth(page, gdi.toUTF8(pinfo).c_str());
HPDF_Page_TextOut (page, w - sw - df , h - df * 2.5f, gdi.toUTF8(pinfo).c_str()); float sy = HPDF_Page_TextWidth(page, "MMM");
HPDF_Page_TextOut (page, w - sw - df , h - sy, gdi.toUTF8(pinfo).c_str());
HPDF_Page_EndText(page); HPDF_Page_EndText(page);
} }
@ -269,7 +273,7 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
} }
} }
selectFont(page, fonts[info[k].ti.font], info[k].ti.format, scale); selectFont(page, fonts[info[k].ti.font], info[k].ti.format, scale*fontScale);
HPDF_Page_BeginText (page); HPDF_Page_BeginText (page);
float r = GetRValue(info[k].ti.color); float r = GetRValue(info[k].ti.color);
float g = GetGValue(info[k].ti.color); float g = GetGValue(info[k].ti.color);
@ -278,14 +282,14 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
string nt = gdi.toUTF8(info[k].ti.text); string nt = gdi.toUTF8(info[k].ti.text);
if (info[k].ti.format & textRight) { if (info[k].ti.format & textRight) {
float w = float(info[k].ti.xlimit) * scale; float w = float(info[k].ti.xlimit) * scale*fontScale;
float sw = HPDF_Page_TextWidth(page, nt.c_str()); float sw = HPDF_Page_TextWidth(page, nt.c_str());
float space = info[k].ti.xlimit > 0 ? 2 * HPDF_Page_GetCharSpace(page) : 0; float space = info[k].ti.xlimit > 0 ? 2 * HPDF_Page_GetCharSpace(page) : 0;
HPDF_Page_TextOut (page, info[k].xp + w - sw - space, h - info[k].yp, HPDF_Page_TextOut (page, info[k].xp + w - sw - space, h - info[k].yp,
nt.c_str()); nt.c_str());
} }
else if (info[k].ti.format & textCenter) { else if (info[k].ti.format & textCenter) {
float w = float(info[k].ti.xlimit) * scale; float w = float(info[k].ti.xlimit) * scale*fontScale;
float sw = HPDF_Page_TextWidth(page, nt.c_str()); float sw = HPDF_Page_TextWidth(page, nt.c_str());
HPDF_Page_TextOut (page, info[k].xp + w - sw/2, h - info[k].yp, HPDF_Page_TextOut (page, info[k].xp + w - sw/2, h - info[k].yp,
nt.c_str()); nt.c_str());

View File

@ -2436,3 +2436,7 @@ Patrol score, rogaining = Patrullpoäng, rogaining
Rogaining points before automatic reduction = Rogainingpoäng före automatisk reduktion Rogaining points before automatic reduction = Rogainingpoäng före automatisk reduktion
Runner's course id = Deltagares banans id Runner's course id = Deltagares banans id
Status code for cancelled entry = Statuskod för återbud Status code for cancelled entry = Statuskod för återbud
Kunde inte öppna databasen (X) = Kunde inte öppna databasen (X)
Kunde inte ladda upp löpardatabasen (X) = Kunde inte ladda upp löpardatabasen (X)
Runner check time = Checktid
ClassNumEntries = Antal anmälda i klassen

View File

@ -98,10 +98,21 @@ const string &xmlparser::encodeXML(const string &input) {
void xmlparser::write(const char *tag, const wstring &Value) void xmlparser::write(const char *tag, const wstring &Value)
{ {
if (!cutMode || !Value.empty()) { if (!cutMode || !Value.empty()) {
auto &valEnc = encodeXML(Value);
if (valEnc.length() > 400) {
fOut() << "<" << tag << ">" fOut() << "<" << tag << ">"
<< encodeXML(Value) << valEnc
<< "</" << tag << ">" << endl; << "</" << tag << ">" << endl;
} }
else {
char bf[512];
sprintf_s(bf, "<%s>%s</%s>\n", tag, valEnc.c_str(), tag);
fOut() << bf;
}
/*fOut() << "<" << tag << ">"
<< encodeXML(Value)
<< "</" << tag << ">" << endl;*/
}
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
} }
@ -109,17 +120,49 @@ void xmlparser::write(const char *tag, const wstring &Value)
void xmlparser::write(const char *tag, const string &Value) void xmlparser::write(const char *tag, const string &Value)
{ {
if (!cutMode || Value!="") { if (!cutMode || Value!="") {
auto &valEnc = encodeXML(Value);
if (valEnc.length() > 400) {
fOut() << "<" << tag << ">" fOut() << "<" << tag << ">"
<< encodeXML(Value) << valEnc
<< "</" << tag << ">" << endl; << "</" << tag << ">" << endl;
} }
else {
char bf[512];
sprintf_s(bf, "<%s>%s</%s>\n", tag, valEnc.c_str(), tag);
fOut() << bf;
}
}
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
} }
void xmlparser::write(const char *tag, const char *Value)
{
if (!cutMode || Value != "") {
auto &valEnc = encodeXML(Value);
if (valEnc.length() > 400) {
fOut() << "<" << tag << ">"
<< valEnc
<< "</" << tag << ">" << endl;
}
else {
char bf[512];
sprintf_s(bf, "<%s>%s</%s>\n", tag, valEnc.c_str(), tag);
fOut() << bf;
}
}
if (!fOut().good())
throw meosException("Writing to XML file failed.");
}
void xmlparser::write(const char *tag) void xmlparser::write(const char *tag)
{ {
fOut() << "<" << tag << "/>" << endl; char bf[128];
sprintf_s(bf, "<%s/>\n", tag);
fOut() << bf;
//fOut() << "<" << tag << "/>" << endl;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
} }
@ -128,7 +171,7 @@ void xmlparser::write(const char *tag, const char *Property, const string &Value
{ {
if (!cutMode || Value!="") { if (!cutMode || Value!="") {
fOut() << "<" << tag << " " << Property << "=\"" fOut() << "<" << tag << " " << Property << "=\""
<< encodeXML(Value) << "\"/>" << endl; << encodeXML(Value) << "\"/>\n";
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -138,7 +181,7 @@ void xmlparser::write(const char *tag, const char *Property, const wstring &Valu
{ {
if (!cutMode || !Value.empty()) { if (!cutMode || !Value.empty()) {
fOut() << "<" << tag << " " << Property << "=\"" fOut() << "<" << tag << " " << Property << "=\""
<< encodeXML(Value) << "\"/>" << endl; << encodeXML(Value) << "\"/>\n";
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -146,7 +189,8 @@ void xmlparser::write(const char *tag, const char *Property, const wstring &Valu
void xmlparser::write(const char *tag, const char *prop, const wchar_t *value) void xmlparser::write(const char *tag, const char *prop, const wchar_t *value)
{ {
write(tag, prop, wstring(value)); encodeString = value;
write(tag, prop, encodeString);
} }
void xmlparser::writeBool(const char *tag, const char *prop, bool value) void xmlparser::writeBool(const char *tag, const char *prop, bool value)
@ -173,7 +217,7 @@ void xmlparser::write(const char *tag, const char *Property, const wstring &Prop
if (!cutMode || Value != L"" || PropValue != L"") { if (!cutMode || Value != L"" || PropValue != L"") {
fOut() << "<" << tag << " " << Property << "=\"" fOut() << "<" << tag << " " << Property << "=\""
<< encodeXML(PropValue) << "\">" << encodeXML(Value) << encodeXML(PropValue) << "\">" << encodeXML(Value)
<< "</" << tag << ">" << endl; << "</" << tag << ">\n";
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -222,10 +266,10 @@ void xmlparser::write(const char *tag, const vector< pair<string, wstring> > &pr
} }
if (!value.empty()) { if (!value.empty()) {
fOut() << ">" << encodeXML(value) fOut() << ">" << encodeXML(value)
<< "</" << tag << ">" << endl; << "</" << tag << ">\n";
} }
else else
fOut() << "/>" << endl; fOut() << "/>\n";
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -239,7 +283,10 @@ void xmlparser::write(const char *tag, const char *prop,
void xmlparser::writeBool(const char *tag, const char *prop, void xmlparser::writeBool(const char *tag, const char *prop,
bool propValue, const wstring &value) { bool propValue, const wstring &value) {
write(tag, prop, propValue ? L"true" : L"false", value); static const wstring wTrue = L"true";
static const wstring wFalse = L"false";
write(tag, prop, propValue ? wTrue : wFalse, value);
} }
/* /*
void xmlparser::write(const char *tag, const char *prop, void xmlparser::write(const char *tag, const char *prop,
@ -255,9 +302,12 @@ void xmlparser::write(const char *tag, const char *prop,
void xmlparser::write(const char *tag, int Value) void xmlparser::write(const char *tag, int Value)
{ {
if (!cutMode || Value!=0) { if (!cutMode || Value!=0) {
fOut() << "<" << tag << ">" char bf[256];
<< Value sprintf_s(bf, "<%s>%d</%s>\n", tag, Value, tag);
<< "</" << tag << ">" << endl; fOut() << bf;
//fOut() << "<" << tag << ">"
// << Value
// << "</" << tag << ">" << endl;
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -266,9 +316,16 @@ void xmlparser::write(const char *tag, int Value)
void xmlparser::writeBool(const char *tag, bool value) void xmlparser::writeBool(const char *tag, bool value)
{ {
if (!cutMode || value) { if (!cutMode || value) {
fOut() << "<" << tag << ">" if (value) {
<< (value ? "true" : "false") char bf[256];
<< "</" << tag << ">" << endl; sprintf_s(bf, "<%s>true</%s>\n", tag, tag);
fOut() << bf;
}
else {
char bf[256];
sprintf_s(bf, "<%s>false</%s>\n", tag, tag);
fOut() << bf;
}
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -280,7 +337,7 @@ void xmlparser::write64(const char *tag, __int64 Value)
if (!cutMode || Value!=0) { if (!cutMode || Value!=0) {
fOut() << "<" << tag << ">" fOut() << "<" << tag << ">"
<< Value << Value
<< "</" << tag << ">" << endl; << "</" << tag << ">\n";
} }
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -289,7 +346,16 @@ void xmlparser::write64(const char *tag, __int64 Value)
void xmlparser::startTag(const char *tag, const char *prop, const wstring &Value) void xmlparser::startTag(const char *tag, const char *prop, const wstring &Value)
{ {
if (tagStackPointer<32) { if (tagStackPointer<32) {
const string &valEnc = encodeXML(Value);
if (valEnc.length() < 128) {
char bf[256];
sprintf_s(bf, "<%s %s=\"%s\">\n", tag, prop, valEnc.c_str());
fOut() << bf;
}
else {
fOut() << "<" << tag << " " << prop << "=\"" << encodeXML(Value) << "\">" << endl; fOut() << "<" << tag << " " << prop << "=\"" << encodeXML(Value) << "\">" << endl;
}
tagStack[tagStackPointer++]=tag; tagStack[tagStackPointer++]=tag;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -302,7 +368,16 @@ void xmlparser::startTag(const char *tag, const char *prop, const wstring &Value
void xmlparser::startTag(const char *tag, const char *prop, const string &Value) void xmlparser::startTag(const char *tag, const char *prop, const string &Value)
{ {
if (tagStackPointer<32) { if (tagStackPointer<32) {
const string &valEnc = encodeXML(Value);
if (valEnc.length() < 128) {
char bf[256];
sprintf_s(bf, "<%s %s=\"%s\">\n", tag, prop, valEnc.c_str());
fOut() << bf;
}
else {
fOut() << "<" << tag << " " << prop << "=\"" << encodeXML(Value) << "\">" << endl; fOut() << "<" << tag << " " << prop << "=\"" << encodeXML(Value) << "\">" << endl;
}
tagStack[tagStackPointer++]=tag; tagStack[tagStackPointer++]=tag;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -318,7 +393,7 @@ void xmlparser::startTag(const char *tag, const vector<string> &propvalue)
for (size_t k=0;k<propvalue.size(); k+=2) { for (size_t k=0;k<propvalue.size(); k+=2) {
fOut() << propvalue[k] << "=\"" << encodeXML(propvalue[k+1]) << "\" "; fOut() << propvalue[k] << "=\"" << encodeXML(propvalue[k+1]) << "\" ";
} }
fOut() << ">" << endl; fOut() << ">\n";
tagStack[tagStackPointer++]=tag; tagStack[tagStackPointer++]=tag;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -330,11 +405,11 @@ void xmlparser::startTag(const char *tag, const vector<string> &propvalue)
void xmlparser::startTag(const char *tag, const vector<wstring> &propvalue) void xmlparser::startTag(const char *tag, const vector<wstring> &propvalue)
{ {
if (tagStackPointer<32) { if (tagStackPointer<32) {
fOut() << "<" << tag << " "; fOut() << "<" << tag ;
for (size_t k=0;k<propvalue.size(); k+=2) { for (size_t k=0;k<propvalue.size(); k+=2) {
fOut() << encodeXML(propvalue[k]) << "=\"" << encodeXML(propvalue[k+1]) << "\" "; fOut() << " " << encodeXML(propvalue[k]) << "=\"" << encodeXML(propvalue[k+1]) << "\"";
} }
fOut() << ">" << endl; fOut() << ">\n";
tagStack[tagStackPointer++]=tag; tagStack[tagStackPointer++]=tag;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -346,7 +421,9 @@ void xmlparser::startTag(const char *tag, const vector<wstring> &propvalue)
void xmlparser::startTag(const char *tag) void xmlparser::startTag(const char *tag)
{ {
if (tagStackPointer<32) { if (tagStackPointer<32) {
fOut() << "<" << tag << ">" << endl; char bf[128];
sprintf_s(bf, "<%s>\n", tag);
fOut() << bf;
tagStack[tagStackPointer++]=tag; tagStack[tagStackPointer++]=tag;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
@ -358,7 +435,11 @@ void xmlparser::startTag(const char *tag)
void xmlparser::endTag() void xmlparser::endTag()
{ {
if (tagStackPointer>0) { if (tagStackPointer>0) {
fOut() << "</" << tagStack[--tagStackPointer] << ">" << endl; char bf[128];
const char *tag = tagStack[--tagStackPointer].c_str();
sprintf_s(bf, "</%s>\n", tag);
fOut() << bf;
if (!fOut().good()) if (!fOut().good())
throw meosException("Writing to XML file failed."); throw meosException("Writing to XML file failed.");
} }

View File

@ -115,6 +115,7 @@ protected:
gdioutput *utfConverter; gdioutput *utfConverter;
mutable wstring encodeString;
public: public:
void access(int index); void access(int index);
@ -158,6 +159,8 @@ public:
void write(const char *tag, const vector< pair<string, wstring> > &propValue, const wstring &value); void write(const char *tag, const vector< pair<string, wstring> > &propValue, const wstring &value);
void write(const char *tag, const string &value); void write(const char *tag, const string &value);
void write(const char *tag, const char *value);
void write(const char *tag, const wstring &value); void write(const char *tag, const wstring &value);
void write(const char *tag, int value); void write(const char *tag, int value);