MeOS version 3.5.826 RC2

This commit is contained in:
Erik Melin 2018-03-25 22:21:24 +02:00
parent cf33e11e22
commit 5327deebbb
33 changed files with 603 additions and 367 deletions

View File

@ -1045,6 +1045,7 @@ void RunnerDB::updateAdd(const oRunner &r, map<int, int> &clubIdMap)
dbe = &dbr; dbe = &dbr;
break; break;
} }
++it;
} }
} }

View File

@ -34,6 +34,7 @@
#include <winsock2.h> #include <winsock2.h>
#include "localizer.h" #include "localizer.h"
#include "meos_util.h" #include "meos_util.h"
#include "gdioutput.h"
#include "oPunch.h" #include "oPunch.h"
#include <algorithm> #include <algorithm>
@ -72,7 +73,6 @@ SportIdent::SportIdent(HWND hWnd, DWORD Id)
//ThreadHandle=0; //ThreadHandle=0;
n_SI_Info=0; n_SI_Info=0;
ZeroTime=0;
InitializeCriticalSection(&SyncObj); InitializeCriticalSection(&SyncObj);
tcpPortOpen=0; tcpPortOpen=0;
@ -859,7 +859,7 @@ int SportIdent::MonitorTCPSI(WORD port, int localZeroTime)
vector<SIPunch> punches(nPunch); vector<SIPunch> punches(nPunch);
r = recv(client, (char*)&punches[0], 8 * nPunch, 0); r = recv(client, (char*)&punches[0], 8 * nPunch, 0);
if (r == 8 * nPunch) { if (r == 8 * nPunch) {
SICard card; SICard card(ConvertedTimeStatus::Hour24);
card.CheckPunch.Code = -1; card.CheckPunch.Code = -1;
card.StartPunch.Code = -1; card.StartPunch.Code = -1;
card.FinishPunch.Code = -1; card.FinishPunch.Code = -1;
@ -1169,7 +1169,7 @@ void SportIdent::getSI5DataExt(HANDLE hComm)
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
BYTE *Card5Data=bf+5; BYTE *Card5Data=bf+5;
SICard card; SICard card(ConvertedTimeStatus::Hour12);
getCard5Data(Card5Data, card); getCard5Data(Card5Data, card);
addCard(card); addCard(card);
} }
@ -1241,7 +1241,7 @@ void SportIdent::getSI6DataExt(HANDLE hComm)
OutputDebugString(L"-ACK-"); OutputDebugString(L"-ACK-");
SICard card; SICard card(ConvertedTimeStatus::Hour24);
getCard6Data(b, card); getCard6Data(b, card);
addCard(card); addCard(card);
} }
@ -1320,7 +1320,7 @@ void SportIdent::getSI9DataExt(HANDLE hComm)
OutputDebugString(L"-ACK-"); OutputDebugString(L"-ACK-");
SICard card; SICard card(ConvertedTimeStatus::Hour24);
if (getCard9Data(b, card)) if (getCard9Data(b, card))
addCard(card); addCard(card);
} }
@ -1419,7 +1419,7 @@ void SportIdent::getSI6Data(HANDLE hComm)
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
OutputDebugString(L"-ACK-"); OutputDebugString(L"-ACK-");
SICard card; SICard card(ConvertedTimeStatus::Hour24);
getCard6Data(b, card); getCard6Data(b, card);
addCard(card); addCard(card);
@ -1469,7 +1469,7 @@ void SportIdent::getSI5Data(HANDLE hComm)
WriteFile(hComm, c, 1, &written, NULL); WriteFile(hComm, c, 1, &written, NULL);
//BYTE *Card5Data=bf+5; //BYTE *Card5Data=bf+5;
SICard card; SICard card(ConvertedTimeStatus::Hour12);
getCard5Data(bf, card); getCard5Data(bf, card);
addCard(card); addCard(card);
@ -1507,7 +1507,7 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card)
data+=16; data+=16;
card.convertedTime = ConvertedTimeStatus::Hour12;
analyseSI5Time(data+3, card.StartPunch.Time, card.StartPunch.Code); analyseSI5Time(data+3, card.StartPunch.Time, card.StartPunch.Code);
analyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code); analyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code);
analyseSI5Time(data+9, card.CheckPunch.Time, card.CheckPunch.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; int series = data[24] & 15;
card.convertedTime = ConvertedTimeStatus::Hour24;
analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code); analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code);
analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code); analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code);
analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code); analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code);
@ -1670,26 +1671,38 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
// DWORD control; // DWORD control;
// DWORD time; // DWORD time;
card.convertedTime = ConvertedTimeStatus::Hour24;
analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code); analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code);
analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code); analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code);
analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code); analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code);
card.nPunch=min(int(data[2]), 192); card.nPunch=min(int(data[2]), 192);
int i; int i;
char lastNameByte[21], firstNameByte[21];
wstring lastName, firstName;
memcpy(card.LastName, data+32, 20); memcpy(lastNameByte, data+32, 20);
for(i=19;i>0 && card.LastName[i]==0x20;i--) lastNameByte[20] = 0;
card.LastName[i]=0; for (i = 19; i >= 0 && lastNameByte[i] == 0x20; i--) {
lastNameByte[i] = 0;
}
memcpy(card.FirstName, data+32+20, 20); string2Wide(lastNameByte, lastName);
for(i=19;i>0 && card.FirstName[i]==0x20;i--) wcsncpy(card.lastName, lastName.c_str(), 20);
card.FirstName[i]=0;
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; data+=128-16;
for(unsigned k=0;k<card.nPunch;k++) for(unsigned k=0;k<card.nPunch;k++) {
{
analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code); analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code);
} }
@ -1731,21 +1744,6 @@ void SportIdent::analyseSI5Time(BYTE *data, DWORD &time, DWORD &control)
{ {
if (*LPWORD(data)!=0xEEEE) { if (*LPWORD(data)!=0xEEEE) {
time=MAKEWORD(data[1], data[0]); time=MAKEWORD(data[1], data[0]);
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.
}
control=0; control=0;
} }
else { 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<int> &ports) void SportIdent::EnumrateSerialPorts(list<int> &ports)
{ {
@ -1867,7 +1895,7 @@ void SportIdent::addCard(const SICard &sic)
void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode) void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode)
{ {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
memset(&sic, 0, sizeof(sic)); memset(&sic, 0, sizeof(sic));
sic.CardNumber=Card; sic.CardNumber=Card;
sic.StartPunch.Code = -1; 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.FinishPunch.Code = oPunch::PunchFinish;
} }
} }
sic.PunchOnly=true; sic.punchOnly = true;
addCard(sic); addCard(sic);
} }
@ -2048,14 +2076,6 @@ bool SportIdent::autoDetect(list<int> &ComPorts)
return !ComPorts.empty(); return !ComPorts.empty();
} }
void SportIdent::setZeroTime(DWORD zt)
{
EnterCriticalSection(&SyncObj);
ZeroTime=zt%(24*3600);
LeaveCriticalSection(&SyncObj);
}
bool SportIdent::isPortOpen(const wstring &com) bool SportIdent::isPortOpen(const wstring &com)
{ {
SI_StationInfo *si = findStation(com); SI_StationInfo *si = findStation(com);
@ -2146,8 +2166,7 @@ static string formatTimeN(int t) {
return nt; return nt;
} }
vector<string> SICard::codeLogData(int row) const vector<string> SICard::codeLogData(gdioutput &gdi, int row) const {
{
vector<string> log; vector<string> log;
log.push_back(itos(row)); log.push_back(itos(row));
@ -2158,14 +2177,10 @@ vector<string> SICard::codeLogData(int row) const
log.push_back(itos(CardNumber)); log.push_back(itos(CardNumber));
log.push_back(""); log.push_back("");
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(gdi.recodeToNarrow(firstName));
log.push_back(lnn); log.push_back(gdi.recodeToNarrow(lastName));
log.push_back(cnn); log.push_back(gdi.recodeToNarrow(club));
log.push_back(""); log.push_back("");
log.push_back(""); log.push_back("");
log.push_back(""); log.push_back("");
@ -2179,11 +2194,12 @@ vector<string> SICard::codeLogData(int row) const
log.push_back(""); log.push_back("");
log.push_back(""); log.push_back("");
//We set monday on every punch, since this is our way of string indicator24 = convertedTime == ConvertedTimeStatus::Hour12 ? "" : "MO";
//saying that we have 24-h clock.
//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) { if (signed(CheckPunch.Code) >= 0) {
log.push_back(itos(CheckPunch.Code)); log.push_back(itos(CheckPunch.Code));
log.push_back("MO"); log.push_back(indicator24);
log.push_back(formatTimeN(CheckPunch.Time)); log.push_back(formatTimeN(CheckPunch.Time));
} }
else { else {
@ -2194,7 +2210,7 @@ vector<string> SICard::codeLogData(int row) const
if (signed(StartPunch.Code) >= 0) { if (signed(StartPunch.Code) >= 0) {
log.push_back(itos(StartPunch.Code)); log.push_back(itos(StartPunch.Code));
log.push_back("MO"); log.push_back(indicator24);
log.push_back(formatTimeN(StartPunch.Time)); log.push_back(formatTimeN(StartPunch.Time));
} }
else { else {
@ -2205,7 +2221,7 @@ vector<string> SICard::codeLogData(int row) const
if (signed(FinishPunch.Code) >= 0) { if (signed(FinishPunch.Code) >= 0) {
log.push_back(itos(FinishPunch.Code)); log.push_back(itos(FinishPunch.Code));
log.push_back("MO"); log.push_back(indicator24);
log.push_back(formatTimeN(FinishPunch.Time)); log.push_back(formatTimeN(FinishPunch.Time));
} }
else { else {
@ -2219,7 +2235,7 @@ vector<string> SICard::codeLogData(int row) const
if (k<int(nPunch)) { if (k<int(nPunch)) {
log.push_back(itos(Punch[k].Code)); log.push_back(itos(Punch[k].Code));
if (Punch[k].Time>0) { if (Punch[k].Time>0) {
log.push_back("MO"); log.push_back(indicator24);
log.push_back(formatTimeN(Punch[k].Time)); log.push_back(formatTimeN(Punch[k].Time));
} }
else { else {
@ -2316,6 +2332,7 @@ string SICard::serializePunches() const {
} }
void SICard::deserializePunches(const string &arg) { void SICard::deserializePunches(const string &arg) {
convertedTime = ConvertedTimeStatus::Hour24;
FinishPunch.Code = -1; FinishPunch.Code = -1;
StartPunch.Code = -1; StartPunch.Code = -1;
CheckPunch.Code = -1; CheckPunch.Code = -1;
@ -2348,5 +2365,5 @@ void SICard::deserializePunches(const string &arg) {
*tp = atoi(mark[1].c_str()); *tp = atoi(mark[1].c_str());
} }
if (out.size() == 1) if (out.size() == 1)
PunchOnly = true; punchOnly = true;
} }

View File

@ -40,6 +40,8 @@ const BYTE NAK=0x15;
// This is taken from r56 and checked in on r63 // This is taken from r56 and checked in on r63
#include <vector> #include <vector>
class gdioutput;
struct SICard5Detect struct SICard5Detect
{ {
BYTE code;//Code; BYTE code;//Code;
@ -49,23 +51,34 @@ struct SICard5Detect
WORD crc; WORD crc;
}; };
struct SIPunch struct SIPunch {
{
DWORD Code; DWORD Code;
DWORD Time; DWORD Time;
void analyseHour12Time(DWORD zeroTime);
};
enum class ConvertedTimeStatus {
Unknown = 0,
Hour12,
Hour24,
Done,
}; };
struct SICard struct SICard
{ {
SICard() { SICard(ConvertedTimeStatus status) {
clear(0); clear(0);
convertedTime = false; convertedTime = status;
} }
// Clears the card if this == condition or condition is 0 // Clears the card if this == condition or condition is 0
void clear(const SICard *condition) { void clear(const SICard *condition) {
if (this==condition || condition==0) if (this==condition || condition==0)
memset(this, 0, sizeof(SICard)); memset(this, 0, sizeof(SICard));
} }
void analyseHour12Time(DWORD zeroTime);
bool empty() const {return CardNumber==0;} bool empty() const {return CardNumber==0;}
DWORD CardNumber; DWORD CardNumber;
SIPunch StartPunch; SIPunch StartPunch;
@ -73,19 +86,19 @@ struct SICard
SIPunch CheckPunch; SIPunch CheckPunch;
DWORD nPunch; DWORD nPunch;
SIPunch Punch[192]; SIPunch Punch[192];
wchar_t FirstName[21]; wchar_t firstName[21];
wchar_t LastName[21]; wchar_t lastName[21];
wchar_t Club[41]; wchar_t club[41];
char readOutTime[32]; char readOutTime[32];
bool PunchOnly; bool punchOnly;
bool convertedTime; ConvertedTimeStatus convertedTime;
// Used for manual time input // Used for manual time input
int runnerId; int runnerId;
int relativeFinishTime; int relativeFinishTime;
bool statusOK; bool statusOK;
bool statusDNF; bool statusDNF;
vector<string> codeLogData(int row) const; vector<string> codeLogData(gdioutput &converter, int row) const;
static vector<string> logHeader(); static vector<string> logHeader();
unsigned calculateHash() const; unsigned calculateHash() const;
@ -147,7 +160,6 @@ protected:
bool readSystemDataV2(SI_StationInfo &si); bool readSystemDataV2(SI_StationInfo &si);
CRITICAL_SECTION SyncObj; CRITICAL_SECTION SyncObj;
DWORD ZeroTime; //Used to analyse times. Seconds 0-24h (0-24*3600)
int readByte_delay(BYTE &byte, HANDLE hComm); int readByte_delay(BYTE &byte, HANDLE hComm);
int readBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm); int readBytes_delay(BYTE *byte, DWORD buffSize, DWORD len, HANDLE hComm);
int readBytesDLE_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<wstring> &info); void getInfoString(const wstring &com, vector<wstring> &info);
bool isPortOpen(const wstring &com); bool isPortOpen(const wstring &com);
void setZeroTime(DWORD zt);
bool autoDetect(list<int> &ComPorts); bool autoDetect(list<int> &ComPorts);
void stopMonitorThread(); void stopMonitorThread();

View File

@ -798,7 +798,7 @@ void PrintResultMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
wstring printError; wstring printError;
lock = true; lock = true;
try { try {
gdioutput gdiPrint("print", gdi.getScale(), gdi.getCP()); gdioutput gdiPrint("print", gdi.getScale());
gdiPrint.clearPage(false); gdiPrint.clearPage(false);
oe->generateList(gdiPrint, true, listInfo, false); oe->generateList(gdiPrint, true, listInfo, false);
if (doPrint) { if (doPrint) {
@ -986,7 +986,7 @@ void PunchMachine::status(gdioutput &gdi)
void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
{ {
#ifndef MEOSDB #ifndef MEOSDB
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
oe->generateTestCard(sic); oe->generateTestCard(sic);
SportIdent &si = TabSI::getSI(gdi); SportIdent &si = TabSI::getSI(gdi);
if (!sic.empty()) { if (!sic.empty()) {
@ -998,7 +998,7 @@ void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
pRunner r=oe->getRunnerByCardNo(sic.CardNumber, 0, false); pRunner r=oe->getRunnerByCardNo(sic.CardNumber, 0, false);
if (r && r->getCardNo()) { if (r && r->getCardNo()) {
sic.CardNumber=r->getCardNo(); sic.CardNumber=r->getCardNo();
sic.PunchOnly=true; sic.punchOnly=true;
sic.nPunch=1; sic.nPunch=1;
sic.Punch[0].Code=radio; sic.Punch[0].Code=radio;
si.addCard(sic); si.addCard(sic);

View File

@ -962,7 +962,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.addSelection("Method", 200, 200, 0, L"Metod:"); gdi.addSelection("Method", 200, 200, 0, L"Metod:");
gdi.addItem("Method", lang.tl("Lottning"), DMRandom); gdi.addItem("Method", lang.tl("Lottning"), DMRandom);
gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT);
gdi.selectItemByData("Method", getDefaultMethod(false)); gdi.selectItemByData("Method", getDefaultMethod({ DMRandom, DMSOFT }));
gdi.fillDown(); gdi.fillDown();
gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie"); gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie");
@ -1566,7 +1566,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.setRestorePoint("MultiDayDraw"); gdi.setRestorePoint("MultiDayDraw");
lastDrawMethod = NOMethod; lastDrawMethod = NOMethod;
drawDialog(gdi, getDefaultMethod(true), *pc); drawDialog(gdi, getDefaultMethod(getSupportedDrawMethods(multiDay)), *pc);
} }
else if (bi.id == "HandleMultiDay") { else if (bi.id == "HandleMultiDay") {
ListBoxInfo lbi; ListBoxInfo lbi;
@ -1576,9 +1576,9 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (!pc) if (!pc)
throw std::exception("Class not found"); throw std::exception("Class not found");
if (gdi.isChecked(bi.id) && (lastDrawMethod == DMReversePursuit || if (!gdi.isChecked(bi.id) && (lastDrawMethod == DMReversePursuit ||
lastDrawMethod == DMPursuit)) { lastDrawMethod == DMPursuit)) {
drawDialog(gdi, getDefaultMethod(false), *pc); drawDialog(gdi, DMSOFT, *pc);
} }
else else
setMultiDayClass(gdi, gdi.isChecked(bi.id), lastDrawMethod); 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("Lottning"), DMRandom);
gdi.addItem("Method", lang.tl("SOFT-lottning"), DMSOFT); 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.addSelection("PairSize", 150, 200, 0, L"Tillämpa parstart:");
gdi.addItem("PairSize", getPairOptions()); gdi.addItem("PairSize", getPairOptions());
@ -3250,15 +3250,22 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
if (lastDrawMethod == method) if (lastDrawMethod == method)
return; return;
bool noUpdate = false;
if (lastDrawMethod == DMPursuit && method == DMReversePursuit) if (lastDrawMethod == DMPursuit && method == DMReversePursuit)
return; noUpdate = true;
if (lastDrawMethod == DMReversePursuit && method == DMPursuit) if (lastDrawMethod == DMReversePursuit && method == DMPursuit)
return; noUpdate = true;
if (lastDrawMethod == DMRandom && method == DMSOFT) if (lastDrawMethod == DMRandom && method == DMSOFT)
return; noUpdate = true;
if (lastDrawMethod == DMSOFT && method == DMRandom) if (lastDrawMethod == DMSOFT && method == DMRandom)
noUpdate = true;
if (noUpdate) {
lastDrawMethod = method;
return; return;
}
int firstStart = 3600, int firstStart = 3600,
interval = 120, interval = 120,
@ -3281,7 +3288,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
} }
gdi.restore("MultiDayDraw", false); gdi.restore("MultiDayDraw", false);
const bool multiDay = oe->hasPrevStage(); const bool multiDay = oe->hasPrevStage() && gdi.isChecked("HandleMultiDay");
if (method == DMSeeded) { if (method == DMSeeded) {
gdi.addString("", 10, "help:seeding_info"); 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.addCheckbox("HandleBibs", "Tilldela nummerlappar:", ClassesCB, lastHandleBibs).setSynchData(&lastHandleBibs);
gdi.dropLine(-0.2); 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.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.fillDown();
gdi.dropLine(2.5); gdi.dropLine(2.5);
gdi.popX(); gdi.popX();
@ -3390,6 +3397,16 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
lastDrawMethod = method; lastDrawMethod = method;
} }
set<DrawMethod> TabClass::getSupportedDrawMethods(bool hasMulti) const {
set<DrawMethod> 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) { void TabClass::setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod) {
gdi.clearList("Method"); 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); gdi.addItem("Method", lang.tl("Omvänd jaktstart"), DMReversePursuit);
} }
else if (defaultMethod > 10) else if (defaultMethod > 10)
defaultMethod = getDefaultMethod(hasMulti); defaultMethod = DMSOFT;
gdi.selectItemByData("Method", defaultMethod); gdi.selectItemByData("Method", defaultMethod);
if (gdi.hasField("Vacanses")) { if (gdi.hasField("Vacanses")) {
gdi.setInputStatus("Vacanses", !hasMulti); gdi.setInputStatus("Vacanses", !hasMulti);
}
if (gdi.hasField("HandleBibs")) {
gdi.setInputStatus("HandleBibs", !hasMulti); gdi.setInputStatus("HandleBibs", !hasMulti);
if (hasMulti) { if (hasMulti) {
@ -4078,28 +4097,12 @@ void TabClass::updateSplitDistribution(gdioutput &gdi, int num, int tot) const {
gdi.refresh(); gdi.refresh();
} }
DrawMethod TabClass::getDefaultMethod(bool allowPursuit) const { DrawMethod TabClass::getDefaultMethod(const set<DrawMethod> &allowedValues) const {
int dm = oe->getPropertyInt("DefaultDrawMethod", DMSOFT); DrawMethod dm = (DrawMethod)oe->getPropertyInt("DefaultDrawMethod", DMSOFT);
if (!allowPursuit) { if (allowedValues.count(dm))
if (dm == DMRandom) return dm;
return DMRandom; else
else return DMSOFT;
return DMSOFT;
}
else {
switch (dm) {
case DMRandom:
return DMRandom;
case DMPursuit:
return DMPursuit;
case DMReversePursuit:
return DMReversePursuit;
case DMSeeded:
return DMSeeded;
default:
return DMSOFT;
}
}
} }
vector< pair<wstring, size_t> > TabClass::getPairOptions() { vector< pair<wstring, size_t> > TabClass::getPairOptions() {

View File

@ -76,6 +76,8 @@ class TabClass :
DrawInfo drawInfo; DrawInfo drawInfo;
void setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod); void setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaultMethod);
set<DrawMethod> getSupportedDrawMethods(bool multiDay) const;
void drawDialog(gdioutput &gdi, DrawMethod method, const oClass &cls); void drawDialog(gdioutput &gdi, DrawMethod method, const oClass &cls);
void pursuitDialog(gdioutput &gdi); void pursuitDialog(gdioutput &gdi);
@ -136,7 +138,7 @@ class TabClass :
void updateSplitDistribution(gdioutput &gdi, int numInClass, int tot) const; void updateSplitDistribution(gdioutput &gdi, int numInClass, int tot) const;
DrawMethod getDefaultMethod(bool allowPursuit) const; DrawMethod getDefaultMethod(const set<DrawMethod> &allowedValues) const;
void enableLoadSettings(gdioutput &gdi); void enableLoadSettings(gdioutput &gdi);

View File

@ -134,7 +134,6 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
oe->setZeroTime(zt); oe->setZeroTime(zt);
oe->synchronize(); oe->synchronize();
if (gSI) gSI->setZeroTime(oe->getZeroTimeNum());
gdi.setWindowTitle(oe->getTitleName()); gdi.setWindowTitle(oe->getTitleName());
gdi.setText("Date", oe->getDate()); gdi.setText("Date", oe->getDate());
@ -159,7 +158,6 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
gdi.setWaitCursor(true); gdi.setWaitCursor(true);
if (oe->open(fileName, true)) { if (oe->open(fileName, true)) {
if (gSI) gSI->setZeroTime(oe->getZeroTimeNum());
gdi.setWindowTitle(oe->getTitleName()); gdi.setWindowTitle(oe->getTitleName());
resetSaveTimer(); resetSaveTimer();
return true; return true;
@ -1766,7 +1764,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
oListInfo li; oListInfo li;
par.selection = allTransfer; par.selection = allTransfer;
oe->generateListInfo(par, gdi.getLineHeight(), 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); oe->generateList(tGdi, true, li, false);
tGdi.writeTableHTML(save, oe->getName(), 0); tGdi.writeTableHTML(save, oe->getName(), 0);
tGdi.openDoc(save.c_str()); tGdi.openDoc(save.c_str());
@ -1851,7 +1849,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
par.setLegNumberCoded(-1); par.setLegNumberCoded(-1);
oListInfo li; oListInfo li;
oe->generateListInfo(par, gdi.getLineHeight(), 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); oe->generateList(tGdi, true, li, false);
tGdi.writeTableHTML(save, oe->getName(), 0); tGdi.writeTableHTML(save, oe->getName(), 0);
tGdi.openDoc(save.c_str()); tGdi.openDoc(save.c_str());
@ -2286,7 +2284,6 @@ void TabCompetition::openCompetition(gdioutput &gdi, int id) {
err = ex.wwhat(); err = ex.wwhat();
} }
if (gSI) gSI->setZeroTime(oe->getZeroTimeNum());
resetSaveTimer(); resetSaveTimer();
oe->setProperty("LastCompetition", id); oe->setProperty("LastCompetition", id);
gdi.setWindowTitle(oe->getTitleName()); gdi.setWindowTitle(oe->getTitleName());
@ -2308,8 +2305,6 @@ int TabCompetition::restoreCB(gdioutput &gdi, int type, void *data) {
gdi.alert("Kunde inte öppna tävlingen."); gdi.alert("Kunde inte öppna tävlingen.");
} }
else { else {
if (gSI) gSI->setZeroTime(oe->getZeroTimeNum());
const wstring &name = oe->getName(); const wstring &name = oe->getName();
if (name.find_last_of(L"}") != name.length()-1) if (name.find_last_of(L"}") != name.length()-1)
oe->setName(name + L" {" + lang.tl(L"återställd") + L"}"); oe->setName(name + L" {" + lang.tl(L"återställd") + L"}");
@ -3903,8 +3898,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); gdi.pushX();
fields.push_back("MaxTime"); fields.push_back("MaxTime");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining) && if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) {
oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) {
fields.push_back("DiffTime"); fields.push_back("DiffTime");
} }
gdi.fillDown(); gdi.fillDown();

View File

@ -877,7 +877,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
pRunner r=oe->getRunner(runnerId, 0); pRunner r=oe->getRunner(runnerId, 0);
if (!r) return 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) if (bi.getExtraInt() == 0)
r->printSplits(gdiprint); r->printSplits(gdiprint);
else else
@ -1053,7 +1053,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
auto &db = oe->getRunnerDatabase(); auto &db = oe->getRunnerDatabase();
bool show = false; bool show = false;
if (ii.text.length() > 1) { 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); auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
if (!rw.empty()) { if (!rw.empty()) {
auto &ac = gdi.addAutoComplete(ii.id); auto &ac = gdi.addAutoComplete(ii.id);
@ -3024,7 +3024,7 @@ void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
gdi.TabFocus(1); gdi.TabFocus(1);
} }
pClub TabRunner::extractClub(gdioutput &gdi) { pClub TabRunner::extractClub(oEvent *oe, gdioutput &gdi) {
oClub *dbClub = nullptr; oClub *dbClub = nullptr;
if (gdi.hasField("Club")) { if (gdi.hasField("Club")) {
auto &db = oe->getRunnerDatabase(); auto &db = oe->getRunnerDatabase();

View File

@ -109,8 +109,9 @@ private:
protected: protected:
void clearCompetitionData(); void clearCompetitionData();
pClub extractClub(gdioutput &gdi);
public: public:
static pClub extractClub(oEvent *oe, gdioutput &gdi);
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override; void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
const char * getTypeStr() const {return "TRunnerTab";} const char * getTypeStr() const {return "TRunnerTab";}

View File

@ -48,12 +48,12 @@
#include "recorder.h" #include "recorder.h"
#include "autocomplete.h" #include "autocomplete.h"
TabSI::TabSI(oEvent *poe):TabBase(poe) { TabSI::TabSI(oEvent *poe):TabBase(poe), activeSIC(ConvertedTimeStatus::Unknown) {
editCardData.tabSI = this; editCardData.tabSI = this;
directEntryGUI.tabSI = this; directEntryGUI.tabSI = this;
interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0; interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0;
useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0; useDatabase = poe->getPropertyInt("Database", 1)!=0;
printSplits = false; printSplits = false;
printStartInfo = false; printStartInfo = false;
savedCardUniqueId = 1; 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) { if (logger == 0) {
logger = new csvparser; logger = new csvparser;
@ -104,7 +104,7 @@ void TabSI::logCard(const SICard &card)
logcounter = 0; logcounter = 0;
} }
vector<string> log = card.codeLogData(++logcounter); vector<string> log = card.codeLogData(gdi, ++logcounter);
logger->outputRow(log); logger->outputRow(log);
} }
@ -143,8 +143,8 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
vector<string> head = SICard::logHeader(); vector<string> head = SICard::logHeader();
saver.outputRow(head); saver.outputRow(head);
int count = 0; int count = 0;
for (list< pair<int, SICard> >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) { for (auto it = savedCards.begin(); it != savedCards.end(); ++it) {
vector<string> log = it->second.codeLogData(++count); vector<string> log = it->second.codeLogData(gdi, ++count);
saver.outputRow(log); saver.outputRow(log);
} }
} }
@ -492,14 +492,16 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
} }
} }
else if (bi.id=="Save") { else if (bi.id=="Save") {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.clear(0);
sic.CheckPunch.Code = -1; sic.CheckPunch.Code = -1;
sic.CardNumber=gdi.getTextNo("SI"); sic.CardNumber=gdi.getTextNo("SI");
int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum()); int f = convertAbsoluteTimeHMS(gdi.getText("Finish"), oe->getZeroTimeNum());
int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum()); int s = convertAbsoluteTimeHMS(gdi.getText("Start"), oe->getZeroTimeNum());
if (f < s) {
f += 24 * 3600;
}
sic.FinishPunch.Time= 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")) { if (!gdi.isChecked("HasFinish")) {
sic.FinishPunch.Code = -1; sic.FinishPunch.Code = -1;
sic.FinishPunch.Time = 0; 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"); 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); gSI->addCard(sic);
} }
else if (bi.id=="SaveP") { else if (bi.id=="SaveP") {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.clear(0); sic.clear(0);
sic.FinishPunch.Code = -1; sic.FinishPunch.Code = -1;
sic.CheckPunch.Code = -1; sic.CheckPunch.Code = -1;
@ -535,7 +547,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (f > 0) { if (f > 0) {
sic.FinishPunch.Time = f; sic.FinishPunch.Time = f;
sic.FinishPunch.Code = 1; sic.FinishPunch.Code = 1;
sic.PunchOnly = true; sic.punchOnly = true;
gSI->addCard(sic); gSI->addCard(sic);
return 0; return 0;
} }
@ -544,7 +556,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (s > 0) { if (s > 0) {
sic.StartPunch.Time = s; sic.StartPunch.Time = s;
sic.StartPunch.Code = 1; sic.StartPunch.Code = 1;
sic.PunchOnly = true; sic.punchOnly = true;
gSI->addCard(sic); gSI->addCard(sic);
return 0; 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].Code=gdi.getTextNo("C1");
sic.Punch[sic.nPunch].Time=convertAbsoluteTimeHMS(gdi.getText("C2"), oe->getZeroTimeNum()); sic.Punch[sic.nPunch].Time=convertAbsoluteTimeHMS(gdi.getText("C2"), oe->getZeroTimeNum());
sic.nPunch = 1; sic.nPunch = 1;
sic.PunchOnly = true; sic.punchOnly = true;
gSI->addCard(sic); gSI->addCard(sic);
} }
else if (bi.id=="Cancel") { else if (bi.id=="Cancel") {
@ -626,7 +638,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.pushX(); gdi.pushX();
SICard si_copy=activeSIC; SICard si_copy=activeSIC;
gEvent->convertTimes(si_copy); gEvent->convertTimes(nullptr, si_copy);
//Find matching class... //Find matching class...
vector<pClass> classes; vector<pClass> classes;
@ -828,6 +840,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.getSelectedItem("Class", lbi); gdi.getSelectedItem("Class", lbi);
if (signed(lbi.data)<=0) { 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")); pClass pc = oe->getClassCreate(0, lang.tl(L"Öppen klass"));
lbi.data = pc->getId(); lbi.data = pc->getId();
pc->setAllowQuickEntry(true); pc->setAllowQuickEntry(true);
@ -975,7 +991,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.restore("ManualInput", false); gdi.restore("ManualInput", false);
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.runnerId = runnerMatchedId; sic.runnerId = runnerMatchedId;
sic.relativeFinishTime = relTime; sic.relativeFinishTime = relTime;
sic.statusOK = ok; sic.statusOK = ok;
@ -1011,7 +1027,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
} }
else if (bi.id == "CCSPrint") { else if (bi.id == "CCSPrint") {
//gdi.print(oe); //gdi.print(oe);
gdioutput gdiPrint("print", gdi.getScale(), gdi.getCP()); gdioutput gdiPrint("print", gdi.getScale());
gdiPrint.clearPage(false); gdiPrint.clearPage(false);
int tCardPosX = cardPosX; 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()) if ((gdi.getData("RunnerId", rid) && rid>0) || !gdi.getText("Club", true).empty())
return 0; // Selected from list 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); pRunner db_r = oe->dbLookUpByName(bi.text, 0, 0, 0);
if (!db_r && lastClubId) if (!db_r && lastClubId)
db_r = oe->dbLookUpByName(bi.text, lastClubId, 0, 0); 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) { else if (type == GUI_COMBOCHANGE) {
ListBoxInfo bi=*(ListBoxInfo *)data; ListBoxInfo bi=*(ListBoxInfo *)data;
if (bi.id == "Runners") { 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<AutoCompleteRecord> items = getRunnerAutoCompelete(oe->getRunnerDatabase(), rw, 0);
ac.setData(items);
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(bi.id);
}
} }
} }
else if (type == GUI_EVENT) { else if (type == GUI_EVENT) {
@ -1160,6 +1195,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
if (ev.id == "AutoComplete") { if (ev.id == "AutoComplete") {
pRunner r = oe->getRunner(runnerMatchedId, 0); pRunner r = oe->getRunner(runnerMatchedId, 0);
if (r) { if (r) {
gdi.clearAutoComplete("");
gdi.setInputFocus("OK1"); gdi.setInputFocus("OK1");
gdi.setText("Runners", r->getName()); gdi.setText("Runners", r->getName());
gdi.setData("RunnerId", runnerMatchedId); gdi.setData("RunnerId", runnerMatchedId);
@ -1325,7 +1361,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
gdi.addTimeoutMilli(50, "TieCard", SportIdentCB).setExtra(runnerMatchedId); gdi.addTimeoutMilli(50, "TieCard", SportIdentCB).setExtra(runnerMatchedId);
} }
else if (cardNo>0 && gdi.getText("Name").empty()) { else if (cardNo>0 && gdi.getText("Name").empty()) {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.clear(0); sic.clear(0);
sic.CardNumber = cardNo; sic.CardNumber = cardNo;
@ -1482,7 +1518,6 @@ SportIdent &TabSI::getSI(const gdioutput &gdi) {
if (!gSI) { if (!gSI) {
HWND hWnd=gdi.getHWNDMain(); HWND hWnd=gdi.getHWNDMain();
gSI = new SportIdent(hWnd, 0); gSI = new SportIdent(hWnd, 0);
gSI->setZeroTime(gEvent->getZeroTimeNum());
} }
return *gSI; return *gSI;
} }
@ -1767,6 +1802,35 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
return; return;
} }
else if (mode == ModeCardData) { 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)); savedCards.push_back(make_pair(savedCardUniqueId++, sic));
if (printSplits) { if (printSplits) {
@ -1789,7 +1853,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
gEvent->synchronizeList(oLCardId, true, false); gEvent->synchronizeList(oLCardId, true, false);
gEvent->synchronizeList(oLRunnerId, false, true); gEvent->synchronizeList(oLRunnerId, false, true);
if (sic.PunchOnly) { if (sic.punchOnly) {
processPunchOnly(gdi, sic); processPunchOnly(gdi, sic);
return; return;
} }
@ -1810,7 +1874,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
throw meosException("Internal error"); throw meosException("Internal error");
//SIPage not loaded... //SIPage not loaded...
if (!r && useDatabase) if (!r && showDatabase())
r=autoMatch(sic, 0); r=autoMatch(sic, 0);
// Assign a class if not already done // Assign a class if not already done
@ -1907,7 +1971,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
if (sic.runnerId == 0) { if (sic.runnerId == 0) {
r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, !readBefore); r = gEvent->getRunnerByCardNo(sic.CardNumber, 0, !readBefore);
if (!r && useDatabase) { if (!r && showDatabase()) {
//Look up in database. //Look up in database.
db_r = gEvent->dbLookUpByCard(sic.CardNumber); db_r = gEvent->dbLookUpByCard(sic.CardNumber);
if (db_r) if (db_r)
@ -1964,17 +2028,17 @@ void TabSI::startInteractive(gdioutput &gdi, const SICard &sic, pRunner r, pRunn
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); 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); gEvent->fillRunners(gdi, "Runners", false, oEvent::RunnerFilterOnlyNoResult);
if (db_r){ if (db_r){
gdi.setText("Runners", db_r->getName()); //Data from DB gdi.setText("Runners", db_r->getName()); //Data from DB
} }
else if (sic.FirstName[0] || sic.LastName[0]){ //Data from SI-card else if (sic.firstName[0] || sic.lastName[0]){ //Data from SI-card
gdi.setText("Runners", wstring(sic.FirstName)+L" "+sic.LastName); gdi.setText("Runners", wstring(sic.lastName) + L", " + sic.firstName);
} }
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { 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"); gEvent->fillClubs(gdi, "Club");
if (db_r) if (db_r)
@ -2082,10 +2146,10 @@ bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent)
wstring warnings; wstring warnings;
// Write read card to log // Write read card to log
logCard(sic); logCard(gdi, sic);
// Convert punch times to relative times. // Convert punch times to relative times.
gEvent->convertTimes(sic); gEvent->convertTimes(nullptr, sic);
if (sic.CheckPunch.Code!=-1) if (sic.CheckPunch.Code!=-1)
card->addPunch(oPunch::PunchCheck, sic.CheckPunch.Time, 0); 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); info += runner->getClass(true);
// Write read card to log // Write read card to log
logCard(sic); logCard(gdi, sic);
// Convert punch times to relative times. // Convert punch times to relative times.
oe->convertTimes(sic); oe->convertTimes(runner, sic);
pCourse prelCourse = runner->getCourse(false); pCourse prelCourse = runner->getCourse(false);
const int finishPT = prelCourse ? prelCourse->getFinishPunchType() : oPunch::PunchFinish; const int finishPT = prelCourse ? prelCourse->getFinishPunchType() : oPunch::PunchFinish;
bool hasFinish = false; bool hasFinish = false;
@ -2395,7 +2459,7 @@ void TabSI::processPunchOnly(gdioutput &gdi, const SICard &csic)
{ {
SICard sic=csic; SICard sic=csic;
DWORD loaded; DWORD loaded;
gEvent->convertTimes(sic); gEvent->convertTimes(nullptr, sic);
oFreePunch *ofp=0; oFreePunch *ofp=0;
if (sic.nPunch==1) if (sic.nPunch==1)
@ -2442,7 +2506,7 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
wstring name; wstring name;
wstring club; wstring club;
int age = 0; int age = 0;
if (useDatabase) { if (showDatabase()) {
pRunner db_r=oe->dbLookUpByCard(sic.CardNumber); pRunner db_r=oe->dbLookUpByCard(sic.CardNumber);
if (db_r) { if (db_r) {
@ -2453,8 +2517,8 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
} }
//Else get name from card //Else get name from card
if (name.empty() && (sic.FirstName[0] || sic.LastName[0])) if (name.empty() && (sic.firstName[0] || sic.lastName[0]))
name=wstring(sic.LastName) + L", " + wstring(sic.FirstName); name=wstring(sic.lastName) + L", " + wstring(sic.firstName);
gdi.setText("Name", name); gdi.setText("Name", name);
if (gdi.hasField("Club")) 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.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:").setHandler(&directEntryGUI);
gdi.addSelection("Class", 150, 200, 0, L"Klass:").setHandler(&directEntryGUI); gdi.addSelection("Class", 150, 200, 0, L"Klass:").setHandler(&directEntryGUI);
oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect); {
vector< pair<wstring, size_t> > 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)) { if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) {
} }
else if (!gdi.selectItemByData("Class", lastClassId)) { else if (!gdi.selectItemByData("Class", lastClassId)) {
@ -2703,7 +2775,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
while(checkpPrintQueue(gdi)); while(checkpPrintQueue(gdi));
} }
else { else {
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
vector<int> mp; vector<int> mp;
r->evaluateCard(true, mp); r->evaluateCard(true, mp);
r->printSplits(gdiprint); r->printSplits(gdiprint);
@ -2714,7 +2786,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) { void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) {
if (printStartInfo) { if (printStartInfo) {
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
r.printStartInfo(gdiprint); r.printStartInfo(gdiprint);
printProtected(gdi, gdiprint); printProtected(gdi, gdiprint);
//gdiprint.print(splitPrinter, oe, false, true); //gdiprint.print(splitPrinter, oe, false, true);
@ -2985,9 +3057,9 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
gdi.removeControl("CancelCard"); gdi.removeControl("CancelCard");
wstring name, club; wstring name, club;
if (card.FirstName[0]) if (card.firstName[0])
name = wstring(card.FirstName) + (card.LastName[0] ? (L" " + wstring(card.LastName)) : L""); name = (card.lastName[0] ? (wstring(card.lastName) + L", ") : L"") + wstring(card.firstName);
club = card.Club; club = card.club;
bool noName = name.empty(); bool noName = name.empty();
bool noClub = club.empty(); bool noClub = club.empty();
if (noName) 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 club = gdi.getBaseInfo("ClubName").getExtra() ? L"" : gdi.getText("ClubName");
wstring given = getGivenName(name); wstring given = getGivenName(name);
wstring familty = getFamilyName(name); wstring familty = getFamilyName(name);
wcsncpy_s(card.FirstName, given.c_str(), 20); wcsncpy_s(card.firstName, given.c_str(), 20);
wcsncpy_s(card.LastName, familty.c_str(), 20); wcsncpy_s(card.lastName, familty.c_str(), 20);
wcsncpy_s(card.Club, club.c_str(), 40); wcsncpy_s(card.club, club.c_str(), 40);
wstring s = name; wstring s = name;
if (!club.empty()) if (!club.empty())
@ -3049,9 +3121,9 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
gdi.pushX(); gdi.pushX();
gdi.fillRight(); gdi.fillRight();
wstring name, clubName; wstring name, clubName;
if (c.FirstName[0] != 0) { if (c.firstName[0] != 0) {
name = wstring(c.FirstName) + L" " + c.LastName; name = wstring(c.firstName) + L" " + c.lastName;
clubName = c.Club; clubName = c.club;
} }
else { else {
const RunnerWDBEntry *r = oe->getRunnerDatabase().getRunnerByCard(c.CardNumber); 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); const oClub *club = oe->getRunnerDatabase().getClub(r->dbe().clubNo);
if (club) { if (club) {
clubName = club->getName(); clubName = club->getName();
wcsncpy_s(c.Club, clubName.c_str(), 20); wcsncpy_s(c.club, clubName.c_str(), 20);
} }
wstring given = r->getGivenName(); wstring given = r->getGivenName();
wstring family = r->getFamilyName(); wstring family = r->getFamilyName();
wcsncpy_s(c.FirstName, given.c_str(), 20); wcsncpy_s(c.firstName, given.c_str(), 20);
wcsncpy_s(c.LastName, family.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) { 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); printCard(gdiprint, cardId, true);
printProtected(gdi, gdiprint); printProtected(gdi, gdiprint);
} }
@ -3266,15 +3338,15 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) {
if (!cls.empty()) { if (!cls.empty()) {
wstring name; wstring name;
if (cards[k].second->FirstName[0]) if (cards[k].second->lastName[0])
name = cards[k].second->FirstName; name = wstring(cards[k].second->lastName) + L", ";
if (cards[k].second->LastName[0]) if (cards[k].second->firstName[0])
name += L" " + wstring(cards[k].second->LastName); name += cards[k].second->firstName;
if (name.empty()) if (name.empty())
name = lang.tl(L"Bricka X#" + itow(cards[k].second->CardNumber)); 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); cards[k].second->CardNumber, 0, true);
processInsertCard(*cards[k].second); processInsertCard(*cards[k].second);
@ -3487,8 +3559,7 @@ void TabSI::showCheckCardStatus(gdioutput &gdi, const string &cmd) {
} }
} }
else if (cmd == "tickoff") { else if (cmd == "tickoff") {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.clear(0);
for (map<int, CardNumberFlags>::const_iterator it = checkedCardFlags.begin(); for (map<int, CardNumberFlags>::const_iterator it = checkedCardFlags.begin();
it != checkedCardFlags.end(); ++it) { it != checkedCardFlags.end(); ++it) {
int stat = it->second; int stat = it->second;
@ -3591,7 +3662,7 @@ bool TabSI::checkpPrintQueue(gdioutput &gdi) {
return false; // Wait a little longer return false; // Wait a little longer
} }
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP()); gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
vector<int> mp; vector<int> mp;
for (size_t m = 0; m < printLen && !printPunchRunnerIdQueue.empty(); m++) { for (size_t m = 0; m < printLen && !printPunchRunnerIdQueue.empty(); m++) {
int rid = printPunchRunnerIdQueue.front().second; int rid = printPunchRunnerIdQueue.front().second;
@ -3720,7 +3791,7 @@ void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType
else if (type == GUI_INPUTCHANGE) { else if (type == GUI_INPUTCHANGE) {
InputInfo &ii = dynamic_cast<InputInfo &>(info); InputInfo &ii = dynamic_cast<InputInfo &>(info);
bool show = false; bool show = false;
if (tabSI->useDatabase && ii.id == "Name") { if (tabSI->showDatabase() && ii.id == "Name") {
auto &db = tabSI->oe->getRunnerDatabase(); auto &db = tabSI->oe->getRunnerDatabase();
if (ii.text.length() > 1) { if (ii.text.length() > 1) {
auto dbClub = tabSI->extractClub(gdi); auto dbClub = tabSI->extractClub(gdi);
@ -3801,3 +3872,8 @@ void TabSI::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
gdi.clearAutoComplete(""); gdi.clearAutoComplete("");
gdi.TabFocus(1); gdi.TabFocus(1);
} }
bool TabSI::showDatabase() const {
return useDatabase && oe->useRunnerDb();
}

View File

@ -192,6 +192,8 @@ protected:
public: public:
bool showDatabase() const;
static vector<AutoCompleteRecord> getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub); static vector<AutoCompleteRecord> getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub);
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override; void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
@ -231,7 +233,7 @@ public:
int siCB(gdioutput &gdi, int type, void *data); 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;} void setCardNumberField(const string &fieldId) {insertCardNumberField=fieldId;}

View File

@ -42,6 +42,7 @@
#include "TabRunner.h" #include "TabRunner.h"
#include "MeOSFeatures.h" #include "MeOSFeatures.h"
#include "RunnerDB.h" #include "RunnerDB.h"
#include "autocomplete.h"
#include "TabSI.h" #include "TabSI.h"
@ -1058,6 +1059,29 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
gdi.getTextNo("DirCard") > 0); 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) { else if (type == GUI_INPUT) {
InputInfo &ii=*(InputInfo *)data; 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<AutoCompleteRecord> 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) { else if (type==GUI_CLEAR) {
if (teamId>0) if (teamId>0)
save(gdi, true); save(gdi, true);
@ -1322,7 +1367,7 @@ bool TabTeam::loadPage(gdioutput &gdi)
} }
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { 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"); oe->fillClubs(gdi, "Club");
drop = true; drop = true;
} }
@ -1897,3 +1942,26 @@ bool TabTeam::warnDuplicateCard(gdioutput &gdi, string id, int cno, pRunner r, v
return false; 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);
}

View File

@ -21,11 +21,12 @@
************************************************************************/ ************************************************************************/
#include "tabbase.h" #include "tabbase.h"
#include "autocompletehandler.h"
struct TeamLineup; struct TeamLineup;
class TabTeam : class TabTeam :
public TabBase public TabBase, AutoCompleteHandler
{ {
private: private:
bool save(gdioutput &gdi, bool dontReloadTeams); bool save(gdioutput &gdi, bool dontReloadTeams);
@ -73,11 +74,11 @@ private:
void switchRunners(pTeam team, int leg, pRunner r, pRunner oldR); void switchRunners(pTeam team, int leg, pRunner r, pRunner oldR);
protected: protected:
void clearCompetitionData(); void clearCompetitionData();
public: public:
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
const char * getTypeStr() const {return "TTeamTab";} const char * getTypeStr() const {return "TTeamTab";}
TabType getType() const {return TTeamTab;} TabType getType() const {return TTeamTab;}

View File

@ -756,7 +756,7 @@ bool Table::keyCommand(gdioutput &gdi, KeyCommandCode code) {
gdi.refresh(); gdi.refresh();
} }
else if (code == KC_PRINT) { else if (code == KC_PRINT) {
gdioutput gdiPrint("temp", gdi.getScale(), gdi.getCP()); gdioutput gdiPrint("temp", gdi.getScale());
gdiPrint.clearPage(false); gdiPrint.clearPage(false);
gdiPrint.print(getEvent(), this); gdiPrint.print(getEvent(), this);
} }

View File

@ -839,17 +839,11 @@ bool csvparser::importPunches(const oEvent &oe, const wstring &file, vector<Punc
return true; return true;
} }
int analyseSITime(const oEvent &oe, const wchar_t *dow, const wchar_t *time) int analyseSITime(const wchar_t *dow, const wchar_t *time, bool &is12Hour)
{ {
int t=-1; int t = oEvent::convertAbsoluteTime(time);
if (trim(dow).length()>0) if (t >= 0 && trim(dow).empty())
t = oe.getRelativeTime(time); is12Hour = true;
else
t = oe.getRelativeTimeFrom12Hour(time);
if (t<0)
t=0;
return t; return t;
} }
@ -935,10 +929,10 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector<wstring> &sp, S
if (cardNo < 1000 || cardNo > 99999999) if (cardNo < 1000 || cardNo > 99999999)
return false; return false;
bool is12Hour = false;
int check = analyseSITime(oe, getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp)); int check = analyseSITime(getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp), is12Hour);
int start = analyseSITime(oe, getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp)); int start = analyseSITime(getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp), is12Hour);
int finish = analyseSITime(oe, getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp)); int finish = analyseSITime(getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp), is12Hour);
int startCode = wtoi(getSIC(sicStart, sp)); int startCode = wtoi(getSIC(sicStart, sp));
int finishCode = wtoi(getSIC(sicFinish, sp)); int finishCode = wtoi(getSIC(sicFinish, sp));
int checkCode = wtoi(getSIC(sicCheck, sp)); int checkCode = wtoi(getSIC(sicCheck, sp));
@ -954,7 +948,7 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector<wstring> &sp, S
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(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) { if (code > 0) {
punches.push_back(make_pair(code, time)); punches.push_back(make_pair(code, time));
} }
@ -998,12 +992,12 @@ bool csvparser::checkSIConfigLine(const oEvent &oe, const vector<wstring> &sp, S
card.Punch[k].Time = punches[k].second; card.Punch[k].Time = punches[k].second;
} }
wcsncpy_s(card.FirstName, fname.c_str(), 20); wcsncpy_s(card.firstName, fname.c_str(), 20);
card.FirstName[20] = 0; card.firstName[20] = 0;
wcsncpy_s(card.LastName, lname.c_str(), 20); wcsncpy_s(card.lastName, lname.c_str(), 20);
card.LastName[20] = 0; card.lastName[20] = 0;
card.nPunch = punches.size(); card.nPunch = punches.size();
card.convertedTime = true; card.convertedTime = is12Hour ? ConvertedTimeStatus::Hour12 : ConvertedTimeStatus::Hour24;
return true; return true;
} }
@ -1061,7 +1055,7 @@ bool csvparser::checkSimanLine(const oEvent &oe, const vector<wstring> &sp, SICa
card.Punch[k].Time = punches[k].second; card.Punch[k].Time = punches[k].second;
} }
card.nPunch = punches.size(); card.nPunch = punches.size();
card.convertedTime = false; card.convertedTime = ConvertedTimeStatus::Hour24; //XXX Not correct in general
return true; return true;
} }
@ -1098,7 +1092,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard
//split(bf, sp); //split(bf, sp);
const vector<wstring> &sp = *it; const vector<wstring> &sp = *it;
SICard card; SICard card(ConvertedTimeStatus::Unknown);
if (checkSimanLine(oe, sp, card)) { if (checkSimanLine(oe, sp, card)) {
cards.push_back(card); cards.push_back(card);
@ -1111,13 +1105,13 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard
else if (sp.size()>28) { else if (sp.size()>28) {
int no = wtoi(sp[0]); int no = wtoi(sp[0]);
card.CardNumber = wtoi(sp[2]); card.CardNumber = wtoi(sp[2]);
wcsncpy_s(card.FirstName, sp[5].c_str(), 20); wcsncpy_s(card.firstName, sp[5].c_str(), 20);
wcsncpy_s(card.LastName, sp[6].c_str(), 20); wcsncpy_s(card.lastName, sp[6].c_str(), 20);
wcsncpy_s(card.Club, sp[7].c_str(), 40); wcsncpy_s(card.club, sp[7].c_str(), 40);
bool hour12 = false;
if (trim(sp[21]).length()>1) { if (trim(sp[21]).length()>1) {
card.CheckPunch.Code = wtoi(sp[19]); 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 { else {
card.CheckPunch.Code = -1; card.CheckPunch.Code = -1;
@ -1126,7 +1120,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard
if (trim(sp[24]).length()>1) { if (trim(sp[24]).length()>1) {
card.StartPunch.Code = wtoi(sp[22]); 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 { else {
card.StartPunch.Code = -1; card.StartPunch.Code = -1;
@ -1135,7 +1129,7 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard
if (trim(sp[27]).length()>1) { if (trim(sp[27]).length()>1) {
card.FinishPunch.Code = wtoi(sp[25]); 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 { else {
card.FinishPunch.Code = -1; card.FinishPunch.Code = -1;
@ -1147,11 +1141,11 @@ bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard
if (sp.size()>28+3*card.nPunch) { if (sp.size()>28+3*card.nPunch) {
for (unsigned k=0;k<card.nPunch;k++) { for (unsigned k=0;k<card.nPunch;k++) {
card.Punch[k].Code = wtoi(sp[29+k*3]); card.Punch[k].Code = wtoi(sp[29+k*3]);
card.Punch[k].Time = analyseSITime(oe, sp[30+k*3].c_str(), sp[31+k*3].c_str()); card.Punch[k].Time = analyseSITime(sp[30+k*3].c_str(), sp[31+k*3].c_str(), hour12);
} }
card.PunchOnly = false; card.punchOnly = false;
nimport++; nimport++;
card.convertedTime = true; card.convertedTime = hour12 ? ConvertedTimeStatus::Hour12 : ConvertedTimeStatus::Hour24;
cards.push_back(card); cards.push_back(card);
} }
} }

View File

@ -363,57 +363,58 @@ ControlRunnersLeft = Antal løbere der mangler at stemple post
ControlVisitors = Forventet antal løbere til post ControlVisitors = Forventet antal løbere til post
Could not load list 'X' = Kunne ikke indlæse liste 'X' Could not load list 'X' = Kunne ikke indlæse liste 'X'
Country = Land Country = Land
Course = Bana Course = Bane
CourseClasses = Banas klasser CourseClasses = Banes klasser
CourseClimb = Banans stigning CourseClimb = Banens højdemeter
CourseLength = Banlängd, specifik bana CourseLength = Banelængde, specifik bane
CourseName = Banans namn CourseName = Banens navn
CourseResult = Bana, resultat CourseResult = Bane, resultater
CourseShortening = Banavkortningar CourseShortening = Baneafkortninger
CourseUsage = Banas antal anmälda CourseStartTime = Bane, starttid
CourseUsageNoVacant = Banas antal anmälda (ej vakanta) CourseUsage = Banes antal tilmeldte
Create Competition = Skapa tävling CourseUsageNoVacant = Banes antal tilmeldte (ej vakante)
Created X distinct forkings using Y courses = Skapade X olika gafflingsalternativ med hjälp av Y banor Create Competition = Dan løb
CurrentTime = Aktuell tid Created X distinct forkings using Y courses = Dannede X forskellige gaflingsalternativer ved hjælp af Y baner
CurrentTime = Aktuel tid
CustomSort = Egen sortering CustomSort = Egen sortering
Döp om = Döp om Döp om = Døb om
Döp om X = Döp om X Döp om X = Døb X om
Data from result module (X) = Data från resultatmodul (X) Data from result module (X) = Data fra resultatmodul (X)
Databasanslutning = Databasanslutning Databasanslutning = Databaseforbindelse
DATABASE ERROR = DATABASFEL DATABASE ERROR = DATABASEFEJL
Databaskälla = Databaskälla Databaskälla = Databaskilde
Databasvarning: X = Databasvarning: X Databasvarning: X = Database advarsel: X
Datorröst som läser upp förvarningar = Datorröst som läser upp förvarningar Datorröst som läser upp förvarningar = Computerstemme der læser forvarslinger op
Datum (för första start) = Datum (för första start) Datum (för första start) = Dato (for første start)
Datum = Datum Datum = Dato
Datumfilter = Datumfilter Datumfilter = Datofilter
Debug = Testkör Debug = Afprøv
Debug Output = Resultat av testkörning Debug Output = Resultat af afprøvning
Debug X for Y = Testkör X med Y Debug X for Y = Afprøv X med Y
Decimalseparator = Decimaltecken Decimalseparator = Decimal separator
DefaultFont = Standardformatering DefaultFont = Standardtegnsæt
Define forking = Definiera gaffling Define forking = Definier gafflinger
Definierade mappningar = Definierade mappningar Definierade mappningar = Definierede mappningar
Dela = Dela Dela = Del
Dela efter placering = Dela efter placering Dela efter placering = Del efter placering
Dela efter ranking = Dela efter ranking Dela efter ranking = Del efter ranking
Dela efter tid = Dela efter tid Dela efter tid = Del efter tid
Dela klass: X = Dela klass: X Dela klass: X = Del klass: X
Dela klassen = Dela klassen Dela klassen = Del klassen
Dela klubbvis = Dela klubbvis Dela klubbvis = Del klubbvis
Dela slumpmässigt = Dela slumpmässigt Dela slumpmässigt = Del tilfældigt
Dela upp = Dela upp Dela upp = Del op
delar placering med X = delar placering med X delar placering med X = deler placering med X
Deltagare %d = Deltagare %d Deltagare %d = Deltagere %d
Deltagare (kvarvarande) = Deltagare (tilbage) Deltagare (kvarvarande) = Deltagere (tilbage)
Deltagare = Deltagare Deltagare = Deltagere
Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltageren 'X' deltager i patruljeklassen 'Y' men savner patrulje. Klassens start- och resultatlister kan derfor blive fejlbehæftede
Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- och resultatlistor kan därmed bli felaktiga = Deltageren 'X' deltar i stafettklasse 'Y' men saknar hold. Klassens start- och resultatlister kan derfor blive fejlbehæftede
Deltagaren 'X' saknar klass = Deltagaren 'X' saknar klass Deltagaren 'X' saknar klass = Deltagar 'X' savner klasse
Deltagarens klass styrs av laget = Deltagarens klass styrs av laget Deltagarens klass styrs av laget = Deltagerens klasse styres af holdet
Deltar ej = Deltar ej Deltar ej = Deltager ikke
Denna etapps nummer = Denna etapps nummer Denna etapps nummer = Denne etappes nummer
Description = Beskrivning Description = Beskrivelse
Destination: X = Destination: X Destination: X = Destination: X
Destinationskatalog = Mappe at gemme i Destinationskatalog = Mappe at gemme i
Det finns anmälningsdata för flera etapper = Det findes timeldinddata for flere etapper Det finns anmälningsdata för flera etapper = Det findes timeldinddata for flere etapper
@ -477,6 +478,7 @@ Endast grundläggande = Grundfunktioner
Endast på obligatoriska sträckor = Håndter kun obligatoriske stræk. Endast på obligatoriska sträckor = Håndter kun obligatoriske stræk.
Enhetens ID-nummer (MAC) = Enhedens ID (MAC) Enhetens ID-nummer (MAC) = Enhedens ID (MAC)
Enhetstyp = Enhedstype Enhetstyp = Enhedstype
EntryTime = Tilmeldingstidspunkt
Error in result module X, method Y (Z) = Fejl i resultatmodul 'X', metode 'Y'\n\nZ Error in result module X, method Y (Z) = Fejl i resultatmodul 'X', metode 'Y'\n\nZ
error:invalidmethod = Den valgte metode gav ikke nogen fordeling. Kildedata utilstrækkelige. error:invalidmethod = Den valgte metode gav ikke nogen fordeling. Kildedata utilstrækkelige.
Etapp = Etape Etapp = Etape
@ -500,6 +502,7 @@ Exportera alla till HTML = Eksporter alle til HTML
Exportera alla till PDF = Exporter alt til PDF Exportera alla till PDF = Exporter alt til PDF
Exportera datafil = Eksporter datafil Exportera datafil = Eksporter datafil
Exportera elektroniska fakturor = Eksporter elektroniske fakturaer Exportera elektroniska fakturor = Eksporter elektroniske fakturaer
Exportera ett kalkylblad med lottningsinställningar som du kan redigera och sedan läsa in igen = Exporter et regneark med lodtrækningsindstillinger som du kan redigere og derefter læse ind igen
Exportera individuella lopp istället för lag = Eksporter individuelle løb istedet for hold Exportera individuella lopp istället för lag = Eksporter individuelle løb istedet for hold
Exportera inställningar och löpardatabaser = Eksporter opsætning og løberdatabaser Exportera inställningar och löpardatabaser = Eksporter opsætning og løberdatabaser
Exportera klubbar (IOF-XML) = Eksporter klubber (IOF-XML) Exportera klubbar (IOF-XML) = Eksporter klubber (IOF-XML)
@ -601,6 +604,7 @@ Filnamnet får inte vara tomt = Filnavnet må ikke være tomt
Filnamnsprefix = Prefix for filnavn Filnamnsprefix = Prefix for filnavn
Filter = Filter Filter = Filter
FilterHasCard = Med brik FilterHasCard = Med brik
FilterNoCancel = Ej afbud
FilterNoCard = Uden brik FilterNoCard = Uden brik
FilterNotVacant = Ikke vakant FilterNotVacant = Ikke vakant
FilterOnlyVacant = Kun vakant FilterOnlyVacant = Kun vakant
@ -752,6 +756,7 @@ help:dbage = Løberdatabasen er ældre end 2 måneder. Vil du hente en opdateret
help:DirectResult = - Hvis der ikke er nogen bane sættes status til OK ved målstempling.\n\n- Hvis der er en bane med radioposter over det hele er det ikke nødvendigt at aflæse brikken. help:DirectResult = - Hvis der ikke er nogen bane sættes status til OK ved målstempling.\n\n- Hvis der er en bane med radioposter over det hele er det ikke nødvendigt at aflæse brikken.
help:duplicate = Lav en lokal kopi af det aktuelle løb. help:duplicate = Lav en lokal kopi af det aktuelle løb.
help:eventorkey = Indtast klubbens API-nøgle for Eventor, den er nødvendig for at kunne tilslutte til Eventor og hente tilmeldinger og løberregister. Nøglen får du af klubbens Eventor-administrator. help:eventorkey = Indtast klubbens API-nøgle for Eventor, den er nødvendig for at kunne tilslutte til Eventor og hente tilmeldinger og løberregister. Nøglen får du af klubbens Eventor-administrator.
help:exportdraw = Du kan exportere et regneark i CSV-format der for hver klasse indeholder, antal tilmeldte og lodtrækningerne. Du kan herefter redigera lodtrækningerne og importere det tillbage til MeOS til lodtrækning.
help:fullscreen = Du kan justere hastigheden med Ctrl+M (hurtigere) respektive Ctrl+N (langsommere) på tastaturet. For at forlade fuldskærm, tryk på Esc. help:fullscreen = Du kan justere hastigheden med Ctrl+M (hurtigere) respektive Ctrl+N (langsommere) på tastaturet. For at forlade fuldskærm, tryk på Esc.
help:import_entry_data = Du kan importere løbere, klasser, klubber og tilmeldinger i et antal forskellige tekst- og XML-formater. Det er ikke nødvendigt at angive samtlige filer. F.eks. indeholder OE-CSV format for tilmeldinger såvel klasser som klubber. I det tilfælde behøver felterne for klasser og klubber ikke at indlæses separat\n\nHvis information om samme løber importeres flere gange, bliver løberens information opdateret de efterfølgende gange. Der dannes ikke flere kopier af løberen i databasen. Det gør at man kan importere eftertilmeldinger ved at importere en opdateret fil med samtlige tilmeldinger. help:import_entry_data = Du kan importere løbere, klasser, klubber og tilmeldinger i et antal forskellige tekst- og XML-formater. Det er ikke nødvendigt at angive samtlige filer. F.eks. indeholder OE-CSV format for tilmeldinger såvel klasser som klubber. I det tilfælde behøver felterne for klasser og klubber ikke at indlæses separat\n\nHvis information om samme løber importeres flere gange, bliver løberens information opdateret de efterfølgende gange. Der dannes ikke flere kopier af løberen i databasen. Det gør at man kan importere eftertilmeldinger ved at importere en opdateret fil med samtlige tilmeldinger.
help:importcourse = Du kan importere baner og klasser fra (eksempelvis) OCAD's eller Condes i IOF XML format. help:importcourse = Du kan importere baner og klasser fra (eksempelvis) OCAD's eller Condes i IOF XML format.
@ -816,6 +821,7 @@ Importerar anmälningar (IOF, xml) = Importerer tilmeldinger (IOF, XML)
Importerar banor (IOF, xml) = Importerer baner (IOF, XML) Importerar banor (IOF, xml) = Importerer baner (IOF, XML)
Importerar klasser (IOF, xml) = Importerer klasser (IOF, XML) Importerar klasser (IOF, xml) = Importerer klasser (IOF, XML)
Importerar klubbar (IOF, xml) = Importerer klubber (IOF, XML) Importerar klubbar (IOF, xml) = Importerer klubber (IOF, XML)
Importerar lottningsinställningar = Importerar lodtrækningsindstilninger
Importerar OCAD csv-fil = Importerer OCAD csv-fil Importerar OCAD csv-fil = Importerer OCAD csv-fil
Importerar OE2003 csv-fil = Importerer OE2003 csv-fil Importerar OE2003 csv-fil = Importerer OE2003 csv-fil
Importerar OS2003 csv-fil = Importerer OS2003 csv-fil Importerar OS2003 csv-fil = Importerer OS2003 csv-fil
@ -860,8 +866,9 @@ Ingen klass = Ingen klasse
Ingen klass vald = Ingen klasse valgt Ingen klass vald = Ingen klasse valgt
Ingen löpare saknar bricka = Ingen løbere mangler SI-brik Ingen löpare saknar bricka = Ingen løbere mangler SI-brik
Ingen matchar 'X' = Ingen matcher 'X' Ingen matchar 'X' = Ingen matcher 'X'
Ingen nummerlapp = Intet brystnummer
Ingen parstart = Individuel start Ingen parstart = Individuel start
Ingen rogaining = Ingen pointløb Ingen rogaining = Intet pointløb
Inget filter = Intet filter Inget filter = Intet filter
Inget nummer = Intet nummer Inget nummer = Intet nummer
Inkludera information om flera lopp per löpare = Inkluder information om flere løb for den enkelte løber Inkludera information om flera lopp per löpare = Inkluder information om flere løb for den enkelte løber
@ -914,6 +921,7 @@ Källa = Kilde(fra)
Källkatalog = Mappe at hente fra Källkatalog = Mappe at hente fra
Kön = Køn Kön = Køn
Kör kontroll inför tävlingen = Foretag kontrol før løbet Kör kontroll inför tävlingen = Foretag kontrol før løbet
Kalkylblad/csv = Regneark/csv
kartor = kort kartor = kort
klar = færdig klar = færdig
Klart = Færdig Klart = Færdig
@ -1322,12 +1330,14 @@ Para ihop = Dan par
Para ihop bricka X med en deltagare = Par brik X med en deltager Para ihop bricka X med en deltagare = Par brik X med en deltager
Parallell = Parallel Parallell = Parallel
Parvis (två och två) = Parvis (to og to) Parvis (två och två) = Parvis (to og to)
Patrol Team Rogaining = Rogaining (Hold/Patrulje)
PatrolClubNameNames = Deltagers (eller patruljes) klub(ber) PatrolClubNameNames = Deltagers (eller patruljes) klub(ber)
PatrolNameNames = Deltagers (eller patruljes) navn(e) PatrolNameNames = Deltagers (eller patruljes) navn(e)
Patrols = Patruljer Patrols = Patruljer
Patrull = Patrulje Patrull = Patrulje
Patrull, 1 SI-pinne = Patrulje, 1 SI-brik Patrull, 1 SI-pinne = Patrulje, 1 SI-brik
Patrull, 2 SI-pinnar = Patrulje, 2 SI-brikker Patrull, 2 SI-pinnar = Patrulje, 2 SI-brikker
Patrullresultat (STOR) = Patruljeresultat (STOR)
PDF = PDF PDF = PDF
Personer = Personer Personer = Personer
Plac = Plac Plac = Plac
@ -1370,7 +1380,8 @@ prefsCurrencySymbol = Valutasymbol
prefsDatabase = Brug løberdatabase prefsDatabase = Brug løberdatabase
prefsDatabaseUpdate = Seneste opdatering af løberdatabase prefsDatabaseUpdate = Seneste opdatering af løberdatabase
prefsDefaultDrawMethod = Foretrukken lodtrækningsmetode prefsDefaultDrawMethod = Foretrukken lodtrækningsmetode
prefsDirectPort = Netværksport for forhåndsinformation om stemplingar prefsDirectPort = Netværksport for forhåndsinformation om stemplinger
prefsDrawInterlace = Klip klasser/baner ved vid lodtrækning
prefsEliteFee = Standard elite startgebyr prefsEliteFee = Standard elite startgebyr
prefsEMail = Arrangør email prefsEMail = Arrangør email
prefsEntryFee = Standard startgebyr prefsEntryFee = Standard startgebyr
@ -1399,6 +1410,7 @@ prefsPort = MySQL netværksport
prefsRentCard = Lej af Si brikker prefsRentCard = Lej af Si brikker
prefsSeniorAge = Aldergrænse for pensionistgebyr prefsSeniorAge = Aldergrænse for pensionistgebyr
prefsServer = Forvalgt netværks server prefsServer = Forvalgt netværks server
prefsServicePort = Forudvalgt serviceport
prefsSpeakerShortNames = Brug initialer i navn prefsSpeakerShortNames = Brug initialer i navn
prefssplitanalysis = Foretag stræktidsanalyse prefssplitanalysis = Foretag stræktidsanalyse
prefsSplitLateFees = Opdel beløb for for sen tilmelding i normal- og tillægsdel ved IOF XML eksport prefsSplitLateFees = Opdel beløb for for sen tilmelding i normal- og tillægsdel ved IOF XML eksport
@ -1526,6 +1538,8 @@ reused card = genbrugt brik
Rogaining-poäng = Points Rogaining-poäng = Points
Rogaining = Pointløb Rogaining = Pointløb
Rogaining points for each team member = Pointløbs points for hvert holdmedlem Rogaining points for each team member = Pointløbs points for hvert holdmedlem
Rogaining results for a patrol = Pointløbsresultater for en patrulje med to eller flere deltagare.
Rogaining results for a team, where each team member collects points individually = Pointløbsresultater for et hold hvor hver deltager individuelt samler point
Rogaining, individuell = Pointløb, individuelt Rogaining, individuell = Pointløb, individuelt
RogainingPunch = Stempling, pointløb RogainingPunch = Stempling, pointløb
Rogainingresultat - %s = Rogaining resultater - %s Rogainingresultat - %s = Rogaining resultater - %s
@ -1566,6 +1580,8 @@ RunnerClassCourseTimeAfter = Tid efter på bane indenfor klasse
RunnerClub = Løbers klub RunnerClub = Løbers klub
RunnerCompleteName = Fulde navn RunnerCompleteName = Fulde navn
RunnerCourse = Løbers bane RunnerCourse = Løbers bane
RunnerEntryDate = Dato for tilmelding
RunnerEntryTime = Tidspunkt for tilmelding
RunnerFamilyName = Efternavn RunnerFamilyName = Efternavn
RunnerFee = Startafgift RunnerFee = Startafgift
RunnerFinish = Løbers måltid RunnerFinish = Løbers måltid
@ -1579,6 +1595,8 @@ RunnerLegNumber = Løbere grupperet efter stræk
RunnerLegNumberAlpha = Formateret turnummer RunnerLegNumberAlpha = Formateret turnummer
RunnerName = Løbers navn RunnerName = Løbers navn
RunnerNationality = Løbers nationalitet RunnerNationality = Løbers nationalitet
RunnerPaid = Betalt beløb
RunnerPayMethod = Betalningsmåde
RunnerPhone = Løbers telefonnummer RunnerPhone = Løbers telefonnummer
RunnerPlace = Løbers placering RunnerPlace = Løbers placering
RunnerPlaceDiff = Løbers placering, forskel RunnerPlaceDiff = Løbers placering, forskel
@ -1776,6 +1794,7 @@ Stämplingar = Stemplinger
Stämplingar saknas: X = Stemplinger mangler: X Stämplingar saknas: X = Stemplinger mangler: X
Stämplingsautomat = Kontrolenhed Stämplingsautomat = Kontrolenhed
Stämplingsintervall (MM:SS) = Stemplingsinterval (MM:SS) Stämplingsintervall (MM:SS) = Stemplingsinterval (MM:SS)
Stämplingsintervall, rogaining-patrull = Stemplingsintervall for pointløbspatrulje
Stämplingstest [!] = Stemplingstest [!] Stämplingstest [!] = Stemplingstest [!]
Stämplingstest = Stemplingstest Stämplingstest = Stemplingstest
Stämplingstid = Stemplingstid Stämplingstid = Stemplingstid
@ -1822,6 +1841,7 @@ Startlista %%s - sträcka %d = Startliste %%s - tur %d
Startlista = Startliste Startlista = Startliste
Startlista ett visst lopp = Startliste for et bestemt løb Startlista ett visst lopp = Startliste for et bestemt løb
Startlista lopp X - Y = Startliste løb X - Y Startlista lopp X - Y = Startliste løb X - Y
Startlista, banvis = Startliste, per bane
Startlista, individuell = Startliste, individuel Startlista, individuell = Startliste, individuel
Startlista, patrull = Startliste, patruljer Startlista, patrull = Startliste, patruljer
Startlista, stafett (lag) = Startliste, stafet (hold) Startlista, stafett (lag) = Startliste, stafet (hold)
@ -2262,7 +2282,7 @@ warn:olddbversion = Databasen bruges af en nyere version af MeOS. Opgradering an
warn:opennewversion = Dette løb er dannet i MeOS X. Du risikerer at tabe data hvis du fortsætter.\n\nVil du fortsætte? warn:opennewversion = Dette løb er dannet i MeOS X. Du risikerer at tabe data hvis du fortsætter.\n\nVil du fortsætte?
warn:updatelegs = Det kan være nødvendigt at opdatere længden af de enkelte baner. warn:updatelegs = Det kan være nødvendigt at opdatere længden af de enkelte baner.
warning:dbproblem = ADVARSEL. Problemer med databaseforbindelsen: 'X'. Forbindelsen genoprettes automatisk. Fortsæt med at arbejde normalt. warning:dbproblem = ADVARSEL. Problemer med databaseforbindelsen: 'X'. Forbindelsen genoprettes automatisk. Fortsæt med at arbejde normalt.
warning:direct_result = OBS. bruf af <Resultat ved målstempling> 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 <Resultat ved målstempling> 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: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_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? warning:has_results = Klassen har allerede resultater. Ændring af turfordelingen er usædvanligt.\n\nVil du fortsætte?

View File

@ -12,7 +12,7 @@ ALLA( = All(
API-nyckel = API key API-nyckel = API key
Accepterade elektroniska fakturor = Accepted electronic invoices Accepterade elektroniska fakturor = Accepted electronic invoices
Adress = Address Adress = Address
Adress och kontakt = Address and contact Adress och kontakt = Address and Contact
Aktivera = Activate Aktivera = Activate
Alla = All Alla = All
Alla banfiler = All course files 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 %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 Bekräfta att deltagaren har lämnat återbud = Please confirm drop out of this runner
Betalat = Paid Betalat = Paid
Betalningsinformation = Payment details Betalningsinformation = Payment Details
Bevakar händelser i X = Monitoring events in X Bevakar händelser i X = Monitoring events in X
Bevakningsprioritering = Select runner to watch Bevakningsprioritering = Select runner to watch
Block = Block Block = Block
@ -1115,7 +1115,7 @@ Tävlingsinställningar = Competition Settings
Tävlingsinställningar (IOF, xml) = Competition settings (IOF, xml) Tävlingsinställningar (IOF, xml) = Competition settings (IOF, xml)
Tävlingsnamn = Competition name Tävlingsnamn = Competition name
Tävlingsrapport = Competition Report Tävlingsrapport = Competition Report
Tävlingsregler = Competition rules Tävlingsregler = Competition Rules
Tävlingsstatistik = Competition Statistics Tävlingsstatistik = Competition Statistics
Underlag för tävlingsavgift = Data for competition fee Underlag för tävlingsavgift = Data for competition fee
Underlista = Sub list Underlista = Sub list
@ -1422,7 +1422,7 @@ xml-data = xml data
Åldersfilter = Age filter Åldersfilter = Age filter
Åldersgräns ungdom = Age limit, low Åldersgräns ungdom = Age limit, low
Åldersgräns äldre = Age limit, high Å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 Ångra = Undo
Återansluten mot databasen, tävlingen synkroniserad = Reconnected to database, competition synchronized Återansluten mot databasen, tävlingen synkroniserad = Reconnected to database, competition synchronized
Återbud = Drop Out Å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 Välj etapp att importera = Select stage to import
ask:savespeaker = Do you wish to save current class and window settings on this computer? 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 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? ask:loadspeaker = Do you wish to recreate previously saved windows on this computer?
Återskapa = Re-create Återskapa = Recreate
Återskapa tidigare sparade fönster- och speakerinställningar = Re-create previously saved windows and settings Å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 Inkludera resultat från tidigare etapper = Include results from all stages
Animation = Animation Animation = Animation
Bakgrund = Background Bakgrund = Background
@ -2292,7 +2292,7 @@ Informationsserver = Information server
Längsta svarstid: X ms = Longest response time: X ms Längsta svarstid: X ms = Longest response time: X ms
MeOS Informationsserver REST-API = MeOS Information Server REST-API MeOS Informationsserver REST-API = MeOS Information Server REST-API
Testa servern = Test the server 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 Server startad på X = Server running on port X
Inconsistent qualification rule, X = Inconsistent qualification rule, 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. 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 FilterNoCancel = Not cancelled
CourseStartTime = Course, start time CourseStartTime = Course, start time
Startlista, banvis = Start list, by course 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) Patrullresultat (STOR) = Patrol results (LARGE)
Patrol Team Rogaining = Patrol Team Rogaining Patrol Team Rogaining = Patrol Team Rogaining
Rogaining results for a patrol = Rogaining results for a patrol of two or more competitors. 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 prefsServicePort = Default service port
Ingen nummerlapp = No bib 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 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.

View File

@ -78,6 +78,7 @@ extern Image image;
static int debugDrawColor = 0; static int debugDrawColor = 0;
#endif #endif
extern int defaultCodePage;
GuiHandler &BaseInfo::getHandler() const { GuiHandler &BaseInfo::getHandler() const {
if (handler == 0) if (handler == 0)
@ -106,9 +107,8 @@ bool gdioutput::skipTextRender(int format) {
#ifndef MEOSDB #ifndef MEOSDB
gdioutput::gdioutput(const string &_tag, double _scale, int defaultCodePage) : gdioutput::gdioutput(const string &_tag, double _scale) :
recorder((Recorder *)0, false), recorder((Recorder *)0, false) {
defaultCodePage(defaultCodePage) {
tag = _tag; tag = _tag;
po_default = new PrinterObject(); po_default = new PrinterObject();
tabs = 0; tabs = 0;
@ -118,8 +118,8 @@ gdioutput::gdioutput(const string &_tag, double _scale, int defaultCodePage) :
isTestMode = false; isTestMode = false;
} }
gdioutput::gdioutput(double _scale, HWND hWnd, const PrinterObject &prndef, int defaultCodePage) : gdioutput::gdioutput(double _scale, HWND hWnd, const PrinterObject &prndef) :
recorder((Recorder *)0, false), defaultCodePage(defaultCodePage) { recorder((Recorder *)0, false) {
hasAnyTimer = false; hasAnyTimer = false;
po_default = new PrinterObject(prndef); po_default = new PrinterObject(prndef);
tabs = 0; tabs = 0;
@ -6378,9 +6378,9 @@ const wstring &gdioutput::widen(const string &input) {
return output; return output;
} }
const wstring &gdioutput::recodeToWide(const string &input) const { const wstring &gdioutput::recodeToWide(const string &input) {
wstring &output = StringCache::getInstance().wget(); wstring &output = StringCache::getInstance().wget();
int cp = 1252; int cp = defaultCodePage;
// if (defaultCodePage > 0) // if (defaultCodePage > 0)
// cp = defaultCodePage; // cp = defaultCodePage;
@ -6406,9 +6406,9 @@ const wstring &gdioutput::recodeToWide(const string &input) const {
return output; return output;
} }
const string &gdioutput::recodeToNarrow(const wstring &input) const { const string &gdioutput::recodeToNarrow(const wstring &input) {
string &output = StringCache::getInstance().get(); string &output = StringCache::getInstance().get();
int cp = 1252; int cp = defaultCodePage;
// if (defaultCodePage > 0) // if (defaultCodePage > 0)
// cp = defaultCodePage; // cp = defaultCodePage;
@ -6428,10 +6428,12 @@ const string &gdioutput::recodeToNarrow(const wstring &input) const {
output = ""; output = "";
return output; return output;
} }
output.reserve(input.size()+1); int res = input.size() * 3 + 2;
output.reserve(res);
output.resize(input.size(), 0); output.resize(input.size(), 0);
BOOL usedDef = false; 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; return output;
} }
/* /*

View File

@ -283,7 +283,6 @@ protected:
shared_ptr<AnimationData> animationData; shared_ptr<AnimationData> animationData;
shared_ptr<AutoCompleteInfo> autoCompleteInfo; shared_ptr<AutoCompleteInfo> autoCompleteInfo;
int defaultCodePage;
public: public:
AutoCompleteInfo &addAutoComplete(const string &key); AutoCompleteInfo &addAutoComplete(const string &key);
@ -324,8 +323,8 @@ public:
bool isTest() const {return isTestMode;} bool isTest() const {return isTestMode;}
const string &getTag() const {return tag;} const string &getTag() const {return tag;}
bool hasTag(const string &t) const {return tag == t;} bool hasTag(const string &t) const {return tag == t;}
const wstring &recodeToWide(const string &input) const; static const wstring &recodeToWide(const string &input);
const string &recodeToNarrow(const wstring &input) const; static const string &recodeToNarrow(const wstring &input);
static const wstring &widen(const string &input); static const wstring &widen(const string &input);
static const string &narrow(const wstring &input); static const string &narrow(const wstring &input);
@ -752,13 +751,12 @@ public:
void closeWindow(); void closeWindow();
void setDBErrorState(bool state); void setDBErrorState(bool state);
int getCP() const {return defaultCodePage;}
friend int TablesCB(gdioutput *gdi, int type, void *data); friend int TablesCB(gdioutput *gdi, int type, void *data);
friend class Table; friend class Table;
friend gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y); friend gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y);
gdioutput(const string &tag, double _scale, int defaultCodePage); gdioutput(const string &tag, double _scale);
gdioutput(double _scale, HWND hWndTarget, const PrinterObject &defprn, int defaultCodePage); gdioutput(double _scale, HWND hWndTarget, const PrinterObject &defprn);
virtual ~gdioutput(); virtual ~gdioutput();
}; };

View File

@ -408,13 +408,18 @@ void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const {
void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) const { void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) const {
vector< pair<string, wstring> > prop; vector< pair<string, wstring> > prop;
prop.push_back(make_pair("org", itow(organizationId))); prop.reserve(10);
prop.push_back(make_pair("cls", itow(classId))); prop.emplace_back("org", itow(organizationId));
prop.push_back(make_pair("stat", itow(status))); prop.emplace_back("cls", itow(classId));
prop.push_back(make_pair("st", itow(startTime))); prop.emplace_back("stat", itow(status));
prop.push_back(make_pair("rt", itow(runningTime))); prop.emplace_back("st", itow(startTime));
prop.emplace_back("rt", itow(runningTime));
if (course != 0) 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); xml.write("base", prop, name);
} }
@ -459,6 +464,13 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
runningTime = rt; runningTime = rt;
ch = true; ch = true;
} }
wstring newBib = bc.getBib();
if (bib != newBib) {
bib = newBib;
ch = true;
}
return ch; return ch;
} }

View File

@ -156,6 +156,7 @@ class InfoBaseCompetitor : public InfoBase {
int status; int status;
int startTime; int startTime;
int runningTime; int runningTime;
wstring bib;
void serialize(xmlbuffer &xml, bool diffOnly, int course) const; void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
bool synchronizeBase(oAbstractRunner &bc); bool synchronizeBase(oAbstractRunner &bc);
public: public:

View File

@ -67,6 +67,7 @@
#include "autocomplete.h" #include "autocomplete.h"
#include "image.h" #include "image.h"
int defaultCodePage = 1252;
Image image; Image image;
gdioutput *gdi_main=0; gdioutput *gdi_main=0;
@ -207,9 +208,13 @@ int APIENTRY WinMain(HINSTANCE hInstance,
enableTests = true; enableTests = true;
} }
HWND hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc); HWND hSplash = nullptr;
ShowWindow(hSplash, SW_SHOW); if (strstr(lpCmdLine, "-nosplash") == 0) {
UpdateWindow(hSplash); hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc);
ShowWindow(hSplash, SW_SHOW);
UpdateWindow(hSplash);
}
DWORD splashStart = GetTickCount(); DWORD splashStart = GetTickCount();
for (int k = 0; k < 100; k++) { for (int k = 0; k < 100; k++) {
@ -253,7 +258,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
HACCEL hAccelTable; HACCEL hAccelTable;
gdi_main = new gdioutput("main", 1.0, 0); gdi_main = new gdioutput("main", 1.0);
gdi_extra.push_back(gdi_main); gdi_extra.push_back(gdi_main);
try { try {
@ -297,6 +302,8 @@ int APIENTRY WinMain(HINSTANCE hInstance,
wstring defLang = gEvent->getPropertyString("Language", L"Svenska"); wstring defLang = gEvent->getPropertyString("Language", L"Svenska");
defaultCodePage = gEvent->getPropertyInt("CodePage", 1252);
// Backward compatibility // Backward compatibility
if (defLang==L"103") if (defLang==L"103")
defLang = L"Svenska"; defLang = L"Svenska";
@ -399,8 +406,10 @@ int APIENTRY WinMain(HINSTANCE hInstance,
gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0), gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0),
gEvent->getPropertyString("TextFont", L"Arial")); gEvent->getPropertyString("TextFont", L"Arial"));
DWORD startupToc = GetTickCount() - splashStart; if (hSplash != nullptr) {
Sleep(min<int>(1000, max<int>(0,700 - startupToc))); DWORD startupToc = GetTickCount() - splashStart;
Sleep(min<int>(1000, max<int>(0, 700 - startupToc)));
}
// Perform application initialization: // Perform application initialization:
if (!InitInstance (hInstance, nCmdShow)) { if (!InitInstance (hInstance, nCmdShow)) {
@ -425,7 +434,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS); hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS);
DestroyWindow(hSplash); DestroyWindow(hSplash);
initMySQLCriticalSection(true); initMySQLCriticalSection(true);
@ -852,7 +860,7 @@ gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x,
ShowWindow(hWnd, SW_SHOWNORMAL); ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd); UpdateWindow(hWnd);
gdioutput *gdi = new gdioutput(tag, 1.0, 0); gdioutput *gdi = new gdioutput(tag, 1.0);
gdi->setFont(gEvent->getPropertyInt("TextSize", 0), gdi->setFont(gEvent->getPropertyInt("TextSize", 0),
gEvent->getPropertyString("TextFont", L"Arial")); 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 //The card has been read and posted to a synchronized
//queue by different thread. Read and process this card. //queue by different thread. Read and process this card.
{ {
SICard sic; SICard sic(ConvertedTimeStatus::Unknown);
while (gSI && gSI->getCard(sic)) while (gSI && gSI->getCard(sic))
InsertSICard(*gdi_main, sic); InsertSICard(*gdi_main, sic);
break; break;

View File

@ -38,7 +38,7 @@ namespace MeOSUtil {
string convertSystemTimeN(const SYSTEMTIME &st); string convertSystemTimeN(const SYSTEMTIME &st);
string convertSystemDateN(const SYSTEMTIME &st); string convertSystemDateN(const SYSTEMTIME &st);
string convertSystemTimeOnlyN(const SYSTEMTIME &st); string convertSystemTimeOnlyN(const SYSTEMTIME &st);
extern int defaultCodePage;
DWORD mainThreadId = -1; DWORD mainThreadId = -1;
StringCache &StringCache::getInstance() { StringCache &StringCache::getInstance() {
@ -180,7 +180,7 @@ SYSTEMTIME Int64SecondToSystemTime(__int64 time) {
//2014-11-03 07:02:00 //2014-11-03 07:02:00
string convertSystemTimeN(const SYSTEMTIME &st) 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, sprintf_s(bf, "%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond); st.wHour, st.wMinute, st.wSecond);
@ -190,7 +190,7 @@ string convertSystemTimeN(const SYSTEMTIME &st)
//2014-11-03 07:02:00 //2014-11-03 07:02:00
wstring convertSystemTime(const SYSTEMTIME &st) 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, swprintf_s(bf, L"%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond); 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) { void string2Wide(const string &in, wstring &out) {
int cp = 1252; int cp = defaultCodePage;
if (in.empty()) { if (in.empty()) {
out = L""; out = L"";
return; return;

View File

@ -29,7 +29,7 @@
//V33: abcde //V33: abcde
//V35: abcde //V35: abcde
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 652 $"); string revision("$Rev: 669 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
@ -39,14 +39,14 @@ int getMeosBuild() {
//V31: abcde //V31: abcde
//V32: abcdefgh //V32: abcdefgh
//V33: abcdefghij //V33: abcdefghij
//V34: abcdfg //V34: abcdfge
wstring getMeosDate() { 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); return date.substr(7,10);
} }
wstring getBuildType() { wstring getBuildType() {
return L"RC1"; // No parantheses (...) return L"RC2"; // No parantheses (...)
} }
wstring getMajorVersion() { wstring getMajorVersion() {
@ -185,4 +185,7 @@ void getSupporters(vector<wstring> &supp)
supp.push_back(L"O-Ringen AB"); supp.push_back(L"O-Ringen AB");
supp.push_back(L"Hans Carlstedt, Sävedalens AIK"); supp.push_back(L"Hans Carlstedt, Sävedalens AIK");
supp.push_back(L"Attunda OK"); 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");
} }

View File

@ -463,6 +463,7 @@ bool oCard::isCardRead(const SICard &card) const
void oCard::getSICard(SICard &card) const { void oCard::getSICard(SICard &card) const {
card.clear(0); card.clear(0);
card.CardNumber = cardNo; card.CardNumber = cardNo;
card.convertedTime = ConvertedTimeStatus::Done;
oPunchList::const_iterator it; oPunchList::const_iterator it;
for (it = punches.begin(); it != punches.end(); ++it) { for (it = punches.begin(); it != punches.end(); ++it) {
if (it->Type>30) if (it->Type>30)

View File

@ -1688,7 +1688,7 @@ void oClass::updateChangedCoursePool() {
} }
} }
SICard card; SICard card(ConvertedTimeStatus::Unknown);
oRunnerList::iterator it; oRunnerList::iterator it;
for (it = oe->Runners.begin(); it != oe->Runners.end(); ++it) { for (it = oe->Runners.begin(); it != oe->Runners.end(); ++it) {
if (it->isRemoved() || it->Class != this) if (it->isRemoved() || it->Class != this)
@ -4284,6 +4284,17 @@ void oClass::loadQualificationFinalScheme(const wstring &fileName) {
inst->synchronize(); inst->synchronize();
} }
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) { void oClass::updateFinalClasses(oRunner *causingResult, bool updateStartNumbers) {

View File

@ -579,6 +579,7 @@ void oEvent::listProperties(bool userProps, vector< pair<string, PropertyType> >
i.insert("addressxpos"); i.insert("addressxpos");
i.insert("AutoSaveTimeOut"); i.insert("AutoSaveTimeOut");
i.insert("ServicePort"); i.insert("ServicePort");
i.insert("CodePage");
propNames.clear(); propNames.clear();
for(map<string, wstring>::const_iterator it = eventProperties.begin(); for(map<string, wstring>::const_iterator it = eventProperties.begin();
@ -924,7 +925,7 @@ bool oEvent::save(const wstring &fileIn) {
xml.startTag("meosdata", "version", getMajorVersion()); xml.startTag("meosdata", "version", getMajorVersion());
xml.write("Name", Name); xml.write("Name", Name);
xml.write("Date", Date); xml.write("Date", Date);
xml.write("ZeroTime", ZeroTime); xml.write("ZeroTime", itos(ZeroTime));
xml.write("NameId", currentNameId); xml.write("NameId", currentNameId);
xml.write("Annotation", Annotation); xml.write("Annotation", Annotation);
xml.write("Id", Id); xml.write("Id", Id);
@ -1119,6 +1120,7 @@ void oEvent::restoreBackup()
bool oEvent::open(const xmlparser &xml) { bool oEvent::open(const xmlparser &xml) {
xmlobject xo; xmlobject xo;
ZeroTime = 0;
xo = xml.getObject("Date"); xo = xml.getObject("Date");
if (xo) Date=xo.getw(); if (xo) Date=xo.getw();
@ -2434,37 +2436,6 @@ int oEvent::getRelativeTime(const wstring &m) const {
else return -1; 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<int> &ids) void oEvent::removeRunner(const vector<int> &ids)
{ {
oRunnerList::iterator it; oRunnerList::iterator it;
@ -4036,12 +4007,47 @@ int oEvent::findBestClass(const SICard &card, vector<pClass> &classes) const
return Distance; 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; 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.Code!=-1){
if (sic.CheckPunch.Time<ZeroTime) if (sic.CheckPunch.Time<ZeroTime)
@ -4819,6 +4825,7 @@ void oEvent::analyzeClassResultStatus() const
void oEvent::generateTestCard(SICard &sic) const void oEvent::generateTestCard(SICard &sic) const
{ {
sic.clear(0); sic.clear(0);
sic.convertedTime == ConvertedTimeStatus::Hour24;
if (Runners.empty()) if (Runners.empty())
return; return;

View File

@ -864,7 +864,7 @@ public:
/** Returns the first start in a class */ /** Returns the first start in a class */
int getFirstStart(int classId = 0) const; int getFirstStart(int classId = 0) const;
void convertTimes(SICard &sic) const; void convertTimes(pRunner runner, SICard &sic) const;
pCard getCard(int Id) const; pCard getCard(int Id) const;
pCard getCardByNumber(int cno) const; pCard getCardByNumber(int cno) const;
@ -941,8 +941,8 @@ public:
/// Convert a clock time string to time relative zero time /// Convert a clock time string to time relative zero time
int getRelativeTime(const string &date, const string &absoluteTime, const string &timeZone) const; int getRelativeTime(const string &date, const string &absoluteTime, const string &timeZone) const;
/// Convert a clock time string (SI5 12 Hour clock) to time relative zero time // Convert a clock time string (SI5 12 Hour clock) to time relative zero time
int getRelativeTimeFrom12Hour(const wstring &absoluteTime) const; //int getRelativeTimeFrom12Hour(const wstring &absoluteTime) const;
/// Convert c clock time string to absolute time (after 00:00:00) /// Convert c clock time string to absolute time (after 00:00:00)
static int convertAbsoluteTime(const string &m); static int convertAbsoluteTime(const string &m);

View File

@ -723,7 +723,7 @@ void oRunner::addPunches(pCard card, vector<int> &missingPunches) {
updateChanged(); updateChanged();
if (card) { if (card) {
if (CardNo==0) if (card->cardNo > 0)
CardNo=card->cardNo; CardNo=card->cardNo;
//315422 //315422
assert(card->tOwner==0 || card->tOwner==this); assert(card->tOwner==0 || card->tOwner==this);
@ -739,7 +739,7 @@ void oRunner::addPunches(pCard card, vector<int> &missingPunches) {
int numCtrlLong = mainCourse->getNumControls(); int numCtrlLong = mainCourse->getNumControls();
int numCtrlShort = shortVersion->getNumControls(); int numCtrlShort = shortVersion->getNumControls();
SICard sic; SICard sic(ConvertedTimeStatus::Unknown);
Card->getSICard(sic); Card->getSICard(sic);
int level = 0; int level = 0;
while (mainCourse->distance(sic) < 0 && abs(numCtrl-numCtrlShort) < abs(numCtrl-numCtrlLong)) { while (mainCourse->distance(sic) < 0 && abs(numCtrl-numCtrlShort) < abs(numCtrl-numCtrlLong)) {

View File

@ -368,8 +368,7 @@ void OnlineInput::processPunches(oEvent &oe, list< vector<wstring> > &rocData) {
void OnlineInput::processCards(gdioutput &gdi, oEvent &oe, const xmlList &cards) { void OnlineInput::processCards(gdioutput &gdi, oEvent &oe, const xmlList &cards) {
for (size_t k = 0; k < cards.size(); k++) { for (size_t k = 0; k < cards.size(); k++) {
SICard sic; SICard sic(ConvertedTimeStatus::Hour24);
sic.clear(0);
sic.CardNumber = cards[k].getObjectInt("number"); sic.CardNumber = cards[k].getObjectInt("number");
if (cards[k].getObject("finish")) if (cards[k].getObject("finish"))
sic.FinishPunch.Time = cards[k].getObject("finish").getObjectInt("time") / 10; sic.FinishPunch.Time = cards[k].getObject("finish").getObjectInt("time") / 10;

View File

@ -254,7 +254,7 @@ void RestServer::computeInternal(oEvent &ref, shared_ptr<RestServer::EventReques
auto res = listCache.find(type); auto res = listCache.find(type);
if (res != listCache.end()) { if (res != listCache.end()) {
gdioutput gdiPrint("print", ref.gdiBase().getScale(), ref.gdiBase().getCP()); gdioutput gdiPrint("print", ref.gdiBase().getScale());
gdiPrint.clearPage(false); gdiPrint.clearPage(false);
if (!res->second.second) { if (!res->second.second) {

View File

@ -2298,7 +2298,7 @@ Lås startlista = Lås startlista
FilterNoCancel = Ej återbud FilterNoCancel = Ej återbud
CourseStartTime = Bana, starttid CourseStartTime = Bana, starttid
Startlista, banvis = Startlista, banvis 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) Patrol Team Rogaining = Rogaining (Lag/Patrull)
Rogaining results for a patrol = Rogainingresultat för en patrull med två eller fler deltagare. Rogaining results for a patrol = Rogainingresultat för en patrull med två eller fler deltagare.
Patrullresultat (STOR) = Patrullresultat (STOR) Patrullresultat (STOR) = Patrullresultat (STOR)
@ -2315,3 +2315,5 @@ prefsDrawInterlace = Saxa klasser/banor vid lottning
prefsServicePort = Förvald serviceport prefsServicePort = Förvald serviceport
Ingen nummerlapp = Ingen nummerlapp 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 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.

View File

@ -376,7 +376,7 @@ void TestMeOS::checkStringRes(const char *str, int count) const {
void TestMeOS::insertCard(int cardNo, const char *ser) const { void TestMeOS::insertCard(int cardNo, const char *ser) const {
SICard sic; SICard sic(ConvertedTimeStatus::Unknown);
sic.CardNumber = cardNo; sic.CardNumber = cardNo;
sic.deserializePunches(ser); sic.deserializePunches(ser);
TabSI::getSI(*gdi_main).addCard(sic); TabSI::getSI(*gdi_main).addCard(sic);