From 5327deebbb0aaf4c13b90d1e2ccdf97b9fd40d8a Mon Sep 17 00:00:00 2001 From: Erik Melin <31467290+erikmelin@users.noreply.github.com> Date: Sun, 25 Mar 2018 22:21:24 +0200 Subject: [PATCH] MeOS version 3.5.826 RC2 --- code/RunnerDB.cpp | 1 + code/SportIdent.cpp | 133 +++++++++++++++------------ code/SportIdent.h | 35 ++++--- code/TabAuto.cpp | 6 +- code/TabClass.cpp | 69 +++++++------- code/TabClass.h | 4 +- code/TabCompetition.cpp | 12 +-- code/TabRunner.cpp | 6 +- code/TabRunner.h | 3 +- code/TabSI.cpp | 198 +++++++++++++++++++++++++++------------- code/TabSI.h | 4 +- code/TabTeam.cpp | 70 +++++++++++++- code/TabTeam.h | 5 +- code/Table.cpp | 2 +- code/csvparser.cpp | 58 ++++++------ code/danish.lng | 126 ++++++++++++++----------- code/english.lng | 20 ++-- code/gdioutput.cpp | 24 ++--- code/gdioutput.h | 10 +- code/infoserver.cpp | 24 +++-- code/infoserver.h | 1 + code/meos.cpp | 28 ++++-- code/meos_util.cpp | 8 +- code/meosversion.cpp | 11 ++- code/oCard.cpp | 1 + code/oClass.cpp | 13 ++- code/oEvent.cpp | 77 +++++++++------- code/oEvent.h | 6 +- code/oRunner.cpp | 4 +- code/onlineinput.cpp | 3 +- code/restserver.cpp | 2 +- code/swedish.lng | 4 +- code/testmeos.cpp | 2 +- 33 files changed, 603 insertions(+), 367 deletions(-) diff --git a/code/RunnerDB.cpp b/code/RunnerDB.cpp index 13be5dd..0391c87 100644 --- a/code/RunnerDB.cpp +++ b/code/RunnerDB.cpp @@ -1045,6 +1045,7 @@ void RunnerDB::updateAdd(const oRunner &r, map &clubIdMap) dbe = &dbr; break; } + ++it; } } diff --git a/code/SportIdent.cpp b/code/SportIdent.cpp index c126215..8d6d89f 100644 --- a/code/SportIdent.cpp +++ b/code/SportIdent.cpp @@ -34,6 +34,7 @@ #include #include "localizer.h" #include "meos_util.h" +#include "gdioutput.h" #include "oPunch.h" #include @@ -72,7 +73,6 @@ SportIdent::SportIdent(HWND hWnd, DWORD Id) //ThreadHandle=0; n_SI_Info=0; - ZeroTime=0; InitializeCriticalSection(&SyncObj); tcpPortOpen=0; @@ -859,7 +859,7 @@ int SportIdent::MonitorTCPSI(WORD port, int localZeroTime) vector punches(nPunch); r = recv(client, (char*)&punches[0], 8 * nPunch, 0); if (r == 8 * nPunch) { - SICard card; + SICard card(ConvertedTimeStatus::Hour24); card.CheckPunch.Code = -1; card.StartPunch.Code = -1; card.FinishPunch.Code = -1; @@ -1169,7 +1169,7 @@ void SportIdent::getSI5DataExt(HANDLE hComm) WriteFile(hComm, c, 1, &written, NULL); BYTE *Card5Data=bf+5; - SICard card; + SICard card(ConvertedTimeStatus::Hour12); getCard5Data(Card5Data, card); addCard(card); } @@ -1241,7 +1241,7 @@ void SportIdent::getSI6DataExt(HANDLE hComm) OutputDebugString(L"-ACK-"); - SICard card; + SICard card(ConvertedTimeStatus::Hour24); getCard6Data(b, card); addCard(card); } @@ -1320,7 +1320,7 @@ void SportIdent::getSI9DataExt(HANDLE hComm) OutputDebugString(L"-ACK-"); - SICard card; + SICard card(ConvertedTimeStatus::Hour24); if (getCard9Data(b, card)) addCard(card); } @@ -1419,7 +1419,7 @@ void SportIdent::getSI6Data(HANDLE hComm) WriteFile(hComm, c, 1, &written, NULL); OutputDebugString(L"-ACK-"); - SICard card; + SICard card(ConvertedTimeStatus::Hour24); getCard6Data(b, card); addCard(card); @@ -1469,7 +1469,7 @@ void SportIdent::getSI5Data(HANDLE hComm) WriteFile(hComm, c, 1, &written, NULL); //BYTE *Card5Data=bf+5; - SICard card; + SICard card(ConvertedTimeStatus::Hour12); getCard5Data(bf, card); addCard(card); @@ -1507,7 +1507,7 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card) data+=16; - + card.convertedTime = ConvertedTimeStatus::Hour12; analyseSI5Time(data+3, card.StartPunch.Time, card.StartPunch.Code); analyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code); analyseSI5Time(data+9, card.CheckPunch.Time, card.CheckPunch.Code); @@ -1571,6 +1571,7 @@ bool SportIdent::getCard9Data(BYTE *data, SICard &card) int series = data[24] & 15; + card.convertedTime = ConvertedTimeStatus::Hour24; analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code); analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code); analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code); @@ -1670,26 +1671,38 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card) // DWORD control; // DWORD time; - + card.convertedTime = ConvertedTimeStatus::Hour24; analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code); analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code); analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code); card.nPunch=min(int(data[2]), 192); int i; + char lastNameByte[21], firstNameByte[21]; + wstring lastName, firstName; - memcpy(card.LastName, data+32, 20); - for(i=19;i>0 && card.LastName[i]==0x20;i--) - card.LastName[i]=0; + memcpy(lastNameByte, data+32, 20); + lastNameByte[20] = 0; + for (i = 19; i >= 0 && lastNameByte[i] == 0x20; i--) { + lastNameByte[i] = 0; + } - memcpy(card.FirstName, data+32+20, 20); - for(i=19;i>0 && card.FirstName[i]==0x20;i--) - card.FirstName[i]=0; + string2Wide(lastNameByte, lastName); + wcsncpy(card.lastName, lastName.c_str(), 20); + + memcpy(firstNameByte, data+32+20, 20); + firstNameByte[20] = 0; + + for (i = 19; i >= 0 && firstNameByte[i] == 0x20; i--) { + firstNameByte[i] = 0; + } + + string2Wide(firstNameByte, firstName); + wcsncpy(card.firstName, firstName.c_str(), 20); data+=128-16; - for(unsigned k=0;kEftermiddag - } - else { - //Eftermiddag - - if ( time >= ZeroTime%(12*3600) ) { - //Eftermiddag - time+=12*3600; - } - // else Efter midnatt OK. - } control=0; } else { @@ -1754,6 +1752,36 @@ void SportIdent::analyseSI5Time(BYTE *data, DWORD &time, DWORD &control) } } +void SICard::analyseHour12Time(DWORD zeroTime) { + if (convertedTime != ConvertedTimeStatus::Hour12) + return; + + StartPunch.analyseHour12Time(zeroTime); + CheckPunch.analyseHour12Time(zeroTime); + FinishPunch.analyseHour12Time(zeroTime); + for (DWORD k = 0; k < nPunch; k++) + Punch[k].analyseHour12Time(zeroTime); + + convertedTime = ConvertedTimeStatus::Hour24; +} + +void SIPunch::analyseHour12Time(DWORD zeroTime) { + if (Code != -1 && Time>=0 && Time <=12*3600) { + if (zeroTime < 12 * 3600) { + //Förmiddag + if (Time < zeroTime) + Time += 12 * 3600; //->Eftermiddag + } + else { + //Eftermiddag + if (Time >= zeroTime % (12 * 3600)) { + //Eftermiddag + Time += 12 * 3600; + } + // else Efter midnatt OK. + } + } +} void SportIdent::EnumrateSerialPorts(list &ports) { @@ -1867,7 +1895,7 @@ void SportIdent::addCard(const SICard &sic) void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode) { - SICard sic; + SICard sic(ConvertedTimeStatus::Hour24); memset(&sic, 0, sizeof(sic)); sic.CardNumber=Card; sic.StartPunch.Code = -1; @@ -1912,7 +1940,7 @@ void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode) sic.FinishPunch.Code = oPunch::PunchFinish; } } - sic.PunchOnly=true; + sic.punchOnly = true; addCard(sic); } @@ -2048,14 +2076,6 @@ bool SportIdent::autoDetect(list &ComPorts) return !ComPorts.empty(); } -void SportIdent::setZeroTime(DWORD zt) -{ - EnterCriticalSection(&SyncObj); - ZeroTime=zt%(24*3600); - LeaveCriticalSection(&SyncObj); - -} - bool SportIdent::isPortOpen(const wstring &com) { SI_StationInfo *si = findStation(com); @@ -2146,8 +2166,7 @@ static string formatTimeN(int t) { return nt; } -vector SICard::codeLogData(int row) const -{ +vector SICard::codeLogData(gdioutput &gdi, int row) const { vector log; log.push_back(itos(row)); @@ -2158,14 +2177,10 @@ vector SICard::codeLogData(int row) const log.push_back(itos(CardNumber)); log.push_back(""); log.push_back(""); - wstring fn(FirstName), ln(LastName), cn(Club); - string fnn(fn.begin(), fn.end()); - string lnn(ln.begin(), ln.end()); - string cnn(cn.begin(), cn.end()); - log.push_back(fnn); - log.push_back(lnn); - log.push_back(cnn); + log.push_back(gdi.recodeToNarrow(firstName)); + log.push_back(gdi.recodeToNarrow(lastName)); + log.push_back(gdi.recodeToNarrow(club)); log.push_back(""); log.push_back(""); log.push_back(""); @@ -2179,11 +2194,12 @@ vector SICard::codeLogData(int row) const log.push_back(""); log.push_back(""); - //We set monday on every punch, since this is our way of - //saying that we have 24-h clock. + string indicator24 = convertedTime == ConvertedTimeStatus::Hour12 ? "" : "MO"; + + //We set monday on every punch for 24-hour clock, since this indicates 24-hour support. Empty for 12-hour punch if (signed(CheckPunch.Code) >= 0) { log.push_back(itos(CheckPunch.Code)); - log.push_back("MO"); + log.push_back(indicator24); log.push_back(formatTimeN(CheckPunch.Time)); } else { @@ -2194,7 +2210,7 @@ vector SICard::codeLogData(int row) const if (signed(StartPunch.Code) >= 0) { log.push_back(itos(StartPunch.Code)); - log.push_back("MO"); + log.push_back(indicator24); log.push_back(formatTimeN(StartPunch.Time)); } else { @@ -2205,7 +2221,7 @@ vector SICard::codeLogData(int row) const if (signed(FinishPunch.Code) >= 0) { log.push_back(itos(FinishPunch.Code)); - log.push_back("MO"); + log.push_back(indicator24); log.push_back(formatTimeN(FinishPunch.Time)); } else { @@ -2219,7 +2235,7 @@ vector SICard::codeLogData(int row) const if (k0) { - log.push_back("MO"); + log.push_back(indicator24); log.push_back(formatTimeN(Punch[k].Time)); } else { @@ -2316,6 +2332,7 @@ string SICard::serializePunches() const { } void SICard::deserializePunches(const string &arg) { + convertedTime = ConvertedTimeStatus::Hour24; FinishPunch.Code = -1; StartPunch.Code = -1; CheckPunch.Code = -1; @@ -2348,5 +2365,5 @@ void SICard::deserializePunches(const string &arg) { *tp = atoi(mark[1].c_str()); } if (out.size() == 1) - PunchOnly = true; + punchOnly = true; } diff --git a/code/SportIdent.h b/code/SportIdent.h index df6ec2b..9fe9570 100644 --- a/code/SportIdent.h +++ b/code/SportIdent.h @@ -40,6 +40,8 @@ const BYTE NAK=0x15; // This is taken from r56 and checked in on r63 #include +class gdioutput; + struct SICard5Detect { BYTE code;//Code; @@ -49,23 +51,34 @@ struct SICard5Detect WORD crc; }; -struct SIPunch -{ +struct SIPunch { DWORD Code; DWORD Time; + + void analyseHour12Time(DWORD zeroTime); +}; + +enum class ConvertedTimeStatus { + Unknown = 0, + Hour12, + Hour24, + Done, }; struct SICard { - SICard() { + SICard(ConvertedTimeStatus status) { clear(0); - convertedTime = false; + convertedTime = status; } // Clears the card if this == condition or condition is 0 void clear(const SICard *condition) { if (this==condition || condition==0) memset(this, 0, sizeof(SICard)); } + + void analyseHour12Time(DWORD zeroTime); + bool empty() const {return CardNumber==0;} DWORD CardNumber; SIPunch StartPunch; @@ -73,19 +86,19 @@ struct SICard SIPunch CheckPunch; DWORD nPunch; SIPunch Punch[192]; - wchar_t FirstName[21]; - wchar_t LastName[21]; - wchar_t Club[41]; + wchar_t firstName[21]; + wchar_t lastName[21]; + wchar_t club[41]; char readOutTime[32]; - bool PunchOnly; - bool convertedTime; + bool punchOnly; + ConvertedTimeStatus convertedTime; // Used for manual time input int runnerId; int relativeFinishTime; bool statusOK; bool statusDNF; - vector codeLogData(int row) const; + vector codeLogData(gdioutput &converter, int row) const; static vector logHeader(); unsigned calculateHash() const; @@ -147,7 +160,6 @@ protected: bool readSystemDataV2(SI_StationInfo &si); CRITICAL_SECTION SyncObj; - DWORD ZeroTime; //Used to analyse times. Seconds 0-24h (0-24*3600) int readByte_delay(BYTE &byte, HANDLE hComm); int readBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm); int readBytesDLE_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm); @@ -200,7 +212,6 @@ public: void getInfoString(const wstring &com, vector &info); bool isPortOpen(const wstring &com); - void setZeroTime(DWORD zt); bool autoDetect(list &ComPorts); void stopMonitorThread(); diff --git a/code/TabAuto.cpp b/code/TabAuto.cpp index 4b0437a..1fc314b 100644 --- a/code/TabAuto.cpp +++ b/code/TabAuto.cpp @@ -798,7 +798,7 @@ void PrintResultMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) wstring printError; lock = true; try { - gdioutput gdiPrint("print", gdi.getScale(), gdi.getCP()); + gdioutput gdiPrint("print", gdi.getScale()); gdiPrint.clearPage(false); oe->generateList(gdiPrint, true, listInfo, false); if (doPrint) { @@ -986,7 +986,7 @@ void PunchMachine::status(gdioutput &gdi) void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) { #ifndef MEOSDB - SICard sic; + SICard sic(ConvertedTimeStatus::Hour24); oe->generateTestCard(sic); SportIdent &si = TabSI::getSI(gdi); if (!sic.empty()) { @@ -998,7 +998,7 @@ void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) pRunner r=oe->getRunnerByCardNo(sic.CardNumber, 0, false); if (r && r->getCardNo()) { sic.CardNumber=r->getCardNo(); - sic.PunchOnly=true; + sic.punchOnly=true; sic.nPunch=1; sic.Punch[0].Code=radio; si.addCard(sic); diff --git a/code/TabClass.cpp b/code/TabClass.cpp index 7569970..1b46e7f 100644 --- a/code/TabClass.cpp +++ b/code/TabClass.cpp @@ -962,7 +962,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data) gdi.addSelection("Method", 200, 200, 0, L"Metod:"); gdi.addItem("Method", lang.tl("Lottning"), DMRandom); gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); - gdi.selectItemByData("Method", getDefaultMethod(false)); + gdi.selectItemByData("Method", getDefaultMethod({ DMRandom, DMSOFT })); gdi.fillDown(); gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie"); @@ -1566,7 +1566,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data) gdi.setRestorePoint("MultiDayDraw"); lastDrawMethod = NOMethod; - drawDialog(gdi, getDefaultMethod(true), *pc); + drawDialog(gdi, getDefaultMethod(getSupportedDrawMethods(multiDay)), *pc); } else if (bi.id == "HandleMultiDay") { ListBoxInfo lbi; @@ -1576,9 +1576,9 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data) if (!pc) throw std::exception("Class not found"); - if (gdi.isChecked(bi.id) && (lastDrawMethod == DMReversePursuit || + if (!gdi.isChecked(bi.id) && (lastDrawMethod == DMReversePursuit || lastDrawMethod == DMPursuit)) { - drawDialog(gdi, getDefaultMethod(false), *pc); + drawDialog(gdi, DMSOFT, *pc); } else setMultiDayClass(gdi, gdi.isChecked(bi.id), lastDrawMethod); @@ -2253,7 +2253,7 @@ void TabClass::showClassSettings(gdioutput &gdi) gdi.addItem("Method", lang.tl("Lottning"), DMRandom); gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); - gdi.selectItemByData("Method", getDefaultMethod(false)); + gdi.selectItemByData("Method", getDefaultMethod({DMRandom, DMSOFT})); gdi.addSelection("PairSize", 150, 200, 0, L"Tillämpa parstart:"); gdi.addItem("PairSize", getPairOptions()); @@ -3250,15 +3250,22 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) { if (lastDrawMethod == method) return; + bool noUpdate = false; + if (lastDrawMethod == DMPursuit && method == DMReversePursuit) - return; + noUpdate = true; if (lastDrawMethod == DMReversePursuit && method == DMPursuit) - return; + noUpdate = true; if (lastDrawMethod == DMRandom && method == DMSOFT) - return; + noUpdate = true; if (lastDrawMethod == DMSOFT && method == DMRandom) + noUpdate = true; + + if (noUpdate) { + lastDrawMethod = method; return; + } int firstStart = 3600, interval = 120, @@ -3281,7 +3288,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) { } gdi.restore("MultiDayDraw", false); - const bool multiDay = oe->hasPrevStage(); + const bool multiDay = oe->hasPrevStage() && gdi.isChecked("HandleMultiDay"); if (method == DMSeeded) { gdi.addString("", 10, "help:seeding_info"); @@ -3352,7 +3359,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) { gdi.addCheckbox("HandleBibs", "Tilldela nummerlappar:", ClassesCB, lastHandleBibs).setSynchData(&lastHandleBibs); gdi.dropLine(-0.2); gdi.addInput("Bib", L"", 10, 0, L"", L"Mata in första nummerlappsnummer, eller blankt för att ta bort nummerlappar"); - gdi.disableInput("Bib"); + gdi.setInputStatus("Bib", lastHandleBibs); gdi.fillDown(); gdi.dropLine(2.5); gdi.popX(); @@ -3390,6 +3397,16 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) { lastDrawMethod = method; } +set TabClass::getSupportedDrawMethods(bool hasMulti) const { + set base = { DMRandom, DMSOFT, DMClumped, DMSimultaneous, DMSeeded }; + if (hasMulti) { + base.insert(DMPursuit); + base.insert(DMReversePursuit); + } + + return base; +} + void TabClass::setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod) { gdi.clearList("Method"); @@ -3404,12 +3421,14 @@ void TabClass::setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaul gdi.addItem("Method", lang.tl("Omvänd jaktstart"), DMReversePursuit); } else if (defaultMethod > 10) - defaultMethod = getDefaultMethod(hasMulti); + defaultMethod = DMSOFT; gdi.selectItemByData("Method", defaultMethod); if (gdi.hasField("Vacanses")) { gdi.setInputStatus("Vacanses", !hasMulti); + } + if (gdi.hasField("HandleBibs")) { gdi.setInputStatus("HandleBibs", !hasMulti); if (hasMulti) { @@ -4078,28 +4097,12 @@ void TabClass::updateSplitDistribution(gdioutput &gdi, int num, int tot) const { gdi.refresh(); } -DrawMethod TabClass::getDefaultMethod(bool allowPursuit) const { - int dm = oe->getPropertyInt("DefaultDrawMethod", DMSOFT); - if (!allowPursuit) { - if (dm == DMRandom) - return DMRandom; - else - return DMSOFT; - } - else { - switch (dm) { - case DMRandom: - return DMRandom; - case DMPursuit: - return DMPursuit; - case DMReversePursuit: - return DMReversePursuit; - case DMSeeded: - return DMSeeded; - default: - return DMSOFT; - } - } +DrawMethod TabClass::getDefaultMethod(const set &allowedValues) const { + DrawMethod dm = (DrawMethod)oe->getPropertyInt("DefaultDrawMethod", DMSOFT); + if (allowedValues.count(dm)) + return dm; + else + return DMSOFT; } vector< pair > TabClass::getPairOptions() { diff --git a/code/TabClass.h b/code/TabClass.h index 638ee08..996068a 100644 --- a/code/TabClass.h +++ b/code/TabClass.h @@ -76,6 +76,8 @@ class TabClass : DrawInfo drawInfo; void setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod); + set getSupportedDrawMethods(bool multiDay) const; + void drawDialog(gdioutput &gdi, DrawMethod method, const oClass &cls); void pursuitDialog(gdioutput &gdi); @@ -136,7 +138,7 @@ class TabClass : void updateSplitDistribution(gdioutput &gdi, int numInClass, int tot) const; - DrawMethod getDefaultMethod(bool allowPursuit) const; + DrawMethod getDefaultMethod(const set &allowedValues) const; void enableLoadSettings(gdioutput &gdi); diff --git a/code/TabCompetition.cpp b/code/TabCompetition.cpp index 17de3a9..a103d63 100644 --- a/code/TabCompetition.cpp +++ b/code/TabCompetition.cpp @@ -134,7 +134,6 @@ bool TabCompetition::save(gdioutput &gdi, bool write) oe->setZeroTime(zt); oe->synchronize(); - if (gSI) gSI->setZeroTime(oe->getZeroTimeNum()); gdi.setWindowTitle(oe->getTitleName()); gdi.setText("Date", oe->getDate()); @@ -159,7 +158,6 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi) gdi.setWaitCursor(true); if (oe->open(fileName, true)) { - if (gSI) gSI->setZeroTime(oe->getZeroTimeNum()); gdi.setWindowTitle(oe->getTitleName()); resetSaveTimer(); return true; @@ -1766,7 +1764,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data) oListInfo li; par.selection = allTransfer; oe->generateListInfo(par, gdi.getLineHeight(), li); - gdioutput tGdi("temp", gdi.getScale(), gdi.getCP()); + gdioutput tGdi("temp", gdi.getScale()); oe->generateList(tGdi, true, li, false); tGdi.writeTableHTML(save, oe->getName(), 0); tGdi.openDoc(save.c_str()); @@ -1851,7 +1849,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data) par.setLegNumberCoded(-1); oListInfo li; oe->generateListInfo(par, gdi.getLineHeight(), li); - gdioutput tGdi("temp", gdi.getScale(), gdi.getCP()); + gdioutput tGdi("temp", gdi.getScale()); oe->generateList(tGdi, true, li, false); tGdi.writeTableHTML(save, oe->getName(), 0); tGdi.openDoc(save.c_str()); @@ -2286,7 +2284,6 @@ void TabCompetition::openCompetition(gdioutput &gdi, int id) { err = ex.wwhat(); } - if (gSI) gSI->setZeroTime(oe->getZeroTimeNum()); resetSaveTimer(); oe->setProperty("LastCompetition", id); gdi.setWindowTitle(oe->getTitleName()); @@ -2308,8 +2305,6 @@ int TabCompetition::restoreCB(gdioutput &gdi, int type, void *data) { gdi.alert("Kunde inte öppna tävlingen."); } else { - if (gSI) gSI->setZeroTime(oe->getZeroTimeNum()); - const wstring &name = oe->getName(); if (name.find_last_of(L"}") != name.length()-1) oe->setName(name + L" {" + lang.tl(L"ĺterställd") + L"}"); @@ -3903,8 +3898,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) { gdi.fillRight(); gdi.pushX(); fields.push_back("MaxTime"); - if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining) && - oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) { + if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) { fields.push_back("DiffTime"); } gdi.fillDown(); diff --git a/code/TabRunner.cpp b/code/TabRunner.cpp index 0a8bd9a..a9041ec 100644 --- a/code/TabRunner.cpp +++ b/code/TabRunner.cpp @@ -877,7 +877,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data) pRunner r=oe->getRunner(runnerId, 0); if (!r) return 0; - gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); + gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter); if (bi.getExtraInt() == 0) r->printSplits(gdiprint); else @@ -1053,7 +1053,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data) auto &db = oe->getRunnerDatabase(); bool show = false; if (ii.text.length() > 1) { - auto dbClub = extractClub(gdi); + auto dbClub = extractClub(oe, gdi); auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10); if (!rw.empty()) { auto &ac = gdi.addAutoComplete(ii.id); @@ -3024,7 +3024,7 @@ void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) { gdi.TabFocus(1); } -pClub TabRunner::extractClub(gdioutput &gdi) { +pClub TabRunner::extractClub(oEvent *oe, gdioutput &gdi) { oClub *dbClub = nullptr; if (gdi.hasField("Club")) { auto &db = oe->getRunnerDatabase(); diff --git a/code/TabRunner.h b/code/TabRunner.h index 3291bf9..2b4988e 100644 --- a/code/TabRunner.h +++ b/code/TabRunner.h @@ -109,8 +109,9 @@ private: protected: void clearCompetitionData(); - pClub extractClub(gdioutput &gdi); public: + static pClub extractClub(oEvent *oe, gdioutput &gdi); + void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override; const char * getTypeStr() const {return "TRunnerTab";} diff --git a/code/TabSI.cpp b/code/TabSI.cpp index 00a9966..ef20be9 100644 --- a/code/TabSI.cpp +++ b/code/TabSI.cpp @@ -48,12 +48,12 @@ #include "recorder.h" #include "autocomplete.h" -TabSI::TabSI(oEvent *poe):TabBase(poe) { +TabSI::TabSI(oEvent *poe):TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) { editCardData.tabSI = this; directEntryGUI.tabSI = this; interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0; - useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0; + useDatabase = poe->getPropertyInt("Database", 1)!=0; printSplits = false; printStartInfo = false; savedCardUniqueId = 1; @@ -89,7 +89,7 @@ static void entryTips(gdioutput &gdi) { } -void TabSI::logCard(const SICard &card) +void TabSI::logCard(gdioutput &gdi, const SICard &card) { if (logger == 0) { logger = new csvparser; @@ -104,7 +104,7 @@ void TabSI::logCard(const SICard &card) logcounter = 0; } - vector log = card.codeLogData(++logcounter); + vector log = card.codeLogData(gdi, ++logcounter); logger->outputRow(log); } @@ -143,8 +143,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) vector head = SICard::logHeader(); saver.outputRow(head); int count = 0; - for (list< pair >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) { - vector log = it->second.codeLogData(++count); + for (auto it = savedCards.begin(); it != savedCards.end(); ++it) { + vector log = it->second.codeLogData(gdi, ++count); saver.outputRow(log); } } @@ -492,14 +492,16 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) } } else if (bi.id=="Save") { - SICard sic; - sic.clear(0); + SICard sic(ConvertedTimeStatus::Hour24); sic.CheckPunch.Code = -1; sic.CardNumber=gdi.getTextNo("SI"); int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum()); int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum()); + if (f < s) { + f += 24 * 3600; + } sic.FinishPunch.Time= f % (24*3600); - sic.StartPunch.Time = f % (24*3600); + sic.StartPunch.Time = s % (24*3600); if (!gdi.isChecked("HasFinish")) { sic.FinishPunch.Code = -1; sic.FinishPunch.Time = 0; @@ -521,10 +523,20 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) gdi.getRecorder().record("insertCard(" + itos(sic.CardNumber) + ", \"" + sic.serializePunches() + "\"); //Readout card"); + if (false) { + sic.convertedTime = ConvertedTimeStatus::Hour12; + sic.StartPunch.Time %= (12 * 3600); + sic.FinishPunch.Time %= (12 * 3600); + sic.CheckPunch.Time %= (12 * 3600); + for (unsigned i = 0; i < sic.nPunch; i++) { + sic.Punch[i].Time %= (12 * 3600); + } + } + gSI->addCard(sic); } else if (bi.id=="SaveP") { - SICard sic; + SICard sic(ConvertedTimeStatus::Hour24); sic.clear(0); sic.FinishPunch.Code = -1; sic.CheckPunch.Code = -1; @@ -535,7 +547,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) if (f > 0) { sic.FinishPunch.Time = f; sic.FinishPunch.Code = 1; - sic.PunchOnly = true; + sic.punchOnly = true; gSI->addCard(sic); return 0; } @@ -544,7 +556,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) if (s > 0) { sic.StartPunch.Time = s; sic.StartPunch.Code = 1; - sic.PunchOnly = true; + sic.punchOnly = true; gSI->addCard(sic); return 0; } @@ -552,7 +564,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) sic.Punch[sic.nPunch].Code=gdi.getTextNo("C1"); sic.Punch[sic.nPunch].Time=convertAbsoluteTimeHMS(gdi.getText("C2"), oe->getZeroTimeNum()); sic.nPunch = 1; - sic.PunchOnly = true; + sic.punchOnly = true; gSI->addCard(sic); } else if (bi.id=="Cancel") { @@ -626,7 +638,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) gdi.pushX(); SICard si_copy=activeSIC; - gEvent->convertTimes(si_copy); + gEvent->convertTimes(nullptr, si_copy); //Find matching class... vector classes; @@ -828,6 +840,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) gdi.getSelectedItem("Class", lbi); if (signed(lbi.data)<=0) { + if (oe->getNumClasses() > 0) { + gdi.alert(L"Ingen klass vald"); + return 0; + } pClass pc = oe->getClassCreate(0, lang.tl(L"Öppen klass")); lbi.data = pc->getId(); pc->setAllowQuickEntry(true); @@ -975,7 +991,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) gdi.restore("ManualInput", false); - SICard sic; + SICard sic(ConvertedTimeStatus::Hour24); sic.runnerId = runnerMatchedId; sic.relativeFinishTime = relTime; sic.statusOK = ok; @@ -1011,7 +1027,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) } else if (bi.id == "CCSPrint") { //gdi.print(oe); - gdioutput gdiPrint("print", gdi.getScale(), gdi.getCP()); + gdioutput gdiPrint("print", gdi.getScale()); gdiPrint.clearPage(false); int tCardPosX = cardPosX; @@ -1135,7 +1151,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) if ((gdi.getData("RunnerId", rid) && rid>0) || !gdi.getText("Club", true).empty()) return 0; // Selected from list - if (!bi.text.empty() && useDatabase) { + if (!bi.text.empty() && showDatabase()) { pRunner db_r = oe->dbLookUpByName(bi.text, 0, 0, 0); if (!db_r && lastClubId) db_r = oe->dbLookUpByName(bi.text, lastClubId, 0, 0); @@ -1151,8 +1167,27 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) else if (type == GUI_COMBOCHANGE) { ListBoxInfo bi=*(ListBoxInfo *)data; if (bi.id == "Runners") { - inputId++; - gdi.addTimeoutMilli(300, "AddRunnerInteractive", SportIdentCB).setExtra(inputId); + + if (!showDatabase()) { + inputId++; + gdi.addTimeoutMilli(300, "AddRunnerInteractive", SportIdentCB).setExtra(inputId); + } + + bool show = false; + if (showDatabase() && bi.text.length() > 1) { + auto rw = oe->getRunnerDatabase().getRunnerSuggestions(bi.text, 0, 20); + if (!rw.empty()) { + auto &ac = gdi.addAutoComplete(bi.id); + ac.setAutoCompleteHandler(this); + vector items = getRunnerAutoCompelete(oe->getRunnerDatabase(), rw, 0); + ac.setData(items); + ac.show(); + show = true; + } + } + if (!show) { + gdi.clearAutoComplete(bi.id); + } } } else if (type == GUI_EVENT) { @@ -1160,6 +1195,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) if (ev.id == "AutoComplete") { pRunner r = oe->getRunner(runnerMatchedId, 0); if (r) { + gdi.clearAutoComplete(""); gdi.setInputFocus("OK1"); gdi.setText("Runners", r->getName()); gdi.setData("RunnerId", runnerMatchedId); @@ -1325,7 +1361,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data) gdi.addTimeoutMilli(50, "TieCard", SportIdentCB).setExtra(runnerMatchedId); } else if (cardNo>0 && gdi.getText("Name").empty()) { - SICard sic; + SICard sic(ConvertedTimeStatus::Hour24); sic.clear(0); sic.CardNumber = cardNo; @@ -1482,7 +1518,6 @@ SportIdent &TabSI::getSI(const gdioutput &gdi) { if (!gSI) { HWND hWnd=gdi.getHWNDMain(); gSI = new SportIdent(hWnd, 0); - gSI->setZeroTime(gEvent->getZeroTimeNum()); } return *gSI; } @@ -1767,6 +1802,35 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic) return; } else if (mode == ModeCardData) { + if (sic.convertedTime == ConvertedTimeStatus::Hour12) { + int locTime = getLocalAbsTime(); + int st = -1; + if (sic.StartPunch.Code != -1) + st = sic.StartPunch.Time; + else if (sic.nPunch > 0 && sic.Punch[0].Code != -1) + st = sic.Punch[0].Time; + + if (st == -1) + st = (locTime + 3600 * 20) % (12 * 3600); + else { + // We got a start time. Calculate running time + if (sic.FinishPunch.Code != -1) { + int rt = (sic.FinishPunch.Time - st + 12 * 3600) % (12 * 3600); + + // Adjust to local time at start; + locTime = (locTime - rt + (24 * 3600)) % (24 * 3600); + } + } + int zt1 = (st + 23 * 3600) % (24 * 3600); + int zt2 = st + 11 * 3600; + int d1 = min(abs(locTime - zt1), abs(locTime - zt1 + 3600 * 24)); + int d2 = min(abs(locTime - zt2), abs(locTime - zt2 + 3600 * 24)); + + if (d1 < d2) + sic.analyseHour12Time(zt1); + else + sic.analyseHour12Time(zt2); + } savedCards.push_back(make_pair(savedCardUniqueId++, sic)); if (printSplits) { @@ -1789,7 +1853,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic) gEvent->synchronizeList(oLCardId, true, false); gEvent->synchronizeList(oLRunnerId, false, true); - if (sic.PunchOnly) { + if (sic.punchOnly) { processPunchOnly(gdi, sic); return; } @@ -1810,7 +1874,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic) throw meosException("Internal error"); //SIPage not loaded... - if (!r && useDatabase) + if (!r && showDatabase()) r=autoMatch(sic, 0); // Assign a class if not already done @@ -1907,7 +1971,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic) if (sic.runnerId == 0) { r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, !readBefore); - if (!r && useDatabase) { + if (!r && showDatabase()) { //Look up in database. db_r = gEvent->dbLookUpByCard(sic.CardNumber); if (db_r) @@ -1964,17 +2028,17 @@ void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunn gdi.fillRight(); gdi.pushX(); - gdi.addCombo("Runners", 200, 300, SportIdentCB, L"Namn:"); + gdi.addCombo("Runners", 300, 300, SportIdentCB, L"Namn:"); gEvent->fillRunners(gdi, "Runners", false, oEvent::RunnerFilterOnlyNoResult); if (db_r){ gdi.setText("Runners", db_r->getName()); //Data from DB } - else if (sic.FirstName[0] || sic.LastName[0]){ //Data from SI-card - gdi.setText("Runners", wstring(sic.FirstName)+L" "+sic.LastName); + else if (sic.firstName[0] || sic.lastName[0]){ //Data from SI-card + gdi.setText("Runners", wstring(sic.lastName) + L", " + sic.firstName); } if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { - gdi.addCombo("Club", 200, 300, 0, L"Klubb:"); + gdi.addCombo("Club", 200, 300, 0, L"Klubb:").setHandler(&directEntryGUI); gEvent->fillClubs(gdi, "Club"); if (db_r) @@ -2082,10 +2146,10 @@ bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent) wstring warnings; // Write read card to log - logCard(sic); + logCard(gdi, sic); // Convert punch times to relative times. - gEvent->convertTimes(sic); + gEvent->convertTimes(nullptr, sic); if (sic.CheckPunch.Code!=-1) card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0); @@ -2235,10 +2299,10 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool info += runner->getClass(true); // Write read card to log - logCard(sic); + logCard(gdi, sic); // Convert punch times to relative times. - oe->convertTimes(sic); + oe->convertTimes(runner, sic); pCourse prelCourse = runner->getCourse(false); const int finishPT = prelCourse ? prelCourse->getFinishPunchType() : oPunch::PunchFinish; bool hasFinish = false; @@ -2395,7 +2459,7 @@ void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic) { SICard sic=csic; DWORD loaded; - gEvent->convertTimes(sic); + gEvent->convertTimes(nullptr, sic); oFreePunch *ofp=0; if (sic.nPunch==1) @@ -2442,7 +2506,7 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic) wstring name; wstring club; int age = 0; - if (useDatabase) { + if (showDatabase()) { pRunner db_r=oe->dbLookUpByCard(sic.CardNumber); if (db_r) { @@ -2453,8 +2517,8 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic) } //Else get name from card - if (name.empty() && (sic.FirstName[0] || sic.LastName[0])) - name=wstring(sic.LastName) + L", " + wstring(sic.FirstName); + if (name.empty() && (sic.firstName[0] || sic.lastName[0])) + name=wstring(sic.lastName) + L", " + wstring(sic.firstName); gdi.setText("Name", name); if (gdi.hasField("Club")) @@ -2565,7 +2629,15 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:").setHandler(&directEntryGUI); gdi.addSelection("Class", 150, 200, 0, L"Klass:").setHandler(&directEntryGUI); - oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect); + { + vector< pair > d; + oe->fillClasses(d, oEvent::extraNumMaps, oEvent::filterOnlyDirect); + if (d.empty() && oe->getNumClasses() > 0) { + gdi.alert(L"Inga klasser tillĺter direktanmälan. Pĺ sidan klasser kan du ändra denna egenskap."); + } + gdi.addItem("Class", d); + } + if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) { } else if (!gdi.selectItemByData("Class", lastClassId)) { @@ -2703,7 +2775,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi) while(checkpPrintQueue(gdi)); } else { - gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); + gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter); vector mp; r->evaluateCard(true, mp); r->printSplits(gdiprint); @@ -2714,7 +2786,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi) void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) { if (printStartInfo) { - gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); + gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter); r.printStartInfo(gdiprint); printProtected(gdi, gdiprint); //gdiprint.print(splitPrinter, oe, false, true); @@ -2985,9 +3057,9 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty gdi.removeControl("CancelCard"); wstring name, club; - if (card.FirstName[0]) - name = wstring(card.FirstName) + (card.LastName[0] ? (L" " + wstring(card.LastName)) : L""); - club = card.Club; + if (card.firstName[0]) + name = (card.lastName[0] ? (wstring(card.lastName) + L", ") : L"") + wstring(card.firstName); + club = card.club; bool noName = name.empty(); bool noClub = club.empty(); if (noName) @@ -3017,9 +3089,9 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty wstring club = gdi.getBaseInfo("ClubName").getExtra() ? L"" : gdi.getText("ClubName"); wstring given = getGivenName(name); wstring familty = getFamilyName(name); - wcsncpy_s(card.FirstName, given.c_str(), 20); - wcsncpy_s(card.LastName, familty.c_str(), 20); - wcsncpy_s(card.Club, club.c_str(), 40); + wcsncpy_s(card.firstName, given.c_str(), 20); + wcsncpy_s(card.lastName, familty.c_str(), 20); + wcsncpy_s(card.club, club.c_str(), 40); wstring s = name; if (!club.empty()) @@ -3049,9 +3121,9 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const { gdi.pushX(); gdi.fillRight(); wstring name, clubName; - if (c.FirstName[0] != 0) { - name = wstring(c.FirstName) + L" " + c.LastName; - clubName = c.Club; + if (c.firstName[0] != 0) { + name = wstring(c.firstName) + L" " + c.lastName; + clubName = c.club; } else { const RunnerWDBEntry *r = oe->getRunnerDatabase().getRunnerByCard(c.CardNumber); @@ -3060,12 +3132,12 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const { const oClub *club = oe->getRunnerDatabase().getClub(r->dbe().clubNo); if (club) { clubName = club->getName(); - wcsncpy_s(c.Club, clubName.c_str(), 20); + wcsncpy_s(c.club, clubName.c_str(), 20); } wstring given = r->getGivenName(); wstring family = r->getFamilyName(); - wcsncpy_s(c.FirstName, given.c_str(), 20); - wcsncpy_s(c.LastName, family.c_str(), 20); + wcsncpy_s(c.firstName, given.c_str(), 20); + wcsncpy_s(c.lastName, family.c_str(), 20); } } @@ -3164,7 +3236,7 @@ int TabSI::analyzePunch(SIPunch &p, int &start, int &accTime, int &days) { } void TabSI::generateSplits(int cardId, gdioutput &gdi) { - gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); + gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter); printCard(gdiprint, cardId, true); printProtected(gdi, gdiprint); } @@ -3266,15 +3338,15 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) { if (!cls.empty()) { wstring name; - if (cards[k].second->FirstName[0]) - name = cards[k].second->FirstName; - if (cards[k].second->LastName[0]) - name += L" " + wstring(cards[k].second->LastName); + if (cards[k].second->lastName[0]) + name = wstring(cards[k].second->lastName) + L", "; + if (cards[k].second->firstName[0]) + name += cards[k].second->firstName; if (name.empty()) name = lang.tl(L"Bricka X#" + itow(cards[k].second->CardNumber)); - oe->addRunner(name, wstring(cards[k].second->Club), cls[0]->getId(), + oe->addRunner(name, wstring(cards[k].second->club), cls[0]->getId(), cards[k].second->CardNumber, 0, true); processInsertCard(*cards[k].second); @@ -3487,8 +3559,7 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) { } } else if (cmd == "tickoff") { - SICard sic; - sic.clear(0); + SICard sic(ConvertedTimeStatus::Hour24); for (map::const_iterator it = checkedCardFlags.begin(); it != checkedCardFlags.end(); ++it) { int stat = it->second; @@ -3591,7 +3662,7 @@ bool TabSI::checkpPrintQueue(gdioutput &gdi) { return false; // Wait a little longer } - gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); + gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter); vector mp; for (size_t m = 0; m < printLen && !printPunchRunnerIdQueue.empty(); m++) { int rid = printPunchRunnerIdQueue.front().second; @@ -3720,7 +3791,7 @@ void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType else if (type == GUI_INPUTCHANGE) { InputInfo &ii = dynamic_cast(info); bool show = false; - if (tabSI->useDatabase && ii.id == "Name") { + if (tabSI->showDatabase() && ii.id == "Name") { auto &db = tabSI->oe->getRunnerDatabase(); if (ii.text.length() > 1) { auto dbClub = tabSI->extractClub(gdi); @@ -3801,3 +3872,8 @@ void TabSI::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) { gdi.clearAutoComplete(""); gdi.TabFocus(1); } + + +bool TabSI::showDatabase() const { + return useDatabase && oe->useRunnerDb(); +} diff --git a/code/TabSI.h b/code/TabSI.h index 89eda21..7a39b84 100644 --- a/code/TabSI.h +++ b/code/TabSI.h @@ -192,6 +192,8 @@ protected: public: + bool showDatabase() const; + static vector getRunnerAutoCompelete(RunnerDB &db, const vector< pair> &rw, pClub dbClub); void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override; @@ -231,7 +233,7 @@ public: int siCB(gdioutput &gdi, int type, void *data); - void logCard(const SICard &card); + void logCard(gdioutput &gdi, const SICard &card); void setCardNumberField(const string &fieldId) {insertCardNumberField=fieldId;} diff --git a/code/TabTeam.cpp b/code/TabTeam.cpp index 7f7bcd0..33fe3b4 100644 --- a/code/TabTeam.cpp +++ b/code/TabTeam.cpp @@ -42,6 +42,7 @@ #include "TabRunner.h" #include "MeOSFeatures.h" #include "RunnerDB.h" +#include "autocomplete.h" #include "TabSI.h" @@ -1058,6 +1059,29 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data) gdi.getTextNo("DirCard") > 0); } + + if (oe->useRunnerDb() && ii.id == "DirName") { + auto &db = oe->getRunnerDatabase(); + bool show = false; + if (ii.text.length() > 1) { + auto dbClub = TabRunner::extractClub(oe, gdi); + auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10); + if (dbClub != nullptr && rw.empty()) // Default: Any club + rw = db.getRunnerSuggestions(ii.text, 0, 10); + + if (!rw.empty()) { + auto &ac = gdi.addAutoComplete(ii.id); + ac.setAutoCompleteHandler(this); + + ac.setData(TabSI::getRunnerAutoCompelete(db, rw, dbClub)); + ac.show(); + show = true; + } + } + if (!show) { + gdi.clearAutoComplete(ii.id); + } + } } else if (type == GUI_INPUT) { InputInfo &ii=*(InputInfo *)data; @@ -1115,6 +1139,27 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data) } } + else if (type == GUI_COMBOCHANGE) { + ListBoxInfo &combo = *(ListBoxInfo *)(data); + bool show = false; + if (oe->useRunnerDb() && combo.id == "Club" && combo.text.length() > 1) { + auto clubs = oe->getRunnerDatabase().getClubSuggestions(combo.text, 20); + if (!clubs.empty()) { + auto &ac = gdi.addAutoComplete(combo.id); + ac.setAutoCompleteHandler(this); + vector items; + for (auto club : clubs) + items.emplace_back(club->getDisplayName(), club->getName(), club->getId()); + + ac.setData(items); + ac.show(); + show = true; + } + } + if (!show) { + gdi.clearAutoComplete(combo.id); + } + } else if (type==GUI_CLEAR) { if (teamId>0) save(gdi, true); @@ -1322,7 +1367,7 @@ bool TabTeam::loadPage(gdioutput &gdi) } if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { - gdi.addCombo("Club", 180, 300, 0, L"Klubb:"); + gdi.addCombo("Club", 180, 300, TeamCB, L"Klubb:"); oe->fillClubs(gdi, "Club"); drop = true; } @@ -1897,3 +1942,26 @@ bool TabTeam::warnDuplicateCard(gdioutput &gdi, string id, int cno, pRunner r, v return false; } } + +void TabTeam::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) { + auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str()); + if (bi) { + int ix = info.getCurrentInt(); + bi->setExtra(ix); + if (info.getTarget() == "Name") { + auto &db = oe->getRunnerDatabase(); + auto runner = db.getRunnerByIndex(ix); + + if (runner && gdi.hasField("Club") && gdi.getText("Club").empty()) { + pClub club = db.getClub(runner->dbe().clubNo); + if (club) + gdi.setText("Club", club->getName()); + } + if (runner && runner->dbe().cardNo > 0 && gdi.hasField("DirCard") && gdi.getText("DirCard").empty()) { + gdi.setText("DirCard", runner->dbe().cardNo); + } + } + } + gdi.clearAutoComplete(""); + gdi.TabFocus(1); +} diff --git a/code/TabTeam.h b/code/TabTeam.h index b959560..5fc2b98 100644 --- a/code/TabTeam.h +++ b/code/TabTeam.h @@ -21,11 +21,12 @@ ************************************************************************/ #include "tabbase.h" +#include "autocompletehandler.h" struct TeamLineup; class TabTeam : - public TabBase + public TabBase, AutoCompleteHandler { private: bool save(gdioutput &gdi, bool dontReloadTeams); @@ -73,11 +74,11 @@ private: void switchRunners(pTeam team, int leg, pRunner r, pRunner oldR); - protected: void clearCompetitionData(); public: + void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override; const char * getTypeStr() const {return "TTeamTab";} TabType getType() const {return TTeamTab;} diff --git a/code/Table.cpp b/code/Table.cpp index bf2bdfb..694a3ad 100644 --- a/code/Table.cpp +++ b/code/Table.cpp @@ -756,7 +756,7 @@ bool Table::keyCommand(gdioutput &gdi, KeyCommandCode code) { gdi.refresh(); } else if (code == KC_PRINT) { - gdioutput gdiPrint("temp", gdi.getScale(), gdi.getCP()); + gdioutput gdiPrint("temp", gdi.getScale()); gdiPrint.clearPage(false); gdiPrint.print(getEvent(), this); } diff --git a/code/csvparser.cpp b/code/csvparser.cpp index 03d1591..46dcaa4 100644 --- a/code/csvparser.cpp +++ b/code/csvparser.cpp @@ -839,17 +839,11 @@ bool csvparser::importPunches(const oEvent &oe, const wstring &file, vector0) - t = oe.getRelativeTime(time); - else - t = oe.getRelativeTimeFrom12Hour(time); - - if (t<0) - t=0; - + int t = oEvent::convertAbsoluteTime(time); + if (t >= 0 && trim(dow).empty()) + is12Hour = true; return t; } @@ -935,10 +929,10 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector &sp, S if (cardNo < 1000 || cardNo > 99999999) return false; - - int check = analyseSITime(oe, getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp)); - int start = analyseSITime(oe, getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp)); - int finish = analyseSITime(oe, getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp)); + bool is12Hour = false; + int check = analyseSITime(getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp), is12Hour); + int start = analyseSITime(getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp), is12Hour); + int finish = analyseSITime(getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp), is12Hour); int startCode = wtoi(getSIC(sicStart, sp)); int finishCode = wtoi(getSIC(sicFinish, sp)); int checkCode = wtoi(getSIC(sicCheck, sp)); @@ -954,7 +948,7 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector &sp, S if (ix+2 >= sp.size()) return false; int code = wtoi(sp[ix]); - int time = analyseSITime(oe, sp[ix+1].c_str(), sp[ix+2].c_str()); + int time = analyseSITime(sp[ix+1].c_str(), sp[ix+2].c_str(), is12Hour); if (code > 0) { punches.push_back(make_pair(code, time)); } @@ -998,12 +992,12 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector &sp, S card.Punch[k].Time = punches[k].second; } - wcsncpy_s(card.FirstName, fname.c_str(), 20); - card.FirstName[20] = 0; - wcsncpy_s(card.LastName, lname.c_str(), 20); - card.LastName[20] = 0; + wcsncpy_s(card.firstName, fname.c_str(), 20); + card.firstName[20] = 0; + wcsncpy_s(card.lastName, lname.c_str(), 20); + card.lastName[20] = 0; card.nPunch = punches.size(); - card.convertedTime = true; + card.convertedTime = is12Hour ? ConvertedTimeStatus::Hour12 : ConvertedTimeStatus::Hour24; return true; } @@ -1061,7 +1055,7 @@ bool csvparser::checkSimanLine(const oEvent &oe, const vector &sp, SICa card.Punch[k].Time = punches[k].second; } card.nPunch = punches.size(); - card.convertedTime = false; + card.convertedTime = ConvertedTimeStatus::Hour24; //XXX Not correct in general return true; } @@ -1098,7 +1092,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector &sp = *it; - SICard card; + SICard card(ConvertedTimeStatus::Unknown); if (checkSimanLine(oe, sp, card)) { cards.push_back(card); @@ -1111,13 +1105,13 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector28) { int no = wtoi(sp[0]); card.CardNumber = wtoi(sp[2]); - wcsncpy_s(card.FirstName, sp[5].c_str(), 20); - wcsncpy_s(card.LastName, sp[6].c_str(), 20); - wcsncpy_s(card.Club, sp[7].c_str(), 40); - + wcsncpy_s(card.firstName, sp[5].c_str(), 20); + wcsncpy_s(card.lastName, sp[6].c_str(), 20); + wcsncpy_s(card.club, sp[7].c_str(), 40); + bool hour12 = false; if (trim(sp[21]).length()>1) { card.CheckPunch.Code = wtoi(sp[19]); - card.CheckPunch.Time = analyseSITime(oe, sp[20].c_str(), sp[21].c_str()); + card.CheckPunch.Time = analyseSITime(sp[20].c_str(), sp[21].c_str(), hour12); } else { card.CheckPunch.Code = -1; @@ -1126,7 +1120,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector1) { card.StartPunch.Code = wtoi(sp[22]); - card.StartPunch.Time = analyseSITime(oe, sp[23].c_str(), sp[24].c_str()); + card.StartPunch.Time = analyseSITime(sp[23].c_str(), sp[24].c_str(), hour12); } else { card.StartPunch.Code = -1; @@ -1135,7 +1129,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector1) { card.FinishPunch.Code = wtoi(sp[25]); - card.FinishPunch.Time = analyseSITime(oe, sp[26].c_str(), sp[27].c_str()); + card.FinishPunch.Time = analyseSITime(sp[26].c_str(), sp[27].c_str(), hour12); } else { card.FinishPunch.Code = -1; @@ -1147,11 +1141,11 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector28+3*card.nPunch) { for (unsigned k=0;k kræver at alle poster er radioposter eller at MeOS kun bruges til tidtagning uden baner.\n\nSkal resultat ved mĂĄlstempling aktiveres? +warning:direct_result = OBS. brug af kræver at alle poster er radioposter eller at MeOS kun bruges til tidtagning uden baner.\n\nSkal resultat ved mĂĄlstempling aktiveres? warning:drawresult = Klassen har allerede resultater, starttider overskrives. Vil du fortsætte? warning:has_entries = Klassen har allerede løbere. Hvis du ændrer turfordelingen kan du miste data.\n\nVil du fortsætte? warning:has_results = Klassen har allerede resultater. Ændring af turfordelingen er usædvanligt.\n\nVil du fortsætte? diff --git a/code/english.lng b/code/english.lng index 5003202..8be6e43 100644 --- a/code/english.lng +++ b/code/english.lng @@ -12,7 +12,7 @@ ALLA( = All( API-nyckel = API key Accepterade elektroniska fakturor = Accepted electronic invoices Adress = Address -Adress och kontakt = Address and contact +Adress och kontakt = Address and Contact Aktivera = Activate Alla = All Alla banfiler = All course files @@ -127,7 +127,7 @@ Behandlar: X = Processing: X Bekräfta att %s byter klass till %s = Please confirm that %s changes class to %s Bekräfta att deltagaren har lämnat ĂĄterbud = Please confirm drop out of this runner Betalat = Paid -Betalningsinformation = Payment details +Betalningsinformation = Payment Details Bevakar händelser i X = Monitoring events in X Bevakningsprioritering = Select runner to watch Block = Block @@ -1115,7 +1115,7 @@ Tävlingsinställningar = Competition Settings Tävlingsinställningar (IOF, xml) = Competition settings (IOF, xml) Tävlingsnamn = Competition name Tävlingsrapport = Competition Report -Tävlingsregler = Competition rules +Tävlingsregler = Competition Rules Tävlingsstatistik = Competition Statistics Underlag för tävlingsavgift = Data for competition fee Underlista = Sub list @@ -1422,7 +1422,7 @@ xml-data = xml data Ă…ldersfilter = Age filter Ă…ldersgräns ungdom = Age limit, low Ă…ldersgräns äldre = Age limit, high -Ă…ldersgränser, reducerad anmälningsavgift = Age limits, fee reduction +Ă…ldersgränser, reducerad anmälningsavgift = Age Limits, Fee Reduction Ă…ngra = Undo Ă…teransluten mot databasen, tävlingen synkroniserad = Reconnected to database, competition synchronized Ă…terbud = Drop Out @@ -2249,9 +2249,9 @@ Det finns anmälningsdata för flera etapper = There is entry data for several s Välj etapp att importera = Select stage to import ask:savespeaker = Do you wish to save current class and window settings on this computer? Spara fönster- och speakerinställningar pĂĄ datorn = Save windows and settings on this computer -ask:loadspeaker = Do you wish to re-create previously saved windows on this computer? -Ă…terskapa = Re-create -Ă…terskapa tidigare sparade fönster- och speakerinställningar = Re-create previously saved windows and settings +ask:loadspeaker = Do you wish to recreate previously saved windows on this computer? +Ă…terskapa = Recreate +Ă…terskapa tidigare sparade fönster- och speakerinställningar = Recreate previously saved windows and settings Inkludera resultat frĂĄn tidigare etapper = Include results from all stages Animation = Animation Bakgrund = Background @@ -2292,7 +2292,7 @@ Informationsserver = Information server Längsta svarstid: X ms = Longest response time: X ms MeOS Informationsserver REST-API = MeOS Information Server REST-API Testa servern = Test the server -help:rest = MeOS REST API lets you access competition data via a webb connection. You can show result lists directly in a webb browser, but you can also request competition data and results in a XML format, suitble for further processing in third party programs and apps. +help:rest = MeOS REST API lets you access competition data via a web connection. You can show result lists directly in a web browser, but you can also request competition data and results in an XML format, suitable for further processing in third party programs and apps. Server startad pĂĄ X = Server running on port X Inconsistent qualification rule, X = Inconsistent qualification rule, X help:LockStartList = MeOS will not update assignement to a locked class even if qualification results are altered. @@ -2301,7 +2301,7 @@ LĂĄs startlista = Lock start list FilterNoCancel = Not cancelled CourseStartTime = Course, start time Startlista, banvis = Start list, by course -Stämplingsintervall, rogaining-patrull = Punch interval within Rogaining patrol +Stämplingsintervall, rogaining-patrull = Punch interval within rogaining patrol Patrullresultat (STOR) = Patrol results (LARGE) Patrol Team Rogaining = Patrol Team Rogaining Rogaining results for a patrol = Rogaining results for a patrol of two or more competitors. @@ -2313,3 +2313,5 @@ prefsDrawInterlace = Interlace class/course when drawing start lists prefsServicePort = Default service port Ingen nummerlapp = No bib Rogaining results for a team, where each team member collects points individually = Rogaining results for a team, where each team member collects points individually +prefsCodePage = Code table for 8 bit text on import/export. +Inga klasser tillĂĄter direktanmälan. PĂĄ sidan klasser kan du ändra denna egenskap. = No class is marked to allow quick entry.\n\nOn the page Classes you can change this property. diff --git a/code/gdioutput.cpp b/code/gdioutput.cpp index 753c55f..0fe4b9f 100644 --- a/code/gdioutput.cpp +++ b/code/gdioutput.cpp @@ -78,6 +78,7 @@ extern Image image; static int debugDrawColor = 0; #endif +extern int defaultCodePage; GuiHandler &BaseInfo::getHandler() const { if (handler == 0) @@ -106,9 +107,8 @@ bool gdioutput::skipTextRender(int format) { #ifndef MEOSDB -gdioutput::gdioutput(const string &_tag, double _scale, int defaultCodePage) : - recorder((Recorder *)0, false), - defaultCodePage(defaultCodePage) { +gdioutput::gdioutput(const string &_tag, double _scale) : + recorder((Recorder *)0, false) { tag = _tag; po_default = new PrinterObject(); tabs = 0; @@ -118,8 +118,8 @@ gdioutput::gdioutput(const string &_tag, double _scale, int defaultCodePage) : isTestMode = false; } -gdioutput::gdioutput(double _scale, HWND hWnd, const PrinterObject &prndef, int defaultCodePage) : - recorder((Recorder *)0, false), defaultCodePage(defaultCodePage) { +gdioutput::gdioutput(double _scale, HWND hWnd, const PrinterObject &prndef) : + recorder((Recorder *)0, false) { hasAnyTimer = false; po_default = new PrinterObject(prndef); tabs = 0; @@ -6378,9 +6378,9 @@ const wstring &gdioutput::widen(const string &input) { return output; } -const wstring &gdioutput::recodeToWide(const string &input) const { +const wstring &gdioutput::recodeToWide(const string &input) { wstring &output = StringCache::getInstance().wget(); - int cp = 1252; + int cp = defaultCodePage; // if (defaultCodePage > 0) // cp = defaultCodePage; @@ -6406,9 +6406,9 @@ const wstring &gdioutput::recodeToWide(const string &input) const { return output; } -const string &gdioutput::recodeToNarrow(const wstring &input) const { +const string &gdioutput::recodeToNarrow(const wstring &input) { string &output = StringCache::getInstance().get(); - int cp = 1252; + int cp = defaultCodePage; // if (defaultCodePage > 0) // cp = defaultCodePage; @@ -6428,10 +6428,12 @@ const string &gdioutput::recodeToNarrow(const wstring &input) const { output = ""; return output; } - output.reserve(input.size()+1); + int res = input.size() * 3 + 2; + output.reserve(res); output.resize(input.size(), 0); BOOL usedDef = false; - WideCharToMultiByte(cp, MB_PRECOMPOSED, input.c_str(), input.size(), &output[0], output.size(), "?", &usedDef); + int ok = WideCharToMultiByte(cp, 0, input.c_str(), input.size(), &output[0], res, "?", &usedDef); + return output; } /* diff --git a/code/gdioutput.h b/code/gdioutput.h index 0d235af..2997051 100644 --- a/code/gdioutput.h +++ b/code/gdioutput.h @@ -283,7 +283,6 @@ protected: shared_ptr animationData; shared_ptr autoCompleteInfo; - int defaultCodePage; public: AutoCompleteInfo &addAutoComplete(const string &key); @@ -324,8 +323,8 @@ public: bool isTest() const {return isTestMode;} const string &getTag() const {return tag;} bool hasTag(const string &t) const {return tag == t;} - const wstring &recodeToWide(const string &input) const; - const string &recodeToNarrow(const wstring &input) const; + static const wstring &recodeToWide(const string &input); + static const string &recodeToNarrow(const wstring &input); static const wstring &widen(const string &input); static const string &narrow(const wstring &input); @@ -752,13 +751,12 @@ public: void closeWindow(); void setDBErrorState(bool state); - int getCP() const {return defaultCodePage;} friend int TablesCB(gdioutput *gdi, int type, void *data); friend class Table; friend gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y); - gdioutput(const string &tag, double _scale, int defaultCodePage); - gdioutput(double _scale, HWND hWndTarget, const PrinterObject &defprn, int defaultCodePage); + gdioutput(const string &tag, double _scale); + gdioutput(double _scale, HWND hWndTarget, const PrinterObject &defprn); virtual ~gdioutput(); }; diff --git a/code/infoserver.cpp b/code/infoserver.cpp index f2cbb9f..ba2ce74 100644 --- a/code/infoserver.cpp +++ b/code/infoserver.cpp @@ -408,13 +408,18 @@ void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const { void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) const { vector< pair > prop; - prop.push_back(make_pair("org", itow(organizationId))); - prop.push_back(make_pair("cls", itow(classId))); - prop.push_back(make_pair("stat", itow(status))); - prop.push_back(make_pair("st", itow(startTime))); - prop.push_back(make_pair("rt", itow(runningTime))); + prop.reserve(10); + prop.emplace_back("org", itow(organizationId)); + prop.emplace_back("cls", itow(classId)); + prop.emplace_back("stat", itow(status)); + prop.emplace_back("st", itow(startTime)); + prop.emplace_back("rt", itow(runningTime)); if (course != 0) - prop.push_back(make_pair("crs", itow(course))); + prop.emplace_back("crs", itow(course)); + + if (!bib.empty()) { + prop.emplace_back("bib", bib); + } xml.write("base", prop, name); } @@ -459,6 +464,13 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) { runningTime = rt; ch = true; } + + wstring newBib = bc.getBib(); + if (bib != newBib) { + bib = newBib; + ch = true; + } + return ch; } diff --git a/code/infoserver.h b/code/infoserver.h index 658fc57..942e77b 100644 --- a/code/infoserver.h +++ b/code/infoserver.h @@ -156,6 +156,7 @@ class InfoBaseCompetitor : public InfoBase { int status; int startTime; int runningTime; + wstring bib; void serialize(xmlbuffer &xml, bool diffOnly, int course) const; bool synchronizeBase(oAbstractRunner &bc); public: diff --git a/code/meos.cpp b/code/meos.cpp index cbac65a..7b22de6 100644 --- a/code/meos.cpp +++ b/code/meos.cpp @@ -67,6 +67,7 @@ #include "autocomplete.h" #include "image.h" +int defaultCodePage = 1252; Image image; gdioutput *gdi_main=0; @@ -207,9 +208,13 @@ int APIENTRY WinMain(HINSTANCE hInstance, enableTests = true; } - HWND hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc); - ShowWindow(hSplash, SW_SHOW); - UpdateWindow(hSplash); + HWND hSplash = nullptr; + if (strstr(lpCmdLine, "-nosplash") == 0) { + hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc); + ShowWindow(hSplash, SW_SHOW); + UpdateWindow(hSplash); + } + DWORD splashStart = GetTickCount(); for (int k = 0; k < 100; k++) { @@ -253,7 +258,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HACCEL hAccelTable; - gdi_main = new gdioutput("main", 1.0, 0); + gdi_main = new gdioutput("main", 1.0); gdi_extra.push_back(gdi_main); try { @@ -297,6 +302,8 @@ int APIENTRY WinMain(HINSTANCE hInstance, wstring defLang = gEvent->getPropertyString("Language", L"Svenska"); + defaultCodePage = gEvent->getPropertyInt("CodePage", 1252); + // Backward compatibility if (defLang==L"103") defLang = L"Svenska"; @@ -399,8 +406,10 @@ int APIENTRY WinMain(HINSTANCE hInstance, gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0), gEvent->getPropertyString("TextFont", L"Arial")); - DWORD startupToc = GetTickCount() - splashStart; - Sleep(min(1000, max(0,700 - startupToc))); + if (hSplash != nullptr) { + DWORD startupToc = GetTickCount() - splashStart; + Sleep(min(1000, max(0, 700 - startupToc))); + } // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { @@ -424,8 +433,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, (HINSTANCE) NULL, GetCurrentThreadId()); hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS); - - + DestroyWindow(hSplash); initMySQLCriticalSection(true); @@ -852,7 +860,7 @@ gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); - gdioutput *gdi = new gdioutput(tag, 1.0, 0); + gdioutput *gdi = new gdioutput(tag, 1.0); gdi->setFont(gEvent->getPropertyInt("TextSize", 0), gEvent->getPropertyString("TextFont", L"Arial")); @@ -1160,7 +1168,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) //The card has been read and posted to a synchronized //queue by different thread. Read and process this card. { - SICard sic; + SICard sic(ConvertedTimeStatus::Unknown); while (gSI && gSI->getCard(sic)) InsertSICard(*gdi_main, sic); break; diff --git a/code/meos_util.cpp b/code/meos_util.cpp index 960274e..91680dd 100644 --- a/code/meos_util.cpp +++ b/code/meos_util.cpp @@ -38,7 +38,7 @@ namespace MeOSUtil { string convertSystemTimeN(const SYSTEMTIME &st); string convertSystemDateN(const SYSTEMTIME &st); string convertSystemTimeOnlyN(const SYSTEMTIME &st); - +extern int defaultCodePage; DWORD mainThreadId = -1; StringCache &StringCache::getInstance() { @@ -180,7 +180,7 @@ SYSTEMTIME Int64SecondToSystemTime(__int64 time) { //2014-11-03 07:02:00 string convertSystemTimeN(const SYSTEMTIME &st) { - char bf[32]; + char bf[64]; sprintf_s(bf, "%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); @@ -190,7 +190,7 @@ string convertSystemTimeN(const SYSTEMTIME &st) //2014-11-03 07:02:00 wstring convertSystemTime(const SYSTEMTIME &st) { - wchar_t bf[32]; + wchar_t bf[64]; swprintf_s(bf, L"%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); @@ -2167,7 +2167,7 @@ void processGeneralTime(const wstring &generalTime, wstring &meosTime, wstring & } void string2Wide(const string &in, wstring &out) { - int cp = 1252; + int cp = defaultCodePage; if (in.empty()) { out = L""; return; diff --git a/code/meosversion.cpp b/code/meosversion.cpp index f1272c0..bf0030f 100644 --- a/code/meosversion.cpp +++ b/code/meosversion.cpp @@ -29,7 +29,7 @@ //V33: abcde //V35: abcde int getMeosBuild() { - string revision("$Rev: 652 $"); + string revision("$Rev: 669 $"); return 174 + atoi(revision.substr(5, string::npos).c_str()); } @@ -39,14 +39,14 @@ int getMeosBuild() { //V31: abcde //V32: abcdefgh //V33: abcdefghij -//V34: abcdfg +//V34: abcdfge wstring getMeosDate() { - wstring date(L"$Date: 2018-03-04 09:44:43 +0100 (sö, 04 mar 2018) $"); + wstring date(L"$Date: 2018-03-25 07:29:55 +0200 (sö, 25 mar 2018) $"); return date.substr(7,10); } wstring getBuildType() { - return L"RC1"; // No parantheses (...) + return L"RC2"; // No parantheses (...) } wstring getMajorVersion() { @@ -185,4 +185,7 @@ void getSupporters(vector &supp) supp.push_back(L"O-Ringen AB"); supp.push_back(L"Hans Carlstedt, Sävedalens AIK"); supp.push_back(L"Attunda OK"); + supp.push_back(L"Siguldas Takas, Latvia"); + supp.push_back(L"Eric Teutsch, Ottawa Orienteering Club, Canada"); + supp.push_back(L"Silkeborg OK, Denmark"); } diff --git a/code/oCard.cpp b/code/oCard.cpp index fcbbb76..22d1a11 100644 --- a/code/oCard.cpp +++ b/code/oCard.cpp @@ -463,6 +463,7 @@ bool oCard::isCardRead(const SICard &card) const void oCard::getSICard(SICard &card) const { card.clear(0); card.CardNumber = cardNo; + card.convertedTime = ConvertedTimeStatus::Done; oPunchList::const_iterator it; for (it = punches.begin(); it != punches.end(); ++it) { if (it->Type>30) diff --git a/code/oClass.cpp b/code/oClass.cpp index 22ba792..656ce4c 100644 --- a/code/oClass.cpp +++ b/code/oClass.cpp @@ -1688,7 +1688,7 @@ void oClass::updateChangedCoursePool() { } } - SICard card; + SICard card(ConvertedTimeStatus::Unknown); oRunnerList::iterator it; for (it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { if (it->isRemoved() || it->Class != this) @@ -4284,6 +4284,17 @@ void oClass::loadQualificationFinalScheme(const wstring &fileName) { inst->synchronize(); } synchronize(); + for (oRunner &r : oe->Runners) { + if (r.getClassRef(false) == this) { + pTeam t = r.getTeam(); + if (t == 0) { + t = oe->addTeam(r.getName(), r.getClubId(), getId()); + t->setStartNo(r.getStartNo(), false); + t->setRunner(0, &r, true); + } + r.synchronizeAll(); + } + } } void oClass::updateFinalClasses(oRunner *causingResult, bool updateStartNumbers) { diff --git a/code/oEvent.cpp b/code/oEvent.cpp index 6b6fc2f..98c1469 100644 --- a/code/oEvent.cpp +++ b/code/oEvent.cpp @@ -579,6 +579,7 @@ void oEvent::listProperties(bool userProps, vector< pair > i.insert("addressxpos"); i.insert("AutoSaveTimeOut"); i.insert("ServicePort"); + i.insert("CodePage"); propNames.clear(); for(map::const_iterator it = eventProperties.begin(); @@ -924,7 +925,7 @@ bool oEvent::save(const wstring &fileIn) { xml.startTag("meosdata", "version", getMajorVersion()); xml.write("Name", Name); xml.write("Date", Date); - xml.write("ZeroTime", ZeroTime); + xml.write("ZeroTime", itos(ZeroTime)); xml.write("NameId", currentNameId); xml.write("Annotation", Annotation); xml.write("Id", Id); @@ -1119,6 +1120,7 @@ void oEvent::restoreBackup() bool oEvent::open(const xmlparser &xml) { xmlobject xo; + ZeroTime = 0; xo = xml.getObject("Date"); if (xo) Date=xo.getw(); @@ -2434,37 +2436,6 @@ int oEvent::getRelativeTime(const wstring &m) const { else return -1; } -int oEvent::getRelativeTimeFrom12Hour(const wstring &m) const -{ - int atime=convertAbsoluteTime(m); - - if (atime>=0 && atime<3600*24) { - int lowBound = ZeroTime; - int highBound = ZeroTime + 3600 * 12; - - bool ok = ( atime >= lowBound && atime <= highBound) || - ( (atime+3600*24) >= lowBound && (atime+3600*24) <= highBound); - - int rtime = atime - ZeroTime; - if (!ok) - rtime += 12 * 3600; - - rtime = (rtime+24*3600)%(24*3600); - - //int rtime=atime-(ZeroTime % (3600*12)); - -/* if (rtime<=0) - rtime+=3600*12; - */ - //Don't allow times just before zero time. - if (rtime>3600*22) - return -1; - - return rtime; - } - else return -1; -} - void oEvent::removeRunner(const vector &ids) { oRunnerList::iterator it; @@ -4036,12 +4007,47 @@ int oEvent::findBestClass(const SICard &card, vector &classes) const return Distance; } -void oEvent::convertTimes(SICard &sic) const +void oEvent::convertTimes(pRunner runner, SICard &sic) const { - if (sic.convertedTime) + assert(sic.convertedTime != ConvertedTimeStatus::Unknown); + if (sic.convertedTime == ConvertedTimeStatus::Done) return; - sic.convertedTime = true; + if (sic.convertedTime == ConvertedTimeStatus::Hour12) { + + int startTime = ZeroTime + 3600; //Add one hour. Subtracted below + if (useLongTimes()) + startTime = 5 * 3600; // Avoid midnight as default. Prefer morning + + int st = -1; + if (runner) { + st = runner->getStartTime(); + if (st > 0) { + startTime = (ZeroTime + st) % (3600 * 24); + } + else { + st = -1; + } + } + + if (st <= -1) { + // Fallback for no start time. Take from card. Will be wrong if more than 12 hour after ZeroTime + if (sic.StartPunch.Code != -1) { + st = sic.StartPunch.Time; + } + else if (sic.nPunch > 0 && sic.Punch[0].Time >= 0) { + st = sic.Punch[0].Time; + } + + if (st >= 0) { // Optimize local zero time w.r.t first punch + int relT12 = (st - ZeroTime + 3600 * 24) % (3600 * 12); + startTime = (ZeroTime + relT12) % (3600 * 24); + } + } + int zt = (startTime + 23 * 3600) % (24 * 3600); // Subtract one hour + sic.analyseHour12Time(zt); + } + sic.convertedTime = ConvertedTimeStatus::Done; if (sic.CheckPunch.Code!=-1){ if (sic.CheckPunch.Time &missingPunches) { updateChanged(); if (card) { - if (CardNo==0) + if (card->cardNo > 0) CardNo=card->cardNo; //315422 assert(card->tOwner==0 || card->tOwner==this); @@ -739,7 +739,7 @@ void oRunner::addPunches(pCard card, vector &missingPunches) { int numCtrlLong = mainCourse->getNumControls(); int numCtrlShort = shortVersion->getNumControls(); - SICard sic; + SICard sic(ConvertedTimeStatus::Unknown); Card->getSICard(sic); int level = 0; while (mainCourse->distance(sic) < 0 && abs(numCtrl-numCtrlShort) < abs(numCtrl-numCtrlLong)) { diff --git a/code/onlineinput.cpp b/code/onlineinput.cpp index 953e969..37511e5 100644 --- a/code/onlineinput.cpp +++ b/code/onlineinput.cpp @@ -368,8 +368,7 @@ void OnlineInput::processPunches(oEvent &oe, list< vector > &rocData) { void OnlineInput::processCards(gdioutput &gdi, oEvent &oe, const xmlList &cards) { for (size_t k = 0; k < cards.size(); k++) { - SICard sic; - sic.clear(0); + SICard sic(ConvertedTimeStatus::Hour24); sic.CardNumber = cards[k].getObjectInt("number"); if (cards[k].getObject("finish")) sic.FinishPunch.Time = cards[k].getObject("finish").getObjectInt("time") / 10; diff --git a/code/restserver.cpp b/code/restserver.cpp index 7815fd7..38d620a 100644 --- a/code/restserver.cpp +++ b/code/restserver.cpp @@ -254,7 +254,7 @@ void RestServer::computeInternal(oEvent &ref, shared_ptrsecond.second) { diff --git a/code/swedish.lng b/code/swedish.lng index 7f11111..28feb80 100644 --- a/code/swedish.lng +++ b/code/swedish.lng @@ -2298,7 +2298,7 @@ LĂĄs startlista = LĂĄs startlista FilterNoCancel = Ej ĂĄterbud CourseStartTime = Bana, starttid Startlista, banvis = Startlista, banvis -Stämplingsintervall, rogaining-patrull = Stämplingsintervall inom rogaining-patrull +Stämplingsintervall, rogaining-patrull = Stämplingsintervall inom rogainingpatrull Patrol Team Rogaining = Rogaining (Lag/Patrull) Rogaining results for a patrol = Rogainingresultat för en patrull med tvĂĄ eller fler deltagare. Patrullresultat (STOR) = Patrullresultat (STOR) @@ -2315,3 +2315,5 @@ prefsDrawInterlace = Saxa klasser/banor vid lottning prefsServicePort = Förvald serviceport Ingen nummerlapp = Ingen nummerlapp Rogaining results for a team, where each team member collects points individually = Rogainingresultat för ett lag där varje lagmedlem samlar poäng individuellt +prefsCodePage = Kodtabell för 8-bitars text vid import/export +Inga klasser tillĂĄter direktanmälan. PĂĄ sidan klasser kan du ändra denna egenskap. = Inga klasser tillĂĄter direktanmälan.\n\nPĂĄ sidan klasser kan du ändra denna egenskap. diff --git a/code/testmeos.cpp b/code/testmeos.cpp index 30efa67..2776f41 100644 --- a/code/testmeos.cpp +++ b/code/testmeos.cpp @@ -376,7 +376,7 @@ void TestMeOS::checkStringRes(const char *str, int count) const { void TestMeOS::insertCard(int cardNo, const char *ser) const { - SICard sic; + SICard sic(ConvertedTimeStatus::Unknown); sic.CardNumber = cardNo; sic.deserializePunches(ser); TabSI::getSI(*gdi_main).addCard(sic);