MeOS version 3.6.1086

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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