MeOS version 3.5.808.

This commit is contained in:
erikmelin 2017-12-25 19:44:08 +01:00
parent adba758c26
commit 4da3c93866
64 changed files with 3415 additions and 744 deletions

View File

@ -2,13 +2,15 @@
#include "RestService.h" #include "RestService.h"
#include "meos_util.h" #include "meos_util.h"
#include "restserver.h" #include "restserver.h"
#include "meosexception.h"
#include <ShellAPI.h>
int AutomaticCB(gdioutput *gdi, int type, void *data); int AutomaticCB(gdioutput *gdi, int type, void *data);
RestService::RestService() : AutoMachine("RestService"), port(-1) { RestService::RestService() : AutoMachine("Informationsserver"), port(-1) {
} }
RestService::~RestService() { RestService::~RestService() {
if (server) { if (server) {
server->stop(); server->stop();
@ -17,14 +19,17 @@ RestService::~RestService() {
} }
void RestService::save(oEvent &oe, gdioutput &gdi) { void RestService::save(oEvent &oe, gdioutput &gdi) {
if (!server) if (!server) {
server = RestServer::construct(); server = RestServer::construct();
int port = gdi.getTextNo("Port"); int xport = gdi.getTextNo("Port");
if (port > 0 && port < 65536) if (xport > 0 && xport < 65536) {
server->startService(port); port = xport;
else server->startService(port);
throw std::exception("Invalid port number"); }
else
throw meosException("Invalid port number");
}
} }
void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) { void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
@ -35,7 +40,7 @@ void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
startCancelInterval(gdi, "Save", created, IntervalNone, L""); startCancelInterval(gdi, "Save", created, IntervalNone, L"");
if (!server) if (!server)
gdi.addInput("Port", itow(port), 10, 0, L"Port:", L"Testa genom http://localhost:[PORT]/meos"); gdi.addInput("Port", itow(port), 10, 0, L"Port:", L"#http://localhost:[PORT]/meos");
else else
gdi.addString("", 0, "Server startad på X#" + itos(port)); gdi.addString("", 0, "Server startad på X#" + itos(port));
@ -46,29 +51,21 @@ void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
void RestService::status(gdioutput &gdi) { void RestService::status(gdioutput &gdi) {
gdi.pushX(); gdi.pushX();
gdi.addString("", 1, name); gdi.addString("", 1, name);
/*if (!baseFile.empty()) {
gdi.fillRight();
gdi.pushX();
gdi.addString("", 0, L"Destination: X#" + baseFile);
if (interval>0) {
gdi.popX();
gdi.dropLine(1);
gdi.addString("", 0, "Säkerhetskopierar om: ");
gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount() - timeout) / 1000);
}
gdi.popX();
}*/
if (server) { if (server) {
gdi.addString("", 0, "Server startad på port X#" + itos(port)); gdi.addString("", 0, "Server startad på X#" + itos(port));
RestServer::Statistics rs; RestServer::Statistics rs;
server->getStatistics(rs); server->getStatistics(rs);
gdi.addString("", 0, "Antal förfrågningar: X#" + itos(rs.numRequests)); gdi.addString("", 0, "Antal förfrågningar: X.#" + itos(rs.numRequests));
gdi.addString("", 0, "Genomsnittlig svarstid: X ms#" + itos(rs.averageResponseTime)); gdi.addString("", 0, "Genomsnittlig svarstid: X ms.#" + itos(rs.averageResponseTime));
gdi.addString("", 0, "Längsta svarstid: X ms#" + itos(rs.maxResponseTime)); gdi.addString("", 0, "Längsta svarstid: X ms.#" + itos(rs.maxResponseTime));
gdi.dropLine(0.6);
gdi.addButton("Update", "Uppdatera").setHandler(this);
gdi.dropLine(0.6);
gdi.addString("", 1, "Testa servern:");
gdi.addString("link", 0, "#http://localhost:" + itos(port) + "/meos").setHandler(this);
} }
gdi.dropLine(2); gdi.dropLine(2);
@ -87,6 +84,12 @@ void RestService::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
void RestService::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) { void RestService::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
if (type == GUI_BUTTON) { if (type == GUI_BUTTON) {
ButtonInfo &bi = static_cast<ButtonInfo&>(info); ButtonInfo &bi = static_cast<ButtonInfo&>(info);
if (bi.id == "Update") {
gdi.getTabs().get(TAutoTab)->loadPage(gdi);
}
}
else if (type == GUI_LINK) {
wstring url = L"http://localhost:" + itow(port) + L"/meos";
ShellExecute(NULL, L"open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
} }
} }

View File

@ -23,13 +23,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <crtdbg.h> #include <crtdbg.h>
#include <memory.h> #include <memory>
#include <tchar.h> #include <tchar.h>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <crtdbg.h>
using namespace std; using namespace std;
bool getUserFile(wchar_t *fileNamePath, const wchar_t *fileName); bool getUserFile(wchar_t *fileNamePath, const wchar_t *fileName);

View File

@ -671,8 +671,11 @@ void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, bool c
else if (type == IntervalSecond) else if (type == IntervalSecond)
gdi.addInput("Interval", intervalIn, 7, 0, L"Tidsintervall (sekunder):"); gdi.addInput("Interval", intervalIn, 7, 0, L"Tidsintervall (sekunder):");
gdi.dropLine(1); gdi.dropLine(1);
gdi.addButton(startCommand, "Starta automaten", AutomaticCB).setExtra(getId()); gdi.addButton(startCommand, created ? "Starta automaten" : "OK", AutomaticCB).setExtra(getId());
gdi.addButton(created ? "Stop":"Cancel", "Avbryt", AutomaticCB).setExtra(getId()); if (!created)
gdi.addButton("Cancel", "Avbryt", AutomaticCB).setExtra(getId());
gdi.addButton("Stop", created ? "Avbryt" : "Stoppa automaten", AutomaticCB).setExtra(getId());
gdi.popX(); gdi.popX();
gdi.fillDown(); gdi.fillDown();

View File

@ -1325,6 +1325,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
return false; return false;
DWORD cid=ClassId; DWORD cid=ClassId;
pClass pc = oe->getClass(cid);
DrawMethod method = DrawMethod(gdi.getSelectedItem("Method").first); DrawMethod method = DrawMethod(gdi.getSelectedItem("Method").first);
int interval = 0; int interval = 0;
@ -1339,6 +1340,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (gdi.hasField("Leg")) { if (gdi.hasField("Leg")) {
leg = gdi.getSelectedItem("Leg").first; leg = gdi.getSelectedItem("Leg").first;
} }
else if (pc && pc->getParentClass() != 0)
leg = -1;
wstring bib; wstring bib;
bool doBibs = false; bool doBibs = false;
@ -1536,6 +1539,19 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
setMultiDayClass(gdi, gdi.isChecked(bi.id), lastDrawMethod); setMultiDayClass(gdi, gdi.isChecked(bi.id), lastDrawMethod);
} }
else if (bi.id == "QualificationFinal") {
save(gdi, true);
pClass pc = oe->getClass(ClassId);
if (!pc)
throw std::exception("Class not found");
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"Qualfication/Final", L"*.xml"));
wstring fileName = gdi.browseForOpen(ext, L"xml");
pc->loadQualificationFinalScheme(fileName);
pc->updateFinalClasses(0, true);
loadPage(gdi);
}
else if (bi.id=="Bibs") { else if (bi.id=="Bibs") {
save(gdi, true); save(gdi, true);
if (!checkClassSelected(gdi)) if (!checkClassSelected(gdi))
@ -1572,7 +1588,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.selectItemByData("BibSettings", bt); gdi.selectItemByData("BibSettings", bt);
wstring bib = pc->getDCI().getString("Bib"); wstring bib = pc->getDCI().getString("Bib");
if (pc->getNumDistinctRunners() > 1) { if (pc->getNumDistinctRunners() > 1 || pc->getQualificationFinal()) {
bibTeamOptions.push_back(make_pair(lang.tl("Oberoende"), BibFree)); bibTeamOptions.push_back(make_pair(lang.tl("Oberoende"), BibFree));
bibTeamOptions.push_back(make_pair(lang.tl("Samma"), BibSame)); bibTeamOptions.push_back(make_pair(lang.tl("Samma"), BibSame));
bibTeamOptions.push_back(make_pair(lang.tl("Ökande"), BibAdd)); bibTeamOptions.push_back(make_pair(lang.tl("Ökande"), BibAdd));
@ -1620,16 +1636,16 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
AutoBibType bt = AutoBibType(gdi.getSelectedItem("BibSettings").first); AutoBibType bt = AutoBibType(gdi.getSelectedItem("BibSettings").first);
pair<int, bool> teamBib = gdi.getSelectedItem("TeamBib"); pair<int, bool> teamBib = gdi.getSelectedItem("BibTeam");
if (teamBib.second) { if (teamBib.second) {
pc->setBibMode(BibMode(teamBib.first)); pc->setBibMode(BibMode(teamBib.first));
} }
pc->getDI().setString("Bib", getBibCode(bt, gdi.getText("Bib"))); pc->getDI().setString("Bib", getBibCode(bt, gdi.getText("Bib")));
pc->synchronize(); pc->synchronize();
int leg = pc->getParentClass() ? -1 : 0;
if (bt == AutoBibManual) { if (bt == AutoBibManual) {
oe->addBib(cid, 0, gdi.getText("Bib")); oe->addBib(cid, leg, gdi.getText("Bib"));
} }
else { else {
oe->setBibClassGap(gdi.getTextNo("BibGap")); oe->setBibClassGap(gdi.getTextNo("BibGap"));
@ -1644,7 +1660,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
par.selection.insert(cid); par.selection.insert(cid);
oListInfo info; oListInfo info;
par.listCode = EStdStartList; par.listCode = EStdStartList;
par.setLegNumberCoded(0); par.setLegNumberCoded(leg);
oe->generateListInfo(par, gdi.getLineHeight(), info); oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateList(gdi, false, info, true); oe->generateList(gdi, false, info, true);
@ -2223,6 +2239,10 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
if (gdi.hasField("DirectResult")) if (gdi.hasField("DirectResult"))
gdi.check("DirectResult", false); gdi.check("DirectResult", false);
if (gdi.hasField("LockStartList")) {
gdi.check("LockStartList", false);
gdi.setInputStatus("LockStartList", false);
}
gdi.check("NoTiming", false); gdi.check("NoTiming", false);
ClassId=cid; ClassId=cid;
@ -2274,6 +2294,11 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
if (gdi.hasField("DirectResult")) if (gdi.hasField("DirectResult"))
gdi.check("DirectResult", pc->hasDirectResult()); gdi.check("DirectResult", pc->hasDirectResult());
if (gdi.hasField("LockStartList")) {
bool active = pc->getParentClass() != 0;
gdi.setInputStatus("LockStartList", active);
gdi.check("LockStartList", active && pc->lockedClassAssignment());
}
ClassId=cid; ClassId=cid;
if (pc->hasTrueMultiCourse()) { if (pc->hasTrueMultiCourse()) {
@ -2344,9 +2369,10 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
pCourse pcourse = pc->getCourse(); pCourse pcourse = pc->getCourse();
gdi.selectItemByData("Courses", pcourse ? pcourse->getId():-2); gdi.selectItemByData("Courses", pcourse ? pcourse->getId():-2);
} }
if (gdi.hasField("QualificationFinal"))
gdi.setInputStatus("QualificationFinal", pc->getParentClass() == 0);
gdi.selectItemByData("Classes", cid); gdi.selectItemByData("Classes", cid);
ClassId=cid; ClassId=cid;
EditChanged=false; EditChanged=false;
} }
@ -2672,6 +2698,12 @@ void TabClass::save(gdioutput &gdi, bool skipReload)
pc->setDirectResult(withDirect); pc->setDirectResult(withDirect);
} }
if (gdi.hasField("LockStartList")) {
bool locked = gdi.isChecked("LockStartList");
if (pc->getParentClass())
pc->lockedClassAssignment(locked);
}
int crs = gdi.getSelectedItem("Courses").first; int crs = gdi.getSelectedItem("Courses").first;
if (crs==0) { if (crs==0) {
@ -2893,11 +2925,28 @@ bool TabClass::loadPage(gdioutput &gdi)
gdi.addCheckbox("DirectResult", "Resultat vid målstämpling", 0, false, gdi.addCheckbox("DirectResult", "Resultat vid målstämpling", 0, false,
"help:DirectResult"); "help:DirectResult");
} }
gdi.dropLine(2); gdi.dropLine(2);
gdi.popX(); gdi.popX();
{
vector<pClass> pcls;
oe->getClasses(pcls, false);
bool hasCF = false;
for (pClass pc : pcls) {
if (pc->getQualificationFinal()) {
hasCF = true;
break;
}
}
if (hasCF) {
gdi.addCheckbox("LockStartList", "Lås startlista", 0, false,
"help:LockStartList");
gdi.dropLine(2);
gdi.popX();
}
}
vector<ButtonData> func; vector<ButtonData> func;
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList)) if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList))
func.push_back(ButtonData("Draw", "Lotta / starttider...", false)); func.push_back(ButtonData("Draw", "Lotta / starttider...", false));
@ -2960,6 +3009,9 @@ bool TabClass::loadPage(gdioutput &gdi)
func.push_back(ButtonData("QuickSettings", "Snabbinställningar", true)); func.push_back(ButtonData("QuickSettings", "Snabbinställningar", true));
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces))
func.push_back(ButtonData("QualificationFinal", "Kval-Final-Schema", false));
RECT funRect; RECT funRect;
funRect.right = gdi.getCX() - 7; funRect.right = gdi.getCX() - 7;
funRect.top = gdi.getCY() - 2; funRect.top = gdi.getCY() - 2;
@ -3216,7 +3268,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
if (method != DMSimultaneous) if (method != DMSimultaneous)
gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval); gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
if (method == DMRandom || method == DMSOFT || method == DMClumped) if (method == DMRandom || method == DMSOFT || method == DMClumped && pc.getParentClass() == 0)
gdi.addInput("Vacanses", itow(vac), 10, 0, L"Antal vakanser:").setSynchData(&lastNumVac); gdi.addInput("Vacanses", itow(vac), 10, 0, L"Antal vakanser:").setSynchData(&lastNumVac);
if ((method == DMRandom || method == DMSOFT || method == DMSeeded) && pc.getNumStages() > 1 && pc.getClassType() != oClassPatrol) { if ((method == DMRandom || method == DMSOFT || method == DMSeeded) && pc.getNumStages() > 1 && pc.getClassType() != oClassPatrol) {
@ -3765,7 +3817,7 @@ void TabClass::getClassSettingsTable(gdioutput &gdi, GUICALLBACK cb) {
else else
gdi.setText("Bib"+ id, bib); gdi.setText("Bib"+ id, bib);
if (useTeam && it->getNumDistinctRunners() > 1) { if (useTeam && (it->getNumDistinctRunners() > 1 || it->getQualificationFinal())) {
gdi.addSelection(et, cyp, "BibTeam" + id, 80, 100, 0, L"", L"Ange relation mellan lagets och deltagarnas nummerlappar."); gdi.addSelection(et, cyp, "BibTeam" + id, 80, 100, 0, L"", L"Ange relation mellan lagets och deltagarnas nummerlappar.");
gdi.addItem("BibTeam" + id, bibTeamOptions); gdi.addItem("BibTeam" + id, bibTeamOptions);
gdi.selectItemByData("BibTeam" + id, it->getBibMode()); gdi.selectItemByData("BibTeam" + id, it->getBibMode());

View File

@ -528,7 +528,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
else else
fee = di.getInt("Fee"); fee = di.getInt("Fee");
wstring info = filtered[k]->getClass() + L", " + filtered[k]->getCompleteIdentification(); wstring info = filtered[k]->getClass(false) + L", " + filtered[k]->getCompleteIdentification();
gdi.addStringUT(0, info + L" (" + oe->formatCurrency(fee) + L")"); gdi.addStringUT(0, info + L" (" + oe->formatCurrency(fee) + L")");
if (count % 5 == 0) if (count % 5 == 0)

View File

@ -111,21 +111,22 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
wstring oldDate = oe->getDate(); wstring oldDate = oe->getDate();
if ((newZT != oldZT || if ((newZT != oldZT ||
longTimes != oldLT || longTimes != oldLT ||
(longTimes && date != oldDate)) && oe->classHasResults(0)) { (longTimes && date != oldDate)) && oe->classHasResults(0)) {
if (!gdi.ask(L"warn:changedtimezero")) { if (!gdi.ask(L"warn:changedtimezero")) {
gdi.setText("ZeroTime", oe->getZeroTime()); gdi.setText("ZeroTime", oe->getZeroTime());
gdi.check("LongTimes", oe->useLongTimes()); gdi.check("LongTimes", oe->useLongTimes());
gdi.setText("Date", oe->getDate()); gdi.setText("Date", oe->getDate());
return 0; return 0;
} }
bool updateTimes = newZT != oldZT && oe->getNumRunners() > 0 && gdi.ask(L"ask:updatetimes"); }
bool updateTimes = newZT != oldZT && oe->getNumRunners() > 0 && gdi.ask(L"ask:updatetimes");
if (updateTimes) { if (updateTimes) {
int delta = oldZT - newZT; int delta = oldZT - newZT;
oe->updateStartTimes(delta); oe->updateStartTimes(delta);
}
} }
oe->setDate(date); oe->setDate(date);
oe->useLongTimes(longTimes); oe->useLongTimes(longTimes);
oe->setName(gdi.getText("Name")); oe->setName(gdi.getText("Name"));
@ -3228,7 +3229,7 @@ void TabCompetition::welcomeToMeOS(gdioutput &gdi) {
void TabCompetition::displayRunners(gdioutput &gdi, const vector<pRunner> &changedClass) const { void TabCompetition::displayRunners(gdioutput &gdi, const vector<pRunner> &changedClass) const {
for (size_t k = 0; k<changedClass.size(); k++) { for (size_t k = 0; k<changedClass.size(); k++) {
gdi.addStringUT(0, changedClass[k]->getName() + L" (" + changedClass[k]->getClass() + L", " + gdi.addStringUT(0, changedClass[k]->getName() + L" (" + changedClass[k]->getClass(true) + L", " +
changedClass[k]->getStartTimeS() + L")"); changedClass[k]->getStartTimeS() + L")");
} }
} }
@ -3991,7 +3992,7 @@ void TabCompetition::checkReadyForResultExport(gdioutput &gdi, const set<int> &c
int numVacant = 0; int numVacant = 0;
for (pRunner r : runners) { for (pRunner r : runners) {
if (!classFilter.empty() && !classFilter.count(r->getClassId())) if (!classFilter.empty() && !classFilter.count(r->getClassId(false)))
continue; continue;
if (r->isVacant()) if (r->isVacant())

View File

@ -601,7 +601,6 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
lastSplitState = par.showSplitTimes; lastSplitState = par.showSplitTimes;
lastLargeSize = par.useLargeSize; lastLargeSize = par.useLargeSize;
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
generateList(gdi); generateList(gdi);
@ -635,10 +634,8 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oListParam par; oListParam par;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
getResultIndividual(par, cnf);
cnf.getIndividual(par.selection); cnf.getIndividual(par.selection);
par.listCode = EStdResultList;
par.showInterTimes = true;
par.setLegNumberCoded(-1);
par.pageBreak = gdi.isChecked("PageBreak"); par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis"); par.splitAnalysis = gdi.isChecked("SplitAnalysis");
@ -667,12 +664,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="StartIndividual") { else if (bi.id=="StartIndividual") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.listCode = EStdStartList;
par.setLegNumberCoded(-1);
par.pageBreak = gdi.isChecked("PageBreak");
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getIndividual(par.selection); getStartIndividual(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB); currentList.setCallback(openRunnerTeamCB);
generateList(gdi); generateList(gdi);
@ -681,33 +676,22 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="StartClub") { else if (bi.id=="StartClub") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.listCode = EStdClubStartList; getStartClub(par);
par.pageBreak = gdi.isChecked("PageBreak"); par.pageBreak = gdi.isChecked("PageBreak");
par.setLegNumberCoded(-1);
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
//cnf.getIndividual(par.selection);
//cnf.getPatrol(par.selection);
// oListInfo foo = currentList;
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB); currentList.setCallback(openRunnerTeamCB);
//currentList.addList(foo);
generateList(gdi); generateList(gdi);
gdi.refresh(); gdi.refresh();
} }
else if (bi.id=="ResultClub") { else if (bi.id=="ResultClub") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.listCode = EStdClubResultList;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.setLegNumberCoded(-1);
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getIndividual(par.selection); getResultClub(par, cnf);
cnf.getPatrol(par.selection);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB); currentList.setCallback(openRunnerTeamCB);
generateList(gdi); generateList(gdi);
@ -735,12 +719,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="TeamStartList") { else if (bi.id=="TeamStartList") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.listCode = EStdTeamStartList;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getRelay(par.selection); getStartTeam(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak"); par.pageBreak = gdi.isChecked("PageBreak");
par.setLegNumberCoded(0);
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB); currentList.setCallback(openRunnerTeamCB);
generateList(gdi); generateList(gdi);
@ -779,11 +761,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="PatrolStartList") { else if (bi.id=="PatrolStartList") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.listCode = EStdPatrolStartList;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getPatrol(par.selection); getStartPatrol(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB); currentList.setCallback(openRunnerTeamCB);
generateList(gdi); generateList(gdi);
@ -792,15 +773,12 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="TeamResults") { else if (bi.id=="TeamResults") {
oe->sanityCheck(gdi, true); oe->sanityCheck(gdi, true);
oListParam par; oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = EStdTeamResultListAll;
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getRelay(par.selection); getResultTeam(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
generateList(gdi); generateList(gdi);
gdi.refresh(); gdi.refresh();
@ -823,7 +801,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oListParam par; oListParam par;
par.pageBreak = gdi.isChecked("PageBreak"); par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis"); par.splitAnalysis = gdi.isChecked("SplitAnalysis");
int race = int(bi.getExtra()); int race = bi.getExtraInt();
par.setLegNumberCoded(race); par.setLegNumberCoded(race);
par.listCode = EStdIndMultiResultListLeg; par.listCode = EStdIndMultiResultListLeg;
ClassConfigInfo cnf; ClassConfigInfo cnf;
@ -854,13 +832,11 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="PatrolResultList") { else if (bi.id=="PatrolResultList") {
oe->sanityCheck(gdi, false); oe->sanityCheck(gdi, false);
oListParam par; oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = EStdPatrolResultList;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getPatrol(par.selection); getResultPatrol(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
@ -871,13 +847,11 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="RogainingResultList") { else if (bi.id=="RogainingResultList") {
oe->sanityCheck(gdi, true); oe->sanityCheck(gdi, true);
oListParam par; oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = ERogainingInd;
ClassConfigInfo cnf; ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf); oe->getClassConfigurationInfo(cnf);
cnf.getRogaining(par.selection); getResultRogaining(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first; par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
oe->generateListInfo(par, gdi.getLineHeight(), currentList); oe->generateListInfo(par, gdi.getLineHeight(), currentList);
@ -2420,3 +2394,127 @@ void TabList::setAnimationMode(gdioutput &gdi) {
gdi.setAnimationMode(make_shared<AnimationData>(gdi, par.timePerPage, par.nColumns, gdi.setAnimationMode(make_shared<AnimationData>(gdi, par.timePerPage, par.nColumns,
par.margin, par.animate)); par.margin, par.animate));
} }
void TabList::getStartIndividual(oListParam &par, ClassConfigInfo &cnf){
par.listCode = EStdStartList;
par.setLegNumberCoded(-1);
cnf.getIndividual(par.selection);
}
void TabList::getStartClub(oListParam &par) {
par.listCode = EStdClubStartList;
par.setLegNumberCoded(-1);
}
void TabList::getResultIndividual(oListParam &par, ClassConfigInfo &cnf) {
cnf.getIndividual(par.selection);
par.listCode = EStdResultList;
par.showInterTimes = true;
par.setLegNumberCoded(-1);
}
void TabList::getResultClub(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = EStdClubResultList;
par.setLegNumberCoded(-1);
cnf.getIndividual(par.selection);
cnf.getPatrol(par.selection);
}
void TabList::getStartPatrol(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = EStdPatrolStartList;
cnf.getPatrol(par.selection);
}
void TabList::getResultPatrol(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = EStdPatrolResultList;
cnf.getPatrol(par.selection);
}
void TabList::getStartTeam(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = EStdTeamStartList;
cnf.getRelay(par.selection);
par.setLegNumberCoded(0);
}
void TabList::getResultTeam(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = EStdTeamResultListAll;
cnf.getRelay(par.selection);
}
void TabList::getResultRogaining(oListParam &par, ClassConfigInfo &cnf) {
par.listCode = ERogainingInd;
cnf.getRogaining(par.selection);
}
void TabList::getPublicLists(oEvent &oe, vector<oListParam> &lists) {
lists.clear();
ClassConfigInfo cnf;
oe.getClassConfigurationInfo(cnf);
if (!cnf.empty()) {
if (cnf.hasIndividual()) {
lists.push_back(oListParam());
getStartIndividual(lists.back(), cnf);
if (oe.getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
lists.push_back(oListParam());
getStartClub(lists.back());
}
}
if (cnf.hasRelay()) {
lists.push_back(oListParam());
getStartTeam(lists.back(), cnf);
}
if (cnf.hasPatrol()) {
lists.push_back(oListParam());
getStartPatrol(lists.back(), cnf);
}
if (cnf.isMultiStageEvent()) {
//gdi.addButton("StartL:inputresult", "Input Results", ListsCB);
}
if (cnf.hasIndividual()) {
lists.push_back(oListParam());
getResultIndividual(lists.back(), cnf);
if (oe.getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
lists.push_back(oListParam());
getResultClub(lists.back(), cnf);
}
//gdi.addButton("ResultIndSplit", "Sträcktider", ListsCB);
if (cnf.isMultiStageEvent()) {
//gdi.addButton("Result:stageresult", "Etappresultat", ListsCB);
//gdi.addButton("Result:finalresult", "Slutresultat", ListsCB);
}
}
if (cnf.hasRelay()) {
lists.push_back(oListParam());
getResultTeam(lists.back(), cnf);
}
if (cnf.hasPatrol()) {
lists.push_back(oListParam());
getResultPatrol(lists.back(), cnf);
}
if (cnf.hasRogaining()) {
//gdi.addButton("Result:rogainingind", "Rogaining", ListsCB).setExtra(2);
}
}
MetaListContainer &lc = oe.getListContainer();
vector< pair<wstring, size_t> > savedParams;
lc.getListParam(savedParams);
for (auto &p : savedParams) {
oListParam &par = lc.getParam(p.second);
lists.push_back(par);
}
if (cnf.hasIndividual()) {
//gdi.addButton("PriceList", "Prisutdelningslista", ListsCB);
}
}

View File

@ -87,7 +87,25 @@ private:
/** Set animation mode*/ /** Set animation mode*/
void setAnimationMode(gdioutput &gdi); void setAnimationMode(gdioutput &gdi);
static void getStartIndividual(oListParam &par, ClassConfigInfo &cnf);
static void getStartClub(oListParam &par);
static void getResultIndividual(oListParam &par, ClassConfigInfo &cnf);
static void getResultClub(oListParam &par, ClassConfigInfo &cnf);
static void getStartPatrol(oListParam &par, ClassConfigInfo &cnf);
static void getResultPatrol(oListParam &par, ClassConfigInfo &cnf);
static void getStartTeam(oListParam &par, ClassConfigInfo &cnf);
static void getResultTeam(oListParam &par, ClassConfigInfo &cnf);
static void getResultRogaining(oListParam &par, ClassConfigInfo &cnf);
public: public:
/** Returns a collection of public lists. */
void static getPublicLists(oEvent &oe, vector<oListParam> &lists);
bool loadPage(gdioutput &gdi); bool loadPage(gdioutput &gdi);
bool loadPage(gdioutput &gdi, const string &command); bool loadPage(gdioutput &gdi, const string &command);

View File

@ -106,7 +106,7 @@ void TabRunner::enableControlButtons(gdioutput &gdi, bool enable, bool vacant)
void TabRunner::selectRunner(gdioutput &gdi, pRunner r) { void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
if (!r) { if (!r) {
runnerId=0; runnerId = 0;
gdi.setText("Name", L""); gdi.setText("Name", L"");
gdi.setText("Bib", L""); gdi.setText("Bib", L"");
gdi.selectItemByData("RCourse", 0); gdi.selectItemByData("RCourse", 0);
@ -158,7 +158,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.enableEditControls(true); gdi.enableEditControls(true);
disablePunchCourse(gdi); disablePunchCourse(gdi);
pRunner parent=r->getMultiRunner(0); pRunner parent = r->getMultiRunner(0);
r->synchronizeAll(); r->synchronizeAll();
//r->apply(false); //r->apply(false);
@ -172,14 +172,14 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.selectItemByData("Runners", parent->getId()); gdi.selectItemByData("Runners", parent->getId());
runnerId=r->getId(); runnerId = r->getId();
gdi.setText("Name", r->getNameRaw()); gdi.setText("Name", r->getNameRaw());
wstring bib = r->getBib(); wstring bib = r->getBib();
if (gdi.hasField("Bib")) { if (gdi.hasField("Bib")) {
gdi.setText("Bib", bib); gdi.setText("Bib", bib);
bool controlBib = r->getTeam() == 0 || (r->getClassRef() && r->getClassRef()->getBibMode() == BibFree); bool controlBib = r->getTeam() == 0 || (r->getClassRef(true) && r->getClassRef(true)->getBibMode() == BibFree);
gdi.setInputStatus("Bib", controlBib); gdi.setInputStatus("Bib", controlBib);
} }
@ -187,10 +187,10 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0); gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
gdi.selectItemByData("RClass", r->getClassId()); gdi.selectItemByData("RClass", r->getClassId(true));
if (gdi.hasField("EditTeam")) { if (gdi.hasField("EditTeam")) {
gdi.setInputStatus("EditTeam", r->getTeam()!=0); gdi.setInputStatus("EditTeam", r->getTeam() != 0);
if (r->getTeam()) { if (r->getTeam()) {
gdi.setText("Team", r->getTeam()->getName()); gdi.setText("Team", r->getTeam()->getName());
@ -217,19 +217,19 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
r->getLegPlacesAcc(placeAcc); r->getLegPlacesAcc(placeAcc);
wstring out; wstring out;
for (size_t k = 0; k<delta.size(); k++) { for (size_t k = 0; k < delta.size(); k++) {
out += itow(place[k]); out += itow(place[k]);
if (k<placeAcc.size()) if (k < placeAcc.size())
out += L" (" + itow(placeAcc[k]) + L")"; out += L" (" + itow(placeAcc[k]) + L")";
if (after[k]>0) if (after[k] > 0)
out+= L" +" + getTimeMS(after[k]); out += L" +" + getTimeMS(after[k]);
if (k<afterAcc.size() && afterAcc[k]>0) if (k < afterAcc.size() && afterAcc[k]>0)
out+= L" (+" + getTimeMS(afterAcc[k]) + L")"; out += L" (+" + getTimeMS(afterAcc[k]) + L")";
if (delta[k]>0) if (delta[k] > 0)
out+= L" B: " + getTimeMS(delta[k]); out += L" B: " + getTimeMS(delta[k]);
out += L" | "; out += L" | ";
@ -241,18 +241,18 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
#endif #endif
if (gdi.hasField("MultiR")) { if (gdi.hasField("MultiR")) {
int numMulti=parent->getNumMulti(); int numMulti = parent->getNumMulti();
if (numMulti==0) { if (numMulti == 0) {
gdi.clearList("MultiR"); gdi.clearList("MultiR");
gdi.disableInput("MultiR"); gdi.disableInput("MultiR");
lastRace=0; lastRace = 0;
} }
else { else {
gdi.clearList("MultiR"); gdi.clearList("MultiR");
gdi.enableInput("MultiR"); gdi.enableInput("MultiR");
for (int k=0;k<numMulti+1;k++) { for (int k = 0; k < numMulti + 1; k++) {
gdi.addItem("MultiR", lang.tl("Lopp X#" + itos(k+1)), k); gdi.addItem("MultiR", lang.tl("Lopp X#" + itos(k + 1)), k);
} }
gdi.selectItemByData("MultiR", r->getRaceNo()); gdi.selectItemByData("MultiR", r->getRaceNo());
} }
@ -264,7 +264,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
updateNumShort(gdi, r->getCourse(false), r); updateNumShort(gdi, r->getCourse(false), r);
int cno = parent->getCardNo(); int cno = parent->getCardNo();
gdi.setText("CardNo", cno>0 ? itow(cno) : L""); gdi.setText("CardNo", cno > 0 ? itow(cno) : L"");
warnDuplicateCard(gdi, cno, r); warnDuplicateCard(gdi, cno, r);
@ -316,9 +316,9 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.setText("PointIn", r->getInputPoints()); gdi.setText("PointIn", r->getInputPoints());
} }
pCard pc=r->getCard(); pCard pc = r->getCard();
pCourse pcourse=r->getCourse(true); pCourse pcourse = r->getCourse(true);
if (pc) { if (pc) {
gdi.setTabStops("Punches", 70); gdi.setTabStops("Punches", 70);
@ -337,6 +337,12 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.clearList("Course"); gdi.clearList("Course");
gdi.disableInput("AddAllC"); gdi.disableInput("AddAllC");
} }
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings) {
TabRunner &dst = dynamic_cast<TabRunner&>(*gdi_settings->getTabs().get(TabType::TRunnerTab));
dst.loadEconomy(*gdi_settings, *r);
}
} }
int RunnerCB(gdioutput *gdi, int type, void *data) int RunnerCB(gdioutput *gdi, int type, void *data)
@ -579,6 +585,12 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
if (gdi.hasField("Fee")) if (gdi.hasField("Fee"))
r->getDI().setInt("Fee", oe->interpretCurrency(gdi.getText("Fee"))); r->getDI().setInt("Fee", oe->interpretCurrency(gdi.getText("Fee")));
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings) {
TabRunner &dst = dynamic_cast<TabRunner&>(*gdi_settings->getTabs().get(TabType::TRunnerTab));
dst.getEconomyHandler(*r)->save(*gdi_settings);
}
r->setStartTimeS(gdi.getText("Start")); r->setStartTimeS(gdi.getText("Start"));
r->setFinishTimeS(gdi.getText("Finish")); r->setFinishTimeS(gdi.getText("Finish"));
@ -608,14 +620,14 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
gdi.alert("För att delta i en lagklass måste deltagaren ingå i ett lag."); gdi.alert("För att delta i en lagklass måste deltagaren ingå i ett lag.");
classId = 0; classId = 0;
} }
else if (r->getTeam()->getClassId() != classId && r->getClassId() != classId) { else if (r->getTeam()->getClassId(true) != classId && r->getClassId(true) != classId) {
gdi.alert("Deltagarens klass styrs av laget."); gdi.alert("Deltagarens klass styrs av laget.");
classId = r->getTeam()->getClassId(); classId = r->getTeam()->getClassId(false);
} }
} }
bool readStatusIn = true; bool readStatusIn = true;
if (r->getClassId() != classId && r->getInputStatus() != StatusNotCompetiting && r->hasInputData()) { if (r->getClassId(true) != classId && r->getInputStatus() != StatusNotCompetiting && r->hasInputData()) {
if (gdi.ask(L"Vill du sätta resultatet från tidigare etapper till <Deltar ej>?")) { if (gdi.ask(L"Vill du sätta resultatet från tidigare etapper till <Deltar ej>?")) {
r->resetInputData(); r->resetInputData();
readStatusIn = false; readStatusIn = false;
@ -635,7 +647,7 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
vector<int> mp; vector<int> mp;
r->evaluateCard(true, mp, 0, true); r->evaluateCard(true, mp, 0, true);
if (r->getClassId() != classId) { if (r->getClassId(true) != classId) {
gdi.alert("Deltagarens klass styrs av laget."); gdi.alert("Deltagarens klass styrs av laget.");
} }
@ -652,11 +664,14 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
r->synchronizeAll(); r->synchronizeAll();
if (r->getClassRef() && r->getClassRef()->hasClassGlobalDependance()) { if (r->getClassRef(false) && r->getClassRef(false)->hasClassGlobalDependence()) {
set<int> cls; set<int> cls;
cls.insert(r->getClassId()); cls.insert(r->getClassId(false));
oe->reEvaluateAll(cls, false); oe->reEvaluateAll(cls, false);
} }
if (r->getClassRef(false))
r->getClassRef(false)->updateFinalClasses(r, false);
} }
else else
runnerId=0; runnerId=0;
@ -938,9 +953,11 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (!runnerId) if (!runnerId)
return 0; return 0;
pRunner r = oe->getRunner(runnerId, 0); pRunner r = oe->getRunner(runnerId, 0);
gdioutput *settings = createExtraWindow("ecosettings", L"Economy for X#" + r->getName(), 400, 200); if (getExtraWindow("ecosettings", true) == 0) {
gdioutput *settings = createExtraWindow("ecosettings", L"Economy", 550, 350);
TabRunner &dst = dynamic_cast<TabRunner&>(*settings->getTabs().get(TabType::TRunnerTab));
dst.loadEconomy(*settings, *r);
}
} }
else if (bi.id=="NoStart") { else if (bi.id=="NoStart") {
if (!runnerId) if (!runnerId)
@ -950,7 +967,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (r && gdi.ask(L"Bekräfta att deltagaren har lämnat återbud.")) { if (r && gdi.ask(L"Bekräfta att deltagaren har lämnat återbud.")) {
if (r->getStartTime()>0) { if (r->getStartTime()>0) {
pRunner newRunner = oe->addRunnerVacant(r->getClassId()); pRunner newRunner = oe->addRunnerVacant(r->getClassId(true));
newRunner->cloneStartTime(r); newRunner->cloneStartTime(r);
newRunner->setStartNo(r->getStartNo(), false); newRunner->setStartNo(r->getStartNo(), false);
if (r->getCourseId()) if (r->getCourseId())
@ -1045,12 +1062,18 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (gdi.isInputChanged("")) { if (gdi.isInputChanged("")) {
pRunner r = oe->getRunner(runnerId, 0); pRunner r = oe->getRunner(runnerId, 0);
bool newName = r && r->getName() != gdi.getText("Name"); bool newName = r && r->getName() != gdi.getText("Name");
save(gdi, runnerId, true); save(gdi, runnerId, true);
if (newName) if (newName)
fillRunnerList(gdi); fillRunnerList(gdi);
} }
else {
pRunner r = oe->getRunner(runnerId, 0);
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings) {
TabRunner &dst = dynamic_cast<TabRunner&>(*gdi_settings->getTabs().get(TabType::TRunnerTab));
dst.getEconomyHandler(*r)->save(*gdi_settings);
}
}
if (bi.data == -1) { if (bi.data == -1) {
fillRunnerList(gdi); fillRunnerList(gdi);
@ -1193,6 +1216,10 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
} }
} }
else if (type==GUI_CLEAR) { else if (type==GUI_CLEAR) {
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings)
gdi_settings->closeWindow();
if (runnerId>0 && currentMode == 0) if (runnerId>0 && currentMode == 0)
save(gdi, runnerId, true); save(gdi, runnerId, true);
@ -1202,7 +1229,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
int id = static_cast<TextInfo*>(data)->getExtraInt(); int id = static_cast<TextInfo*>(data)->getExtraInt();
oRunner *vacancy = oe->getRunner(id, 0); oRunner *vacancy = oe->getRunner(id, 0);
if (vacancy==0 || vacancy->getClassId()==0) if (vacancy==0 || vacancy->getClassId(false)==0)
return -1; return -1;
pRunner r = oe->getRunner(runnerId, 0); pRunner r = oe->getRunner(runnerId, 0);
@ -1215,7 +1242,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
wchar_t bf[1024]; wchar_t bf[1024];
swprintf_s(bf, lang.tl("Bekräfta att %s byter klass till %s.").c_str(), swprintf_s(bf, lang.tl("Bekräfta att %s byter klass till %s.").c_str(),
r->getName().c_str(), vacancy->getClass().c_str()); r->getName().c_str(), vacancy->getClass(true).c_str());
if (gdi.ask(wstring(L"#") + bf)) { if (gdi.ask(wstring(L"#") + bf)) {
vacancy->synchronize(); vacancy->synchronize();
@ -1226,11 +1253,11 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
temp.setTemporary(); temp.setTemporary();
temp.setBib(r->getBib(), 0, false, false); temp.setBib(r->getBib(), 0, false, false);
temp.setStartNo(r->getStartNo(), false); temp.setStartNo(r->getStartNo(), false);
temp.setClassId(r->getClassId(), true); temp.setClassId(r->getClassId(true), true);
temp.apply(false, 0, false); temp.apply(false, 0, false);
temp.cloneStartTime(r); temp.cloneStartTime(r);
r->setClassId(vacancy->getClassId(), true); r->setClassId(vacancy->getClassId(true), true);
// Remove or create multi runners // Remove or create multi runners
r->createMultiRunner(true, true); r->createMultiRunner(true, true);
r->apply(false, 0, false); r->apply(false, 0, false);
@ -1243,7 +1270,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
r->resetInputData(); r->resetInputData();
} }
vacancy->setClassId(temp.getClassId(), true); vacancy->setClassId(temp.getClassId(true), true);
// Remove or create multi runners // Remove or create multi runners
vacancy->createMultiRunner(true, true); vacancy->createMultiRunner(true, true);
vacancy->apply(false, 0, false); vacancy->apply(false, 0, false);
@ -1321,7 +1348,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
int birthYear = 0; int birthYear = 0;
pClub pc = oe->getClubCreate(0, club); pClub pc = oe->getClubCreate(0, club);
r->updateFromDB(name, pc->getId(), r->getClassId(), cardNo, birthYear); r->updateFromDB(name, pc->getId(), r->getClassId(false), cardNo, birthYear);
r->setName(name, true); r->setName(name, true);
r->setCardNo(cardNo, true); r->setCardNo(cardNo, true);
@ -1377,7 +1404,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
// Print start certificate // Print start certificate
tsi.generateStartInfo(gdi, *r); tsi.generateStartInfo(gdi, *r);
showVacancyList(gdi, "", r->getClassId()); showVacancyList(gdi, "", r->getClassId(true));
} }
else if (type==GUI_INPUT) { else if (type==GUI_INPUT) {
InputInfo ii=*(InputInfo *)data; InputInfo ii=*(InputInfo *)data;
@ -1473,7 +1500,7 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
for (size_t k = 0; k < runnersToReport.size(); k++) { for (size_t k = 0; k < runnersToReport.size(); k++) {
pRunner r = oe->getRunner(runnersToReport[k].first, 0); pRunner r = oe->getRunner(runnersToReport[k].first, 0);
if (r && r->getTeam()) { if (r && r->getTeam()) {
pClass cls = oe->getClass(r->getClassId()); pClass cls = r->getClassRef(true);
if (cls && cls->getClassType() == oClassPatrol) if (cls && cls->getClassType() == oClassPatrol)
continue; continue;
@ -1511,7 +1538,7 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
tInfo += L" " + t->getStatusS(); tInfo += L" " + t->getStatusS();
} }
gdi.addStringUT(fontMediumPlus, t->getClass()); gdi.addStringUT(fontMediumPlus, t->getClass(true));
gdi.addStringUT(boldLarge, tInfo); gdi.addStringUT(boldLarge, tInfo);
gdi.dropLine(); gdi.dropLine();
@ -1542,19 +1569,19 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) { void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
pRunner r = oe->getRunner(id, 0); pRunner r = oe->getRunner(id, 0);
if (!r || ! r->getClassRef()) if (!r || ! r->getClassRef(false))
return; return;
gdi.pushX(); gdi.pushX();
gdi.fillDown(); gdi.fillDown();
if (r->getTeam() == 0) { if (r->getTeam() == 0) {
gdi.addStringUT(fontMediumPlus, r->getClass()); gdi.addStringUT(fontMediumPlus, r->getClass(true));
gdi.addStringUT(boldLarge, r->getCompleteIdentification()); gdi.addStringUT(boldLarge, r->getCompleteIdentification());
} }
else { else {
wstring s; wstring s;
if (r->getTeam()) if (r->getTeam())
s += r->getClassRef()->getLegNumber(r->getLegNumber()); s += r->getClassRef(false)->getLegNumber(r->getLegNumber());
s += L": " + r->getName(); s += L": " + r->getName();
gdi.addStringUT(boldText, s); gdi.addStringUT(boldText, s);
@ -1573,7 +1600,7 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
if (r->statusOK()) { if (r->statusOK()) {
int total, finished, dns; int total, finished, dns;
oe->getNumClassRunners(r->getClassId(), r->getLegNumber(), total, finished, dns); oe->getNumClassRunners(r->getClassId(true), r->getLegNumber(), total, finished, dns);
if (r->getTeam() == 0) { if (r->getTeam() == 0) {
gdi.addString("", fontMediumPlus, L"Tid: X, nuvarande placering Y/Z.#" + str + L"#" + r->getPlaceS() + L"#" + itow(finished)); gdi.addString("", fontMediumPlus, L"Tid: X, nuvarande placering Y/Z.#" + str + L"#" + r->getPlaceS() + L"#" + itow(finished));
@ -2005,7 +2032,7 @@ void TabRunner::listRunners(gdioutput &gdi, const vector<pRunner> &r, bool filte
sprintf_s(bf, "%d.", k+1); sprintf_s(bf, "%d.", k+1);
gdi.addStringUT(yp, xp, 0, bf); gdi.addStringUT(yp, xp, 0, bf);
gdi.addStringUT(yp, xp+40, 0, r[k]->getNameAndRace(true), 190); gdi.addStringUT(yp, xp+40, 0, r[k]->getNameAndRace(true), 190);
gdi.addStringUT(yp, xp+200, 0, r[k]->getClass(), 140); gdi.addStringUT(yp, xp+200, 0, r[k]->getClass(true), 140);
gdi.addStringUT(yp, xp+350, 0, r[k]->getClub(), 190); gdi.addStringUT(yp, xp+350, 0, r[k]->getClub(), 190);
int c = r[k]->getCardNo(); int c = r[k]->getCardNo();
if (c>0) { if (c>0) {
@ -2224,6 +2251,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
card->synchronize(); card->synchronize();
r->synchronize(true); r->synchronize(true);
r->evaluateCard(true, mp); r->evaluateCard(true, mp);
r->hasManuallyUpdatedTimeStatus();
card->fillPunches(gdi, "Punches", pc); card->fillPunches(gdi, "Punches", pc);
UpdateStatus(gdi, r); UpdateStatus(gdi, r);
} }
@ -2246,6 +2274,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
r->synchronize(true); r->synchronize(true);
r->evaluateCard(true, mp); r->evaluateCard(true, mp);
card->fillPunches(gdi, "Punches", r->getCourse(true)); card->fillPunches(gdi, "Punches", r->getCourse(true));
r->hasManuallyUpdatedTimeStatus();
UpdateStatus(gdi, r); UpdateStatus(gdi, r);
} }
else if (bi.id=="SaveC"){ else if (bi.id=="SaveC"){
@ -2274,6 +2303,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
card->synchronize(); card->synchronize();
r->synchronize(); r->synchronize();
r->evaluateCard(true, mp); r->evaluateCard(true, mp);
r->hasManuallyUpdatedTimeStatus();
card->fillPunches(gdi, "Punches", r->getCourse(true)); card->fillPunches(gdi, "Punches", r->getCourse(true));
UpdateStatus(gdi, r); UpdateStatus(gdi, r);
gdi.selectItemByData("Punches", lbi.data); gdi.selectItemByData("Punches", lbi.data);
@ -2380,14 +2410,17 @@ bool TabRunner::loadPage(gdioutput &gdi)
} }
gdi.fillRight(); gdi.fillRight();
gdi.addSelection("RClass", 130, 300, RunnerCB, L"Klass:"); bool hasEco = oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy);
gdi.addSelection("RClass", hasEco ? 130 : 170, 300, RunnerCB, L"Klass:");
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0); gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { if (hasEco) {
//gdi.addInput("Fee", L"", 4, 0, L"Avgift:");
gdi.fillDown(); gdi.fillDown();
gdi.addInput("Fee", L"", 4, 0, L"Avgift:"); gdi.dropLine();
//gdi.addButton("Economy", "@" + itos(131), RunnerCB, "Ekonomi..."); gdi.addButton("Economy", "Ekonomi...", RunnerCB, "");
} }
else { else {
gdi.fillDown(); gdi.fillDown();
@ -2652,7 +2685,7 @@ void TabRunner::fillRunnerList(gdioutput &gdi) {
} }
bool TabRunner::canSetStart(pRunner r) const { bool TabRunner::canSetStart(pRunner r) const {
pClass pc = r->getTeam() ? r->getTeam()->getClassRef() : r->getClassRef(); pClass pc = r->getTeam() ? r->getTeam()->getClassRef(false) : r->getClassRef(true);
if (pc && pc->getNumStages() > 0) { if (pc && pc->getNumStages() > 0) {
StartTypes st = pc->getStartType(r->getLegNumber()); StartTypes st = pc->getStartType(r->getLegNumber());
@ -2778,3 +2811,138 @@ void TabRunner::autoGrowCourse(gdioutput &gdi) {
gdi.refresh(); gdi.refresh();
} }
} }
void TabRunner::EconomyHandler::init(oRunner &r) {
oe = r.getEvent();
runnerId = r.getId();
}
oRunner &TabRunner::EconomyHandler::getRunner() const {
pRunner p = oe->getRunner(runnerId, 0);
if (!p)
throw meosException("Löpare saknas");
return *p;
}
TabRunner::EconomyHandler *TabRunner::getEconomyHandler(oRunner &r) {
if (!ecoHandler)
ecoHandler = make_shared<EconomyHandler>();
ecoHandler->init(r);
return ecoHandler.get();
}
void TabRunner::EconomyHandler::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
if (type == GuiEventType::GUI_BUTTON) {
ButtonInfo &bi = dynamic_cast<ButtonInfo &>(info);
if (bi.id == "Close") {
save(gdi);
gdi.closeWindow();
}
else if (bi.id == "Save") {
save(gdi);
}
else if (bi.id == "Cancel") {
TabRunner &dst = dynamic_cast<TabRunner&>(*gdi.getTabs().get(TabType::TRunnerTab));
dst.loadEconomy(gdi, getRunner());
}
}
else if (type == GuiEventType::GUI_INPUTCHANGE) {
InputInfo &ii = dynamic_cast<InputInfo &>(info);
if (ii.id == "Fee") {
gdi.check("ModFee", ii.changed() || getRunner().hasFlag(oAbstractRunner::FlagFeeSpecified));
}
else if (ii.id == "PaidAmount") {
int paid = oe->interpretCurrency(ii.text);
gdi.setInputStatus("PayMode", paid != 0);
}
}
}
void TabRunner::EconomyHandler::save(gdioutput &gdi) {
oRunner &r = getRunner();
if (r.getTeam() == 0) {
r.getDI().setDate("EntryDate", gdi.getText("EntryDate"));
int t = convertAbsoluteTimeHMS(gdi.getText("EntryTime"), -1);
r.getDI().setInt("EntryTime", t);
}
int fee = oe->interpretCurrency(gdi.getText("Fee"));
if (r.getClassRef(true)) {
int def = r.getClassRef(true)->getEntryFee(r.getEntryDate(), r.getBirthAge());
r.setFlag(oAbstractRunner::FlagFeeSpecified, def != fee);
}
r.getDI().setInt("Fee", fee);
int cf = oe->interpretCurrency(gdi.getText("Card"));
if (cf > 0 || cf == 0 && r.getDCI().getInt("CardFee") != -1)
r.getDI().setInt("CardFee", cf);
int paid = oe->interpretCurrency(gdi.getText("PaidAmount"));
r.getDI().setInt("Paid", paid);
if (paid != 0) {
int m = gdi.getSelectedItem("").first;
if (m != 1000)
r.getDI().setInt("PayMode", m);
}
}
void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
gdi.clearPage(false);
gdi.fillDown();
gdi.pushX();
gdi.addString("", fontMediumPlus, L"Ekonomihantering, X#" + r.getCompleteIdentification());
auto h = getEconomyHandler(r);
gdi.fillRight();
gdi.addInput("EntryDate", r.getEntryDate(true), 10, 0, L"Anmälningsdatum:");
gdi.fillDown();
gdi.addInput("EntryTime", formatTime(r.getDCI().getInt("EntryTime")), 10, 0, L"Anmälningstid:");
gdi.setInputStatus("EntryDate", r.getTeam() == 0);
gdi.setInputStatus("EntryTime", r.getTeam() == 0);
gdi.popX();
gdi.dropLine();
gdi.fillRight();
gdi.addInput("Fee", oe->formatCurrency(r.getDCI().getInt("Fee")), 5, 0, L"Avgift:").setHandler(h);
int cf = r.getDCI().getInt("CardFee");
if (cf == -1) // Borrowed, zero fee
cf = 0;
gdi.addInput("Card", oe->formatCurrency(cf), 5, 0, L"Brickhyra:");
int paid = r.getDCI().getInt("Paid");
gdi.addInput("PaidAmount", oe->formatCurrency(paid), 5, 0, L"Betalat:").setHandler(h);
gdi.fillDown();
gdi.dropLine();
vector< pair<wstring, size_t> > pm;
oe->getPayModes(pm);
int mypm = r.getDCI().getInt("PayMode");
//pm.insert(pm.begin(), make_pair(lang.tl(L"Faktureras"), 1000));
gdi.addSelection("PayMode", 110, 100, SportIdentCB);
gdi.addItem("PayMode", pm);
gdi.selectItemByData("PayMode", mypm);
gdi.autoGrow("PayMode");
gdi.setInputStatus("PayMode", paid != 0);
gdi.dropLine();
gdi.popX();
gdi.addString("", 1, "Manuellt gjorda justeringar");
gdi.fillRight();
gdi.addCheckbox("ModFee", "Avgift", 0, r.hasFlag(oAbstractRunner::FlagFeeSpecified));
gdi.disableInput("ModFee");
gdi.addCheckbox("ModCls", "Klass", 0, r.hasFlag(oAbstractRunner::FlagUpdateClass));
gdi.disableInput("ModCls");
gdi.fillDown();
gdi.addCheckbox("ModCls", "Namn", 0, r.hasFlag(oAbstractRunner::FlagUpdateName));
gdi.disableInput("ModCls");
gdi.fillRight();
gdi.addButton("Cancel", "Ångra").setHandler(h);
gdi.addButton("Close", "Stäng").setHandler(h);
gdi.addButton("Save", "Spara").setHandler(h);
gdi.refresh();
}

View File

@ -91,6 +91,21 @@ private:
static void autoGrowCourse(gdioutput &gdi); static void autoGrowCourse(gdioutput &gdi);
void loadEconomy(gdioutput &gdi, oRunner &r);
class EconomyHandler : public GuiHandler {
int runnerId;
oEvent *oe;
oRunner &getRunner() const;
public:
void init(oRunner &r);
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
void save(gdioutput &gdi);
};
shared_ptr<EconomyHandler> ecoHandler;
EconomyHandler *getEconomyHandler(oRunner &r);
protected: protected:
void clearCompetitionData(); void clearCompetitionData();
@ -104,6 +119,8 @@ public:
bool loadPage(gdioutput &gdi); bool loadPage(gdioutput &gdi);
bool loadPage(gdioutput &gdi, int runnerId); bool loadPage(gdioutput &gdi, int runnerId);
TabRunner(oEvent *oe); TabRunner(oEvent *oe);
~TabRunner(void); ~TabRunner(void);

View File

@ -818,7 +818,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
pRunner cardRunner = oe->getRunnerByCardNo(cardNo, 0, true); pRunner cardRunner = oe->getRunnerByCardNo(cardNo, 0, true);
if (cardNo>0 && cardRunner!=0 && cardRunner!=r) { if (cardNo>0 && cardRunner!=0 && cardRunner!=r) {
gdi.alert(L"Bricknummret är upptaget (X).#" + cardRunner->getName() + L", " + cardRunner->getClass()); gdi.alert(L"Bricknummret är upptaget (X).#" + cardRunner->getName() + L", " + cardRunner->getClass(true));
return 0; return 0;
} }
@ -857,7 +857,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
} }
lastClubId=r->getClubId(); lastClubId=r->getClubId();
lastClassId=r->getClassId(); lastClassId=r->getClassId(true);
lastFee = gdi.getText("Fee", true); lastFee = gdi.getText("Fee", true);
int lastFeeNum = oe->interpretCurrency(lastFee); int lastFeeNum = oe->interpretCurrency(lastFee);
@ -890,10 +890,10 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
wchar_t bf[256]; wchar_t bf[256];
if (r->getClubId() != 0) { if (r->getClubId() != 0) {
swprintf_s(bf, L"(%d), %s, %s", r->getCardNo(), r->getClub().c_str(), swprintf_s(bf, L"(%d), %s, %s", r->getCardNo(), r->getClub().c_str(),
r->getClass().c_str()); r->getClass(true).c_str());
} }
else { else {
swprintf_s(bf, L"(%d), %s", r->getCardNo(), r->getClass().c_str()); swprintf_s(bf, L"(%d), %s", r->getCardNo(), r->getClass(true).c_str());
} }
wstring info(bf); wstring info(bf);
@ -1810,7 +1810,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
autoAssignClass(r, sic); autoAssignClass(r, sic);
if (interactiveReadout) { if (interactiveReadout) {
if (r && r->getClassId() && !readBefore && !sameCardNewRace) { if (r && r->getClassId(false) && !readBefore && !sameCardNewRace) {
//We can do a silent read-out... //We can do a silent read-out...
processCard(gdi, r, sic, true); processCard(gdi, r, sic, true);
return; return;
@ -1823,7 +1823,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
} }
else { else {
if (!readBefore) { if (!readBefore) {
if (r && r->getClassId() && !sameCardNewRace) if (r && r->getClassId(false) && !sameCardNewRace)
processCard(gdi, r, sic, true); processCard(gdi, r, sic, true);
else else
processUnmatched(gdi, sic, true); processUnmatched(gdi, sic, true);
@ -1839,7 +1839,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
// Assign a class if not already done // Assign a class if not already done
autoAssignClass(r, sic); autoAssignClass(r, sic);
if (r && r->getClassId() && !readBefore && !sameCardNewRace) { if (r && r->getClassId(false) && !readBefore && !sameCardNewRace) {
//We can do a silent read-out... //We can do a silent read-out...
processCard(gdi, r, sic, true); processCard(gdi, r, sic, true);
return; return;
@ -1923,7 +1923,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
// Assign a class if not already done // Assign a class if not already done
autoAssignClass(r, sic); autoAssignClass(r, sic);
if (r && r->getClassId() && !r->getCard()) { if (r && r->getClassId(false) && !r->getCard()) {
SICard copy = sic; SICard copy = sic;
activeSIC.clear(0); activeSIC.clear(0);
processCard(gdi, r, copy); //Everyting is OK processCard(gdi, r, copy); //Everyting is OK
@ -2148,11 +2148,11 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
//Update from SQL-source //Update from SQL-source
runner->synchronize(); runner->synchronize();
if (!runner->getClassId()) if (!runner->getClassId(false))
runner->setClassId(gEvent->addClass(lang.tl(L"Okänd klass"))->getId(), true); runner->setClassId(gEvent->addClass(lang.tl(L"Okänd klass"))->getId(), true);
// Choose course from pool // Choose course from pool
pClass cls=gEvent->getClass(runner->getClassId()); pClass cls = runner->getClassRef(false);
if (cls && cls->hasCoursePool()) { if (cls && cls->hasCoursePool()) {
unsigned leg=runner->legToRun(); unsigned leg=runner->legToRun();
@ -2171,11 +2171,11 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
} }
} }
pClass pclass=gEvent->getClass(runner->getClassId()); pClass pclass = runner->getClassRef(true);
if (!runner->getCourse(false) && !csic.isManualInput()) { if (!runner->getCourse(false) && !csic.isManualInput()) {
if (pclass && !pclass->hasMultiCourse() && !pclass->hasDirectResult()) { if (pclass && !pclass->hasMultiCourse() && !pclass->hasDirectResult()) {
pCourse pcourse=gEvent->addCourse(runner->getClass()); pCourse pcourse=gEvent->addCourse(pclass->getName());
pclass->setCourse(pcourse); pclass->setCourse(pcourse);
for(unsigned i=0;i<csic.nPunch; i++) for(unsigned i=0;i<csic.nPunch; i++)
@ -2222,8 +2222,10 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
cardno = itow(sic.CardNumber); cardno = itow(sic.CardNumber);
info = runner->getName() + L" (" + cardno + L"), " + runner->getClub() info = runner->getName() + L" (" + cardno + L"), ";
+ L", " + runner->getClass(); if (!runner->getClub().empty())
info += runner->getClub() + +L", ";
info += runner->getClass(true);
// Write read card to log // Write read card to log
logCard(sic); logCard(sic);
@ -2260,7 +2262,7 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
} }
else { else {
//Manual input //Manual input
info = runner->getName() + L", " + runner->getClub() + L", " + runner->getClass(); info = runner->getName() + L", " + runner->getClub() + L", " + runner->getClass(true);
runner->setCard(0); runner->setCard(0);
if (csic.statusOK) { if (csic.statusOK) {
@ -2297,7 +2299,10 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
gEvent->calculateResults(oEvent::RTClassResult); gEvent->calculateResults(oEvent::RTClassResult);
if (runner->getTeam()) if (runner->getTeam())
gEvent->calculateTeamResults(runner->getLegNumber(), false); gEvent->calculateTeamResults(runner->getLegNumber(), false);
wstring placeS = runner->getTeam() ? runner->getTeam()->getLegPlaceS(runner->getLegNumber(), false) : runner->getPlaceS(); bool qfClass = runner->getClassId(false) != runner->getClassId(true);
wstring placeS = (runner->getTeam() && !qfClass) ?
runner->getTeam()->getLegPlaceS(runner->getLegNumber(), false) :
runner->getPlaceS();
if (!silent) { if (!silent) {
gdi.fillDown(); gdi.fillDown();
@ -2322,7 +2327,7 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
} }
else { else {
wstring msg = L"#" + runner->getName() + L" (" + cardno + L")\n"+ wstring msg = L"#" + runner->getName() + L" (" + cardno + L")\n"+
runner->getClub() + L". " + runner->getClass() + runner->getClub() + L". " + runner->getClass(true) +
L"\n" + lang.tl("Tid: ") + runner->getRunningTimeS() + lang.tl(L", Plats ") + placeS; L"\n" + lang.tl("Tid: ") + runner->getRunningTimeS() + lang.tl(L", Plats ") + placeS;
gdi.addInfoBox("SIINFO", msg, 10000); gdi.addInfoBox("SIINFO", msg, 10000);
@ -2359,7 +2364,7 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
} }
else { else {
wstring statusmsg = L"#" + runner->getName() + L" (" + cardno + L")\n"+ wstring statusmsg = L"#" + runner->getName() + L" (" + cardno + L")\n"+
runner->getClub() + L". "+ runner->getClass() + runner->getClub() + L". "+ runner->getClass(true) +
L"\n" + msg; L"\n" + msg;
gdi.addInfoBox("SIINFO", statusmsg, 10000); gdi.addInfoBox("SIINFO", statusmsg, 10000);
@ -2594,7 +2599,7 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
if (gdi.hasField("Club")) { if (gdi.hasField("Club")) {
gdi.selectItemByData("Club", r->getClubId()); gdi.selectItemByData("Club", r->getClubId());
} }
gdi.selectItemByData("Class", r->getClassId()); gdi.selectItemByData("Class", r->getClassId(true));
oDataConstInterface dci = r->getDCI(); oDataConstInterface dci = r->getDCI();
if (gdi.hasField("Fee")) if (gdi.hasField("Fee"))
@ -2729,7 +2734,7 @@ void TabSI::checkMoreCardsInQueue(gdioutput &gdi) {
} }
bool TabSI::autoAssignClass(pRunner r, const SICard &sic) { bool TabSI::autoAssignClass(pRunner r, const SICard &sic) {
if (r && r->getClassId()==0) { if (r && r->getClassId(false)==0) {
vector<pClass> classes; vector<pClass> classes;
int dist = oe->findBestClass(sic, classes); int dist = oe->findBestClass(sic, classes);
@ -2737,7 +2742,7 @@ bool TabSI::autoAssignClass(pRunner r, const SICard &sic) {
r->setClassId(classes[0]->getId(), true); r->setClassId(classes[0]->getId(), true);
} }
return r && r->getClassId() != 0; return r && r->getClassId(false) != 0;
} }
void TabSI::showManualInput(gdioutput &gdi) { void TabSI::showManualInput(gdioutput &gdi) {

View File

@ -717,6 +717,10 @@ void TabSpeaker::generateControlList(gdioutput &gdi, int classId)
vector<oClass::TrueLegInfo> stages; vector<oClass::TrueLegInfo> stages;
pc->getTrueStages(stages); pc->getTrueStages(stages);
if (pc->getQualificationFinal()) {
while (stages.size() > 1)
stages.pop_back(); //Ignore for qualification race
}
int leg = selectedControl[pc->getId()].getLeg(); int leg = selectedControl[pc->getId()].getLeg();
const bool multiDay = oe->hasPrevStage(); const bool multiDay = oe->hasPrevStage();
@ -1017,6 +1021,8 @@ bool TabSpeaker::loadPage(gdioutput &gdi)
} }
} }
gdi.setRestorePoint("classes");
if (classId == -1) { if (classId == -1) {
string btn = "Events"; string btn = "Events";
if (gdi.hasField(btn)) if (gdi.hasField(btn))
@ -1028,8 +1034,6 @@ bool TabSpeaker::loadPage(gdioutput &gdi)
gdi.sendCtrlMessage(btn); gdi.sendCtrlMessage(btn);
} }
gdi.setRestorePoint("classes");
gdi.refresh(); gdi.refresh();
return true; return true;
} }

View File

@ -188,7 +188,7 @@ void TabTeam::selectTeam(gdioutput &gdi, pTeam t)
gdi.enableInput("Remove"); gdi.enableInput("Remove");
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone); oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.selectItemByData("RClass", t->getClassId()); gdi.selectItemByData("RClass", t->getClassId(false));
gdi.selectItemByData("Teams", t->getId()); gdi.selectItemByData("Teams", t->getId());
if (gdi.hasField("StatusIn")) { if (gdi.hasField("StatusIn")) {
@ -353,14 +353,14 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
gdi.getSelectedItem("RClass", lbi); gdi.getSelectedItem("RClass", lbi);
int classId = lbi.data; int classId = lbi.data;
bool newClass = t->getClassId() != classId; bool newClass = t->getClassId(false) != classId;
set<int> classes; set<int> classes;
bool globalDep = false; bool globalDep = false;
if (t->getClassRef()) if (t->getClassRef(false))
globalDep = t->getClassRef()->hasClassGlobalDependance(); globalDep = t->getClassRef(false)->hasClassGlobalDependence();
classes.insert(classId); classes.insert(classId);
classes.insert(t->getClassId()); classes.insert(t->getClassId(false));
bool readStatusIn = true; bool readStatusIn = true;
if (newClass && t->getInputStatus() != StatusNotCompetiting && t->hasInputData()) { if (newClass && t->getInputStatus() != StatusNotCompetiting && t->hasInputData()) {
@ -402,7 +402,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
pClass pc=oe->getClass(classId); pClass pc=oe->getClass(classId);
if (pc) { if (pc) {
globalDep |= pc->hasClassGlobalDependance(); globalDep |= pc->hasClassGlobalDependence();
for (unsigned i=0;i<pc->getNumStages(); i++) { for (unsigned i=0;i<pc->getNumStages(); i++) {
char bf[16]; char bf[16];
@ -428,7 +428,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
// Same runner set // Same runner set
if (oldId == r->getId()) { if (oldId == r->getId()) {
if (newName) { if (newName) {
r->updateFromDB(name, r->getClubId(), r->getClassId(), r->updateFromDB(name, r->getClubId(), r->getClassId(false),
cardNo, 0); cardNo, 0);
r->setName(name, true); r->setName(name, true);
} }
@ -447,12 +447,12 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
if (!t->getClub().empty()) if (!t->getClub().empty())
r->setClub(t->getClub()); r->setClub(t->getClub());
r->resetPersonalData(); r->resetPersonalData();
r->updateFromDB(name, r->getClubId(), r->getClassId(), r->updateFromDB(name, r->getClubId(), r->getClassId(false),
cardNo, 0); cardNo, 0);
} }
} }
else else
r=oe->addRunner(name, t->getClubId(), t->getClassId(), cardNo, 0, false); r=oe->addRunner(name, t->getClubId(), t->getClassId(false), cardNo, 0, false);
r->setName(name, true); r->setName(name, true);
r->setCardNo(cardNo, true); r->setCardNo(cardNo, true);
@ -594,7 +594,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
} }
else if (bi.id == "DirOK") { else if (bi.id == "DirOK") {
pTeam t = oe->getTeam(teamId); pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef()) if (!t || !t->getClassRef(false))
return 0; return 0;
int leg = bi.getExtraInt(); int leg = bi.getExtraInt();
@ -632,7 +632,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
bool rent = gdi.isChecked("DirRent"); bool rent = gdi.isChecked("DirRent");
if (r == 0) { if (r == 0) {
r = oe->addRunner(name, clb ? clb->getId() : t->getClubId(), t->getClassId(), card, 0, false); r = oe->addRunner(name, clb ? clb->getId() : t->getClubId(), t->getClassId(false), card, 0, false);
} }
if (rent) if (rent)
r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee")); r->getDI().setInt("CardFee", oe->getDI().getInt("CardFee"));
@ -671,10 +671,10 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
} }
else if (bi.id == "ChangeKey") { else if (bi.id == "ChangeKey") {
pTeam t = oe->getTeam(teamId); pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef()) if (!t || !t->getClassRef(false))
return 0; return 0;
pClass pc = t->getClassRef(); pClass pc = t->getClassRef(false);
gdi.restore("ChangeKey", false); gdi.restore("ChangeKey", false);
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); gdi.pushX();
@ -695,10 +695,10 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
} }
else if (bi.id == "SaveKey") { else if (bi.id == "SaveKey") {
pTeam t = oe->getTeam(teamId); pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef()) if (!t || !t->getClassRef(false))
return 0; return 0;
pClass pc = t->getClassRef(); pClass pc = t->getClassRef(false);
int nf = pc->getNumForks(); int nf = pc->getNumForks();
ListBoxInfo lbi; ListBoxInfo lbi;
gdi.getSelectedItem("ForkKey", lbi); gdi.getSelectedItem("ForkKey", lbi);
@ -752,7 +752,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
pTeam t = oe->getTeam(teamId); pTeam t = oe->getTeam(teamId);
if (t == 0) if (t == 0)
return 0; return 0;
pClass pc = t->getClassRef(); pClass pc = t->getClassRef(false);
if (pc == 0) if (pc == 0)
return 0; return 0;
@ -806,7 +806,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
continue; continue;
if (clubs.count(clsR[i]->getClubId()) == 0) if (clubs.count(clsR[i]->getClubId()) == 0)
continue; continue;
if (clsR[i]->getClassId() != t->getClassId()) if (clsR[i]->getClassId(false) != t->getClassId(false))
continue; continue;
if (clsR[i]->getName() == anon) if (clsR[i]->getName() == anon)
continue; continue;
@ -839,7 +839,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
if (usedR.count(clsR[i]->getId())) if (usedR.count(clsR[i]->getId()))
continue; continue;
const wstring &club = clsR[i]->getClub(); const wstring &club = clsR[i]->getClub();
wstring id = clsR[i]->getName() + L", " + clsR[i]->getClass(); wstring id = clsR[i]->getName() + L", " + clsR[i]->getClass(false);
if (!club.empty()) if (!club.empty())
id += L" (" + club + L")"; id += L" (" + club + L")";
@ -999,7 +999,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
pc->getNumStages() == shownRunners) { pc->getNumStages() == shownRunners) {
// Keep team setup, i.e. do nothing // Keep team setup, i.e. do nothing
} }
else if (t && pc && (t->getClassId()==bi.data else if (t && pc && (t->getClassId(false)==bi.data
|| t->getNumRunners()==pc->getNumStages()) ) || t->getNumRunners()==pc->getNumStages()) )
loadTeamMembers(gdi, 0,0,t); loadTeamMembers(gdi, 0,0,t);
else else
@ -1134,7 +1134,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t) void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
{ {
if (ClassId==0) if (ClassId==0)
if (t) ClassId=t->getClassId(); if (t) ClassId=t->getClassId(false);
classId=ClassId; classId=ClassId;
gdi.restore("",false); gdi.restore("",false);
@ -1696,7 +1696,7 @@ void TabTeam::doAddTeamMembers(gdioutput &gdi) {
for (size_t k = 0; k < t.size(); k++) { for (size_t k = 0; k < t.size(); k++) {
pTeam mt = t[k]; pTeam mt = t[k];
pClass cls = mt->getClassRef(); pClass cls = mt->getClassRef(false);
if (cls == 0) if (cls == 0)
continue; continue;
bool ch = false; bool ch = false;
@ -1845,7 +1845,7 @@ void TabTeam::switchRunners(pTeam t, int leg, pRunner r, pRunner oldR) {
else if (oldR) { else if (oldR) {
t->setRunner(leg, 0, false); t->setRunner(leg, 0, false);
t->synchronize(true); t->synchronize(true);
oldR->setClassId(r->getClassId(), true); oldR->setClassId(r->getClassId(false), true);
oldR->evaluateCard(true, mp, 0, true); oldR->evaluateCard(true, mp, 0, true);
oldR->synchronize(true); oldR->synchronize(true);
} }

BIN
code/bmp00001.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

View File

@ -352,7 +352,7 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
if (pc) { if (pc) {
pc->synchronize(); pc->synchronize();
if (pr->getClassId() == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass)) if (pr->getClassId(false) == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass))
pr->setClassId(pc->getId(), false); pr->setClassId(pc->getId(), false);
} }
} }
@ -397,8 +397,8 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
course->synchronize(); course->synchronize();
} }
if (course) { if (course) {
if (pr->getClassId() != 0) if (pr->getClassId(false) != 0)
event.getClass(pr->getClassId())->setCourse(course); event.getClass(pr->getClassId(false))->setCourse(course);
else else
pr->setCourseId(course->getId()); pr->setCourseId(course->getId());
} }
@ -1253,23 +1253,71 @@ void csvparser::parse(const wstring &file, list< vector<string> > &data) {
fin.close(); fin.close();
}*/ }*/
void csvparser::parseUnicode(const wstring &file, list< vector<wstring> > &data) {
fin.open(file, ifstream::in | ifstream::binary);
fin.seekg(0, ios_base::end);
size_t len = int(fin.tellg())-2;
if (len == 0)
return;
fin.seekg(2); // BOM
assert(len % 2 == 0);
vector<wchar_t> bf(len / 2 + 1);
fin.read((char *)&bf[0], len);
vector<wstring> rows;
int spp = 0;
for (size_t k = 0; k < len / 2; k++) {
if (bf[spp] == '\r')
spp++;
if (bf[k] == '\n') {
bf[k] = 0;
if (k > 0 && bf[k - 1] == '\r')
bf[k - 1] = 0;
wstring r = &bf[spp];
spp = k + 1;
rows.push_back(r);
}
}
if (size_t(spp + 1) < len / 2) {
wstring r = &bf[spp];
rows.push_back(r);
}
vector<wchar_t *> sp;
for (size_t k = 0; k < rows.size(); k++) {
split(const_cast<wchar_t*>(rows[k].c_str()), sp);
if (!sp.empty()) {
data.push_back(vector<wstring>());
data.back().resize(sp.size());
for (size_t k = 0; k < sp.size(); k++) {
data.back()[k] = sp[k];
}
}
}
}
void csvparser::parse(const wstring &file, list< vector<wstring> > &data) { void csvparser::parse(const wstring &file, list< vector<wstring> > &data) {
data.clear(); data.clear();
fin.open(file); fin.open(file);
// const size_t bf_size = 8192;
fin.seekg(0, ios_base::end);
auto len = fin.tellg();
fin.seekg(0);
string rbf; string rbf;
if (!fin.good()) if (!fin.good())
throw meosException("Failed to read file"); throw meosException("Failed to read file");
bool isUTF8 = false; bool isUTF8 = false;
bool isUnicode = false;
bool firstLine = true; bool firstLine = true;
vector<wchar_t *> sp; vector<wchar_t *> sp;
wchar_t wbf[buff_pre_alloc]; vector<wchar_t> wbf_a;
wbf_a.resize(size_t(len));
wchar_t *wbf = &wbf_a[0];
wstring w; wstring w;
while(std::getline(fin, rbf)) { while(std::getline(fin, rbf)) {
const char *bf = rbf.c_str(); const char *bf = rbf.c_str();
if (firstLine) { if (firstLine) {
@ -1278,27 +1326,23 @@ void csvparser::parse(const wstring &file, list< vector<wstring> > &data) {
bf += 3; bf += 3;
} }
else if (bf[0] == -1 && bf[1] == -2) { else if (bf[0] == -1 && bf[1] == -2) {
isUnicode = true; fin.close();
bf += 2; vector<wchar_t>().swap(wbf_a);
parseUnicode(file, data);
return;
} }
} }
if (isUnicode) { if (isUTF8) {
int len = 0;
if (bf[len] == 0 && bf[len+1] != 0)
len++;
split((wchar_t*)&bf[len], sp);
}
else if (isUTF8) {
int len = strlen(bf); int len = strlen(bf);
int wlen = MultiByteToWideChar(CP_UTF8, 0, bf, len, wbf, buff_pre_alloc); int wlen = MultiByteToWideChar(CP_UTF8, 0, bf, len, wbf, buff_pre_alloc);
wbf[wlen] = 0; wbf[wlen] = 0;
split(wbf, sp); split(&wbf[0], sp);
} }
else { else {
w = gdi_main->recodeToWide(bf); w = gdi_main->recodeToWide(bf);
wchar_t *wbf = const_cast<wchar_t *>(w.c_str()); wchar_t *wbfL = const_cast<wchar_t *>(w.c_str());
split(wbf, sp); split(wbfL, sp);
} }
firstLine = false; firstLine = false;

View File

@ -99,6 +99,8 @@ protected:
map<SIConfigFields, int> siconfigmap; map<SIConfigFields, int> siconfigmap;
const wchar_t *getSIC(SIConfigFields sic, const vector<wstring> &sp) const; const wchar_t *getSIC(SIConfigFields sic, const vector<wstring> &sp) const;
void parseUnicode(const wstring &file, list< vector<wstring> > &data);
// Check and process a punch line // Check and process a punch line
static int selectPunchIndex(const wstring &competitionDate, const vector<wstring> &sp, static int selectPunchIndex(const wstring &competitionDate, const vector<wstring> &sp,
int &cardIndex, int &timeIndex, int &dateIndex, int &cardIndex, int &timeIndex, int &dateIndex,

View File

@ -2284,3 +2284,17 @@ RunnerEntryTime = Competitor's entry time
RunnerPaid = Paid amount RunnerPaid = Paid amount
RunnerPayMethod = Payment method RunnerPayMethod = Payment method
EntryTime = Entry Time EntryTime = Entry Time
Ekonomihantering, X = Economy status, X
Manuellt gjorda justeringar = Manually made adjustments
Antal förfrågningar: X = Number of requests: X
Genomsnittlig svarstid: X ms = Average response time: X ms
Informationsserver = Information server
Längsta svarstid: X ms = Longest response time: X ms
MeOS Informationsserver REST-API = MeOS Information Server REST-API
Testa servern = Test the server
help:rest = MeOS REST API lets you access competition data via a webb connection. You can show result lists directly in a webb browser, but you can also request competition data and results in a XML format, suitble for further processing in third party programs and apps.
Server startad på X = Server running on port X
Inconsistent qualification rule, X = Inconsistent qualification rule, X
help:LockStartList = MeOS will not update assignement to a locked class even if qualification results are altered.
Kval-Final-Schema = Load qualification scheme
Lås startlista = Lock start list

View File

@ -4215,7 +4215,7 @@ void gdioutput::calcStringSize(TextInfo &ti, HDC hDC_in) const
HDC hDC=hDC_in; HDC hDC=hDC_in;
if (!hDC) { if (!hDC) {
assert(hWndTarget!=0); // assert(hWndTarget!=0);
hDC=GetDC(hWndTarget); hDC=GetDC(hWndTarget);
} }
RECT rc; RECT rc;

View File

@ -78,6 +78,7 @@ GeneralResult::GeneralResult(void) {
GeneralResult::~GeneralResult(void) { GeneralResult::~GeneralResult(void) {
} }
// Needed to generate template instances
void GRINSTANCE() { void GRINSTANCE() {
vector<oRunner *> a; vector<oRunner *> a;
vector<oTeam *> b; vector<oTeam *> b;
@ -86,6 +87,7 @@ void GRINSTANCE() {
gr.sort(b, SortByFinishTime); gr.sort(b, SortByFinishTime);
} }
void GeneralResult::setContext(const oListParam *contextIn) { void GeneralResult::setContext(const oListParam *contextIn) {
context = contextIn; context = contextIn;
} }
@ -230,8 +232,10 @@ template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const
const int maxT = 3600 * 100; const int maxT = 3600 * 100;
for(size_t k = 0; k < rt.size(); k++) { for(size_t k = 0; k < rt.size(); k++) {
arr[k].first = 0; arr[k].first = 0;
if (ps == ClassWise) if (ps == ClassWise) {
arr[k].first = rt[k]->getClassRef() ? rt[k]->getClassRef()->getSortIndex() : 0; pClass sclass = rt[k]->getClassRef(true);
arr[k].first = sclass ? sclass->getSortIndex() : 0;
}
else if (ps == CourseWise) { else if (ps == CourseWise) {
oRunner *r = dynamic_cast<oRunner *>(rt[k]); oRunner *r = dynamic_cast<oRunner *>(rt[k]);
arr[k].first = r && r->getCourse(false) ? r->getCourse(false)->getId() : 0; arr[k].first = r && r->getCourse(false) ? r->getCourse(false)->getId() : 0;
@ -266,7 +270,10 @@ template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const
} }
} }
void GeneralResult::calculateIndividualResults(vector<oRunner *> &runners, oListInfo::ResultType resType, bool sortRunners, int inputNumber) const { void GeneralResult::calculateIndividualResults(vector<oRunner *> &runners,
oListInfo::ResultType resType,
bool sortRunners,
int inputNumber) const {
if (runners.empty()) if (runners.empty())
return; return;
@ -286,7 +293,7 @@ void GeneralResult::calculateIndividualResults(vector<oRunner *> &runners, oList
int ln = r->getLegNumber(); int ln = r->getLegNumber();
const oTeam *pt = r->getTeam(); const oTeam *pt = r->getTeam();
if (pt) { if (pt) {
const oClass *tcls = pt->getClassRef(); const oClass *tcls = pt->getClassRef(false);
if (tcls && tcls->getClassType() == oClassRelay) { if (tcls && tcls->getClassType() == oClassRelay) {
int dummy; int dummy;
tcls->splitLegNumberParallel(r->getLegNumber(), ln, dummy); tcls->splitLegNumberParallel(r->getLegNumber(), ln, dummy);
@ -294,6 +301,10 @@ void GeneralResult::calculateIndividualResults(vector<oRunner *> &runners, oList
} }
runnerScore[k].principalSort = runnerScore[k].principalSort * 50 + ln; runnerScore[k].principalSort = runnerScore[k].principalSort * 50 + ln;
} }
else if (resType == oListInfo::Coursewise) {
pCourse crs = r->getCourse(false);
runnerScore[k].principalSort = crs ? crs->getId() : 0;
}
else else
runnerScore[k].principalSort = 0; runnerScore[k].principalSort = 0;
@ -474,10 +485,10 @@ RunnerStatus TotalResultAtControl::deduceStatus(oRunner &runner) const {
if (runner.getTeam() && getListParamTimeFromControl() <= 0) { if (runner.getTeam() && getListParamTimeFromControl() <= 0) {
// Only use input time when start time is used // Only use input time when start time is used
const pTeam t = runner.getTeam(); const pTeam t = runner.getTeam();
if (runner.getLegNumber()>0 && t->getClassRef()) { if (runner.getLegNumber()>0 && t->getClassRef(false)) {
// Find base leg // Find base leg
int legIx = runner.getLegNumber(); int legIx = runner.getLegNumber();
const pClass cls = t->getClassRef(); const pClass cls = t->getClassRef(false);
while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx))) while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx)))
legIx--; legIx--;
if (legIx > 0) if (legIx > 0)
@ -504,10 +515,10 @@ int TotalResultAtControl::deduceTime(oRunner &runner, int startTime) const {
if (runner.getTeam() && getListParamTimeFromControl() <= 0) { if (runner.getTeam() && getListParamTimeFromControl() <= 0) {
// Only use input time when start time is used // Only use input time when start time is used
const pTeam t = runner.getTeam(); const pTeam t = runner.getTeam();
if (runner.getLegNumber()>0 && t->getClassRef()) { if (runner.getLegNumber()>0 && t->getClassRef(false)) {
// Find base leg // Find base leg
int legIx = runner.getLegNumber(); int legIx = runner.getLegNumber();
const pClass cls = t->getClassRef(); const pClass cls = t->getClassRef(false);
while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx))) while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx)))
legIx--; legIx--;
if (legIx > 0) if (legIx > 0)
@ -1125,11 +1136,10 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.addSymbol("RunnerCourse", team.getResultCache(oTeam::RCCCourse)); parser.addSymbol("RunnerCourse", team.getResultCache(oTeam::RCCCourse));
parser.addSymbol("RunnerSplitTimes", team.getResultCache(oTeam::RCCSplitTime)); parser.addSymbol("RunnerSplitTimes", team.getResultCache(oTeam::RCCSplitTime));
pClass cls = team.getClassRef(); pClass cls = team.getClassRef(true);
if (cls) { if (cls) {
int nl = max<int>(1, cls->getNumStages()-1); int nl = max<int>(1, cls->getNumStages()-1);
parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(nl, false)); parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(nl, false));
} }
} }
@ -1237,7 +1247,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
parser.addSymbol("SplitTimesAccumulated", e); parser.addSymbol("SplitTimesAccumulated", e);
} }
pClass cls = runner.getClassRef(); pClass cls = runner.getClassRef(true);
if (cls) { if (cls) {
int nl = runner.getLegNumber(); int nl = runner.getLegNumber();
parser.addSymbol("ShortestClassTime", cls->getBestLegTime(nl)); parser.addSymbol("ShortestClassTime", cls->getBestLegTime(nl));
@ -1303,3 +1313,294 @@ void DynamicResult::debugDumpVariables(gdioutput &gdi, bool includeSymbols) cons
gdi.dropLine(); gdi.dropLine();
} }
} }
void GeneralResult::calculateIndividualResults(vector<pRunner> &runners,
const pair<int, int> & controlId,
bool totalResults,
const string &resTag,
oListInfo::ResultType resType,
int inputNumber,
oEvent &oe,
vector<GeneralResultInfo> &results) {
results.reserve(runners.size());
if (resTag.empty() && resType == ClassWise) {
GeneralResultInfo ri;
if (controlId.second == oPunch::PunchFinish &&
controlId.first == oPunch::PunchStart) {
if (!totalResults) {
oe.calculateResults(oEvent::RTClassResult, true);
for (pRunner r : runners) {
ri.status = r->getStatus();
if (ri.status == StatusUnknown) {
if (r->getFinishTime() == 0)
continue;
ri.status = StatusOK; // Preliminary status
}
if (ri.status == StatusOK)
ri.place = r->getPlace();
else
ri.place = 0;
ri.score = r->getRogainingPoints(false);
ri.time = r->getRunningTime();
ri.src = r;
results.push_back(ri);
}
}
else {
oe.calculateResults(oEvent::RTTotalResult, true);
for (pRunner r : runners) {
ri.status = r->getTotalStatus();
if (ri.status == StatusUnknown && r->getInputStatus() == StatusOK) {
if (r->getFinishTime() == 0)
continue;
ri.status = StatusOK; // Preliminary status
}
if (ri.status == StatusOK)
ri.place = r->getTotalPlace();
else
ri.place = 0;
ri.score = r->getRogainingPoints(true);
ri.time = r->getTotalRunningTime();
ri.src = r;
results.push_back(ri);
}
}
}
else {
oe.calculateSplitResults(controlId.first, controlId.second);
ri.score = 0; // Undefined
for (pRunner r : runners) {
ri.status = r->getTempStatus();
if (ri.status == StatusUnknown) {
continue;
}
if (ri.status == StatusMP && r->getStatus() != StatusMP)
continue; // Control that is not needed requested
if (ri.status == StatusOK)
ri.place = r->getPlace();
else
ri.place = 0;
ri.time = r->getTempTime();
if (ri.time <= 0 && ri.status == StatusOK)
continue;
ri.src = r;
results.push_back(ri);
}
}
}
else {
wstring srcDMY;
GeneralResult *gResult = 0;
shared_ptr<GeneralResult> specialInstance;
oListParam param;
param.useControlIdResultTo = controlId.second;
param.useControlIdResultFrom = controlId.first;
if (!resTag.empty())
gResult = &oe.getGeneralResult(resTag, srcDMY);
else {
if (controlId.second == oPunch::PunchFinish &&
controlId.first == oPunch::PunchStart && !totalResults)
specialInstance = make_shared<GeneralResult>();
else if (!totalResults)
specialInstance = make_shared<ResultAtControl>();
else
specialInstance = make_shared<TotalResultAtControl>();
gResult = specialInstance.get();
}
gResult->setContext(&param);
gResult->calculateIndividualResults(runners, resType, true, inputNumber);
gResult->clearContext();
map<int, bool> mapHasCourse;
GeneralResultInfo ri;
for (pRunner r : runners) {
const auto &tmp = r->getTempResult(0);
ri.status = tmp.getStatus();
if (ri.status == StatusUnknown) {
if (r->getFinishTime() == 0)
continue;
ri.status = StatusOK; // Preliminary status
}
if (ri.status == StatusOK)
ri.place = tmp.getPlace();
else
ri.place = 0;
if ((controlId.first != oPunch::PunchStart ||
controlId.second != oPunch::PunchFinish) && ri.status == StatusMP && r->getStatus() != StatusMP) {
continue;
}
ri.score = tmp.getPoints();
ri.time = tmp.getRunningTime();
if (controlId.first != oPunch::PunchStart && ri.time <= 0 && ri.status == StatusOK)
continue; // Wrong order, skip
ri.src = r;
results.push_back(ri);
}
}
}
shared_ptr<GeneralResult::BaseResultContext>
GeneralResult::calculateTeamResults(vector<pTeam> &teams,
int leg,
const pair<int, int> &controlId,
bool totalResults,
const string &resTag,
oListInfo::ResultType resType,
int inputNumber,
oEvent &oe,
vector<GeneralResultInfo> &results) {
shared_ptr<BaseResultContext> out = make_shared<BaseResultContext>();
out->leg = leg;
out->controlId = controlId;
out->totalResults = totalResults;
results.reserve(teams.size());
if (resTag.empty()) {
out->useModule = false;
if (controlId.second == oPunch::PunchFinish) {
oe.calculateTeamResults(false);
GeneralResultInfo ri;
for (pTeam r : teams) {
ri.status = r->getStatus();
if (ri.status == StatusUnknown) {
if (r->getFinishTime() == 0)
continue;
ri.status = StatusOK; // Preliminary status
}
if (ri.status == StatusOK)
ri.place = r->getPlace();
else
ri.place = 0;
ri.score = r->getRogainingPoints(false);
ri.status = r->getStatus();
ri.time = r->getRunningTime();
ri.src = r;
results.push_back(ri);
}
}
else {
set<int> clsId;
for (pTeam t : teams)
clsId.insert(t->getClassId(false));
oe.calculateTeamResultAtControl(clsId, leg, controlId.second, totalResults);
GeneralResultInfo ri;
for (pTeam r : teams) {
const auto &tmp = r->getTempResult(0);
ri.status = tmp.getStatus();
if (ri.status == StatusUnknown || ri.status == StatusMP)
continue;
ri.place = tmp.getPlace();
ri.score = tmp.getPoints();
ri.time = tmp.getRunningTime();
ri.src = r;
results.push_back(ri);
}
}
}
else {
out->useModule = true;
wstring srcDMY;
auto &gResult = oe.getGeneralResult(resTag, srcDMY);
gResult.calculateTeamResults(teams, resType, true, inputNumber);
GeneralResultInfo ri;
for (pTeam r : teams) {
const auto &tmp = r->getTempResult(0);
ri.status = tmp.getStatus();
if (ri.status == StatusUnknown) {
if (r->getFinishTime() == 0)
continue;
ri.status = StatusOK; // Preliminary status
}
if (ri.status == StatusOK)
ri.place = tmp.getPlace();
else
ri.place = 0;
ri.score = tmp.getPoints();
ri.time = tmp.getRunningTime();
ri.src = r;
results.push_back(ri);
}
}
return out;
}
int GeneralResult::GeneralResultInfo::getNumSubresult(const BaseResultContext &context) const {
int cid = src->getClassId(false);
if (cid == 0)
return 0;
if (context.resIntervalCache.count(cid)) {
const auto &cached = context.resIntervalCache[cid];
return cached.second - cached.first;
}
else {
const pClass cls = src->getClassRef(false);
int leg = context.leg == -1 ? cls->getNumStages() : context.leg;
int nb = cls->getNextBaseLeg(leg);
if (nb == -1)
nb = cls->getNumStages();
int pb = cls->getPreceedingLeg(leg)+1;
context.resIntervalCache[cid] = make_pair(pb, nb);
return nb - pb;
}
}
bool GeneralResult::GeneralResultInfo::getSubResult(const BaseResultContext &context,
int ix, GeneralResultInfo &out) const {
if (getNumSubresult(context) == 0)
return false; // Ensure cache is setup
int base = context.resIntervalCache[src->getClassId(false)].first;
pRunner r = pTeam(src)->getRunner(base + ix);
if (r == 0)
return false;
out.place = 0; // Not defined
out.src = r;
if (context.useModule) {
out.score = r->tmpResult.getPoints();
out.status = r->tmpResult.getStatus();
out.time = r->tmpResult.getRunningTime();
}
else {
if (context.controlId.second == oPunch::PunchFinish) {
out.score = r->getRogainingPoints(false);
out.status = r->getStatus();
out.time = r->getRunningTime();
}
else {
out.score = 0; // Undefined
r->getSplitTime(context.controlId.second, out.status, out.time);
}
}
if (out.status == StatusUnknown && out.time > 0)
out.status = StatusOK;
if (out.status == StatusUnknown)
return false;
return true;
}

View File

@ -42,8 +42,6 @@ protected:
enum PrincipalSort {None, ClassWise, CourseWise}; enum PrincipalSort {None, ClassWise, CourseWise};
virtual PrincipalSort getPrincipalSort() const {return ClassWise;}
virtual int score(oTeam &team, RunnerStatus st, int time, int points) const; virtual int score(oTeam &team, RunnerStatus st, int time, int points) const;
virtual RunnerStatus deduceStatus(oTeam &team) const; virtual RunnerStatus deduceStatus(oTeam &team) const;
virtual int deduceTime(oTeam &team) const; virtual int deduceTime(oTeam &team) const;
@ -64,6 +62,82 @@ protected:
public: public:
struct BaseResultContext {
private:
int leg;
bool useModule;
pair<int,int> controlId; // Start - finish
bool totalResults;
mutable map<int, pair<int, int> > resIntervalCache;
friend class GeneralResult;
};
struct GeneralResultInfo {
oAbstractRunner *src;
int time;
RunnerStatus status;
int score;
int place;
int getNumSubresult(const BaseResultContext &context) const;
bool getSubResult(const BaseResultContext &context, int ix, GeneralResultInfo &out) const;
inline bool compareResult(const GeneralResultInfo &o) const {
if (status != o.status)
return RunnerStatusOrderMap[status] < RunnerStatusOrderMap[o.status];
if (place != o.place)
return place < o.place;
const wstring &name = src->getName();
const wstring &oname = o.src->getName();
return CompareString(LOCALE_USER_DEFAULT, 0,
name.c_str(), name.length(),
oname.c_str(), oname.length()) == CSTR_LESS_THAN;
}
bool operator<(const GeneralResultInfo &o) const {
pClass cls = src->getClassRef(true);
pClass ocls = o.src->getClassRef(true);
if (cls != ocls) {
int so = cls ? cls->getSortIndex() : 0;
int oso = ocls ? ocls->getSortIndex() : 0;
if (so != oso)
return so < oso;
// Use id as fallback
so = cls ? cls->getId() : 0;
oso = ocls ? ocls->getId() : 0;
if (so != oso)
return so < oso;
}
return compareResult(o);
}
};
static void calculateIndividualResults(vector<pRunner> &runners,
const pair<int, int> &controlId,
bool totalResults,
const string &resTag,
oListInfo::ResultType resType,
int inputNumber,
oEvent &oe,
vector<GeneralResultInfo> &results);
static shared_ptr<BaseResultContext> calculateTeamResults(vector<pTeam> &teams,
int leg,
const pair<int, int> &controlId,
bool totalResults,
const string &resTag,
oListInfo::ResultType resType,
int inputNumber,
oEvent &oe,
vector<GeneralResultInfo> &results);
void setContext(const oListParam *context); void setContext(const oListParam *context);
void clearContext(); void clearContext();

300
code/html1.htm Normal file
View File

@ -0,0 +1,300 @@
<h1>Documentation of MeOS REST API</h1>
<h2>Competition</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=competition">/meos?get=competition</a></pre>
<b>Returns:</b>
<p>MOP Competition XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*competition date="2015-09-06" organizer="Orienteringsklubben Linn&eacute;" homepage="http://www.oklinne.nu">Stafett-DM, Uppland*/competition>
*/MOPComplete>
</pre>
<h2>Classes</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=class">/meos?get=class</a></pre>
<b>Returns:</b>
<p>MOP Classes XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*cls id="1" ord="10" radio="90,130;90,130;90,130">D21*/cls>
*cls id="100" ord="1000" radio="90,130">M7*/cls>
*/MOPComplete>
</pre>
<b>Remarks:</b> The attribute <i>ord</i> should be used to sort classes. The attribute <i>radio</i>
lists the MeOS default radio control for each class and leg.
Each leg of the class is separated by ';' and each radio control within a leg with ','.
Note that you may query for results at any control; the listed
controls are only for convenience.
<h2>Controls</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=control">/meos?get=control</a></pre>
<b>Returns:</b>
<p>MOP Controls XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*control id="31">[31]*/control>
*control id="32">[32]*/control>
*control id="50">Radio 1*/control>
*/MOPComplete>
</pre>
<h2>Competitors</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=competitor">/meos?get=competitor</a></pre>
<pre>/meos?get=competitor#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul><li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li></ul>
<b>Returns:</b>
<p>MOP Competitors XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*cmp id="3565">
*base org="570" cls="5" stat="1" st="360000" rt="20580">Elsa Winter*/base>
*input it="20340" tstat="1"/>
*/cmp>
*cmp id="55851">
*base org="134" cls="7" stat="1" st="380710" rt="46910">Anna Spring*/base>
*/cmp>
*/MOPComplete>
</pre>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li>
<li><i>st</i> Start time. In 1/10 seconds after 00:00:00.</li>
<li><i>rt</i> Running time. In 1/10 seconds.</li>
<li><i>input/it</i> Input running time accumulated from earlier races. In 1/10 seconds.</li>
<li><i>input/st</i> Input status from earlier races.</li>
</ul>
<h2>Teams</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=team">/meos?get=team</a></pre>
<pre>/meos?get=team#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul><li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li></ul>
<b>Returns:</b>
<p>MOP Teams XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*tm id="2928771">
*base org="396" cls="5" stat="1" st="360000" rt="65770">IF Thor 1*/base>
*r>34346;48866,866,0;32609*/r>
*/tm>
*tm id="2928346">
*base org="134" cls="5" stat="1" st="360000" rt="99660">OK Enen 1*/base>
*r>42020;55851;35732*/r>
*/tm>
*/MOPComplete>
</pre>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li>
<li><i>st</i> Start time. In 1/10 seconds after 00:00:00.</li>
<li><i>rt</i> Running time (At finish, last leg). In 1/10 seconds.</li>
<li><i>r</i> List of runners in the team. A ';' is used to separate the legs, a ',' within a legs
are used to list paralell runners. A '0' indicates a vacant leg, which may or may
not be valid for the team, depending on the rules.</li>
</ul>
<h2>Organizations and Clubs</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=organization">/meos?get=organization</a></pre>
<b>Returns:</b>
<p>MOP Organization XML</p>
<b>Example:</b>
<pre>
*MOPComplete>
*org id="1012">BAOC*/org>
*org id="598">Dalaportens OL*/org>
*org id="133">Enebybergs IF*/org>
*org id="140">Falkenbergs OK*/org>
*/MOPComplete>
</pre>
<h2>Results</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=result">/meos?get=result</a></pre>
<pre>/meos?get=result#class=*c1>,*c2>,...</pre>
<pre>/meos?get=result#to=*c1></pre>
<pre>/meos?get=result#from=*c1></pre>
<pre>/meos?get=result#leg=*leg></pre>
<pre>/meos?get=result#module=*module></pre>
<pre>/meos?get=result#module=*module>#argument=*arg></pre>
<pre><a href="/meos?get=result&limit=1">/meos?get=result#limit=*limit></a></pre>
<pre><a href="/meos?get=result&total=true">/meos?get=result#total=*true/false></a></pre>
<pre><a href="/meos?get=result&type=GlobalIndividual">/meos?get=result#type=*type></a></pre>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
<li><i>from</i> Returns the result measuring time from a specific control. If a specified class
does not visit the control, an empty result set is returned; no error is given.
The default is the start.</li>
<li><i>to</i> Returns the result at a specific control. If a specified class does not visit the control,
an empty result set is returned; no error is given. The default is the finish.</li>
<li><i>leg</i> In a team competition, returns result for a specified leg. If the leg is parallel,
the result is for the completed parallel leg. The leg number refer to the flat view in
MeOS class settings, i.e., for a setup "1, 2a, 2b, 2c, 3", correspons to flat leg numbers,
"1, 2, 3, 4, 5". The default is the last leg.</li>
<li><i>module</i> The result module tag to use for the result calculation.
The support of the leg and control options depends on result module. The default is no module.</li>
<li><i>argument</i> A numeric argument, defined and used by the result module.</li>
<li><i>limit</i> Limit the number of results per class. If there is a tie, the number of returned results
may be higher than the requested. The default is no limit.</li>
<li><i>total</i> Set to <b>true</b> if you want to calculate total results, i.e., results including earliers stages.</li>
<li><i>type</i> Use one of <b>ClassIndividual</b> (default for individual classes), <b>CourseIndividual</b>, <b>GlobalIndividual</b>, or
<b>LegIndividual</b> to calculate individual results. <b>CourseIndividual</b> calculates result
per course, ignoring class. <b>GlobalIndividual</b> calculates results without
considering classes, <b>LegIndividual</b> calculates results considering classes and legs.
Use one of <b>ClassTeam</b> (default for team classes) or <b>GlobalTeam</b> to calculate team
results. <b>GlobalTeam</b> calculates team results without considering classes.</li>
</ul>
<b>Returns:</b>
<p>MOP Individual or Team Result XML. The result list is sorted according to the result. Note than disqualified
competitors are also included; for example a competitor with status *DNS> will be returned with this status for
all radio controls. You may want to filter out such entries, depending on your application.
</p>
<b>Examples:</b>
<p>Individual results at the finish.</p>
<pre>
*MOPComplete>
*results location="Finish">
*person cls="100" stat="1" st="387240" rt="21880" place="1">
*name id="134940">Isac Ulvesson*/name>
*org id="2184">BOIC*/org>
*/person>
*person cls="100" stat="1" st="387700" rt="22720" place="2">
*name id="134923">Anne Brahe*/name>
*org id="2253">IFA*/org>
*/person>
*person cls="100" stat="1" st="382570" rt="23260" place="3">
*name id="134914">Dan Andersson*/name>
*org id="5938">OK Kompassen*/org>
*/person>
*/results>
*/MOPComplete>
</pre>
<p>Team results, leg 2 at Radio 1, leg has three parallel runners.</p>
<pre>
*MOPComplete>
*results leg="2" location="Radio 1">
*team cls="6" stat="1" st="372000" rt="32030" place="1">
*name id="2927509">OK Linn&eacute; 1*/name>
*org id="84">OK Linn&eacute;*/org>
*person cls="6" leg="2" stat="1" st="392720" rt="11310">
*name id="52054">John Woods*/name>
*org id="84">OK Linn&eacute;*/club>
*/person>
*person cls="6" leg="3" stat="3" st="392720">
*name id="134850">Ralph Audoro*/name>
*org id="84">OK Linn&eacute;*/org>
*/person>
*person cls="6" leg="4" stat="1" st="392720" rt="12850">
*name id="134851">Niel Success*/name>
*club id="84">OK Linn&eacute;*/club>
*/person>
*/team>
*/results>
*/MOPComplete>
</pre>
<p>Roganing results, Invoke with argument module=rogaining, which is a built in module.</p>
<pre>
*MOPComplete>
*results module="rogaining" location="Finish">
*person cls="1" stat="1" score="26" st="324000" rt="72550" place="1">
*name id="4">Omar Rue*/name>
*/person>
*person cls="1" stat="1" score="25" st="324000" rt="72730" place="2">
*name id="3">Oscar Wilde*/name>
*/person>
*person cls="1" stat="1" score="25" st="324000" rt="72780" place="3">
*name id="5">Alice Alison*/name>
*/person>
*person cls="1" stat="5" score="26" st="324000" rt="72590">
*name id="6">Reimund Rossinger*/name>
*/person>
*/results>
*/MOPComplete>
</pre>
<b>Remarks:</b>
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course/i> is included.
<pre>
*person cls="1" stat="1" st="324000" rt="72550" place="1" course=28>
*name id="4">Jordan Griesmer*/name>
*/person>
</pre>
<h2>IOF XML Results</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=iofresult">/meos?get=iofresult</a></pre>
<pre>/meos?get=iofresult#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
</ul>
<b>Returns:</b>
<p>IOF XML version 3.0 result list.</p>
<h2>IOF XML Startlist</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=iofstart">/meos?get=iofstart</a></pre>
<pre>/meos?get=iofstart#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
</ul>
<b>Returns:</b>
<p>IOF XML version 3.0 start list.</p>

View File

@ -203,7 +203,7 @@ bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set<int> &incl
vector<pTeam> t; vector<pTeam> t;
oe.getTeams(0, t, false); oe.getTeams(0, t, false);
for (size_t k = 0; k < t.size(); k++) { for (size_t k = 0; k < t.size(); k++) {
if (!includeCls.count(t[k]->getClassId())) if (!includeCls.count(t[k]->getClassId(true)))
continue; continue;
int wid = t[k]->getId(); int wid = t[k]->getId();
knownId.insert(wid); knownId.insert(wid);
@ -228,7 +228,7 @@ bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set<int> &incl
vector<pRunner> r; vector<pRunner> r;
oe.getRunners(0, 0, r, false); oe.getRunners(0, 0, r, false);
for (size_t k = 0; k < r.size(); k++) { for (size_t k = 0; k < r.size(); k++) {
if (!includeCls.count(r[k]->getClassId())) if (!includeCls.count(r[k]->getClassId(true)))
continue; continue;
int wid = r[k]->getId(); int wid = r[k]->getId();
knownId.insert(wid); knownId.insert(wid);
@ -397,7 +397,7 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
ch = true; ch = true;
} }
int cls = bc.getClassId(); int cls = bc.getClassId(true);
if (cls != classId) { if (cls != classId) {
classId = cls; classId = cls;
ch = true; ch = true;
@ -463,8 +463,8 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
bool ch = synchronize(useTotalResults, r); bool ch = synchronize(useTotalResults, r);
vector<RadioTime> newRT; vector<RadioTime> newRT;
if (r.getClassId() > 0) { if (r.getClassId(false) > 0) {
const vector<int> &radios = cmp.getControls(r.getClassId(), r.getLegNumber()); const vector<int> &radios = cmp.getControls(r.getClassId(false), r.getLegNumber());
for (size_t k = 0; k < radios.size(); k++) { for (size_t k = 0; k < radios.size(); k++) {
RadioTime radioTime; RadioTime radioTime;
RunnerStatus s_split; RunnerStatus s_split;
@ -520,7 +520,7 @@ void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
bool InfoTeam::synchronize(oTeam &t) { bool InfoTeam::synchronize(oTeam &t) {
bool ch = synchronizeBase(t); bool ch = synchronizeBase(t);
const pClass cls = t.getClassRef(); const pClass cls = t.getClassRef(true);
if (cls) { if (cls) {
vector< vector<int> > r; vector< vector<int> > r;

View File

@ -127,12 +127,13 @@ class InfoClass : public InfoBase {
class InfoOrganization : public InfoBase { class InfoOrganization : public InfoBase {
protected: protected:
wstring name; wstring name;
bool synchronize(oClub &c);
void serialize(xmlbuffer &xml, bool diffOnly) const;
public: public:
InfoOrganization(int id); InfoOrganization(int id);
virtual ~InfoOrganization() {} virtual ~InfoOrganization() {}
bool synchronize(oClub &c);
void serialize(xmlbuffer &xml, bool diffOnly) const;
friend class InfoCompetition; friend class InfoCompetition;
}; };
@ -183,9 +184,10 @@ class InfoTeam : public InfoBaseCompetitor {
protected: protected:
// The outer level holds legs, the inner level holds (parallel/patrol) runners on each leg. // The outer level holds legs, the inner level holds (parallel/patrol) runners on each leg.
vector< vector<int> > competitors; vector< vector<int> > competitors;
public:
bool synchronize(oTeam &t); bool synchronize(oTeam &t);
void serialize(xmlbuffer &xml, bool diffOnly) const; void serialize(xmlbuffer &xml, bool diffOnly) const;
public:
InfoTeam(int id); InfoTeam(int id);
virtual ~InfoTeam() {} virtual ~InfoTeam() {}
friend class InfoCompetition; friend class InfoCompetition;

View File

@ -335,7 +335,7 @@ void IOF30Interface::personCourseAssignment(gdioutput &gdi, xmlList &xAssignment
xPAssignment.getObjectString("ClassName", cls); xPAssignment.getObjectString("ClassName", cls);
multimap<wstring, pRunner>::const_iterator res = name2Runner.find(person); multimap<wstring, pRunner>::const_iterator res = name2Runner.find(person);
while (res != name2Runner.end() && person == res->first) { while (res != name2Runner.end() && person == res->first) {
if (cls.empty() || res->second->getClass() == cls) { if (cls.empty() || res->second->getClass(false) == cls) {
r = res->second; r = res->second;
break; break;
} }
@ -386,7 +386,7 @@ void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
if (!bib.empty()) if (!bib.empty())
bib2Team[bib] = allT[k]; bib2Team[bib] = allT[k];
nameClass2Team[make_pair(allT[k]->getName(), allT[k]->getClass())] = allT[k]; nameClass2Team[make_pair(allT[k]->getName(), allT[k]->getClass(false))] = allT[k];
} }
for (size_t k = 0; k < xAssignment.size(); k++) { for (size_t k = 0; k < xAssignment.size(); k++) {
@ -426,7 +426,7 @@ void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAssignment, void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAssignment,
const map<wstring, pCourse> &courses) { const map<wstring, pCourse> &courses) {
if (!team.getClassRef()) if (!team.getClassRef(false))
return; return;
for (size_t k = 0; k <xAssignment.size(); k++) { for (size_t k = 0; k <xAssignment.size(); k++) {
@ -443,11 +443,11 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
if (xLegOrder) if (xLegOrder)
legorder = xLegOrder.getInt() - 1; legorder = xLegOrder.getInt() - 1;
int legId = team.getClassRef()->getLegNumberLinear(leg, legorder); int legId = team.getClassRef(false)->getLegNumberLinear(leg, legorder);
if (legId>=0) { if (legId>=0) {
pRunner r = team.getRunner(legId); pRunner r = team.getRunner(legId);
if (r == 0) { if (r == 0) {
r = oe.addRunner(lang.tl(L"N.N."), team.getClubId(), team.getClassId(), 0, 0, false); r = oe.addRunner(lang.tl(L"N.N."), team.getClubId(), team.getClassId(false), 0, 0, false);
if (r) { if (r) {
r->setEntrySource(entrySourceId); r->setEntrySource(entrySourceId);
r->flagEntryTouched(true); r->flagEntryTouched(true);
@ -460,7 +460,7 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
} }
} }
else else
gdi.addString("", 0, L"Bantilldelning för 'X' hänvisar till en sträcka som inte finns#" + team.getClass()).setColor(colorRed); gdi.addString("", 0, L"Bantilldelning för 'X' hänvisar till en sträcka som inte finns#" + team.getClass(false)).setColor(colorRed);
} }
else { else {
wstring name; wstring name;
@ -543,8 +543,8 @@ void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignmen
for (bibIterT it = range.first; it != range.second; ++it) { for (bibIterT it = range.first; it != range.second; ++it) {
int ln = it->second->getLegNumber(); int ln = it->second->getLegNumber();
int rLegNumber = 0, rLegOrder = 0; int rLegNumber = 0, rLegOrder = 0;
if (it->second->getClassRef()) if (it->second->getClassRef(false))
it->second->getClassRef()->splitLegNumberParallel(ln, rLegNumber, rLegOrder); it->second->getClassRef(false)->splitLegNumberParallel(ln, rLegNumber, rLegOrder);
bool match = true; bool match = true;
if (leg != 0 && leg != rLegNumber+1) if (leg != 0 && leg != rLegNumber+1)
match = false; match = false;
@ -569,14 +569,14 @@ void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignmen
vector<pTeam> t; vector<pTeam> t;
oe.getTeams(0, t); oe.getTeams(0, t);
for (size_t i = 0; i < t.size(); i++) for (size_t i = 0; i < t.size(); i++)
clsName2Team[make_pair(t[i]->getClass(), t[i]->getName())] = t[i]; clsName2Team[make_pair(t[i]->getClass(false), t[i]->getName())] = t[i];
c2TeamInit = true; c2TeamInit = true;
} }
teamIterT res = clsName2Team.find(make_pair(className, teamName)); teamIterT res = clsName2Team.find(make_pair(className, teamName));
if (res != clsName2Team.end()) { if (res != clsName2Team.end()) {
pClass cls = res->second->getClassRef(); pClass cls = res->second->getClassRef(false);
if (cls) { if (cls) {
int ln = cls->getLegNumberLinear(leg, legOrder); int ln = cls->getLegNumberLinear(leg, legOrder);
pRunner r = res->second->getRunner(ln); pRunner r = res->second->getRunner(ln);
@ -863,7 +863,7 @@ void IOF30Interface::readEntryList(gdioutput &gdi, xmlobject &xo, bool removeNon
key[j] = it->second[j].second; key[j] = it->second[j].second;
sort(key.begin(), key.end()); sort(key.begin(), key.end());
classLegEqClasses[t->getClassId()].insert(key); classLegEqClasses[t->getClassId(false)].insert(key);
} }
} }
} }
@ -1326,7 +1326,7 @@ pTeam IOF30Interface::readTeamEntry(gdioutput &gdi, xmlobject &xTeam,
map<int, vector<LegInfo> > localTeamClassConfig; map<int, vector<LegInfo> > localTeamClassConfig;
pClass pc = readClass(xTeam.getObject("Class"), localTeamClassConfig); pClass pc = readClass(xTeam.getObject("Class"), localTeamClassConfig);
if (pc && (t->getClassId() == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) ) { if (pc && (t->getClassId(false) == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) ) {
t->setClassId(pc->getId(), false); t->setClassId(pc->getId(), false);
} }
wstring bib; wstring bib;
@ -1392,7 +1392,7 @@ pTeam IOF30Interface::readTeamStart(gdioutput &gdi, pClass pc, xmlobject &xTeam,
return 0; return 0;
// Class // Class
if (pc && (t->getClassId() == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) ) if (pc && (t->getClassId(false) == 0 || !t->hasFlag(oAbstractRunner::FlagUpdateClass)) )
t->setClassId(pc->getId(), false); t->setClassId(pc->getId(), false);
wstring bib; wstring bib;
@ -1534,7 +1534,7 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
if (cardNo > 0 && r == 0 && team) { if (cardNo > 0 && r == 0 && team) {
// We got no person, but a card number. Add the runner anonymously. // We got no person, but a card number. Add the runner anonymously.
r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(), cardNo, 0, false); r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(false), cardNo, 0, false);
r->flagEntryTouched(true); r->flagEntryTouched(true);
r->setEntrySource(entrySourceId); r->setEntrySource(entrySourceId);
r->synchronize(); r->synchronize();
@ -1555,21 +1555,21 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
map<int, vector<LegInfo> > localTeamClassConfig; map<int, vector<LegInfo> > localTeamClassConfig;
pClass pc = readClass(xo.getObject("Class"), localTeamClassConfig); pClass pc = readClass(xo.getObject("Class"), localTeamClassConfig);
if (pc && (r->getClassId() == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) ) if (pc && (r->getClassId(false) == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) )
r->setClassId(pc->getId(), false); r->setClassId(pc->getId(), false);
if (team) { if (team) {
int leg = xo.getObjectInt("Leg"); int leg = xo.getObjectInt("Leg");
int legorder = xo.getObjectInt("LegOrder"); int legorder = xo.getObjectInt("LegOrder");
int legindex = max(0, leg - 1); int legindex = max(0, leg - 1);
map<int, vector<LegInfo> >::const_iterator res = teamClassConfig.find(team->getClassId()); map<int, vector<LegInfo> >::const_iterator res = teamClassConfig.find(team->getClassId(false));
if (res != teamClassConfig.end()) { if (res != teamClassConfig.end()) {
legindex = getIndexFromLegPos(leg, legorder, res->second); legindex = getIndexFromLegPos(leg, legorder, res->second);
} }
if (personId2TeamLeg.find(r->getId()) == personId2TeamLeg.end()) { if (personId2TeamLeg.find(r->getId()) == personId2TeamLeg.end()) {
if (team->getClassRef()) if (team->getClassRef(false))
legindex = team->getClassRef()->getLegRunner(legindex); legindex = team->getClassRef(false)->getLegRunner(legindex);
// Ensure unique // Ensure unique
team->setRunner(legindex, r, false); team->setRunner(legindex, r, false);
@ -1676,7 +1676,7 @@ pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo
int leg = starts[k].getObjectInt("Leg"); int leg = starts[k].getObjectInt("Leg");
int legorder = starts[k].getObjectInt("LegOrder"); int legorder = starts[k].getObjectInt("LegOrder");
int legindex = max(0, leg - 1); int legindex = max(0, leg - 1);
map<int, vector<LegInfo> >::const_iterator res = teamClassConfig.find(team->getClassId()); map<int, vector<LegInfo> >::const_iterator res = teamClassConfig.find(team->getClassId(false));
if (res != teamClassConfig.end()) { if (res != teamClassConfig.end()) {
legindex = getIndexFromLegPos(leg, legorder, res->second); legindex = getIndexFromLegPos(leg, legorder, res->second);
} }
@ -1698,7 +1698,7 @@ pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo
} }
} }
if (pc && (r->getClassId() == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) ) if (pc && (r->getClassId(false) == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)) )
r->setClassId(pc->getId(), true); r->setClassId(pc->getId(), true);
r->synchronize(); r->synchronize();
@ -1961,7 +1961,7 @@ void IOF30Interface::writeAssignedFee(xmlparser &xml, const oAbstractRunner &tr,
if (paid >= paidForCard) { if (paid >= paidForCard) {
paid -= paidForCard; // Included in card service fee paid -= paidForCard; // Included in card service fee
} }
const pClass pc = tr.getClassRef(); const oClass *pc = tr.getClassRef(false);
if (!splitLateFee || !pc || !tr.hasLateEntryFee()) { if (!splitLateFee || !pc || !tr.hasLateEntryFee()) {
xml.startTag("AssignedFee"); xml.startTag("AssignedFee");
string type = tr.hasLateEntryFee() ? "Late" : "Normal"; string type = tr.hasLateEntryFee() ? "Late" : "Normal";
@ -2476,7 +2476,6 @@ void IOF30Interface::writeClass(xmlparser &xml, const oClass &c) {
else if (stat == oClass::InvalidRefund) else if (stat == oClass::InvalidRefund)
xml.write("Status", L"InvalidatedNoFee"); xml.write("Status", L"InvalidatedNoFee");
xml.endTag(); xml.endTag();
} }
@ -2537,7 +2536,7 @@ void IOF30Interface::writePersonResult(xmlparser &xml, const oRunner &r,
if (teamMember) { if (teamMember) {
oRunner const *resultHolder = &r; oRunner const *resultHolder = &r;
cTeam t = r.getTeam(); cTeam t = r.getTeam();
pClass cls = r.getClassRef(); const oClass *cls = r.getClassRef(false);
if (t && cls) { if (t && cls) {
int leg = r.getLegNumber(); int leg = r.getLegNumber();
@ -2614,9 +2613,9 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("TimeBehind", after); xml.write("TimeBehind", after);
} }
if (r.getClassRef()) { if (r.getClassRef(false)) {
if (r.statusOK() && r.getClassRef()->getNoTiming() == false) { if (r.statusOK() && r.getClassRef(false)->getNoTiming() == false) {
if (!teamMember && r.getPlace() > 0 && r.getPlace() < 50000) { if (!teamMember && r.getPlace() > 0 && r.getPlace() < 50000) {
xml.write("Position", r.getPlace()); xml.write("Position", r.getPlace());
} }
@ -2634,19 +2633,19 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Status", formatStatus(r.getStatus())); xml.write("Status", formatStatus(r.getStatus()));
if ( (r.getTeam() && r.getClassRef()->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) { if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult"); xml.startTag("OverallResult");
int rt = r.getTotalRunningTime(); int rt = r.getTotalRunningTime();
if (rt > 0) if (rt > 0)
xml.write("Time", rt); xml.write("Time", rt);
bool hasTiming = r.getClassRef()->getNoTiming() == false; bool hasTiming = r.getClassRef(false)->getNoTiming() == false;
RunnerStatus stat = r.getTotalStatus(); RunnerStatus stat = r.getTotalStatus();
int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0; int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0;
if (stat == StatusOK && hasTiming) { if (stat == StatusOK && hasTiming) {
int after = r.getTotalRunningTime() - r.getClassRef()->getTotalLegLeaderTime(tleg, true); int after = r.getTotalRunningTime() - r.getClassRef(true)->getTotalLegLeaderTime(tleg, true);
if (after >= 0) if (after >= 0)
xml.write("TimeBehind", after); xml.write("TimeBehind", after);
} }
@ -3100,7 +3099,7 @@ void IOF30Interface::writeStart(xmlparser &xml, const oRunner &r,
void IOF30Interface::writeLegOrder(xmlparser &xml, const oRunner &r) const { void IOF30Interface::writeLegOrder(xmlparser &xml, const oRunner &r) const {
// Team member race result // Team member race result
int legNumber, legOrder; int legNumber, legOrder;
const pClass pc = r.getClassRef(); const oClass *pc = r.getClassRef(false);
if (pc) { if (pc) {
bool par = pc->splitLegNumberParallel(r.getLegNumber(), legNumber, legOrder); bool par = pc->splitLegNumberParallel(r.getLegNumber(), legNumber, legOrder);
xml.write("Leg", legNumber + 1); xml.write("Leg", legNumber + 1);

View File

@ -112,7 +112,7 @@ void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) {
pair<int, int> key = make_pair(r->getId(), pp[k]->getControlId()); pair<int, int> key = make_pair(r->getId(), pp[k]->getControlId());
processedPunches[key] = max(processedPunches[key], pp[k]->getAdjustedTime()); processedPunches[key] = max(processedPunches[key], pp[k]->getAdjustedTime());
if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId())) if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId(true)))
continue; // Filter class continue; // Filter class
if (pp[k]->getTypeCode() == fromPunch) { if (pp[k]->getTypeCode() == fromPunch) {
@ -182,7 +182,7 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
if (!r) if (!r)
continue; continue;
if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId())) if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId(true)))
continue; // Filter class continue; // Filter class
pair<int, int> key = make_pair(r->getId(), pp[k]->getControlId()); pair<int, int> key = make_pair(r->getId(), pp[k]->getControlId());

View File

@ -1149,6 +1149,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
delete gSI; delete gSI;
gSI=0; gSI=0;
for (size_t k = 0; k < gdi_extra.size(); k++) {
if (gdi_extra[k])
gdi_extra[k]->clearPage(false, false);
}
if (gEvent) { if (gEvent) {
try { try {
gEvent->save(); gEvent->save();

View File

@ -28,10 +28,29 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// //
BMP_TEST BITMAP "bitmap1.bmp" BMP_TEST BITMAP "bitmap1.bmp"
#endif // Neutral resources #endif // Neutral resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Neutral (Default) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD)
LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDB_ECO BITMAP "bmp00001.bmp"
#endif // Neutral (Default) resources
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// English (United States) resources // English (United States) resources
@ -48,6 +67,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// remains consistent on all systems. // remains consistent on all systems.
IDI_MEOS ICON "meos.ICO" IDI_MEOS ICON "meos.ICO"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Menu // Menu
@ -160,6 +180,14 @@ BEGIN
END END
END END
/////////////////////////////////////////////////////////////////////////////
//
// HTML
//
IDR_HTML1 HTML "html1.htm"
#endif // Swedish (Sweden) resources #endif // Swedish (Sweden) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -1368,7 +1368,7 @@ static void decomposeClassName(const wstring &name, vector<wstring> &dec) {
for (size_t i = 0; i < name.size(); i++) { for (size_t i = 0; i < name.size(); i++) {
int bchar = toLowerStripped(name[i]); int bchar = toLowerStripped(name[i]);
if (isspace(bchar) || bchar == '-' || bchar == 160) { if (myIsSpace(bchar) || bchar == '-' || bchar == 160) {
if (!dec.back().empty()) if (!dec.back().empty())
dec.push_back(wstring()); dec.push_back(wstring());
continue; continue;
@ -1823,7 +1823,7 @@ void capitalize(wstring &str) {
int getTimeZoneInfo(const wstring &date) { int getTimeZoneInfo(const wstring &date) {
static wchar_t lastDate[16] = {0}; static wchar_t lastDate[16] = {0};
static int lastValue = -1; static int lastValue = -1;
// Local cacheing // Local caching
if (lastValue != -1 && lastDate == date) { if (lastValue != -1 && lastDate == date) {
return lastValue; return lastValue;
} }
@ -2161,8 +2161,14 @@ void processGeneralTime(const wstring &generalTime, wstring &meosTime, wstring &
} }
void string2Wide(const string &in, wstring &out) { void string2Wide(const string &in, wstring &out) {
out.clear(); int cp = 1252;
out.insert(out.begin(), in.begin(), in.end());// XXX Simple extend if (in.empty()) {
out = L"";
return;
}
out.reserve(in.size() + 1);
out.resize(in.size(), 0);
MultiByteToWideChar(cp, MB_PRECOMPOSED, in.c_str(), in.size(), &out[0], out.size() * sizeof(wchar_t));
} }
void wide2String(const wstring &in, string &out) { void wide2String(const wstring &in, string &out) {

View File

@ -1906,7 +1906,7 @@ OpFailStatus MeosSQL::syncUpdate(oRunner *r, bool forceWriteAll)
<< " StartTime=" << r->startTime << ", " << " StartTime=" << r->startTime << ", "
<< " FinishTime=" << r->FinishTime << ", " << " FinishTime=" << r->FinishTime << ", "
<< " Course=" << r->getCourseId() << ", " << " Course=" << r->getCourseId() << ", "
<< " Class=" << r->getClassId() << ", " << " Class=" << r->getClassId(false) << ", "
<< " Club=" << r->getClubId() << ", " << " Club=" << r->getClubId() << ", "
<< " Card=" << r->getCardId() << ", " << " Card=" << r->getCardId() << ", "
<< " Status=" << r->status << ", " << " Status=" << r->status << ", "
@ -2101,7 +2101,7 @@ OpFailStatus MeosSQL::syncUpdate(oTeam *t, bool forceWriteAll) {
<< " Runners=" << quote << t->getRunners() << ", " << " Runners=" << quote << t->getRunners() << ", "
<< " StartTime=" << t->startTime << ", " << " StartTime=" << t->startTime << ", "
<< " FinishTime=" << t->FinishTime << ", " << " FinishTime=" << t->FinishTime << ", "
<< " Class=" << t->getClassId() << ", " << " Class=" << t->getClassId(false) << ", "
<< " Club=" << t->getClubId() << ", " << " Club=" << t->getClubId() << ", "
<< " StartNo=" << t->getStartNo() << ", " << " StartNo=" << t->getStartNo() << ", "
<< " Status=" << t->status << " Status=" << t->status

View File

@ -335,6 +335,7 @@
<ClCompile Include="prefseditor.cpp" /> <ClCompile Include="prefseditor.cpp" />
<ClCompile Include="printer.cpp" /> <ClCompile Include="printer.cpp" />
<ClCompile Include="progress.cpp" /> <ClCompile Include="progress.cpp" />
<ClCompile Include="qualification_final.cpp" />
<ClCompile Include="random.cpp"> <ClCompile Include="random.cpp">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -420,6 +421,7 @@
<ClInclude Include="pdfwriter.h" /> <ClInclude Include="pdfwriter.h" />
<ClInclude Include="prefseditor.h" /> <ClInclude Include="prefseditor.h" />
<ClInclude Include="Printer.h" /> <ClInclude Include="Printer.h" />
<ClInclude Include="qualification_final.h" />
<ClInclude Include="recorder.h" /> <ClInclude Include="recorder.h" />
<ClInclude Include="restserver.h" /> <ClInclude Include="restserver.h" />
<ClInclude Include="RestService.h" /> <ClInclude Include="RestService.h" />
@ -482,6 +484,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="bitmap1.bmp" /> <None Include="bitmap1.bmp" />
<None Include="html1.htm">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="meos.ico" /> <None Include="meos.ico" />
<None Include="small.ico" /> <None Include="small.ico" />
</ItemGroup> </ItemGroup>

View File

@ -27,9 +27,9 @@
//V2: ABCDEFGHIHJKMN //V2: ABCDEFGHIHJKMN
//V31: a //V31: a
//V33: abcde //V33: abcde
//V35: abc //V35: abcde
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 621 $"); string revision("$Rev: 634 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
@ -41,7 +41,7 @@ int getMeosBuild() {
//V33: abcdefghij //V33: abcdefghij
//V34: abcdfg //V34: abcdfg
wstring getMeosDate() { wstring getMeosDate() {
wstring date(L"$Date: 2017-10-21 22:43:38 +0200 (lö, 21 okt 2017) $"); wstring date(L"$Date: 2017-12-25 16:08:33 +0100 (mÃ¥, 25 dec 2017) $");
return date.substr(7,10); return date.substr(7,10);
} }
@ -109,7 +109,7 @@ void getSupporters(vector<string> &supp)
supp.push_back("Oskarström OK"); supp.push_back("Oskarström OK");
supp.push_back("Skogslöparna"); supp.push_back("Skogslöparna");
supp.push_back("OK Milan"); supp.push_back("OK Milan");
supp.push_back("GoIF Tjalve"); supp.push_back("Tjalve IF");
supp.push_back("OK Skärmen"); supp.push_back("OK Skärmen");
supp.push_back("Østkredsen"); supp.push_back("Østkredsen");
supp.push_back("OK Roskilde"); supp.push_back("OK Roskilde");
@ -177,4 +177,7 @@ void getSupporters(vector<string> &supp)
supp.push_back("Åke Larsson, OK Hedströmmen"); supp.push_back("Åke Larsson, OK Hedströmmen");
supp.push_back("Avesta OK"); supp.push_back("Avesta OK");
supp.push_back("Motionsorientering Göteborg"); supp.push_back("Motionsorientering Göteborg");
supp.push_back("OK Måsen");
supp.push_back("IF Thor");
supp.push_back("SOS Jindrichuv Hradec");
} }

View File

@ -54,6 +54,7 @@ oBase::oBase(oEvent *poe)
counter = 0; counter = 0;
Modified.update(); Modified.update();
correctionNeeded = true; correctionNeeded = true;
localObject = false;
} }
oBase::~oBase() oBase::~oBase()
@ -68,6 +69,8 @@ bool oBase::synchronize(bool writeOnly)
} }
if (oe && oe->HasDBConnection && (changed || !writeOnly)) { if (oe && oe->HasDBConnection && (changed || !writeOnly)) {
correctionNeeded = false; correctionNeeded = false;
if (localObject)
return false;
return oe->msSynchronize(this); return oe->msSynchronize(this);
} }
else { else {
@ -79,17 +82,6 @@ bool oBase::synchronize(bool writeOnly)
return true; return true;
} }
void oBase::clearCombo(HWND hWnd)
{
SendMessage(hWnd, CB_RESETCONTENT, 0, 0);
}
void oBase::addToCombo(HWND hWnd, const string &str, int data)
{
int index=SendMessage(hWnd, CB_ADDSTRING, 0, LPARAM(str.c_str()));
SendMessage(hWnd, CB_SETITEMDATA, index, data);
}
void oBase::setExtIdentifier(__int64 id) void oBase::setExtIdentifier(__int64 id)
{ {
getDI().setInt64("ExtId", id); getDI().setInt64("ExtId", id);

View File

@ -75,7 +75,7 @@ private:
void resetChangeStatus() {changed &= reChanged;} void resetChangeStatus() {changed &= reChanged;}
bool reChanged; bool reChanged;
bool changed; bool changed;
bool localObject;
const static unsigned long long BaseGenStringFlag = 1ull << 63; const static unsigned long long BaseGenStringFlag = 1ull << 63;
const static unsigned long long Base36StringFlag = 1ull << 62; const static unsigned long long Base36StringFlag = 1ull << 62;
const static unsigned long long ExtStringMask = ~(BaseGenStringFlag|Base36StringFlag); const static unsigned long long ExtStringMask = ~(BaseGenStringFlag|Base36StringFlag);
@ -106,15 +106,17 @@ protected:
/** Change the id of the object */ /** Change the id of the object */
virtual void changeId(int newId); virtual void changeId(int newId);
//Used for handeling GUI combo boxes;
static void clearCombo(HWND hWnd);
static void addToCombo(HWND hWnd, const string &str, int data);
/** Get internal data buffers for DI */ /** Get internal data buffers for DI */
virtual oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const = 0; virtual oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const = 0;
virtual int getDISize() const = 0; virtual int getDISize() const = 0;
void setLocalObject() { localObject = true; }
public: public:
// Returns true if the object is local, not stored in DB/On disc
bool isLocalObject() { return localObject; }
/// Returns textual information on the object /// Returns textual information on the object
virtual wstring getInfo() const = 0; virtual wstring getInfo() const = 0;

View File

@ -43,6 +43,8 @@
#include "gdistructures.h" #include "gdistructures.h"
#include "meosexception.h" #include "meosexception.h"
#include "random.h" #include "random.h"
#include "qualification_final.h"
#include "generalresult.h"
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Construction/Destruction // Construction/Destruction
@ -64,6 +66,7 @@ oClass::oClass(oEvent *poe): oBase(poe)
tCoursesChanged = false; tCoursesChanged = false;
tStatusRevision = 0; tStatusRevision = 0;
tShowMultiDialog = false; tShowMultiDialog = false;
parentClass = 0;
} }
oClass::oClass(oEvent *poe, int id): oBase(poe) oClass::oClass(oEvent *poe, int id): oBase(poe)
@ -73,7 +76,7 @@ oClass::oClass(oEvent *poe, int id): oBase(poe)
if (id == 0) if (id == 0)
id = oe->getFreeClassId(); id = oe->getFreeClassId();
Id=id; Id=id;
oe->qFreeClassId = max(id, oe->qFreeClassId); oe->qFreeClassId = max(id % MaxClassId, oe->qFreeClassId);
tLeaderTime.resize(1); tLeaderTime.resize(1);
tNoTiming = -1; tNoTiming = -1;
tIgnoreStartPunch = -1; tIgnoreStartPunch = -1;
@ -85,6 +88,8 @@ oClass::oClass(oEvent *poe, int id): oBase(poe)
tCoursesChanged = false; tCoursesChanged = false;
tStatusRevision = 0; tStatusRevision = 0;
tShowMultiDialog = false; tShowMultiDialog = false;
parentClass = 0;
} }
oClass::~oClass() oClass::~oClass()
@ -359,7 +364,7 @@ int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNo
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->getClassId()==Id) { if (it->getClassId(true)==Id) {
if (it->skip()) if (it->skip())
continue; continue;
if (checkFirstLeg && it->tLeg > 0) if (checkFirstLeg && it->tLeg > 0)
@ -412,7 +417,7 @@ void oClass::setName(const wstring &name)
oDataContainer &oClass::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { oDataContainer &oClass::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const {
data = (pvoid)oData; data = (pvoid)oData;
olddata = (pvoid)oDataOld; olddata = (pvoid)oDataOld;
strData = 0; strData = const_cast< vector <vector<wstring> >* >(&oDataStr);
return *oe->oClassData; return *oe->oClassData;
} }
@ -1067,13 +1072,14 @@ const vector< pair<wstring, size_t> > &oEvent::fillClasses(vector< pair<wstring,
if (rit->isRemoved()) if (rit->isRemoved())
continue; continue;
if (rit->Class) { pClass pc = rit->getClassRef(true);
if (rit->Class->getNumStages() > 0 && rit->Class->getStartType(rit->tLeg) != STDrawn) if (pc) {
if (pc->getNumStages() > 0 && pc->getStartType(rit->tLeg) != STDrawn)
needTime = false; needTime = false;
} }
if (rit->tStartTime==0 && needTime) if (rit->tStartTime==0 && needTime)
undrawn.insert(rit->getClassId()); undrawn.insert(rit->getClassId(true));
hasRunner.insert(rit->getClassId()); hasRunner.insert(rit->getClassId(true));
} }
} }
else if (extended == extraNumMaps) else if (extended == extraNumMaps)
@ -1137,9 +1143,9 @@ void oEvent::getNotDrawnClasses(set<int> &classes, bool someMissing)
synchronizeList(oLRunnerId); synchronizeList(oLRunnerId);
for (rit=Runners.begin(); rit != Runners.end(); ++rit) { for (rit=Runners.begin(); rit != Runners.end(); ++rit) {
if (rit->tStartTime>0) if (rit->tStartTime>0)
drawn.insert(rit->getClassId()); drawn.insert(rit->getClassId(true));
else if (someMissing) else if (someMissing)
classes.insert(rit->getClassId()); classes.insert(rit->getClassId(true));
} }
// Return all classe where some runner has no start time // Return all classe where some runner has no start time
@ -1231,28 +1237,6 @@ bool oClass::isCourseUsed(int Id) const
return false; return false;
} }
string oClass::getClassResultStatus() const
{
list<oRunner>::iterator it;
int nrunner=0;
int nrunner_finish=0;
for (it=oe->Runners.begin(); it!=oe->Runners.end();++it) {
if (it->getClassId()==Id){
nrunner++;
if (it->getStatus())
nrunner_finish++;
}
}
char bf[128];
sprintf_s(bf, "%d/%d", nrunner_finish, nrunner);
return bf;
}
bool oClass::hasTrueMultiCourse() const { bool oClass::hasTrueMultiCourse() const {
if (MultiCourse.empty()) if (MultiCourse.empty())
return false; return false;
@ -1516,7 +1500,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
int maxleg = pc->getLastStageIndex(); int maxleg = pc->getLastStageIndex();
for (it=Runners.begin(); it != Runners.end(); ++it){ for (it=Runners.begin(); it != Runners.end(); ++it){
if (!it->skip() && it->getClassId()==id && it->getStatus() != StatusNotCompetiting) { if (!it->skip() && it->getClassId(true)==id && it->getStatus() != StatusNotCompetiting) {
if (leg==0) { if (leg==0) {
total++; total++;
@ -1543,7 +1527,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
oTeamList::const_iterator it; oTeamList::const_iterator it;
for (it=Teams.begin(); it != Teams.end(); ++it) { for (it=Teams.begin(); it != Teams.end(); ++it) {
if (it->getClassId()==id) { if (it->getClassId(true)==id) {
total++; total++;
if (it->tStatus!=StatusUnknown || if (it->tStatus!=StatusUnknown ||
@ -2695,7 +2679,7 @@ void oClass::getStatistics(const set<int> &feeLock, int &entries, int &started)
if (it->getStatus() == StatusNotCompetiting) if (it->getStatus() == StatusNotCompetiting)
continue; continue;
if (it->getClassId()==Id) { if (it->getClassId(false)==Id) {
if (feeLock.empty() || feeLock.count(it->getDCI().getInt("Fee"))) { if (feeLock.empty() || feeLock.count(it->getDCI().getInt("Fee"))) {
entries++; entries++;
if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS && it->tStatus != StatusCANCEL) if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS && it->tStatus != StatusCANCEL)
@ -2789,6 +2773,22 @@ void oClass::reinitialize()
tMaxTime = oe->getMaximalTime(); tMaxTime = oe->getMaximalTime();
} }
wstring wInfo = getDI().getString("Qualification");
if (!wInfo.empty()) {
if (!qualificatonFinal)
qualificatonFinal = make_shared<QualificationFinal>(MaxClassId, Id);
qualificatonFinal->init(wInfo);
virtualClasses.resize(getNumQualificationFinalClasses());
int nc = qualificatonFinal->getNumClasses();
for (int i = 1; i <= nc; i++)
getVirtualClass(i);
}
else {
qualificatonFinal.reset();
}
tNoTiming = -1; tNoTiming = -1;
tIgnoreStartPunch = -1; tIgnoreStartPunch = -1;
} }
@ -3787,7 +3787,7 @@ void oClass::extractBibPatterns(oEvent &oe, map<int, pair<wstring, int> > &patte
patterns.clear(); patterns.clear();
wchar_t pattern[32]; wchar_t pattern[32];
for (size_t k = t.size(); k > 0; k--) { for (size_t k = t.size(); k > 0; k--) {
int cls = t[k-1]->getClassId(); int cls = t[k-1]->getClassId(true);
if (cls == 0) if (cls == 0)
continue; continue;
const wstring &bib = t[k-1]->getBib(); const wstring &bib = t[k-1]->getBib();
@ -3806,7 +3806,7 @@ void oClass::extractBibPatterns(oEvent &oe, map<int, pair<wstring, int> > &patte
for (size_t k = r.size(); k > 0; k--) { for (size_t k = r.size(); k > 0; k--) {
if (r[k-1]->getTeam() != 0) if (r[k-1]->getTeam() != 0)
continue; continue;
int cls = r[k-1]->getClassId(); int cls = r[k-1]->getClassId(true);
if (cls == 0) if (cls == 0)
continue; continue;
const wstring &bib = r[k-1]->getBib(); const wstring &bib = r[k-1]->getBib();
@ -4061,7 +4061,7 @@ void oClass::drawSeeded(ClassSeedMethod seed, int leg, int firstStart,
} }
} }
bool oClass::hasClassGlobalDependance() const { bool oClass::hasClassGlobalDependence() const {
for (size_t k = 0; k < legInfo.size(); k++) { for (size_t k = 0; k < legInfo.size(); k++) {
if (legInfo[k].startMethod == STHunting) if (legInfo[k].startMethod == STHunting)
return true; return true;
@ -4139,6 +4139,8 @@ int oClass::getNextBaseLeg(int leg) const {
} }
int oClass::getPreceedingLeg(int leg) const { int oClass::getPreceedingLeg(int leg) const {
if (size_t(leg) >= legInfo.size())
leg = legInfo.size() - 1;
for (int k = leg; k > 0; k--) { for (int k = leg; k > 0; k--) {
if (!(legInfo[k].isParallel() || legInfo[k].isOptional())) if (!(legInfo[k].isParallel() || legInfo[k].isOptional()))
return k-1; return k-1;
@ -4147,9 +4149,242 @@ int oClass::getPreceedingLeg(int leg) const {
} }
bool oClass::lockedForking() const { bool oClass::lockedForking() const {
return getDCI().getInt("Locked") != 0; return (getDCI().getInt("Locked") & 1) == 1;
} }
void oClass::lockedForking(bool locked) { void oClass::lockedForking(bool locked) {
getDI().setInt("Locked", locked); int current = getDCI().getInt("Locked");
getDI().setInt("Locked", locked ? (current | 1) : (current & ~1));
}
bool oClass::lockedClassAssignment() const {
return (getDCI().getInt("Locked") & 2) == 2;
}
void oClass::lockedClassAssignment(bool locked) {
int current = getDCI().getInt("Locked");
getDI().setInt("Locked", locked ? (current | 2) : (current & ~2));
}
oClass *oClass::getVirtualClass(int instance, bool allowCreation) {
if (instance == 0)
return this;
if (parentClass)
return parentClass->getVirtualClass(instance, allowCreation);
if (size_t(instance) < virtualClasses.size() && virtualClasses[instance])
return virtualClasses[instance];
if (instance >= getNumQualificationFinalClasses())
return this; // Invalid
virtualClasses.resize(getNumQualificationFinalClasses());
int virtId = Id + instance * MaxClassId;
virtualClasses[instance] = oe->getClass(virtId);
if (virtualClasses[instance]) {
virtualClasses[instance]->parentClass = pClass(this);
return virtualClasses[instance];
}
configureInstance(instance, allowCreation);
if (virtualClasses[instance])
return virtualClasses[instance];
return this; // Fallback
}
const oClass *oClass::getVirtualClass(int instance) const {
if (instance == 0)
return this;
if (parentClass)
return parentClass->getVirtualClass(instance);
if (size_t(instance) < virtualClasses.size() && virtualClasses[instance])
return virtualClasses[instance];
if (instance >= getNumQualificationFinalClasses())
return this; // Invalid
virtualClasses.resize(getNumQualificationFinalClasses());
int virtId = Id + instance * MaxClassId;
virtualClasses[instance] = oe->getClass(virtId);
if (virtualClasses[instance]) {
virtualClasses[instance]->parentClass = pClass(this);
return virtualClasses[instance];
}
configureInstance(instance, false);
if (virtualClasses[instance])
return virtualClasses[instance];
return this; // Fallback
}
void oClass::configureInstance(int instance, bool allowCreation) const {
int virtId = Id + instance * MaxClassId;
virtualClasses[instance] = oe->getClass(virtId);
if (virtualClasses[instance]) {
virtualClasses[instance]->parentClass = pClass(this);
return;
}
if (!allowCreation)
return;
oClass copy(*this);
copy.Id = Id + instance * MaxClassId;
copy.setExtIdentifier(copy.Id);
copy.Name += makeDash(L"-") + qualificatonFinal->getInstanceName(instance);
copy.setLocalObject();
copy.parentClass = pClass(this);
copy.tSortIndex += instance;
copy.getDI().setInt("SortIndex", copy.tSortIndex);
copy.legInfo.clear();
copy.MultiCourse.clear();
copy.getDI().setString("Qualification", L"");
virtualClasses[instance] = oe->addClass(copy);
}
int oClass::getNumQualificationFinalClasses() const {
if (qualificatonFinal)
return qualificatonFinal->getNumClasses()+1;
return 0;
}
void oClass::loadQualificationFinalScheme(const wstring &fileName) {
auto qf = make_shared<QualificationFinal>(MaxClassId, Id);
qf->import(fileName);
wstring enc;
qf->encode(enc);
int ns = qf->getNumStages();
setNumStages(ns);
for (int i = 1; i < ns; i++) {
setStartType(i, StartTypes::STDrawn, true);
setLegType(i, LegTypes::LTNormal);
setLegRunner(i, 0);
}
qualificatonFinal = qf;
getDI().setString("Qualification", enc);
for (int i = 0; i < qualificatonFinal->getNumClasses(); i++) {
pClass inst = getVirtualClass(i+1, true);
inst->synchronize();
}
synchronize();
}
void oClass::updateFinalClasses(oRunner *causingResult, bool updateStartNumbers) {
if (!qualificatonFinal)
return;
assert(!causingResult || causingResult->Class == this);
int instance = causingResult ? causingResult->classInstance() : 0;
pClass currentInst = getVirtualClass(instance, false);
if (instance == virtualClasses.size())
return; // Final class
int maxDepth = getNumStages();
bool needIter = true;
int limit = virtualClasses.size() - 1;
while (needIter && --maxDepth > 0) {
needIter = false;
if (size_t(instance) >= virtualClasses.size())
break; // Final class
vector< vector<pRunner> > classSplit(virtualClasses.size());
for (oRunner &r : oe->Runners) {
if (r.isRemoved() || !r.Class)
continue;
if (r.Class != this && (r.Class->getId() % MaxClassId) != getId())
continue;
int inst = r.Class == this ? r.classInstance() : (r.Class->getId() - getId()) & MaxClassId;
if (inst == 0 && r.tLeg > 0)
continue; // Only allow base class for leg 0.
if (inst < instance || inst >= limit)
continue;
classSplit[inst].push_back(&r);
}
GeneralResult gr;
for (int i = instance; i < limit; i++) {
if (classSplit[i].empty())
continue;
if (i == 0 && qualificatonFinal->noQualification(i)) {
set<int> allowed;
qualificatonFinal->getBaseClassInstances(allowed);
// Place all in this group
for (pRunner r : classSplit[i]) {
auto di = r->getDI();
int oldHeat = di.getInt("Heat");
if (allowed.count(oldHeat) || classSplit.size() < 2)
continue;
// Take the smallest gruop. User can set heat explicitly of other distribution is wanted.
int heat = 1;
for (int i : allowed) {
if (size_t(i) < classSplit.size() &&
classSplit[heat].size() > classSplit[i].size())
heat = i;
}
if (heat != oldHeat) {
bool lockedStartList = getVirtualClass(heat)->lockedClassAssignment() ||
getVirtualClass(oldHeat)->lockedClassAssignment();
if (!lockedStartList) {
pClass oldClass = r->getClassRef(true);
oldClass->markSQLChanged(-1, 0);
di.setInt("Heat", heat);
r->classInstanceRev.first = -1;
r->synchronize();
}
}
}
}
gr.calculateIndividualResults(classSplit[i], oListInfo::Classwise, true, 0);
int lastPlace = 0, orderPlace = 1;
int numEqual = 0;
for (size_t k = 0; k < classSplit[i].size(); k++) {
auto &res = classSplit[i][k]->getTempResult();
int heat = 0;
if (res.getStatus() == StatusOK) {
int place = res.getPlace();
if (lastPlace == place)
numEqual++;
else
numEqual = 0;
auto nextFinal = qualificatonFinal->getNextFinal(i, orderPlace, numEqual);
heat = nextFinal.first;
lastPlace = place;
}
orderPlace++;
oRunner &thisRunner = *classSplit[i][k];
pRunner runnerToChange = thisRunner.getMultiRunner(thisRunner.getRaceNo() + 1);
if (runnerToChange) {
auto di = runnerToChange->getDI();
int oldHeat = di.getInt("Heat");
if (heat != oldHeat) {
bool lockedStartList = getVirtualClass(heat)->lockedClassAssignment() ||
getVirtualClass(oldHeat)->lockedClassAssignment();
if (!lockedStartList) {
pClass oldClass = runnerToChange->getClassRef(true);
oldClass->markSQLChanged(-1, 0);
di.setInt("Heat", heat);
runnerToChange->classInstanceRev.first = -1;
runnerToChange->synchronize();
if (runnerToChange->getFinishTime() > 0)
needIter = true;
}
}
}
}
if (needIter) {
instance = i+1; // Need not process last class again
break;
}
}
}
} }

View File

@ -40,6 +40,8 @@ class oClass;
typedef oClass* pClass; typedef oClass* pClass;
class oDataInterface; class oDataInterface;
const int MaxClassId = 1000000;
enum PersonSex; enum PersonSex;
enum StartTypes { enum StartTypes {
@ -132,6 +134,7 @@ struct ClassResultInfo {
int lastStartTime; int lastStartTime;
}; };
class QualificationFinal;
enum ClassType {oClassIndividual=1, oClassPatrol=2, enum ClassType {oClassIndividual=1, oClassPatrol=2,
oClassRelay=3, oClassIndividRelay=4}; oClassRelay=3, oClassIndividRelay=4};
@ -206,7 +209,7 @@ protected:
BYTE oData[dataSize]; BYTE oData[dataSize];
BYTE oDataOld[dataSize]; BYTE oDataOld[dataSize];
vector< vector<wstring> > oDataStr;
//Multicourse data //Multicourse data
string codeMultiCourse() const; string codeMultiCourse() const;
//Fill courseId with id:s of used courses. //Fill courseId with id:s of used courses.
@ -258,14 +261,34 @@ protected:
static long long setupForkKey(const vector<int> indices, const vector< vector< vector<int> > > &courseKeys, vector<int> &ws); static long long setupForkKey(const vector<int> indices, const vector< vector< vector<int> > > &courseKeys, vector<int> &ws);
mutable vector<pClass> virtualClasses;
pClass parentClass;
shared_ptr<QualificationFinal> qualificatonFinal;
void configureInstance(int instance, bool allowCreation) const;
public: public:
/** The master class in a qualification/final scheme. */
const pClass getParentClass() const { return parentClass; }
const QualificationFinal *getQualificationFinal() const { return qualificatonFinal.get(); }
/** Returns the number of possible final classes.*/
int getNumQualificationFinalClasses() const;
void loadQualificationFinalScheme(const wstring &fileName);
void updateFinalClasses(oRunner *causingResult, bool updateStartNumbers);
static void initClassId(oEvent &oe); static void initClassId(oEvent &oe);
// Return true if forking in the class is locked // Return true if forking in the class is locked
bool lockedForking() const; bool lockedForking() const;
void lockedForking(bool locked); void lockedForking(bool locked);
bool lockedClassAssignment() const;
void lockedClassAssignment(bool locked);
// Draw data // Draw data
int getDrawFirstStart() const; int getDrawFirstStart() const;
void setDrawFirstStart(int st); void setDrawFirstStart(int st);
@ -286,7 +309,7 @@ public:
void drawSeeded(ClassSeedMethod seed, int leg, int firstStart, int interval, const vector<int> &groups, void drawSeeded(ClassSeedMethod seed, int leg, int firstStart, int interval, const vector<int> &groups,
bool noClubNb, bool reverse, int pairSize); bool noClubNb, bool reverse, int pairSize);
/** Returns true if the class is setup so that changeing one runner can effect all others. (Pursuit)*/ /** Returns true if the class is setup so that changeing one runner can effect all others. (Pursuit)*/
bool hasClassGlobalDependance() const; bool hasClassGlobalDependence() const;
// Autoassign new bibs // Autoassign new bibs
static void extractBibPatterns(oEvent &oe, map<int, pair<wstring, int> > &patterns); static void extractBibPatterns(oEvent &oe, map<int, pair<wstring, int> > &patterns);
pair<int, wstring> getNextBib(map<int, pair<wstring, int> > &patterns); // Version that calculates next free bib from cached data (fast, no gap usage) pair<int, wstring> getNextBib(map<int, pair<wstring, int> > &patterns); // Version that calculates next free bib from cached data (fast, no gap usage)
@ -315,6 +338,9 @@ public:
return false; return false;
} }
oClass *getVirtualClass(int instance, bool allowCreation);
const oClass *getVirtualClass(int instance) const;
ClassStatus getClassStatus() const; ClassStatus getClassStatus() const;
ClassMetaType interpretClassType() const; ClassMetaType interpretClassType() const;
@ -441,9 +467,6 @@ public:
void setDirectResult(bool directResult); void setDirectResult(bool directResult);
bool hasDirectResult() const; bool hasDirectResult() const;
string getClassResultStatus() const;
bool isCourseUsed(int Id) const; bool isCourseUsed(int Id) const;
wstring getLength(int leg) const; wstring getLength(int leg) const;
@ -472,7 +495,7 @@ public:
void setNumStages(int no); void setNumStages(int no);
bool operator<(const oClass &b){return tSortIndex<b.tSortIndex;} bool operator<(const oClass &b) {return tSortIndex<b.tSortIndex || (tSortIndex == b.tSortIndex && Id < b.Id);}
// Get total number of runners running this class. // Get total number of runners running this class.
// Use checkFirstLeg to only check the number of runners running leg 1. // Use checkFirstLeg to only check the number of runners running leg 1.

View File

@ -428,7 +428,6 @@ void oEvent::getClubs(vector<pClub> &c, bool sort) {
} }
} }
void oEvent::viewClubMembers(gdioutput &gdi, int clubId) void oEvent::viewClubMembers(gdioutput &gdi, int clubId)
{ {
sortRunners(ClassStartTime); sortRunners(ClassStartTime);
@ -440,10 +439,12 @@ void oEvent::viewClubMembers(gdioutput &gdi, int clubId)
int nt = 0; int nt = 0;
// Update teams // Update teams
for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) { for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) {
if (it->skip())
continue;
if (it->getClubId() == clubId) { if (it->getClubId() == clubId) {
if (nt==0) if (nt==0)
gdi.addString("", 1, "Lag(flera)"); gdi.addString("", 1, "Lag(flera)");
gdi.addStringUT(0, it->getName() + L", " + it->getClass() ); gdi.addStringUT(0, it->getName() + L", " + it->getClass(false) );
nt++; nt++;
} }
} }
@ -451,10 +452,12 @@ void oEvent::viewClubMembers(gdioutput &gdi, int clubId)
gdi.dropLine(); gdi.dropLine();
// Update runners // Update runners
for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) {
if (it->skip())
continue;
if (it->getClubId() == clubId) { if (it->getClubId() == clubId) {
if (nr==0) if (nr==0)
gdi.addString("", 1, "Löpare:"); gdi.addString("", 1, "Löpare:");
gdi.addStringUT(0, it->getName() + L", " + it->getClass() ); gdi.addStringUT(0, it->getName() + L", " + it->getClass(true) );
nr++; nr++;
} }
} }
@ -496,7 +499,7 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
wstring ts; wstring ts;
if (!inTeam) if (!inTeam)
line.addString(xs+data.clsPos, r->getClass()); line.addString(xs+data.clsPos, r->getClass(true));
if (r->getStatus() == StatusUnknown) if (r->getStatus() == StatusUnknown)
ts = L"-"; ts = L"-";
@ -504,8 +507,8 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
if (r->getStatus()==StatusOK) { if (r->getStatus()==StatusOK) {
ClassType type = oClassIndividual; ClassType type = oClassIndividual;
cTeam t = r->getTeam(); cTeam t = r->getTeam();
if (t && r->getClassRef()) if (t && r->getClassRef(false))
type = r->getClassRef()->getClassType(); type = r->getClassRef(false)->getClassType();
if (type == oClassIndividRelay || type == oClassRelay) { if (type == oClassIndividRelay || type == oClassRelay) {
int leg = r->getLegNumber(); int leg = r->getLegNumber();
@ -541,7 +544,7 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
if (res != definedPayModes.end()) if (res != definedPayModes.end())
payMode = ", " + res->second; payMode = ", " + res->second;
*/ */
if (r->getClassRef() && r->getClassRef()->getClassStatus() == oClass::InvalidRefund) { if (r->getClassRef(false) && r->getClassRef(false)->getClassStatus() == oClass::InvalidRefund) {
fee = 0; fee = 0;
card = 0; card = 0;
} }
@ -574,7 +577,7 @@ void oClub::addTeamInvoiceLine(const pTeam t, const map<int, wstring> &definedPa
return; return;
line.addString(xs, t->getName()); line.addString(xs, t->getName());
line.addString(xs+data.clsPos, t->getClass()); line.addString(xs+data.clsPos, t->getClass(false));
wstring ts; wstring ts;
if (t->getStatus() == StatusUnknown) if (t->getStatus() == StatusUnknown)
@ -588,7 +591,7 @@ void oClub::addTeamInvoiceLine(const pTeam t, const map<int, wstring> &definedPa
} }
if (t->getClassRef() && t->getClassRef()->getClassStatus() == oClass::InvalidRefund) { if (t->getClassRef(false) && t->getClassRef(false)->getClassStatus() == oClass::InvalidRefund) {
fee = 0; fee = 0;
} }

View File

@ -998,3 +998,21 @@ void oControl::getClasses(vector<pClass> &cls) const {
cls.push_back(pClass(&*it)); cls.push_back(pClass(&*it));
} }
} }
int oControl::getControlIdByName(const oEvent &oe, const string &name) {
if (_stricmp(name.c_str(), "finish") == 0)
return oPunch::PunchFinish;
if (_stricmp(name.c_str(), "start") == 0)
return oPunch::PunchStart;
vector<pControl> ac;
oe.getControls(ac, true);
wstring wname = oe.gdiBase().recodeToWide(name);
for (pControl c : ac) {
if (_wcsicmp(c->getName().c_str(), wname.c_str()) == 0)
return c->getId();
}
return 0;
}

View File

@ -117,6 +117,7 @@ protected:
void changedObject(); void changedObject();
public: public:
static int getControlIdByName(const oEvent &oe, const string &name);
// Returns true if controls is considered a radio control. // Returns true if controls is considered a radio control.
bool isValidRadio() const; bool isValidRadio() const;

View File

@ -289,8 +289,7 @@ __int64 oDataContainer::getInt64(const void *data, const char *Name) const
} }
} }
bool oDataContainer::setString(oBase *ob, const char *name, const wstring &v) bool oDataContainer::setString(oBase *ob, const char *name, const wstring &v) {
{
oDataInfo *odi=findVariable(name); oDataInfo *odi=findVariable(name);
if (!odi) if (!odi)

View File

@ -441,6 +441,7 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
oClassData->addVariableInt("Unordered", oDataContainer::oIS8U, "Oordnade parallella"); oClassData->addVariableInt("Unordered", oDataContainer::oIS8U, "Oordnade parallella");
oClassData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat"); oClassData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat");
oClassData->addVariableInt("Locked", oDataContainer::oIS8U, "Låst gaffling"); oClassData->addVariableInt("Locked", oDataContainer::oIS8U, "Låst gaffling");
oClassData->addVariableString("Qualification", "Kvalschema");
oTeamData = new oDataContainer(oTeam::dataSize); oTeamData = new oDataContainer(oTeam::dataSize);
oTeamData->addVariableCurrency("Fee", "Anm. avgift"); oTeamData->addVariableCurrency("Fee", "Anm. avgift");
@ -1210,6 +1211,7 @@ bool oEvent::open(const xmlparser &xml) {
} }
toc("class"); toc("class");
reinitializeClasses();
//Get clubs //Get clubs
xo=xml.getObject("ClubList"); xo=xml.getObject("ClubList");
@ -1839,7 +1841,7 @@ void oEvent::updateFreeId(oBase *obj)
qFreeRunnerId=max(obj->Id, qFreeRunnerId); qFreeRunnerId=max(obj->Id, qFreeRunnerId);
} }
else if (typeid(*obj)==typeid(oClass)){ else if (typeid(*obj)==typeid(oClass)){
qFreeClassId=max(obj->Id, qFreeClassId); qFreeClassId=max(obj->Id % MaxClassId, qFreeClassId);
} }
else if (typeid(*obj)==typeid(oCourse)){ else if (typeid(*obj)==typeid(oCourse)){
qFreeCourseId=max(obj->Id, qFreeCourseId); qFreeCourseId=max(obj->Id, qFreeCourseId);
@ -1881,7 +1883,7 @@ void oEvent::updateFreeId()
oClassList::iterator it; oClassList::iterator it;
qFreeClassId=0; qFreeClassId=0;
for (it=Classes.begin(); it != Classes.end(); ++it) for (it=Classes.begin(); it != Classes.end(); ++it)
qFreeClassId=max(qFreeClassId, it->Id); qFreeClassId=max(qFreeClassId, it->Id % MaxClassId);
} }
{ {
oCourseList::iterator it; oCourseList::iterator it;
@ -2553,17 +2555,27 @@ void oEvent::removeCourse(int Id)
void oEvent::removeClass(int Id) void oEvent::removeClass(int Id)
{ {
oClassList::iterator it; oClassList::iterator it;
vector<int> subRemove;
for (it=Classes.begin(); it != Classes.end(); ++it){ for (it = Classes.begin(); it != Classes.end(); ++it){
if (it->Id==Id){ if (it->Id==Id){
if (it->getQualificationFinal()) {
for (int n = 0; n < it->getNumQualificationFinalClasses(); n++) {
const oClass *pc = it->getVirtualClass(n);
if (pc && pc != &*it)
subRemove.push_back(pc->getId());
}
}
if (HasDBConnection) if (HasDBConnection)
msRemove(&*it); msRemove(&*it);
Classes.erase(it); Classes.erase(it);
dataRevision++; dataRevision++;
updateTabs(); updateTabs();
return; break;
} }
} }
for (int id : subRemove) {
removeClass(id);
}
} }
void oEvent::removeControl(int Id) void oEvent::removeControl(int Id)
@ -2642,17 +2654,33 @@ bool oEvent::isCourseUsed(int Id) const
bool oEvent::isClassUsed(int Id) const bool oEvent::isClassUsed(int Id) const
{ {
pClass cl = getClass(Id);
if (cl && cl->parentClass) {
if (isClassUsed(cl->parentClass->Id))
return true;
}
set<int> idToCheck;
idToCheck.insert(Id);
if (cl) {
for (int i = 0; i < cl->getNumQualificationFinalClasses(); i++)
idToCheck.insert(cl->getVirtualClass(i)->getId());
}
//Search runners //Search runners
oRunnerList::const_iterator it; oRunnerList::const_iterator it;
for (it=Runners.begin(); it != Runners.end(); ++it){ for (it=Runners.begin(); it != Runners.end(); ++it){
if (it->getClassId()==Id) if (it->isRemoved())
continue;
if (idToCheck.count(it->getClassId(false)))
return true; return true;
} }
//Search teams //Search teams
oTeamList::const_iterator tit; oTeamList::const_iterator tit;
for (tit=Teams.begin(); tit != Teams.end(); ++tit){ for (tit=Teams.begin(); tit != Teams.end(); ++tit){
if (tit->getClassId()==Id) if (it->isRemoved())
continue;
if (idToCheck.count(tit->getClassId(false)))
return true; return true;
} }
return false; return false;
@ -2713,7 +2741,7 @@ bool oEvent::classHasResults(int Id) const
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if ( (Id == 0 || it->getClassId() == Id) && (it->getCard() || it->FinishTime)) if ( (Id == 0 || it->getClassId(true) == Id) && (it->getCard() || it->FinishTime))
return true; return true;
} }
@ -2722,10 +2750,16 @@ bool oEvent::classHasResults(int Id) const
bool oEvent::classHasTeams(int Id) const bool oEvent::classHasTeams(int Id) const
{ {
oTeamList::const_iterator it; pClass pc = oe->getClass(Id);
if (pc == 0)
return false;
if (pc->getQualificationFinal() != 0)
return false;
oTeamList::const_iterator it;
for (it=Teams.begin(); it != Teams.end(); ++it) for (it=Teams.begin(); it != Teams.end(); ++it)
if (it->getClassId()==Id) if (!it->isRemoved() && it->getClassId(false)==Id)
return true; return true;
return false; return false;
@ -2768,8 +2802,8 @@ void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb)
if (it->skip() || !it->isVacant()) if (it->skip() || !it->isVacant())
continue; continue;
if (it->getClassId() != Id) { if (it->getClassId(true) != Id) {
Id=it->getClassId(); Id=it->getClassId(true);
y+=lh/2; y+=lh/2;
if (nRunner>=RunnersPerCol) { if (nRunner>=RunnersPerCol) {
@ -2779,7 +2813,7 @@ void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb)
} }
gdi.addStringUT(y, x+dx[0], 1, it->getClass()); gdi.addStringUT(y, x+dx[0], 1, it->getClass(true));
y+=lh+lh/3; y+=lh+lh/3;
} }
@ -2865,7 +2899,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
} }
if (unknown) { if (unknown) {
if (id != it->getClassId()) { if (id != it->getClassId(false)) {
if (nr>0) { if (nr>0) {
gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); gdi.addString("", y, x, 0, "Antal: X#"+itos(nr));
y+=lh; y+=lh;
@ -2876,11 +2910,11 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
y += lh; y += lh;
} }
y += lh; y += lh;
id = it->getClassId(); id = it->getClassId(false);
gdi.addStringUT(y, x, 1, it->getClass()); gdi.addStringUT(y, x, 1, it->getClass(false));
y += lh; y += lh;
} }
gdi.addStringUT(y, x, 0, it->getClass()); gdi.addStringUT(y, x, 0, it->getClass(false));
nr++; nr++;
gdi.addStringUT(y, x+100, 0, it->getName(), 0, cb).setExtra(it->getId()).id = "T"; gdi.addStringUT(y, x+100, 0, it->getName(), 0, cb).setExtra(it->getId()).id = "T";
y+=lh; y+=lh;
@ -2920,15 +2954,15 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
if (it->tStatus == StatusUnknown) { if (it->tStatus == StatusUnknown) {
if (id != it->getClassId()) { if (id != it->getClassId(true)) {
if (nr>0) { if (nr>0) {
gdi.addString("", y, x, 0, "Antal: X#"+itos(nr)); gdi.addString("", y, x, 0, "Antal: X#"+itos(nr));
y+=lh; y+=lh;
nr=0; nr=0;
} }
y += lh; y += lh;
id = it->getClassId(); id = it->getClassId(true);
gdi.addStringUT(y, x, 1, it->getClass()); gdi.addStringUT(y, x, 1, it->getClass(true));
y += lh; y += lh;
} }
@ -2982,7 +3016,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
gdi.addToolTip("", L"#" + punches + L". " + otherRunners, 0, &rc); gdi.addToolTip("", L"#" + punches + L". " + otherRunners, 0, &rc);
} }
} }
gdi.addStringUT(y, x+dx[3], 0, it->getClass()); gdi.addStringUT(y, x+dx[3], 0, it->getClass(true));
y+=lh; y+=lh;
} }
} }
@ -3126,7 +3160,7 @@ void oEvent::generateMinuteStartlist(gdioutput &gdi) {
} }
gdi.addStringUT(src_y, x+dx[2], fontMedium, r[0]->getClub(), dx[3]-dx[2]-4); gdi.addStringUT(src_y, x+dx[2], fontMedium, r[0]->getClub(), dx[3]-dx[2]-4);
gdi.addStringUT(src_y, x+dx[3], fontMedium, r[0]->getClass()); gdi.addStringUT(src_y, x+dx[3], fontMedium, r[0]->getClass(true));
y+=lh; y+=lh;
} }
} }
@ -3689,7 +3723,7 @@ void oEvent::reEvaluateCourse(int CourseId, bool DoSync)
set<int> classes; set<int> classes;
for(it=Runners.begin(); it != Runners.end(); ++it){ for(it=Runners.begin(); it != Runners.end(); ++it){
if (it->getCourse(false) && it->getCourse(false)->getId()==CourseId){ if (it->getCourse(false) && it->getCourse(false)->getId()==CourseId){
classes.insert(it->getClassId()); classes.insert(it->getClassId(true));
} }
} }
@ -3710,7 +3744,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
} }
for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) {
if (!cls.empty() && cls.count(tit->getClassId()) == 0) if (!cls.empty() && cls.count(tit->getClassId(false)) == 0)
continue; continue;
tit->resetTmpStore(); tit->resetTmpStore();
@ -3727,7 +3761,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
oRunnerList::iterator it; oRunnerList::iterator it;
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!cls.empty() && cls.count(it->getClassId()) == 0) if (!cls.empty() && cls.count(it->getClassId(true)) == 0)
continue; continue;
if (!it->tInTeam) { if (!it->tInTeam) {
@ -3742,7 +3776,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
while (needupdate) { while (needupdate) {
needupdate = false; needupdate = false;
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!cls.empty() && cls.count(it->getClassId()) == 0) if (!cls.empty() && cls.count(it->getClassId(true)) == 0)
continue; continue;
if (!it->isRemoved()) { if (!it->isRemoved()) {
@ -3760,7 +3794,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
// Update team start times etc. // Update team start times etc.
for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) { for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) {
if (!tit->isRemoved()) { if (!tit->isRemoved()) {
if (!cls.empty() && cls.count(tit->getClassId()) == 0) if (!cls.empty() && cls.count(tit->getClassId(true)) == 0)
continue; continue;
tit->apply(false, 0, true); tit->apply(false, 0, true);
@ -3771,7 +3805,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
} }
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!it->isRemoved()) { if (!it->isRemoved()) {
if (!cls.empty() && cls.count(it->getClassId()) == 0) if (!cls.empty() && cls.count(it->getClassId(true)) == 0)
continue; continue;
if (!it->tInTeam) if (!it->tInTeam)
@ -3805,7 +3839,7 @@ void oEvent::reEvaluateChanged()
it->clearSplitAnalysis(); it->clearSplitAnalysis();
it->resetLeaderTime(); it->resetLeaderTime();
it->reinitialize(); it->reinitialize();
resetClasses[it->getId()] = it->hasClassGlobalDependance(); resetClasses[it->getId()] = it->hasClassGlobalDependence();
} }
} }
@ -3833,11 +3867,11 @@ void oEvent::reEvaluateChanged()
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
int clz = it->getClassId(true);
if (resetClasses.count(it->getClassId())) if (resetClasses.count(clz))
it->storeTimes(); it->storeTimes();
if (!it->wasSQLChanged() && !resetClasses[it->getClassId()]) if (!it->wasSQLChanged() && !resetClasses[clz])
continue; continue;
pTeam t = it->tInTeam; pTeam t = it->tInTeam;
@ -3926,7 +3960,7 @@ void oEvent::reCalculateLeaderTimes(int classId)
while (needupdate) { while (needupdate) {
needupdate = false; needupdate = false;
for (oRunnerList::iterator it=Runners.begin(); it != Runners.end(); ++it) { for (oRunnerList::iterator it=Runners.begin(); it != Runners.end(); ++it) {
if (!it->isRemoved() && (classId==0 || classId==it->getClassId())) { if (!it->isRemoved() && (classId==0 || classId==it->getClassId(true))) {
if (it->tLeg == leg) if (it->tLeg == leg)
it->storeTimes(); it->storeTimes();
else if (it->tLeg>leg) else if (it->tLeg>leg)
@ -4097,7 +4131,7 @@ int oEvent::getFirstStart(int classId) const {
int minTime=3600*24; int minTime=3600*24;
while(it!=Runners.end()){ while(it!=Runners.end()){
if (!it->isRemoved() && classId==0 || it->getClassId()==classId) if (!it->isRemoved() && classId==0 || it->getClassId(true)==classId)
if (it->tStartTime < minTime && it->tStatus!=StatusNotCompetiting && it->tStartTime>0) if (it->tStartTime < minTime && it->tStatus!=StatusNotCompetiting && it->tStartTime>0)
minTime = it->tStartTime; minTime = it->tStartTime;
++it; ++it;
@ -4168,17 +4202,26 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
sortRunners(ClassStartTimeClub); sortRunners(ClassStartTimeClub);
oRunnerList::iterator it; oRunnerList::iterator it;
pClass cls = getClass(ClassId);
if (cls == 0)
throw meosException("Class not found");
if (cls->getParentClass())
cls->getParentClass()->setBibMode(BibFree);
if (!firstNumber.empty()) { if (!firstNumber.empty()) {
cls->setBibMode(BibFree);
wchar_t pattern[32]; wchar_t pattern[32];
int num = oClass::extractBibPattern(firstNumber, pattern); int num = oClass::extractBibPattern(firstNumber, pattern);
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if ( (ClassId==0 || it->getClassId()==ClassId) && it->legToRun()==leg) { if ( (ClassId==0 || it->getClassId(true)==ClassId) && (it->legToRun()==leg || leg == -1)) {
wchar_t bib[32]; wchar_t bib[32];
swprintf_s(bib, pattern, num); swprintf_s(bib, pattern, num);
it->setBib(bib, num, true, false); pClass pc = it->getClassRef(true);
it->setBib(bib, num, pc ? !pc->lockedForking() : true, false);
num++; num++;
it->synchronize(); it->synchronize();
} }
@ -4188,7 +4231,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
for(it=Runners.begin(); it != Runners.end(); ++it){ for(it=Runners.begin(); it != Runners.end(); ++it){
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (ClassId==0 || it->getClassId()==ClassId) { if (ClassId==0 || it->getClassId(true)==ClassId) {
it->getDI().setString("Bib", L"");//Update only bib it->getDI().setString("Bib", L"");//Update only bib
it->synchronize(); it->synchronize();
} }
@ -4206,8 +4249,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
for (it=Teams.begin(); it != Teams.end(); ++it) { for (it=Teams.begin(); it != Teams.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (ClassId==0 || it->getClassId()==ClassId) { if (ClassId==0 || it->getClassId(false)==ClassId) {
if (it->getClassRef() && it->getClassRef()->getBibMode() != BibFree) { if (it->getClassRef(false) && it->getClassRef(false)->getBibMode() != BibFree) {
for (size_t i = 0; i < it->Runners.size(); i++) { for (size_t i = 0; i < it->Runners.size(); i++) {
if (it->Runners[i]) { if (it->Runners[i]) {
//runnerStartNo[it->Runners[i]->getId()] = it->Runners[i]->getStartNo(); //runnerStartNo[it->Runners[i]->getId()] = it->Runners[i]->getStartNo();
@ -4232,7 +4275,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (ClassId == 0 || it->getClassId() == ClassId) { if (ClassId == 0 || it->getClassId(false) == ClassId) {
wchar_t bib[32]; wchar_t bib[32];
swprintf_s(bib, pattern, num); swprintf_s(bib, pattern, num);
bool lockedStartNo = it->Class && it->Class->lockedForking(); bool lockedStartNo = it->Class && it->Class->lockedForking();
@ -4250,7 +4293,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
} }
else { else {
for(it=Teams.begin(); it != Teams.end(); ++it){ for(it=Teams.begin(); it != Teams.end(); ++it){
if (ClassId==0 || it->getClassId()==ClassId) { if (ClassId==0 || it->getClassId(false)==ClassId) {
it->getDI().setString("Bib", L""); //Update only bib it->getDI().setString("Bib", L""); //Update only bib
it->apply(true, 0, false); it->apply(true, 0, false);
} }
@ -4265,7 +4308,7 @@ void oEvent::addAutoBib() {
int clsId = -1; int clsId = -1;
int bibGap = oe->getBibClassGap(); int bibGap = oe->getBibClassGap();
int interval = 1; int interval = 1;
set<int> isTeamCls;
wchar_t pattern[32] = {0}; wchar_t pattern[32] = {0};
wchar_t storedPattern[32]; wchar_t storedPattern[32];
wcscpy_s(storedPattern, L"%d"); wcscpy_s(storedPattern, L"%d");
@ -4283,24 +4326,26 @@ void oEvent::addAutoBib() {
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) { for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
if (tit->skip()) if (tit->skip())
continue; continue;
pClass cls = tit->getClassRef(); pClass cls = tit->getClassRef(false);
if (cls == 0) if (cls == 0)
continue; continue;
teamStartNo[tit->getId()] = tit->getStartNo(); teamStartNo[tit->getId()] = tit->getStartNo();
wstring bibInfo = cls->getDCI().getString("Bib"); wstring bibInfo = cls->getDCI().getString("Bib");
bool teamAssign = !bibInfo.empty(); bool teamAssign = !bibInfo.empty() && cls->getNumStages() > 1;
bool freeMode = cls->getBibMode()==BibFree; bool freeMode = cls->getBibMode()==BibFree;
if (!teamAssign && freeMode) if (!teamAssign && freeMode)
continue; // Manul or none continue; // Manul or none
isTeamCls.insert(cls->getId());
bool addBib = bibInfo != L"-"; bool addBib = bibInfo != L"-";
if (addBib && teamAssign) if (addBib && teamAssign)
tit->setStartNo(0, false); tit->setStartNo(0, false);
if (tit->getClassRef() && tit->getClassRef()->getBibMode() != BibFree) { if (tit->getClassRef(false) && tit->getClassRef(false)->getBibMode() != BibFree) {
for (size_t i = 0; i < tit->Runners.size(); i++) { for (size_t i = 0; i < tit->Runners.size(); i++) {
if (tit->Runners[i]) { if (tit->Runners[i]) {
if (addBib && teamAssign) if (addBib && teamAssign)
@ -4318,15 +4363,15 @@ void oEvent::addAutoBib() {
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) { for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
if (tit->skip()) if (tit->skip())
continue; continue;
int clsId = tit->getClassId(); int clsId = tit->getClassId(false);
cls2TeamList[clsId].push_back(&*tit); cls2TeamList[clsId].push_back(&*tit);
} }
map<int, vector<pRunner> > cls2RunnerList; map<int, vector<pRunner> > cls2RunnerList;
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->skip() || !it->getClassId()) if (it->isRemoved() || !it->getClassId(false))
continue; continue;
int clsId = it->getClassId(); int clsId = it->getClassId(true);
cls2RunnerList[clsId].push_back(&*it); cls2RunnerList[clsId].push_back(&*it);
} }
@ -4362,7 +4407,7 @@ void oEvent::addAutoBib() {
number = oClass::extractBibPattern(bibInfo, pattern); number = oClass::extractBibPattern(bibInfo, pattern);
} }
if (cls->getNumStages() > 1) { if (isTeamCls.count(clsId)) {
vector<pTeam> &tl = cls2TeamList[clsId]; vector<pTeam> &tl = cls2TeamList[clsId];
if (cls->getBibMode() == BibAdd) { if (cls->getBibMode() == BibAdd) {
@ -4405,18 +4450,23 @@ void oEvent::addAutoBib() {
tl[k]->apply(true, 0, false); tl[k]->apply(true, 0, false);
} }
} }
continue; continue;
} }
else { else {
interval = 1; interval = 1;
vector<pRunner> &rl = cls2RunnerList[clsId]; vector<pRunner> &rl = cls2RunnerList[clsId];
bool locked = cls->lockedForking();
if (pattern[0] && cls->getParentClass()) {
// Switch to free mode if bib set for subclass
cls->getParentClass()->setBibMode(BibFree);
cls->setBibMode(BibFree);
}
for (size_t k = 0; k < rl.size(); k++) { for (size_t k = 0; k < rl.size(); k++) {
if (pattern[0]) { if (pattern[0]) {
wchar_t buff[32]; wchar_t buff[32];
swprintf_s(buff, pattern, number); swprintf_s(buff, pattern, number);
rl[k]->setBib(buff, number, true, false); rl[k]->setBib(buff, number, !locked, false);
number += interval; number += interval;
} }
else { else {
@ -4436,7 +4486,7 @@ void oEvent::checkOrderIdMultipleCourses(int ClassId)
//Find first free order //Find first free order
for(it=Runners.begin(); it != Runners.end(); ++it){ for(it=Runners.begin(); it != Runners.end(); ++it){
if (ClassId==0 || it->getClassId()==ClassId){ if (ClassId==0 || it->getClassId(false)==ClassId){
it->synchronize();//Ensure we are up-to-date it->synchronize();//Ensure we are up-to-date
order=max(order, it->StartNo); order=max(order, it->StartNo);
} }
@ -4444,7 +4494,7 @@ void oEvent::checkOrderIdMultipleCourses(int ClassId)
//Assign orders //Assign orders
for(it=Runners.begin(); it != Runners.end(); ++it){ for(it=Runners.begin(); it != Runners.end(); ++it){
if (ClassId==0 || it->getClassId()==ClassId) if (ClassId==0 || it->getClassId(false)==ClassId)
if (it->StartNo==0){ if (it->StartNo==0){
it->StartNo=++order; it->StartNo=++order;
it->updateChanged(); //Mark as changed. it->updateChanged(); //Mark as changed.
@ -4610,7 +4660,7 @@ void oEvent::loadProperties(const wchar_t *file) {
bool compareClubClassTeamName(const oRunner &a, const oRunner &b) bool compareClubClassTeamName(const oRunner &a, const oRunner &b)
{ {
if (a.Club==b.Club) { if (a.Club==b.Club) {
if (a.Class==b.Class) { if (a.getClassId(true) == b.getClassId(true)) {
if (a.tInTeam==b.tInTeam) if (a.tInTeam==b.tInTeam)
return a.tRealName<b.tRealName; return a.tRealName<b.tRealName;
else if (a.tInTeam) { else if (a.tInTeam) {
@ -4621,11 +4671,10 @@ bool compareClubClassTeamName(const oRunner &a, const oRunner &b)
return b.tInTeam!=0; return b.tInTeam!=0;
} }
else else
return a.getClass()<b.getClass(); return a.getClass(true)<b.getClass(true);
} }
else else
return a.getClub()<b.getClub(); return a.getClub()<b.getClub();
} }
void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb) void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
@ -4656,7 +4705,7 @@ void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
wstring r; wstring r;
if (it->Class) if (it->Class)
r+=it->getClass()+L", "; r+=it->getClass(false)+L", ";
if (it->tInTeam) { if (it->tInTeam) {
r+=itow(it->tInTeam->getStartNo()); + L" " + it->tInTeam->getName(); r+=itow(it->tInTeam->getStartNo()); + L" " + it->tInTeam->getName();
@ -5345,7 +5394,7 @@ void oEvent::applyEventFees(bool updateClassFromEvent,
if (it->skip()) if (it->skip())
continue; continue;
if (allClass || classFilter.count(it->getClassId())) { if (allClass || classFilter.count(it->getClassId(true))) {
it->addClassDefaultFee(true); it->addClassDefaultFee(true);
it->synchronize(true); it->synchronize(true);
} }
@ -5451,7 +5500,7 @@ void oEvent::removeVacanies(int classId) {
if (it->skip() || !it->isVacant()) if (it->skip() || !it->isVacant())
continue; continue;
if (classId!=0 && it->getClassId()!=classId) if (classId!=0 && it->getClassId(false)!=classId)
continue; continue;
if (!isRunnerUsed(it->Id)) if (!isRunnerUsed(it->Id))
@ -5472,7 +5521,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (onlyThisClass > 0 && it->getClassId() != onlyThisClass) if (onlyThisClass > 0 && it->getClassId(false) != onlyThisClass)
continue; continue;
if (it->sName.empty()) { if (it->sName.empty()) {
if (!warnNoName) { if (!warnNoName) {
@ -5502,7 +5551,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (!warnNoTeam) { if (!warnNoTeam) {
gdi.alert(L"Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- " gdi.alert(L"Deltagaren 'X' deltar i stafettklassen 'Y' men saknar lag. Klassens start- "
L"och resultatlistor kan därmed bli felaktiga.#" + it->getName() + L"och resultatlistor kan därmed bli felaktiga.#" + it->getName() +
L"#" + it->getClass()); L"#" + it->getClass(false));
warnNoTeam = true; warnNoTeam = true;
} }
} }
@ -5510,7 +5559,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (!warnNoPatrol) { if (!warnNoPatrol) {
gdi.alert(L"Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- " gdi.alert(L"Deltagaren 'X' deltar i patrullklassen 'Y' men saknar patrull. Klassens start- "
L"och resultatlistor kan därmed bli felaktiga.#" + it->getName() + L"och resultatlistor kan därmed bli felaktiga.#" + it->getName() +
+ L"#" + it->getClass()); + L"#" + it->getClass(false));
warnNoPatrol = true; warnNoPatrol = true;
} }
} }
@ -5524,7 +5573,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (onlyThisClass > 0 && it->getClassId() != onlyThisClass) if (onlyThisClass > 0 && it->getClassId(false) != onlyThisClass)
continue; continue;
if (it->sName.empty()) { if (it->sName.empty()) {
@ -5549,7 +5598,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (type == oClassIndividual) { if (type == oClassIndividual) {
if (!warnIndividualTeam) { if (!warnIndividualTeam) {
gdi.alert(L"Laget 'X' deltar i individuella klassen 'Y'. Klassens start- och resultatlistor " gdi.alert(L"Laget 'X' deltar i individuella klassen 'Y'. Klassens start- och resultatlistor "
L"kan därmed bli felaktiga.#" + it->getName() + L"#" + it->getClass()); L"kan därmed bli felaktiga.#" + it->getName() + L"#" + it->getClass(true));
warnIndividualTeam = true; warnIndividualTeam = true;
} }
} }
@ -5571,6 +5620,9 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (onlyThisClass > 0 && it->getId() != onlyThisClass) if (onlyThisClass > 0 && it->getId() != onlyThisClass)
continue; continue;
if (it->getQualificationFinal())
continue;
if (it->hasMultiCourse()) { if (it->hasMultiCourse()) {
for (unsigned k=0;k<it->getNumStages(); k++) { for (unsigned k=0;k<it->getNumStages(); k++) {
StartTypes st = it->getStartType(k); StartTypes st = it->getStartType(k);
@ -5786,7 +5838,7 @@ wstring oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes,
r.StartNo = it->StartNo; r.StartNo = it->StartNo;
r.CardNo = it->CardNo; r.CardNo = it->CardNo;
r.Club = ce.getClub(it->getClubId()); r.Club = ce.getClub(it->getClubId());
r.Class = ce.getClass(it->getClassId()); r.Class = ce.getClass(it->getClassId(false));
if (cloneCourses) if (cloneCourses)
r.Course = ce.getCourse(it->getCourseId()); r.Course = ce.getCourse(it->getCourseId());
@ -5819,7 +5871,7 @@ wstring oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes,
t.sName = it->sName; t.sName = it->sName;
t.StartNo = it->StartNo; t.StartNo = it->StartNo;
t.Club = ce.getClub(it->getClubId()); t.Club = ce.getClub(it->getClubId());
t.Class = ce.getClass(it->getClassId()); t.Class = ce.getClass(it->getClassId(false));
if (cloneTimes) if (cloneTimes)
t.startTime = it->startTime; t.startTime = it->startTime;
@ -5879,7 +5931,7 @@ bool checkTargetClass(pRunner target, pRunner source,
if (changeClassMethod == oEvent::TransferAnyway) if (changeClassMethod == oEvent::TransferAnyway)
return true; return true;
if (!compareClassName(target->getClass(), source->getClass())) { if (!compareClassName(target->getClass(false), source->getClass(false))) {
// Store all vacant positions in the right class // Store all vacant positions in the right class
int targetClass = -1; int targetClass = -1;
@ -5894,10 +5946,10 @@ bool checkTargetClass(pRunner target, pRunner source,
for (oClassList::const_iterator cit = Classes.begin(); cit != Classes.end(); ++cit) { for (oClassList::const_iterator cit = Classes.begin(); cit != Classes.end(); ++cit) {
if (cit->isRemoved()) if (cit->isRemoved())
continue; continue;
if (compareClassName(cit->getName(), source->getClass())) { if (compareClassName(cit->getName(), source->getClass(false))) {
targetClass = cit->getId(); targetClass = cit->getId();
if (targetClass == source->getClassId() || cit->getName() == source->getClass()) if (targetClass == source->getClassId(false) || cit->getName() == source->getClass(false))
break; // Assume exact match break; // Assume exact match
} }
} }
@ -5907,7 +5959,7 @@ bool checkTargetClass(pRunner target, pRunner source,
for (size_t j = 0; j < targetVacant.size(); j++) { for (size_t j = 0; j < targetVacant.size(); j++) {
if (!targetVacant[j]) if (!targetVacant[j])
continue; continue;
if (targetVacant[j]->getClassId() == targetClass) if (targetVacant[j]->getClassId(false) == targetClass)
vacantIx.insert(j); vacantIx.insert(j);
} }
int posToUse = -1; int posToUse = -1;
@ -5935,12 +5987,12 @@ bool checkTargetClass(pRunner target, pRunner source,
int oldStart = target->getStartTime(); int oldStart = target->getStartTime();
wstring oldBib = target->getBib(); wstring oldBib = target->getBib();
int oldSN = target->getStartNo(); int oldSN = target->getStartNo();
int oldClass = target->getClassId(); int oldClass = target->getClassId(false);
pRunner tgt = targetVacant[posToUse]; pRunner tgt = targetVacant[posToUse];
target->cloneStartTime(tgt); target->cloneStartTime(tgt);
target->setBib(tgt->getBib(), 0, false, false); target->setBib(tgt->getBib(), 0, false, false);
target->setStartNo(tgt->getStartNo(), false); target->setStartNo(tgt->getStartNo(), false);
target->setClassId(tgt->getClassId(), false); target->setClassId(tgt->getClassId(false), false);
tgt->setStartTime(oldStart, true, false); tgt->setStartTime(oldStart, true, false);
tgt->setBib(oldBib, 0, false, false); tgt->setBib(oldBib, 0, false, false);
@ -6122,7 +6174,7 @@ void oEvent::transferResult(oEvent &ce,
for (size_t j = 0; j < cnd.size(); j++) { for (size_t j = 0; j < cnd.size(); j++) {
pRunner src = remainingRunners[cnd[j]]; pRunner src = remainingRunners[cnd[j]];
int p = 0; int p = 0;
if (src->getClass() == it->getClass()) if (src->getClass(false) == it->getClass(false))
p += 1; p += 1;
if (src->getBirthYear() == it->getBirthYear()) if (src->getBirthYear() == it->getBirthYear())
p += 2; p += 2;
@ -6165,7 +6217,7 @@ void oEvent::transferResult(oEvent &ce,
} }
pRunner targetVacant = ce.getRunner(src->getId(), 0); pRunner targetVacant = ce.getRunner(src->getId(), 0);
if (targetVacant && targetVacant->isVacant() && compareClassName(targetVacant->getClass(), src->getClass()) ) { if (targetVacant && targetVacant->isVacant() && compareClassName(targetVacant->getClass(false), src->getClass(false)) ) {
targetVacant->setName(src->getName(), false); targetVacant->setName(src->getName(), false);
targetVacant->setClub(src->getClub()); targetVacant->setClub(src->getClub());
targetVacant->setCardNo(src->getCardNo(), false); targetVacant->setCardNo(src->getCardNo(), false);
@ -6173,13 +6225,13 @@ void oEvent::transferResult(oEvent &ce,
assignedVacant.push_back(targetVacant); assignedVacant.push_back(targetVacant);
} }
else { else {
pClass dstClass = ce.getClass(src->getClassId()); pClass dstClass = ce.getClass(src->getClassId(false));
if (dstClass && compareClassName(dstClass->getName(), src->getClass())) { if (dstClass && compareClassName(dstClass->getName(), src->getClass(false))) {
if ( (!src->hasFlag(oAbstractRunner::FlagTransferSpecified) && allowNewEntries.count(src->getClassId())) if ( (!src->hasFlag(oAbstractRunner::FlagTransferSpecified) && allowNewEntries.count(src->getClassId(false)))
|| src->hasFlag(oAbstractRunner::FlagTransferNew)) { || src->hasFlag(oAbstractRunner::FlagTransferNew)) {
if (src->getClubId() > 0) if (src->getClubId() > 0)
ce.getClubCreate(src->getClubId(), src->getClub()); ce.getClubCreate(src->getClubId(), src->getClub());
pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(false),
src->getCardNo(), src->getBirthYear(), true); src->getCardNo(), src->getBirthYear(), true);
dst->cloneData(src); dst->cloneData(src);
dst->setInputData(*src); dst->setInputData(*src);
@ -6188,7 +6240,7 @@ void oEvent::transferResult(oEvent &ce,
else if (transferAllNoCompete) { else if (transferAllNoCompete) {
if (src->getClubId() > 0) if (src->getClubId() > 0)
ce.getClubCreate(src->getClubId(), src->getClub()); ce.getClubCreate(src->getClubId(), src->getClub());
pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(), pRunner dst = ce.addRunner(src->getName(), src->getClubId(), src->getClassId(false),
0, src->getBirthYear(), true); 0, src->getBirthYear(), true);
dst->cloneData(src); dst->cloneData(src);
dst->setInputData(*src); dst->setInputData(*src);
@ -6313,7 +6365,7 @@ void oEvent::transferResult(oEvent &ce,
for (size_t j = 0; j < cnd.size(); j++) { for (size_t j = 0; j < cnd.size(); j++) {
pTeam src = remainingTeams[cnd[j]]; pTeam src = remainingTeams[cnd[j]];
int p = 0; int p = 0;
if (src->getClass() == it->getClass()) if (src->getClass(false) == it->getClass(false))
p += 1; p += 1;
if (p > point) { if (p > point) {
winnerIx = cnd[j]; winnerIx = cnd[j];

View File

@ -447,7 +447,7 @@ protected:
void exportIOFResults(xmlparser &xml, bool selfContained, const set<int> &classes, int leg, bool oldStylePatrol); void exportIOFResults(xmlparser &xml, bool selfContained, const set<int> &classes, int leg, bool oldStylePatrol);
void exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldStylePatrol); void exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldStylePatrol);
/** Set up transient data in cassss */ /** Set up transient data in classes */
void reinitializeClasses(); void reinitializeClasses();
/** Analyze the result status of each class*/ /** Analyze the result status of each class*/
@ -779,7 +779,7 @@ public:
short partialCount; short partialCount;
short legNumber; short legNumber;
inline int classId() const {return r->getClassId();} inline int classId() const {return r->getClassId(true);}
inline int leg() const {return legNumber;} inline int leg() const {return legNumber;}
}; };
@ -917,7 +917,6 @@ public:
bool empty() const; bool empty() const;
void generateMinuteStartlist(gdioutput &gdi); void generateMinuteStartlist(gdioutput &gdi);
void generateMinuteStartlist(const string &file);
bool classHasTeams(int Id) const; bool classHasTeams(int Id) const;
bool classHasResults(int Id) const; bool classHasResults(int Id) const;
@ -982,12 +981,14 @@ public:
bool saveRunnerDatabase(const wchar_t *file, bool onlyLocal); bool saveRunnerDatabase(const wchar_t *file, bool onlyLocal);
enum ResultType {RTClassResult, RTTotalResult, RTCourseResult, RTClassCourseResult}; enum ResultType {RTClassResult, RTTotalResult, RTCourseResult, RTClassCourseResult};
void calculateResults(ResultType result); void calculateResults(ResultType result, bool includePreliminary = false);
void calculateRogainingResults(); void calculateRogainingResults();
void calculateResults(list<oSpeakerObject> &rl); void calculateResults(list<oSpeakerObject> &rl);
void calculateTeamResults(bool totalMultiday); void calculateTeamResults(bool totalMultiday);
bool calculateTeamResults(int leg, bool totalMultiday); bool calculateTeamResults(int leg, bool totalMultiday);
// Set results for specified classes to tempResult
void calculateTeamResultAtControl(const set<int> &classId, int leg, int controlId, bool totalResults);
bool sortRunners(SortOrder so); bool sortRunners(SortOrder so);
/** If linear leg is true, leg is interpreted as actual leg numer, otherwise w.r.t to parallel legs. */ /** If linear leg is true, leg is interpreted as actual leg numer, otherwise w.r.t to parallel legs. */

View File

@ -565,13 +565,13 @@ void oEvent::optimizeStartOrder(vector< vector<pair<int, int> > > &StartField, D
int relPos = relSt / di.baseInterval; int relPos = relSt / di.baseInterval;
if (st>0 && relSt>=0 && relPos<3000 && (relSt%di.baseInterval) == 0) { if (st>0 && relSt>=0 && relPos<3000 && (relSt%di.baseInterval) == 0) {
if (otherClasses.count(it->getClassId())==0) if (otherClasses.count(it->getClassId(false))==0)
continue; continue;
if (!di.startName.empty() && it->Class && it->Class->getStart()!=di.startName) if (!di.startName.empty() && it->Class && it->Class->getStart()!=di.startName)
continue; continue;
ClassInfo &ci = otherClasses[it->getClassId()]; ClassInfo &ci = otherClasses[it->getClassId(false)];
int k = 0; int k = 0;
while(true) { while(true) {
if (k==StartField.size()) { if (k==StartField.size()) {
@ -688,14 +688,18 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
if (spec[k].vacances>0 && pc->getClassType()==oClassRelay) if (spec[k].vacances>0 && pc->getClassType()==oClassRelay)
throw std::exception("Vakanser stöds ej i stafett."); throw std::exception("Vakanser stöds ej i stafett.");
if (spec[k].vacances>0 && spec[k].leg>0) if (spec[k].vacances>0 && (spec[k].leg>0 || pc->getParentClass()))
throw std::exception("Det går endast att sätta in vakanser på sträcka 1."); throw std::exception("Det går endast att sätta in vakanser på sträcka 1.");
if (size_t(spec[k].leg) < pc->legInfo.size()) { if (size_t(spec[k].leg) < pc->legInfo.size()) {
pc->legInfo[spec[k].leg].startMethod = STDrawn; //Automatically change start method pc->legInfo[spec[k].leg].startMethod = STDrawn; //Automatically change start method
} }
else if (spec[k].leg == -1) {
for (size_t j = 0; j < pc->legInfo.size(); j++)
pc->legInfo[j].startMethod = STDrawn; //Automatically change start method
}
clsId2Ix[spec[k].classID] = k; clsId2Ix[spec[k].classID] = k;
if (!multiDay && spec[k].leg == 0) if (!multiDay && spec[k].leg == 0 && pc->getParentClass() == 0)
clsIdClearVac.insert(spec[k].classID); clsIdClearVac.insert(spec[k].classID);
} }
@ -709,7 +713,7 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
vector<int> toRemove; vector<int> toRemove;
//Remove old vacances //Remove old vacances
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (clsIdClearVac.count(it->getClassId())) { if (clsIdClearVac.count(it->getClassId(true))) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (it->tInTeam) if (it->tInTeam)
@ -734,11 +738,12 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
} }
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!it->isRemoved() && clsId2Ix.count(it->getClassId())) { int cid = it->getClassId(true);
if (!it->isRemoved() && clsId2Ix.count(cid)) {
if (it->getStatus() == StatusNotCompetiting) if (it->getStatus() == StatusNotCompetiting)
continue; continue;
int ix = clsId2Ix[it->getClassId()]; int ix = clsId2Ix[cid];
if (it->legToRun() == spec[ix].leg ) { if (it->legToRun() == spec[ix].leg || spec[ix].leg == -1) {
runners.push_back(&*it); runners.push_back(&*it);
spec[ix].ntimes++; spec[ix].ntimes++;
} }
@ -753,12 +758,12 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
int baseInterval = 10*60; int baseInterval = 10*60;
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!it->isRemoved() && clsId2Ix.count(it->getClassId())) { if (!it->isRemoved() && clsId2Ix.count(it->getClassId(true))) {
if (it->getStatus() == StatusNotCompetiting) if (it->getStatus() == StatusNotCompetiting)
continue; continue;
int st = it->getStartTime(); int st = it->getStartTime();
int ix = clsId2Ix[it->getClassId()]; int ix = clsId2Ix[it->getClassId(false)];
if (st>0) { if (st>0) {
first[ix] = min(first[ix], st); first[ix] = min(first[ix], st);
@ -839,7 +844,6 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
nextFreeStartNo = max<int>(nextFreeStartNo, minStartNo + stimes.size()); nextFreeStartNo = max<int>(nextFreeStartNo, minStartNo + stimes.size());
} }
void getLargestClub(map<int, vector<pRunner> > &clubRunner, vector<pRunner> &largest) void getLargestClub(map<int, vector<pRunner> > &clubRunner, vector<pRunner> &largest)
{ {
size_t maxClub=0; size_t maxClub=0;
@ -1176,7 +1180,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
continue; continue;
if (it->tLeg != leg) if (it->tLeg != leg)
continue; continue;
if (it->isVacant() && notDrawn.count(it->getClassId())==1) if (it->isVacant() && notDrawn.count(it->getClassId(false))==1)
continue; continue;
pClass pc = it->Class; pClass pc = it->Class;

View File

@ -47,7 +47,7 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
for (it=Runners.begin(); it!=Runners.end(); ++it) { for (it=Runners.begin(); it!=Runners.end(); ++it) {
int st = 0; int st = 0;
if (controlIdFrom > 0) { if (controlIdFrom > 0 && controlIdFrom != oPunch::PunchStart) {
RunnerStatus stat; RunnerStatus stat;
it->getSplitTime(controlIdFrom, stat, st); it->getSplitTime(controlIdFrom, stat, st);
if (stat != StatusOK) { if (stat != StatusOK) {
@ -56,7 +56,7 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
continue; continue;
} }
} }
if (controlIdTo == 0) { if (controlIdTo == 0 || controlIdTo == oPunch::PunchFinish) {
it->tempRT = max(0, it->FinishTime - (st + it->tStartTime) ); it->tempRT = max(0, it->FinishTime - (st + it->tStartTime) );
if (it->tempRT > 0) if (it->tempRT > 0)
it->tempRT += it->getTimeAdjustment(); it->tempRT += it->getTimeAdjustment();
@ -79,8 +79,8 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
int cTime=0; int cTime=0;
for (it=Runners.begin(); it != Runners.end(); ++it){ for (it=Runners.begin(); it != Runners.end(); ++it){
if (it->getClassId()!=cClassId){ if (it->getClassId(true)!=cClassId){
cClassId=it->getClassId(); cClassId=it->getClassId(true);
cPlace=0; cPlace=0;
vPlace=0; vPlace=0;
cTime=0; cTime=0;
@ -105,7 +105,7 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
} }
} }
void oEvent::calculateResults(ResultType resultType) { void oEvent::calculateResults(ResultType resultType, bool includePreliminary) {
const bool totalResults = resultType == RTTotalResult; const bool totalResults = resultType == RTTotalResult;
const bool courseResults = resultType == RTCourseResult; const bool courseResults = resultType == RTCourseResult;
const bool classCourseResults = resultType == RTClassCourseResult; const bool classCourseResults = resultType == RTClassCourseResult;
@ -135,7 +135,7 @@ void oEvent::calculateResults(ResultType resultType) {
// Start new "class" // Start new "class"
if (classCourseResults) { if (classCourseResults) {
const pCourse crs = it->getCourse(false); const pCourse crs = it->getCourse(false);
int crsId = it->getClassId() * 997 + (crs ? crs->getId() : 0); int crsId = it->getClassId(true) * 997 + (crs ? crs->getId() : 0);
if (crsId != cClassId) { if (crsId != cClassId) {
cClassId = crsId; cClassId = crsId;
cPlace=0; cPlace=0;
@ -156,8 +156,8 @@ void oEvent::calculateResults(ResultType resultType) {
cTime=0; cTime=0;
} }
} }
else if (it->getClassId() != cClassId || it->tDuplicateLeg!=cDuplicateLeg || it->tLegEquClass != cLegEquClass) { else if (it->getClassId(true) != cClassId || it->tDuplicateLeg!=cDuplicateLeg || it->tLegEquClass != cLegEquClass) {
cClassId=it->getClassId(); cClassId=it->getClassId(true);
useResults = it->Class ? !it->Class->getNoTiming() : false; useResults = it->Class ? !it->Class->getNoTiming() : false;
cPlace=0; cPlace=0;
vPlace=0; vPlace=0;
@ -176,7 +176,7 @@ void oEvent::calculateResults(ResultType resultType) {
else if (!totalResults) { else if (!totalResults) {
int tPlace = 0; int tPlace = 0;
if (it->tStatus==StatusOK){ if (it->tStatus==StatusOK || (includePreliminary && it->tStatus == StatusUnknown && it->FinishTime > 0)){
cPlace++; cPlace++;
int rt = it->getRunningTime() + it->getNumShortening() * 3600 * 24* 8; int rt = it->getRunningTime() + it->getNumShortening() * 3600 * 24* 8;
@ -200,7 +200,8 @@ void oEvent::calculateResults(ResultType resultType) {
else { else {
int tt = it->getTotalRunningTime(it->FinishTime, true); int tt = it->getTotalRunningTime(it->FinishTime, true);
if (it->getTotalStatus() == StatusOK && tt>0) { RunnerStatus totStat = it->getTotalStatus();
if (totStat == StatusOK || (includePreliminary && totStat == StatusUnknown) && tt>0) {
cPlace++; cPlace++;
if (tt > cTime) if (tt > cTime)
@ -236,8 +237,8 @@ void oEvent::calculateRogainingResults() {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (it->getClassId()!=cClassId || it->tDuplicateLeg!=cDuplicateLeg) { if (it->getClassId(true)!=cClassId || it->tDuplicateLeg!=cDuplicateLeg) {
cClassId = it->getClassId(); cClassId = it->getClassId(true);
useResults = it->Class ? !it->Class->getNoTiming() : false; useResults = it->Class ? !it->Class->getNoTiming() : false;
cPlace = 0; cPlace = 0;
vPlace = 0; vPlace = 0;
@ -515,3 +516,81 @@ void oEvent::getGeneralResults(bool onlyEditable, vector< pair<int, pair<string,
} }
} }
} }
struct TeamResultContainer {
pTeam team;
int runningTime;
RunnerStatus status;
bool operator<(const TeamResultContainer &o) const {
pClass cls = team->getClassRef(false);
pClass ocls = o.team->getClassRef(false);
if (cls != ocls) {
int so = cls ? cls->getSortIndex() : 0;
int oso = ocls ? ocls->getSortIndex() : 0;
if (so != oso)
return so < oso;
}
if (status != o.status)
return status < o.status;
if (runningTime != o.runningTime)
return runningTime < o.runningTime;
return false;
}
};
void oEvent::calculateTeamResultAtControl(const set<int> &classId, int leg, int courseControlId, bool totalResults) {
vector<TeamResultContainer> objs;
objs.reserve(Teams.size());
oSpeakerObject temp;
for (auto &t : Teams) {
if (t.isRemoved())
continue;
if (!classId.empty() && !classId.count(t.getClassId(false)))
continue;
temp.reset();
t.fillSpeakerObject(leg, courseControlId, -1, totalResults, temp);
if (!temp.owner)
continue;
TeamResultContainer trc;
trc.runningTime = temp.runningTime.time;
trc.status = temp.status;
trc.team = &t;
objs.push_back(trc);
}
sort(objs.begin(), objs.end());
int cClass = -1;
int cPlace = -1;
int placeCounter = -1;
int cTime = 0;
for (size_t i = 0; i < objs.size(); i++) {
pTeam team = objs[i].team;
int c = team->getClassId(false);
if (c != cClass) {
cClass = c;
placeCounter = 1;
cTime = -1;
}
else {
placeCounter++;
}
if (cTime != objs[i].runningTime) {
cPlace = placeCounter;
}
team->tmpResult.startTime = team->getStartTime();
team->tmpResult.status = objs[i].status;
team->tmpResult.runningTime = objs[i].runningTime;
team->tmpResult.place = objs[i].status == StatusOK ? cPlace : 0;
team->tmpResult.points = 0; // Not supported
}
}

View File

@ -251,6 +251,7 @@ bool oEvent::synchronizeList(oListId id, bool preSyncEvent, bool postSyncEvent)
advanceInformationPunches.clear(); advanceInformationPunches.clear();
if (postSyncEvent) { if (postSyncEvent) {
reinitializeClasses();
reEvaluateChanged(); reEvaluateChanged();
resetChangeStatus(); resetChangeStatus();
return true; return true;

View File

@ -561,7 +561,7 @@ void oEvent::speakerList(gdioutput &gdi, int ClassId, int leg, int ControlId,
if (classHasTeams(ClassId)) { if (classHasTeams(ClassId)) {
oTeamList::iterator it=Teams.begin(); oTeamList::iterator it=Teams.begin();
while(it!=Teams.end()){ while(it!=Teams.end()){
if (it->getClassId()==ClassId && !it->skip()) { if (it->getClassId(true)==ClassId && !it->skip()) {
oSpeakerObject so; oSpeakerObject so;
it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so); it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so);
if (so.owner) if (so.owner)
@ -571,15 +571,23 @@ void oEvent::speakerList(gdioutput &gdi, int ClassId, int leg, int ControlId,
} }
} }
else { else {
oRunnerList::iterator it=Runners.begin(); pClass pc = getClass(ClassId);
while(it!=Runners.end()){ bool qfBaseClass = pc && pc->getQualificationFinal();
if (it->getClassId()==ClassId && !it->skip()) { bool qfFinalClass = pc && pc->getParentClass();
if (qfBaseClass || qfFinalClass)
leg = 0;
for(auto &it : Runners){
if (it.getClassId(true) == ClassId && !it.isRemoved()) {
if (qfBaseClass && it.getLegNumber() > 0)
continue;
oSpeakerObject so; oSpeakerObject so;
it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so); it.fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so);
if (so.owner) if (so.owner)
speakerList.push_back(so); speakerList.push_back(so);
} }
++it;
} }
} }
if (speakerList.empty()) { if (speakerList.empty()) {
@ -1089,9 +1097,9 @@ int oEvent::setupTimeLineEvents(int classId, int currentTime)
if (false && startTimes.size() == 1) { if (false && startTimes.size() == 1) {
oRunner &r = *started[firstNonEmpty][0]; oRunner &r = *started[firstNonEmpty][0];
oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(), 0, 0); oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(true), 0, 0);
TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime, tl)); TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime, tl));
it->second.setMessage(L"X har startat.#" + r.getClass()); it->second.setMessage(L"X har startat.#" + r.getClass(true));
} }
else { else {
for (size_t j = 0; j<started.size(); j++) { for (size_t j = 0; j<started.size(); j++) {
@ -1106,15 +1114,15 @@ int oEvent::setupTimeLineEvents(int classId, int currentTime)
prio = oTimeLine::PHigh; prio = oTimeLine::PHigh;
else if (p == 1) else if (p == 1)
prio = oTimeLine::PMedium; prio = oTimeLine::PMedium;
oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, prio, r.getClassId(), r.getId(), &r); oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, prio, r.getClassId(true), r.getId(), &r);
TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime + 1, tl)); TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime + 1, tl));
it->second.setMessage(L"har startat."); it->second.setMessage(L"har startat.");
} }
else if (!startedClass) { else if (!startedClass) {
// The entire class started // The entire class started
oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(), 0, 0); oTimeLine tl(r.tStartTime, oTimeLine::TLTStart, oTimeLine::PHigh, r.getClassId(true), 0, 0);
TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime, tl)); TimeLineIterator it = timeLineEvents.insert(pair<int, oTimeLine>(r.tStartTime, tl));
it->second.setMessage(L"X har startat.#" + r.getClass()); it->second.setMessage(L"X har startat.#" + r.getClass(true));
startedClass = true; startedClass = true;
} }
} }
@ -1203,7 +1211,7 @@ void oEvent::timeLinePrognose(TempResultMap &results, TimeRunner &tr, int prelT,
else if (p>6 + prio * 5) else if (p>6 + prio * 5)
mp = oTimeLine::PLow; mp = oTimeLine::PLow;
oTimeLine tl(tr.time, oTimeLine::TLTExpected, mp, tr.runner->getClassId(), radioId, tr.runner); oTimeLine tl(tr.time, oTimeLine::TLTExpected, mp, tr.runner->getClassId(true), radioId, tr.runner);
TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl)); TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl));
tlit->second.setMessage(msg); tlit->second.setMessage(msg);
} }
@ -1411,7 +1419,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 10) else if (place <= 10)
mp = oTimeLine::PMedium; mp = oTimeLine::PMedium;
oTimeLine tl(radio[k].time, oTimeLine::TLTRadio, mp, r.getClassId(), rc[j].first, &r); oTimeLine tl(radio[k].time, oTimeLine::TLTRadio, mp, r.getClassId(true), rc[j].first, &r);
TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl)); TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl));
tlit->second.setMessage(msg).setDetail(detail); tlit->second.setMessage(msg).setDetail(detail);
} }
@ -1509,7 +1517,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 20) else if (place <= 20)
mp = oTimeLine::PMedium; mp = oTimeLine::PMedium;
oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(), r.getId(), &r); oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(true), r.getId(), &r);
TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl)); TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(tl.getTime(), tl));
tlit->second.setMessage(msg).setDetail(detail); tlit->second.setMessage(msg).setDetail(detail);
} }
@ -1535,7 +1543,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 20) else if (place <= 20)
mp = oTimeLine::PMedium; mp = oTimeLine::PMedium;
oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(), r.getId(), &r); oTimeLine tl(r.FinishTime, oTimeLine::TLTFinish, mp, r.getClassId(true), r.getId(), &r);
TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(t, tl)); TimeLineIterator tlit = timeLineEvents.insert(pair<int, oTimeLine>(t, tl));
wstring msg; wstring msg;
if (r.getStatus() != StatusDQ) if (r.getStatus() != StatusDQ)
@ -1558,7 +1566,7 @@ void oEvent::renderTimeLineEvents(gdioutput &gdi) const
wstring msg = t>0 ? getAbsTime(t) : makeDash(L"--:--:--"); wstring msg = t>0 ? getAbsTime(t) : makeDash(L"--:--:--");
oAbstractRunner *r = it->second.getSource(*this); oAbstractRunner *r = it->second.getSource(*this);
if (r) { if (r) {
msg += L" (" + r->getClass() + L") "; msg += L" (" + r->getClass(true) + L") ";
msg += r->getName() + L", " + r->getClub(); msg += r->getName() + L", " + r->getClub();
} }
msg += L", " + lang.tl(it->second.getMessage()); msg += L", " + lang.tl(it->second.getMessage());
@ -1676,7 +1684,7 @@ void oEvent::getResultEvents(const set<int> &classFilter, const set<int> &punchF
teamLegStatusOK.reserve(Teams.size() * 5); teamLegStatusOK.reserve(Teams.size() * 5);
map<int, int> teamStatusPos; map<int, int> teamStatusPos;
for (oTeamList::const_iterator it = Teams.begin(); it != Teams.end(); ++it) { for (oTeamList::const_iterator it = Teams.begin(); it != Teams.end(); ++it) {
if (!classFilter.count(it->getClassId())) if (!classFilter.count(it->getClassId(false)))
continue; continue;
int base = teamLegStatusOK.size(); int base = teamLegStatusOK.size();
@ -1699,7 +1707,7 @@ void oEvent::getResultEvents(const set<int> &classFilter, const set<int> &punchF
for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) { for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) {
const oRunner &r = *it; const oRunner &r = *it;
if (r.isRemoved() || !classFilter.count(r.getClassId())) if (r.isRemoved() || !classFilter.count(r.getClassId(true)))
continue; continue;
if (r.prelStatusOK() || r.getStatus() != StatusUnknown) { if (r.prelStatusOK() || r.getStatus() != StatusUnknown) {
RunnerStatus stat = r.prelStatusOK() ? StatusOK : r.getStatus(); RunnerStatus stat = r.prelStatusOK() ? StatusOK : r.getStatus();
@ -1738,7 +1746,7 @@ void oEvent::getResultEvents(const set<int> &classFilter, const set<int> &punchF
continue; continue;
pRunner r = getRunner(fp.tRunnerId, 0); pRunner r = getRunner(fp.tRunnerId, 0);
if (r == 0 || !classFilter.count(r->getClassId()) || r->getCard()) if (r == 0 || !classFilter.count(r->getClassId(true)) || r->getCard())
continue; continue;
int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true); int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true);
@ -1766,7 +1774,7 @@ void oEvent::getResultEvents(const set<int> &classFilter, const set<int> &punchF
if (fp.isRemoved() || fp.tRunnerId == 0 || fp.Type == oPunch::PunchCheck || fp.Type == oPunch::PunchStart) if (fp.isRemoved() || fp.tRunnerId == 0 || fp.Type == oPunch::PunchCheck || fp.Type == oPunch::PunchStart)
continue; continue;
pRunner r = getRunner(fp.tRunnerId, 0); pRunner r = getRunner(fp.tRunnerId, 0);
if (r == 0 || !classFilter.count(r->getClassId())) if (r == 0 || !classFilter.count(r->getClassId(true)))
continue; continue;
int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true); int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true);
int ctrl = oControl::getIdIndexFromCourseControlId(courseControlId).first; int ctrl = oControl::getIdIndexFromCourseControlId(courseControlId).first;

View File

@ -1037,7 +1037,7 @@ void oFreeImport::test(const oRunnerList &li)
givenDB.insert(it->getGivenName().c_str()); givenDB.insert(it->getGivenName().c_str());
familyDB.insert(it->getFamilyName().c_str()); familyDB.insert(it->getFamilyName().c_str());
clubDB.insert(it->getClub().c_str()); clubDB.insert(it->getClub().c_str());
classDB.insert(it->getClass().c_str()); classDB.insert(it->getClass(true).c_str());
} }

View File

@ -475,14 +475,14 @@ pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFi
if (tr && tr->getStatus() == StatusUnknown && time > 0) { if (tr && tr->getStatus() == StatusUnknown && time > 0) {
tr->synchronize(); tr->synchronize();
if (type == oPunch::PunchStart) { if (type == oPunch::PunchStart) {
if (tr->getClassRef() && !tr->getClassRef()->ignoreStartPunch()) if (tr->getClassRef(false) && !tr->getClassRef(true)->ignoreStartPunch())
tr->setStartTime(time, true, false); tr->setStartTime(time, true, false);
} }
else else
tr->setFinishTime(time); tr->setFinishTime(time);
// Direct result // Direct result
if (type == oPunch::PunchFinish && tr->getClassRef() && tr->getClassRef()->hasDirectResult()) { if (type == oPunch::PunchFinish && tr->getClassRef(false) && tr->getClassRef(true)->hasDirectResult()) {
if (tr->getCourse(false) == 0 && tr->getCard() == 0) { if (tr->getCourse(false) == 0 && tr->getCard() == 0) {
tr->setStatus(StatusOK, true, false, true); tr->setStatus(StatusOK, true, false, true);
} }

View File

@ -218,9 +218,9 @@ bool oEvent::exportOECSV(const wchar_t *file, int languageTypeIndex, bool includ
row[OEclubcity] = gdibase.recodeToNarrow(it->getClub()); row[OEclubcity] = gdibase.recodeToNarrow(it->getClub());
} }
row[OEnat] = gdibase.recodeToNarrow(di.getString("Nationality")); row[OEnat] = gdibase.recodeToNarrow(di.getString("Nationality"));
row[OEclassno] = conv_is(it->getClassId()); row[OEclassno] = conv_is(it->getClassId(true));
row[OEclassshortname] = gdibase.recodeToNarrow(it->getClass()); row[OEclassshortname] = gdibase.recodeToNarrow(it->getClass(true));
row[OEclassname] = gdibase.recodeToNarrow(it->getClass()); row[OEclassname] = gdibase.recodeToNarrow(it->getClass(true));
row[OErent] = conv_is(di.getInt("CardFee")); row[OErent] = conv_is(di.getInt("CardFee"));
row[OEfee] = conv_is(di.getInt("Fee")); row[OEfee] = conv_is(di.getInt("Fee"));
@ -300,7 +300,7 @@ void oEvent::importXML_EntryData(gdioutput &gdi, const wstring &file,
vector< pair<int, int> > runnersInTeam; vector< pair<int, int> > runnersInTeam;
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) {
if (!it->isRemoved() && it->tInTeam) { if (!it->isRemoved() && it->tInTeam) {
runnersInTeam.push_back(make_pair(it->getId(), it->getClassId()) ); runnersInTeam.push_back(make_pair(it->getId(), it->getClassId(false)) );
} }
} }
@ -597,7 +597,7 @@ void oEvent::importXML_EntryData(gdioutput &gdi, const wstring &file,
int id = runnersInTeam[k].first; int id = runnersInTeam[k].first;
int classId = runnersInTeam[k].second; int classId = runnersInTeam[k].second;
pRunner r = getRunner(id, 0); pRunner r = getRunner(id, 0);
if (r && !r->tInTeam && r->getClassId() == classId) { if (r && !r->tInTeam && r->getClassId(false) == classId) {
toRemove.push_back(r->getId()); toRemove.push_back(r->getId());
} }
} }
@ -2048,7 +2048,7 @@ void oClass::exportIOFStart(xmlparser &xml) {
if (getClassType() == oClassIndividual || getClassType() == oClassIndividRelay) { if (getClassType() == oClassIndividual || getClassType() == oClassIndividRelay) {
for (oRunnerList::iterator it = oe->Runners.begin(); it!=oe->Runners.end(); ++it) { for (oRunnerList::iterator it = oe->Runners.begin(); it!=oe->Runners.end(); ++it) {
if (it->getClassId() != getId() || it->isRemoved()) if (it->getClassId(true) != getId() || it->isRemoved())
continue; continue;
xml.startTag("PersonStart"); xml.startTag("PersonStart");
@ -2096,7 +2096,7 @@ void oClass::exportIOFStart(xmlparser &xml) {
bool writeTeamName = !useEventor || getClassType() != oClassPatrol; bool writeTeamName = !useEventor || getClassType() != oClassPatrol;
for (oTeamList::iterator it = oe->Teams.begin(); it!=oe->Teams.end(); ++it) { for (oTeamList::iterator it = oe->Teams.begin(); it!=oe->Teams.end(); ++it) {
if (it->getClassId() != getId() || it->isRemoved()) if (it->getClassId(true) != getId() || it->isRemoved())
continue; continue;
xml.startTag("TeamStart"); xml.startTag("TeamStart");
@ -2218,7 +2218,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (it->Runners.size()>=2 && it->Runners[0] && it->Runners[1]) { if (it->Runners.size()>=2 && it->Runners[0] && it->Runners[1]) {
if (it->getClassId()!=Id) { if (it->getClassId(true)!=Id) {
if (ClassStarted) xml.endTag(); if (ClassStarted) xml.endTag();
if (!it->Class || it->Class->getClassType()!=oClassPatrol) { if (!it->Class || it->Class->getClassType()!=oClassPatrol) {
@ -2227,7 +2227,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
continue; continue;
} }
if ((!classes.empty() && classes.count(it->getClassId()) == 0) || leg != -1) { if ((!classes.empty() && classes.count(it->getClassId(true)) == 0) || leg != -1) {
skipClass=true; skipClass=true;
ClassStarted=false; ClassStarted=false;
continue; continue;
@ -2236,9 +2236,9 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
skipClass=false; skipClass=false;
xml.startTag("ClassResult"); xml.startTag("ClassResult");
ClassStarted=true; ClassStarted=true;
Id=it->getClassId(); Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass()); xml.write("ClassShortName", it->getClass(true));
} }
if (skipClass) if (skipClass)
@ -2315,7 +2315,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
if (it->isRemoved() || (leg != -1 && it->tLeg != leg) || it->isVacant()) if (it->isRemoved() || (leg != -1 && it->tLeg != leg) || it->isVacant())
continue; continue;
if (it->getClassId()!=Id) { if (it->getClassId(true)!=Id) {
if (ClassStarted) xml.endTag(); if (ClassStarted) xml.endTag();
if (!it->Class) { if (!it->Class) {
@ -2332,7 +2332,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
continue; continue;
} }
if ( (!classes.empty() && classes.count(it->getClassId()) == 0) ) { if ( (!classes.empty() && classes.count(it->getClassId(true)) == 0) ) {
skipClass=true; skipClass=true;
ClassStarted=false; ClassStarted=false;
continue; continue;
@ -2341,9 +2341,9 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("ClassResult"); xml.startTag("ClassResult");
ClassStarted=true; ClassStarted=true;
skipClass=false; skipClass=false;
Id=it->getClassId(); Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass()); xml.write("ClassShortName", it->getClass(true));
} }
if (skipClass) if (skipClass)
@ -2419,7 +2419,7 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
for(oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { for(oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (it->getClassId()!=Id) { if (it->getClassId(true)!=Id) {
if (ClassStarted) { if (ClassStarted) {
xml.endTag(); xml.endTag();
ClassStarted = false; ClassStarted = false;
@ -2442,7 +2442,7 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
continue; continue;
} }
if (!classes.empty() && classes.count(it->getClassId()) == 0) { if (!classes.empty() && classes.count(it->getClassId(true)) == 0) {
skipClass=true; skipClass=true;
continue; continue;
} }
@ -2450,9 +2450,9 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
skipClass=false; skipClass=false;
xml.startTag("ClassResult"); xml.startTag("ClassResult");
ClassStarted=true; ClassStarted=true;
Id=it->getClassId(); Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass()); xml.write("ClassShortName", it->getClass(true));
} }
if (skipClass) if (skipClass)

View File

@ -396,9 +396,9 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
continue; continue;
// Case when runner/team has different class // Case when runner/team has different class
bool teamOK = it->getTeam() && clsSel.count(it->getTeam()->getClassId()); bool teamOK = it->getTeam() && clsSel.count(it->getTeam()->getClassId(false));
if (!clsSel.empty() && (!teamOK && clsSel.count(it->getClassId()) == 0)) if (!clsSel.empty() && (!teamOK && clsSel.count(it->getClassId(true)) == 0))
continue; continue;
totWord.clear(); totWord.clear();
@ -417,7 +417,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
} }
rout.clear(); rout.clear();
while (numIter-- > 0) { while (numIter-- > 0) {
const wstring &out = oe->formatListString(pp, par, it->tInTeam, pRunner(&*it), it->Club, it->Class, c); const wstring &out = oe->formatListString(pp, par, it->tInTeam, pRunner(&*it), it->Club, pClass(it->getClassRef(true)), c);
//row[k] = max(row[k], int(out.length())); //row[k] = max(row[k], int(out.length()));
if (out.length() > rout.length()) if (out.length() > rout.length())
rout = out; rout = out;
@ -474,7 +474,7 @@ const wstring & oEvent::formatListString(EPostType type, const pRunner r) const
oListParam par; oListParam par;
par.setLegNumberCoded(r->tLeg); par.setLegNumberCoded(r->tLeg);
pp.type = type; pp.type = type;
return formatListString(pp, par, r->tInTeam, r, r->Club, r->Class, ctr); return formatListString(pp, par, r->tInTeam, r, r->Club, r->getClassRef(true), ctr);
} }
const wstring & oEvent::formatListString(EPostType type, const pRunner r, const wstring & oEvent::formatListString(EPostType type, const pRunner r,
@ -485,7 +485,7 @@ const wstring & oEvent::formatListString(EPostType type, const pRunner r,
par.setLegNumberCoded(r->tLeg); par.setLegNumberCoded(r->tLeg);
pp.type = type; pp.type = type;
pp.text = format; pp.text = format;
return formatListString(pp, par, r->tInTeam, r, r->Club, r->Class, ctr); return formatListString(pp, par, r->tInTeam, r, r->Club, r->getClassRef(true), ctr);
} }
@ -572,16 +572,16 @@ const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListP
break; break;
case lRunnerLegNumberAlpha: case lRunnerLegNumberAlpha:
if (t && t->getClassRef() && legIndex >= 0) { if (t && t->getClassRef(false) && legIndex >= 0) {
wstring legStr = t->getClassRef()->getLegNumber(legIndex); wstring legStr = t->getClassRef(false)->getLegNumber(legIndex);
wcscpy_s(bfw, legStr.c_str()); wcscpy_s(bfw, legStr.c_str());
} }
break; break;
case lRunnerLegNumber: case lRunnerLegNumber:
if (t && t->getClassRef() && legIndex >= 0) { if (t && t->getClassRef(false) && legIndex >= 0) {
int legNumber, legOrder; int legNumber, legOrder;
t->getClassRef()->splitLegNumberParallel(legIndex, legNumber, legOrder); t->getClassRef(false)->splitLegNumberParallel(legIndex, legNumber, legOrder);
wsptr = &itow(legNumber+1); wsptr = &itow(legNumber+1);
} }
break; break;
@ -727,7 +727,7 @@ const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListP
try { try {
const wstring &res = formatListStringAux(pp, par, t, t ? t->getRunner(legIndex) : 0, const wstring &res = formatListStringAux(pp, par, t, t ? t->getRunner(legIndex) : 0,
t ? t->getClubRef() : 0, t ? t->getClubRef() : 0,
t ? t->getClassRef() : 0, counter); t ? t->getClassRef(false) : 0, counter);
reentrantLock = false; reentrantLock = false;
return res; return res;
} }
@ -928,7 +928,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
if (t) { if (t) {
pRunner r1 = t->getRunner(0); pRunner r1 = t->getRunner(0);
pRunner r2 = t->getRunner(1); pRunner r2 = t->getRunner(1);
if (r1 && r2) { if (r1 && r2 && r2->tParentRunner != r1) {
swprintf_s(wbf, L"%s / %s", r1->getName().c_str(),r2->getName().c_str()); swprintf_s(wbf, L"%s / %s", r1->getName().c_str(),r2->getName().c_str());
} }
else if (r1) { else if (r1) {
@ -1375,7 +1375,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
break; break;
case lRunnerCard: case lRunnerCard:
if (r && r->CardNo > 0) if (r && r->getCardNo() > 0)
swprintf_s(wbf, L"%d", r->getCardNo()); swprintf_s(wbf, L"%d", r->getCardNo());
break; break;
case lRunnerRank: case lRunnerRank:
@ -2212,7 +2212,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
if (it->isRemoved() || it->tStatus == StatusNotCompetiting) if (it->isRemoved() || it->tStatus == StatusNotCompetiting)
continue; continue;
if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId(false))==0)
continue; continue;
it->apply(false, 0, true); it->apply(false, 0, true);
} }
@ -2263,11 +2263,10 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
if (it->isRemoved() || it->tStatus == StatusNotCompetiting) if (it->isRemoved() || it->tStatus == StatusNotCompetiting)
continue; continue;
if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId(true))==0)
continue; continue;
//if (it->legToRun() != li.lp.legNumber && li.lp.legNumber!=-1) if (!li.lp.matchLegNumber(it->getClassRef(false), it->legToRun()))
if (!li.lp.matchLegNumber(it->getClassRef(), it->legToRun()))
continue; continue;
if (li.filter(EFilterExcludeDNS)) if (li.filter(EFilterExcludeDNS))
@ -2348,29 +2347,29 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
wstring newKey; wstring newKey;
printPostInfo.par.relayLegIndex = -1; printPostInfo.par.relayLegIndex = -1;
calculatePrintPostKey(li.subHead, gdi, li.lp, it->tInTeam, &*it, it->Club, it->Class, printPostInfo.counter, newKey); calculatePrintPostKey(li.subHead, gdi, li.lp, it->tInTeam, &*it, it->Club, it->getClassRef(true), printPostInfo.counter, newKey);
if (newKey != oldKey) { if (newKey != oldKey) {
if (li.lp.pageBreak) { if (li.lp.pageBreak) {
if (!oldKey.empty()) if (!oldKey.empty())
gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, "");
} }
gdi.addStringUT(pagePageInfo, it->getClass()); gdi.addStringUT(pagePageInfo, it->getClass(true));
oldKey.swap(newKey); oldKey.swap(newKey);
printPostInfo.counter.level2=0; printPostInfo.counter.level2=0;
printPostInfo.counter.level3=0; printPostInfo.counter.level3=0;
printPostInfo.reset(); printPostInfo.reset();
printPostInfo.par.relayLegIndex = -1; printPostInfo.par.relayLegIndex = -1;
formatPrintPost(li.subHead, printPostInfo, it->tInTeam, &*it, it->Club, it->Class, 0, 0, -1); formatPrintPost(li.subHead, printPostInfo, it->tInTeam, &*it, it->Club, it->getClassRef(true), 0, 0, -1);
} }
if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2<li.lp.filterMaxPer) { if (li.lp.filterMaxPer==0 || printPostInfo.counter.level2<li.lp.filterMaxPer) {
printPostInfo.reset(); printPostInfo.reset();
printPostInfo.par.relayLegIndex = it->tLeg; printPostInfo.par.relayLegIndex = it->tLeg;
formatPrintPost(li.listPost, printPostInfo, it->tInTeam, &*it, it->Club, it->Class, 0, 0, -1); formatPrintPost(li.listPost, printPostInfo, it->tInTeam, &*it, it->Club, it->getClassRef(true), 0, 0, -1);
if (li.listSubType==li.EBaseTypePunches) { if (li.listSubType==li.EBaseTypePunches) {
listGeneratePunches(li.subListPost, gdi, li.lp, it->tInTeam, &*it, it->Club, it->Class); listGeneratePunches(li.subListPost, gdi, li.lp, it->tInTeam, &*it, it->Club, it->getClassRef(true));
} }
} }
++printPostInfo.counter; ++printPostInfo.counter;
@ -2397,7 +2396,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
if (it->isRemoved() || it->tStatus == StatusNotCompetiting) if (it->isRemoved() || it->tStatus == StatusNotCompetiting)
continue; continue;
if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId())==0) if (!li.lp.selection.empty() && li.lp.selection.count(it->getClassId(true))==0)
continue; continue;
tlist.push_back(&*it); tlist.push_back(&*it);
} }
@ -2416,7 +2415,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
for (size_t k = 0; k < tlist.size(); k++) { for (size_t k = 0; k < tlist.size(); k++) {
pTeam it = tlist[k]; pTeam it = tlist[k];
int linearLegSpec = li.lp.getLegNumber(it->getClassRef()); int linearLegSpec = li.lp.getLegNumber(it->getClassRef(false));
if (gResult && it->getTempResult(0).getStatus() == StatusNotCompetiting) if (gResult && it->getTempResult(0).getStatus() == StatusNotCompetiting)
continue; continue;
@ -2475,12 +2474,12 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, ""); gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, "");
} }
wstring legInfo; wstring legInfo;
if (linearLegSpec >= 0 && it->getClassRef()) { if (linearLegSpec >= 0 && it->getClassRef(false)) {
// Specified leg // Specified leg
legInfo = lang.tl(L", Str. X#" + li.lp.getLegName()); legInfo = lang.tl(L", Str. X#" + li.lp.getLegName());
} }
gdi.addStringUT(pagePageInfo, it->getClass() + legInfo); // Teamlist gdi.addStringUT(pagePageInfo, it->getClass(true) + legInfo); // Teamlist
oldKey.swap(newKey); oldKey.swap(newKey);
printPostInfo.counter.level2=0; printPostInfo.counter.level2=0;
@ -2561,7 +2560,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
printPostInfo.keepToghether = suitableBreak; printPostInfo.keepToghether = suitableBreak;
printPostInfo.par.relayLegIndex = tr[k] ? tr[k]->tLeg : -1; printPostInfo.par.relayLegIndex = tr[k] ? tr[k]->tLeg : -1;
formatPrintPost(li.subListPost, printPostInfo, &*it, tr[k], formatPrintPost(li.subListPost, printPostInfo, &*it, tr[k],
it->Club, tr[k]->Class, 0, 0, -1); it->Club, tr[k]->getClassRef(true), 0, 0, -1);
printPostInfo.counter.level3++; printPostInfo.counter.level3++;
} }
} }
@ -2579,7 +2578,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
} }
else { else {
formatPrintPost(li.subListPost, printPostInfo, &*it, tr[usedIx[k]], formatPrintPost(li.subListPost, printPostInfo, &*it, tr[usedIx[k]],
it->Club, tr[usedIx[k]]->Class, 0, 0, -1); it->Club, tr[usedIx[k]]->getClassRef(true), 0, 0, -1);
} }
printPostInfo.counter.level3++; printPostInfo.counter.level3++;
} }
@ -2632,16 +2631,15 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
} }
bool startClub = false; bool startClub = false;
pRunner pLeader = 0;
for (rit = Runners.begin(); rit != Runners.end(); ++rit) { for (rit = Runners.begin(); rit != Runners.end(); ++rit) {
if (rit->isRemoved() || rit->tStatus == StatusNotCompetiting) if (rit->isRemoved() || rit->tStatus == StatusNotCompetiting)
continue; continue;
if (!li.lp.selection.empty() && li.lp.selection.count(rit->getClassId())==0) if (!li.lp.selection.empty() && li.lp.selection.count(rit->getClassId(true))==0)
continue; continue;
if (!li.lp.matchLegNumber(rit->getClassRef(), rit->legToRun())) if (!li.lp.matchLegNumber(rit->getClassRef(false), rit->legToRun()))
continue; continue;
if (li.filter(EFilterExcludeDNS)) if (li.filter(EFilterExcludeDNS))
@ -2657,8 +2655,6 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
continue; continue;
} }
if (!pLeader || pLeader->Class != rit->Class)
pLeader = &*rit;
if (rit->Club == &*it) { if (rit->Club == &*it) {
if (!startClub) { if (!startClub) {
if (li.lp.pageBreak) { if (li.lp.pageBreak) {
@ -2680,7 +2676,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
printPostInfo.counter.level3=0; printPostInfo.counter.level3=0;
printPostInfo.reset(); printPostInfo.reset();
printPostInfo.par.relayLegIndex = rit->tLeg; printPostInfo.par.relayLegIndex = rit->tLeg;
formatPrintPost(li.listPost, printPostInfo, 0, &*rit, &*it, rit->Class, 0, 0, -1); formatPrintPost(li.listPost, printPostInfo, 0, &*rit, &*it, rit->getClassRef(true), 0, 0, -1);
if (li.subListPost.empty()) if (li.subListPost.empty())
continue; continue;
} }

View File

@ -294,6 +294,24 @@ class MetaListContainer;
struct oListParam { struct oListParam {
oListParam(); oListParam();
bool operator==(const oListParam& a) const {
return a.listCode == listCode &&
a.selection == selection &&
a.useControlIdResultFrom == useControlIdResultFrom &&
a.useControlIdResultTo == useControlIdResultTo &&
a.filterMaxPer == filterMaxPer &&
a.pageBreak == pageBreak &&
a.showInterTimes == showInterTimes &&
a.showSplitTimes == showSplitTimes &&
a.inputNumber == inputNumber &&
a.nextList == nextList &&
a.previousList == previousList &&
a.bgColor == bgColor &&
a.bgColor2 == bgColor2 &&
a.bgImage == bgImage &&
a.legNumber == legNumber;
}
EStdListType listCode; EStdListType listCode;
GUICALLBACK cb; GUICALLBACK cb;
set<int> selection; set<int> selection;
@ -389,6 +407,7 @@ public:
Global, Global,
Classwise, Classwise,
Legwise, Legwise,
Coursewise
}; };
static bool addRunners(EBaseType t) {return t == EBaseTypeRunner || t == EBaseTypeClub;} static bool addRunners(EBaseType t) {return t == EBaseTypeRunner || t == EBaseTypeClub;}

View File

@ -405,7 +405,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
no_club.push_back(&*r_it); no_club.push_back(&*r_it);
} }
if (r_it->getClassId()==0) if (r_it->getClassId(false)==0)
no_class.push_back(&*r_it); no_class.push_back(&*r_it);
else if (needCourse && r_it->getCourse(false)==0) else if (needCourse && r_it->getCourse(false)==0)
no_course.push_back(&*r_it); no_course.push_back(&*r_it);
@ -481,7 +481,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_course.empty() && ++i<20){ while(!no_course.empty() && ++i<20){
pRunner r=no_course.front(); pRunner r=no_course.front();
no_course.pop_front(); no_course.pop_front();
wstring name = r->getClass() + L": " + r->getName(); wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty()) if (!r->getClub().empty())
name += L" ("+ r->getClub()+ L")"; name += L" ("+ r->getClub()+ L")";
gdi.addStringUT(0, name); gdi.addStringUT(0, name);
@ -497,7 +497,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_club.empty() && ++i<20){ while(!no_club.empty() && ++i<20){
pRunner r=no_club.front(); pRunner r=no_club.front();
no_club.pop_front(); no_club.pop_front();
gdi.addStringUT(0, r->getClass() + L": " + r->getName()); gdi.addStringUT(0, r->getClass(true) + L": " + r->getName());
} }
if (!no_club.empty()) gdi.addStringUT(1, Ellipsis); if (!no_club.empty()) gdi.addStringUT(1, Ellipsis);
} }
@ -510,7 +510,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_start.empty() && ++i<20){ while(!no_start.empty() && ++i<20){
pRunner r=no_start.front(); pRunner r=no_start.front();
no_start.pop_front(); no_start.pop_front();
wstring name = r->getClass() + L": " + r->getName(); wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty()) if (!r->getClub().empty())
name += L" (" + r->getClub() + L")"; name += L" (" + r->getClub() + L")";
@ -526,7 +526,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_card.empty() && ++i<20){ while(!no_card.empty() && ++i<20){
pRunner r=no_card.front(); pRunner r=no_card.front();
no_card.pop_front(); no_card.pop_front();
wstring name = r->getClass() + L": " + r->getName(); wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty()) if (!r->getClub().empty())
name += L" (" + r->getClub() + L")"; name += L" (" + r->getClub() + L")";
@ -543,7 +543,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!si_duplicate.empty() && ++i<50){ while(!si_duplicate.empty() && ++i<50){
pRunner r=si_duplicate.front(); pRunner r=si_duplicate.front();
si_duplicate.pop_front(); si_duplicate.pop_front();
wstring name = r->getClass() + L" / " + r->getName(); wstring name = r->getClass(true) + L" / " + r->getName();
if (!r->getClub().empty()) if (!r->getClub().empty())
name += L" (" + r->getClub() + L")"; name += L" (" + r->getClub() + L")";
name += L": " + itow(r->getCardNo()); name += L": " + itow(r->getCardNo());
@ -566,7 +566,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
header = true; header = true;
} }
wstring name = r->getClass() + L" / " + r->getName(); wstring name = r->getClass(true) + L" / " + r->getName();
if (!r->getClub().empty()) if (!r->getClub().empty())
name += L" (" + r->getClub() + L")"; name += L" (" + r->getClub() + L")";
name += L": " + itow(r->getCardNo()); name += L": " + itow(r->getCardNo());
@ -589,7 +589,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it) { for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it) {
if (t_it->isRemoved()) if (t_it->isRemoved())
continue; continue;
pClass pc=getClass(t_it->getClassId()); pClass pc=getClass(t_it->getClassId(true));
if (pc){ if (pc){
for(unsigned i=0;i<pc->getNumStages();i++){ for(unsigned i=0;i<pc->getNumStages();i++){
@ -604,7 +604,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
bool any = false; bool any = false;
for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){ for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){
if (r_it->_objectmarker>1) { if (r_it->_objectmarker>1) {
wstring name = r_it->getClass() + L": " + r_it->getName(); wstring name = r_it->getClass(true) + L": " + r_it->getName();
if (!r_it->getClub().empty()) if (!r_it->getClub().empty())
name += L" (" + r_it->getClub() + L")"; name += L" (" + r_it->getClub() + L")";
@ -626,7 +626,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
if (r_it->isRemoved()) if (r_it->isRemoved())
continue; continue;
if (r_it->_objectmarker==0){ //Only consider runners not in a team. if (r_it->_objectmarker==0){ //Only consider runners not in a team.
gdi.addStringUT(y, x+tab[0], 0, r_it->getClass(), tab[1]-tab[0]); gdi.addStringUT(y, x+tab[0], 0, r_it->getClass(true), tab[1]-tab[0]);
wstring name = r_it->getName(); wstring name = r_it->getName();
if (!r_it->getClub().empty()) if (!r_it->getClub().empty())
name += L" (" + r_it->getClub() + L")"; name += L" (" + r_it->getClub() + L")";
@ -650,9 +650,9 @@ void oEvent::generatePreReport(gdioutput &gdi) {
gdi.addString("", 1, "Lag(flera)"); gdi.addString("", 1, "Lag(flera)");
for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it){ for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it){
pClass pc=getClass(t_it->getClassId()); pClass pc=getClass(t_it->getClassId(false));
gdi.addStringUT(0, t_it->getClass() + L": " + t_it->getName() + L" " + t_it->getStartTimeS()); gdi.addStringUT(0, t_it->getClass(false) + L": " + t_it->getName() + L" " + t_it->getStartTimeS());
if (pc){ if (pc){
for(unsigned i=0;i<pc->getNumStages();i++){ for(unsigned i=0;i<pc->getNumStages();i++){

View File

@ -44,6 +44,7 @@
#include "socket.h" #include "socket.h"
#include "MeOSFeatures.h" #include "MeOSFeatures.h"
#include "oListInfo.h" #include "oListInfo.h"
#include "qualification_final.h"
oRunner::RaceIdFormatter oRunner::raceIdFormatter; oRunner::RaceIdFormatter oRunner::raceIdFormatter;
@ -420,8 +421,27 @@ void oAbstractRunner::setClassId(int id, bool isManualUpdate) {
// Update all classes (for multirunner) // Update all classes (for multirunner)
void oRunner::setClassId(int id, bool isManualUpdate) void oRunner::setClassId(int id, bool isManualUpdate)
{ {
if (tParentRunner) if (Class && Class->getQualificationFinal() && isManualUpdate) {
tParentRunner->setClassId(id, isManualUpdate); int heat = Class->getQualificationFinal()->getHeatFromClass(id, Class->getId());
if (heat >= 0) {
int oldHeat = getDI().getInt("Heat");
if (heat != oldHeat) {
pClass oldHeatClass = getClassRef(true);
getDI().setInt("Heat", heat);
pClass newHeatClass = getClassRef(true);
oldHeatClass->clearCache(true);
newHeatClass->clearCache(true);
tSplitRevision = 0;
}
}
return;
}
if (tParentRunner) {
assert(!isManualUpdate); // Do not support! This may be destroyed if calling tParentRunner->setClass
return;
}
else { else {
pClass pc = Class; pClass pc = Class;
pClass nPc = id>0 ? oe->getClass(id):0; pClass nPc = id>0 ? oe->getClass(id):0;
@ -451,7 +471,7 @@ void oRunner::setClassId(int id, bool isManualUpdate)
if (Class != 0 && Class != pc && tInTeam==0 && if (Class != 0 && Class != pc && tInTeam==0 &&
Class->isSingleRunnerMultiStage()) { Class->isSingleRunnerMultiStage()) {
if (!isTemporaryObject) { if (!isTemporaryObject) {
pTeam t = oe->addTeam(getName(), getClubId(), getClassId()); pTeam t = oe->addTeam(getName(), getClubId(), getClassId(false));
t->setStartNo(StartNo, false); t->setStartNo(StartNo, false);
t->setRunner(0, this, true); t->setRunner(0, this, true);
} }
@ -765,91 +785,89 @@ pCourse oRunner::getCourse(bool useAdaptedCourse) const {
if (Course) if (Course)
tCrs = Course; tCrs = Course;
else if (Class) { else if (Class) {
if (Class->hasMultiCourse()) { const oClass *cls = getClassRef(true);
if (cls->hasMultiCourse()) {
if (tInTeam) { if (tInTeam) {
if (size_t(tLeg) >= tInTeam->Runners.size() || tInTeam->Runners[tLeg] != this) { if (size_t(tLeg) >= tInTeam->Runners.size() || tInTeam->Runners[tLeg] != this) {
tInTeam->quickApply(); tInTeam->quickApply();
} }
} }
if (tInTeam && Class->hasUnorderedLegs()) { if (Class == cls) {
vector< pair<int, pCourse> > group; if (tInTeam && Class->hasUnorderedLegs()) {
Class->getParallelCourseGroup(tLeg, StartNo, group); vector< pair<int, pCourse> > group;
Class->getParallelCourseGroup(tLeg, StartNo, group);
if (group.size() == 1) { if (group.size() == 1) {
tCrs = group[0].second; tCrs = group[0].second;
}
else {
// Remove used courses
int myStart = 0;
for (size_t k = 0; k < group.size(); k++) {
if (group[k].first == tLeg)
myStart = k;
pRunner tr = tInTeam->getRunner(group[k].first);
if (tr && tr->Course) {
// The course is assigned. Remove from group
for (size_t j = 0; j < group.size(); j++) {
if (group[j].second == tr->Course) {
group[j].second = 0;
break;
}
}
}
}
// Clear out already preliminary assigned courses
for (int k = 0; k < myStart; k++) {
pRunner r = tInTeam->getRunner(group[k].first);
if (r && !r->Course) {
size_t j = k;
while (j < group.size()) {
if (group[j].second) {
group[j].second = 0;
break;
}
else j++;
}
}
}
for (size_t j = 0; j < group.size(); j++) {
int ix = (j + myStart) % group.size();
pCourse gcrs = group[ix].second;
if (gcrs) {
tCrs = gcrs;
break;
}
}
}
}
else if (tInTeam) {
unsigned leg = legToRun();
tCrs = Class->getCourse(leg, StartNo);
} }
else { else {
// Remove used courses if (unsigned(tDuplicateLeg) < Class->MultiCourse.size()) {
int myStart = 0; vector<pCourse> &courses = Class->MultiCourse[tDuplicateLeg];
if (courses.size() > 0) {
for (size_t k = 0; k < group.size(); k++) { int index = StartNo % courses.size();
if (group[k].first == tLeg) tCrs = courses[index];
myStart = k;
pRunner tr = tInTeam->getRunner(group[k].first);
if (tr && tr->Course) {
// The course is assigned. Remove from group
for (size_t j = 0; j < group.size(); j++) {
if (group[j].second == tr->Course) {
group[j].second = 0;
break;
}
}
}
}
// Clear out already preliminary assigned courses
for (int k = 0; k < myStart; k++) {
pRunner r = tInTeam->getRunner(group[k].first);
if (r && !r->Course) {
size_t j = k;
while (j < group.size()) {
if (group[j].second) {
group[j].second = 0;
break;
}
else j++;
}
}
}
for (size_t j = 0; j < group.size(); j++) {
int ix = (j + myStart) % group.size();
pCourse gcrs = group[ix].second;
if (gcrs) {
tCrs = gcrs;
break;
} }
} }
} }
} }
else if (tInTeam) {
unsigned leg=legToRun();
tCrs = Class->getCourse(leg, StartNo);
/*if (leg<Class->MultiCourse.size()) {
vector<pCourse> &courses=Class->MultiCourse[leg];
if (courses.size()>0) {
int index=StartNo;
if (index>0)
index = (index-1) % courses.size();
tCrs = courses[index];
}
}*/
}
else { else {
if (unsigned(tDuplicateLeg)<Class->MultiCourse.size()) { // Final / qualification classes
vector<pCourse> &courses=Class->MultiCourse[tDuplicateLeg]; tCrs = cls->getCourse(0, StartNo);
if (courses.size()>0) {
int index=StartNo % courses.size();
tCrs = courses[index];
}
}
} }
} }
else else
tCrs = Class->Course; tCrs = cls->Course;
} }
if (tCrs && useAdaptedCourse) { if (tCrs && useAdaptedCourse) {
@ -1329,6 +1347,19 @@ bool oRunner::evaluateCard(bool doApply, vector<int> & MissingPunches,
doAdjustTimes(course); doAdjustTimes(course);
tRogainingPointsGross = tRogainingPoints; tRogainingPointsGross = tRogainingPoints;
if (oldStatus!=*refStatus || oldFT!=FinishTime) {
clearSplitAnalysis = true;
}
if ((inTeam || !tUseStartPunch) && doApply)
apply(sync, 0, false); //Post apply. Update start times.
if (tCachedRunningTime != FinishTime - *refStartTime) {
tCachedRunningTime = FinishTime - *refStartTime;
clearSplitAnalysis = true;
}
if (time_limit > 0) { if (time_limit > 0) {
int rt = getRunningTime(); int rt = getRunningTime();
if (rt > 0) { if (rt > 0) {
@ -1342,17 +1373,7 @@ bool oRunner::evaluateCard(bool doApply, vector<int> & MissingPunches,
} }
} }
if (oldStatus!=*refStatus || oldFT!=FinishTime) {
clearSplitAnalysis = true;
}
if ((inTeam || !tUseStartPunch) && doApply)
apply(sync, 0, false); //Post apply. Update start times.
if (tCachedRunningTime != FinishTime - *refStartTime) {
tCachedRunningTime = FinishTime - *refStartTime;
clearSplitAnalysis = true;
}
// Clear split analysis data if necessary // Clear split analysis data if necessary
bool clear = splitTimes.size() != oldTimes.size() || clearSplitAnalysis; bool clear = splitTimes.size() != oldTimes.size() || clearSplitAnalysis;
@ -1650,8 +1671,8 @@ int oRunner::getRaceRunningTime(int leg) const
bool oRunner::sortSplit(const oRunner &a, const oRunner &b) bool oRunner::sortSplit(const oRunner &a, const oRunner &b)
{ {
int acid=a.getClassId(); int acid=a.getClassId(true);
int bcid=b.getClassId(); int bcid=b.getClassId(true);
if (acid!=bcid) if (acid!=bcid)
return acid<bcid; return acid<bcid;
else if (a.tempStatus != b.tempStatus) else if (a.tempStatus != b.tempStatus)
@ -1661,21 +1682,29 @@ bool oRunner::sortSplit(const oRunner &a, const oRunner &b)
if (a.tempRT!=b.tempRT) if (a.tempRT!=b.tempRT)
return a.tempRT<b.tempRT; return a.tempRT<b.tempRT;
} }
return a.tRealName<b.tRealName; return CompareString(LOCALE_USER_DEFAULT, 0,
a.tRealName.c_str(), a.tRealName.length(),
b.tRealName.c_str(), b.tRealName.length()) == CSTR_LESS_THAN;
} }
} }
bool oRunner::operator <(const oRunner &c) { bool oRunner::operator<(const oRunner &c) const {
if (!Class || !c.Class) const oClass * myClass = getClassRef(true);
return size_t(Class)<size_t(c.Class); const oClass * cClass = c.getClassRef(true);
else if (Class == c.Class && Class->getClassStatus() != oClass::Normal) if (!myClass || !cClass)
return size_t(myClass)<size_t(cClass);
else if (Class == cClass && Class->getClassStatus() != oClass::Normal)
return CompareString(LOCALE_USER_DEFAULT, 0, return CompareString(LOCALE_USER_DEFAULT, 0,
tRealName.c_str(), tRealName.length(), tRealName.c_str(), tRealName.length(),
c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN; c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN;
if (oe->CurrentSortOrder==ClassStartTime) { if (oe->CurrentSortOrder==ClassStartTime) {
if (Class->Id != c.Class->Id) if (myClass->Id != cClass->Id) {
return Class->tSortIndex < c.Class->tSortIndex; if (myClass->tSortIndex != cClass->tSortIndex)
return myClass->tSortIndex < cClass->tSortIndex;
else
return myClass->Id < cClass->Id;
}
else if (tStartTime != c.tStartTime) { else if (tStartTime != c.tStartTime) {
if (tStartTime <= 0 && c.tStartTime > 0) if (tStartTime <= 0 && c.tStartTime > 0)
return false; return false;
@ -1697,8 +1726,8 @@ bool oRunner::operator <(const oRunner &c) {
RunnerStatus stat = tStatus == StatusUnknown ? StatusOK : tStatus; RunnerStatus stat = tStatus == StatusUnknown ? StatusOK : tStatus;
RunnerStatus cstat = c.tStatus == StatusUnknown ? StatusOK : c.tStatus; RunnerStatus cstat = c.tStatus == StatusUnknown ? StatusOK : c.tStatus;
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tLegEquClass != c.tLegEquClass) else if (tLegEquClass != c.tLegEquClass)
return tLegEquClass < c.tLegEquClass; return tLegEquClass < c.tLegEquClass;
else if (tDuplicateLeg != c.tDuplicateLeg) else if (tDuplicateLeg != c.tDuplicateLeg)
@ -1730,8 +1759,8 @@ bool oRunner::operator <(const oRunner &c) {
} }
} }
else if (oe->CurrentSortOrder == ClassCourseResult) { else if (oe->CurrentSortOrder == ClassCourseResult) {
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex;
const pCourse crs1 = getCourse(false); const pCourse crs1 = getCourse(false);
const pCourse crs2 = c.getCourse(false); const pCourse crs2 = c.getCourse(false);
@ -1805,8 +1834,8 @@ bool oRunner::operator <(const oRunner &c) {
return ft > cft; return ft > cft;
} }
else if (oe->CurrentSortOrder == ClassFinishTime){ else if (oe->CurrentSortOrder == ClassFinishTime){
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
if (tStatus != c.tStatus) if (tStatus != c.tStatus)
return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus]; return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus];
else{ else{
@ -1834,8 +1863,8 @@ bool oRunner::operator <(const oRunner &c) {
return et > cet; return et > cet;
} }
else if (oe->CurrentSortOrder == ClassPoints) { else if (oe->CurrentSortOrder == ClassPoints) {
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tDuplicateLeg != c.tDuplicateLeg) else if (tDuplicateLeg != c.tDuplicateLeg)
return tDuplicateLeg < c.tDuplicateLeg; return tDuplicateLeg < c.tDuplicateLeg;
else if (tStatus != c.tStatus) else if (tStatus != c.tStatus)
@ -1852,8 +1881,8 @@ bool oRunner::operator <(const oRunner &c) {
} }
} }
else if (oe->CurrentSortOrder==ClassTotalResult) { else if (oe->CurrentSortOrder==ClassTotalResult) {
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tDuplicateLeg != c.tDuplicateLeg) else if (tDuplicateLeg != c.tDuplicateLeg)
return tDuplicateLeg < c.tDuplicateLeg; return tDuplicateLeg < c.tDuplicateLeg;
else { else {
@ -1902,8 +1931,8 @@ bool oRunner::operator <(const oRunner &c) {
} }
} }
else if (oe->CurrentSortOrder==ClassStartTimeClub) { else if (oe->CurrentSortOrder==ClassStartTimeClub) {
if (Class != c.Class) if (myClass != cClass)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tStartTime != c.tStartTime) { else if (tStartTime != c.tStartTime) {
if (tStartTime <= 0 && c.tStartTime > 0) if (tStartTime <= 0 && c.tStartTime > 0)
return false; return false;
@ -1916,8 +1945,8 @@ bool oRunner::operator <(const oRunner &c) {
} }
} }
else if (oe->CurrentSortOrder==ClassTeamLeg) { else if (oe->CurrentSortOrder==ClassTeamLeg) {
if (Class->Id != c.Class->Id) if (myClass->Id != cClass->Id)
return Class->tSortIndex < c.Class->tSortIndex; return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tInTeam != c.tInTeam) { else if (tInTeam != c.tInTeam) {
if (tInTeam == 0) if (tInTeam == 0)
return true; return true;
@ -1959,7 +1988,7 @@ void oAbstractRunner::setClub(const wstring &clubName)
updateChanged(); updateChanged();
if (Class) { if (Class) {
// Vacant clubs have special logic // Vacant clubs have special logic
Class->tResultInfo.clear(); getClassRef(true)->tResultInfo.clear();
} }
if (Club && Club->isVacant()) { // Clear entry date/time for vacant if (Club && Club->isVacant()) { // Clear entry date/time for vacant
getDI().setInt("EntryDate", 0); getDI().setInt("EntryDate", 0);
@ -2326,7 +2355,7 @@ void oEvent::getRunners(int classId, int courseId, vector<pRunner> &r, bool sort
continue; continue;
} }
if (classId <= 0 || it->getClassId() == classId) if (classId <= 0 || it->getClassId(true) == classId)
r.push_back(&*it); r.push_back(&*it);
} }
} }
@ -2364,7 +2393,7 @@ pRunner oRunner::nextNeedReadout() const {
// For a runner in a team, first the team for the card // For a runner in a team, first the team for the card
for (size_t k = 0; k < tInTeam->Runners.size(); k++) { for (size_t k = 0; k < tInTeam->Runners.size(); k++) {
pRunner tr = tInTeam->Runners[k]; pRunner tr = tInTeam->Runners[k];
if (tr && tr->CardNo == CardNo && !tr->Card && !tr->statusOK()) if (tr && tr->getCardNo() == CardNo && !tr->Card && !tr->statusOK())
return tr; return tr;
} }
} }
@ -2432,9 +2461,11 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
} }
else { else {
if (time <= 0) { //No time specified. Card readout search if (time <= 0) { //No time specified. Card readout search
pRunner secondTry = 0;
//First try runners with no card read or a different card read. //First try runners with no card read or a different card read.
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->skip()) if (it->isRemoved())
continue; continue;
if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL)) if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL))
continue; continue;
@ -2442,9 +2473,15 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
continue; continue;
pRunner ret; pRunner ret;
if (it->CardNo==cardNo && (ret = it->nextNeedReadout()) != 0) if (it->CardNo == cardNo && (ret = it->nextNeedReadout()) != 0) {
return ret; if (!it->skip())
return ret;
else if (secondTry == 0 || secondTry->tLeg > ret->tLeg)
secondTry = ret;
}
} }
if (secondTry)
return secondTry;
} }
else { else {
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
@ -2745,11 +2782,11 @@ const vector< pair<wstring, size_t> > &oEvent::fillRunners(vector< pair<wstring,
if (compact) { if (compact) {
swprintf_s(bf, L"%s, %s (%s)", it->getNameAndRace(true).c_str(), swprintf_s(bf, L"%s, %s (%s)", it->getNameAndRace(true).c_str(),
it->getClub().c_str(), it->getClub().c_str(),
it->getClass().c_str()); it->getClass(true).c_str());
} else { } else {
swprintf_s(bf, L"%s\t%s\t%s", it->getNameAndRace(true).c_str(), swprintf_s(bf, L"%s\t%s\t%s", it->getNameAndRace(true).c_str(),
it->getClass().c_str(), it->getClass(true).c_str(),
it->getClub().c_str()); it->getClub().c_str());
} }
out.push_back(make_pair(bf, it->Id)); out.push_back(make_pair(bf, it->Id));
@ -2769,7 +2806,7 @@ const vector< pair<wstring, size_t> > &oEvent::fillRunners(vector< pair<wstring,
if ( it->getClubId() != lVacId || lVacId == 0) if ( it->getClubId() != lVacId || lVacId == 0)
out.push_back(make_pair(it->getUIName(), it->Id)); out.push_back(make_pair(it->getUIName(), it->Id));
else { else {
swprintf_s(bf, L"%s (%s)", it->getUIName().c_str(), it->getClass().c_str()); swprintf_s(bf, L"%s (%s)", it->getUIName().c_str(), it->getClass(true).c_str());
out.push_back(make_pair(bf, it->Id)); out.push_back(make_pair(bf, it->Id));
} }
} }
@ -2879,7 +2916,7 @@ void oRunner::createMultiRunner(bool createMaster, bool sync)
if (!multiRunner[k-1]) { if (!multiRunner[k-1]) {
update = true; update = true;
multiRunner[k-1]=oe->addRunner(sName, getClubId(), multiRunner[k-1]=oe->addRunner(sName, getClubId(),
getClassId(), 0, 0, false); getClassId(false), 0, 0, false);
multiRunner[k-1]->tDuplicateLeg=k; multiRunner[k-1]->tDuplicateLeg=k;
multiRunner[k-1]->tParentRunner=this; multiRunner[k-1]->tParentRunner=this;
@ -2909,6 +2946,12 @@ pRunner oRunner::getPredecessor() const
bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) { bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) {
createMultiRunner(false, sync); createMultiRunner(false, sync);
if (sync) {
for (size_t k = 0; k < multiRunner.size(); k++) {
if (multiRunner[k])
multiRunner[k]->synchronize(true);
}
}
tLeg = -1; tLeg = -1;
tLegEquClass = 0; tLegEquClass = 0;
tUseStartPunch=true; tUseStartPunch=true;
@ -3045,7 +3088,7 @@ void oEvent::generateRunnerTableData(Table &table, oRunner *addRunner)
oRunnerList::iterator it; oRunnerList::iterator it;
table.reserve(Runners.size()); table.reserve(Runners.size());
for (it=Runners.begin(); it != Runners.end(); ++it){ for (it=Runners.begin(); it != Runners.end(); ++it){
if (!it->skip()){ if (!it->isRemoved()){
it->addTableRow(table); it->addTableRow(table);
} }
} }
@ -3088,11 +3131,13 @@ void oRunner::addTableRow(Table &table) const
table.set(row++, it, TID_ID, itow(getId()), false); table.set(row++, it, TID_ID, itow(getId()), false);
table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); table.set(row++, it, TID_MODIFIED, getTimeStamp(), false);
table.set(row++, it, TID_RUNNER, getUIName(), true); if (tParentRunner == 0)
table.set(row++, it, TID_RUNNER, getUIName(), true);
table.set(row++, it, TID_CLASSNAME, getClass(), true, cellSelection); else
table.set(row++, it, TID_RUNNER, getUIName() + L" (" + itow(tDuplicateLeg+1) + L")", false);
table.set(row++, it, TID_CLASSNAME, getClass(true), true, cellSelection);
table.set(row++, it, TID_COURSE, getCourseName(), true, cellSelection); table.set(row++, it, TID_COURSE, getCourseName(), true, cellSelection);
table.set(row++, it, TID_CLUB, getClub(), true, cellCombo); table.set(row++, it, TID_CLUB, getClub(), tParentRunner == 0, cellCombo);
table.set(row++, it, TID_TEAM, tInTeam ? tInTeam->getName() : L"", false); table.set(row++, it, TID_TEAM, tInTeam ? tInTeam->getName() : L"", false);
table.set(row++, it, TID_LEG, tInTeam ? itow(tLeg+1) : L"" , false); table.set(row++, it, TID_LEG, tInTeam ? itow(tLeg+1) : L"" , false);
@ -3138,7 +3183,7 @@ bool oRunner::inputData(int id, const wstring &input,
throw std::exception("Tomt namn inte tillåtet."); throw std::exception("Tomt namn inte tillåtet.");
if (sName != input && tRealName != input) { if (sName != input && tRealName != input) {
updateFromDB(input, getClubId(), getClassId(), getCardNo(), getBirthYear()); updateFromDB(input, getClubId(), getClassId(false), getCardNo(), getBirthYear());
setName(input, true); setName(input, true);
synchronizeAll(); synchronizeAll();
} }
@ -3184,7 +3229,7 @@ bool oRunner::inputData(int id, const wstring &input,
else else
pc = oe->getClubCreate(0, input); pc = oe->getClubCreate(0, input);
updateFromDB(getName(), pc ? pc->getId():0, getClassId(), getCardNo(), getBirthYear()); updateFromDB(getName(), pc ? pc->getId():0, getClassId(false), getCardNo(), getBirthYear());
setClub(pc ? pc->getName() : L""); setClub(pc ? pc->getName() : L"");
synchronize(true); synchronize(true);
@ -3195,7 +3240,7 @@ bool oRunner::inputData(int id, const wstring &input,
case TID_CLASSNAME: case TID_CLASSNAME:
setClassId(inputId, true); setClassId(inputId, true);
synchronize(true); synchronize(true);
output = getClass(); output = getClass(true);
break; break;
case TID_STATUS: { case TID_STATUS: {
@ -3258,7 +3303,7 @@ void oRunner::fillInput(int id, vector< pair<wstring, size_t> > &out, size_t &se
else if (id==TID_CLASSNAME) { else if (id==TID_CLASSNAME) {
oe->fillClasses(out, oEvent::extraNone, oEvent::filterNone); oe->fillClasses(out, oEvent::extraNone, oEvent::filterNone);
out.push_back(make_pair(lang.tl(L"Ingen klass"), 0)); out.push_back(make_pair(lang.tl(L"Ingen klass"), 0));
selected = getClassId(); selected = getClassId(true);
} }
else if (id==TID_CLUB) { else if (id==TID_CLUB) {
oe->fillClubs(out); oe->fillClubs(out);
@ -3378,7 +3423,7 @@ void oRunner::getSplitTime(int courseControlId, RunnerStatus &stat, int &rt) con
{ {
rt = 0; rt = 0;
stat = StatusUnknown; stat = StatusUnknown;
int cardno = tParentRunner ? tParentRunner->CardNo : CardNo; int cardno = getCardNo();
if (courseControlId==oPunch::PunchFinish && if (courseControlId==oPunch::PunchFinish &&
FinishTime>0 && tStatus!=StatusUnknown) { FinishTime>0 && tStatus!=StatusUnknown) {
@ -3643,7 +3688,9 @@ const wstring &oAbstractRunner::getBib() const
} }
void oRunner::setBib(const wstring &bib, int bibNumerical, bool updateStartNo, bool tmpOnly) { void oRunner::setBib(const wstring &bib, int bibNumerical, bool updateStartNo, bool tmpOnly) {
if (tParentRunner) const bool freeBib = !Class || Class->getBibMode() == BibMode::BibFree;
if (tParentRunner && !freeBib)
tParentRunner->setBib(bib, bibNumerical, updateStartNo, tmpOnly); tParentRunner->setBib(bib, bibNumerical, updateStartNo, tmpOnly);
else { else {
if (updateStartNo) if (updateStartNo)
@ -3657,10 +3704,11 @@ void oRunner::setBib(const wstring &bib, int bibNumerical, bool updateStartNo, b
if (oe) if (oe)
oe->bibStartNoToRunnerTeam.clear(); oe->bibStartNoToRunnerTeam.clear();
} }
if (!freeBib) {
for (size_t k=0;k<multiRunner.size();k++) { for (size_t k = 0; k < multiRunner.size(); k++) {
if (multiRunner[k]) { if (multiRunner[k]) {
multiRunner[k]->getDI().setString("Bib", bib); multiRunner[k]->getDI().setString("Bib", bib);
}
} }
} }
} }
@ -3848,7 +3896,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
gdi.dropLine(0.5); gdi.dropLine(0.5);
pCourse pc = getCourse(true); pCourse pc = getCourse(true);
gdi.addStringUT(bnormal, getName() + L", " + getClass()); gdi.addStringUT(bnormal, getName() + L", " + getClass(true));
gdi.addStringUT(normal, getClub()); gdi.addStringUT(normal, getClub());
gdi.dropLine(0.5); gdi.dropLine(0.5);
gdi.addStringUT(normal, lang.tl("Start: ") + getStartTimeS() + lang.tl(", Mål: ") + getFinishTimeS()); gdi.addStringUT(normal, lang.tl("Start: ") + getStartTimeS() + lang.tl(", Mål: ") + getFinishTimeS());
@ -4175,7 +4223,7 @@ void oRunner::printStartInfo(gdioutput &gdi) const {
if (!bib.empty()) if (!bib.empty())
bib = bib + L": "; bib = bib + L": ";
gdi.addStringUT(boldSmall, bib + getName() + L", " + getClass()); gdi.addStringUT(boldSmall, bib + getName() + L", " + getClass(true));
gdi.addStringUT(fontSmall, getClub()); gdi.addStringUT(fontSmall, getClub());
gdi.dropLine(0.5); gdi.dropLine(0.5);
@ -4274,7 +4322,7 @@ void oEvent::updateRunnersFromDB()
for (it=Runners.begin(); it != Runners.end(); ++it) { for (it=Runners.begin(); it != Runners.end(); ++it) {
if (!it->isVacant() && !it->isRemoved()) if (!it->isVacant() && !it->isRemoved())
it->updateFromDB(it->sName, it->getClubId(), it->getClassId(), it->getCardNo(), it->getBirthYear()); it->updateFromDB(it->sName, it->getClubId(), it->getClassId(false), it->getCardNo(), it->getBirthYear());
} }
} }
@ -5258,6 +5306,10 @@ void oRunner::markClassChanged(int controlId) {
assert(controlId < 4096); assert(controlId < 4096);
if (Class) { if (Class) {
Class->markSQLChanged(tLeg, controlId); Class->markSQLChanged(tLeg, controlId);
pClass cls2 = getClassRef(true);
if (cls2 != Class)
cls2->markSQLChanged(-1, controlId);
if (tInTeam && tInTeam->Class != Class && tInTeam->Class) { if (tInTeam && tInTeam->Class != Class && tInTeam->Class) {
tInTeam->Class->markSQLChanged(tLeg, controlId); tInTeam->Class->markSQLChanged(tLeg, controlId);
} }
@ -5535,10 +5587,13 @@ int oRunner::getRanking() const {
} }
void oAbstractRunner::hasManuallyUpdatedTimeStatus() { void oAbstractRunner::hasManuallyUpdatedTimeStatus() {
if (Class && Class->hasClassGlobalDependance()) { if (Class && Class->hasClassGlobalDependence()) {
set<int> cls; set<int> cls;
oe->reEvaluateAll(cls, false); oe->reEvaluateAll(cls, false);
} }
if (Class) {
Class->updateFinalClasses(dynamic_cast<oRunner *>(this), false);
}
} }
bool oRunner::canShareCard(const pRunner other, int newCardNo) const { bool oRunner::canShareCard(const pRunner other, int newCardNo) const {
@ -5555,7 +5610,7 @@ bool oRunner::canShareCard(const pRunner other, int newCardNo) const {
if (!getTeam() || other->getTeam() != getTeam()) if (!getTeam() || other->getTeam() != getTeam())
return false; return false;
pClass tCls = getTeam()->getClassRef(); const oClass * tCls = getTeam()->getClassRef(false);
if (!tCls || tCls != Class) if (!tCls || tCls != Class)
return false; return false;
@ -5598,3 +5653,24 @@ bool oAbstractRunner::hasLateEntryFee() const {
return late; return late;
} }
int oRunner::classInstance() const {
if (classInstanceRev.first == oe->dataRevision)
return classInstanceRev.second;
classInstanceRev.second = getDCI().getInt("Heat");
if (Class)
classInstanceRev.second = min(classInstanceRev.second, Class->getNumQualificationFinalClasses());
classInstanceRev.first = oe->dataRevision;
return classInstanceRev.second;
}
const wstring &oAbstractRunner::getClass(bool virtualClass) const {
if (Class) {
if (virtualClass)
return Class->getVirtualClass(classInstance())->Name;
else
return Class->Name;
}
else return _EmptyWString;
}

View File

@ -255,17 +255,28 @@ public:
const pClub getClubRef() const {return Club;} const pClub getClubRef() const {return Club;}
pClub getClubRef() {return Club;} pClub getClubRef() {return Club;}
virtual int classInstance() const = 0;
const pClass getClassRef() const {return Class;} const oClass *getClassRef(bool virtualClass) const {
pClass getClassRef() {return Class;} return (virtualClass && Class) ? Class->getVirtualClass(classInstance()) : Class;
}
pClass getClassRef(bool virtualClass) {
return pClass((virtualClass && Class) ? Class->getVirtualClass(classInstance()) : Class);
}
virtual const wstring &getClub() const {if (Club) return Club->name; else return _EmptyWString;} virtual const wstring &getClub() const {if (Club) return Club->name; else return _EmptyWString;}
virtual int getClubId() const {if (Club) return Club->Id; else return 0;} virtual int getClubId() const {if (Club) return Club->Id; else return 0;}
virtual void setClub(const wstring &clubName); virtual void setClub(const wstring &clubName);
virtual pClub setClubId(int clubId); virtual pClub setClubId(int clubId);
virtual const wstring &getClass() const {if (Class) return Class->Name; else return _EmptyWString;} const wstring &getClass(bool virtualClass) const;
virtual int getClassId() const {if (Class) return Class->Id; else return 0;} int getClassId(bool virtualClass) const {
if (Class)
return virtualClass ? Class->getVirtualClass(classInstance())->Id : Class->Id;
return 0;
}
virtual void setClassId(int id, bool isManualUpdate); virtual void setClassId(int id, bool isManualUpdate);
virtual int getStartNo() const {return StartNo;} virtual int getStartNo() const {return StartNo;}
virtual void setStartNo(int no, bool storeTmpOnly); virtual void setStartNo(int no, bool storeTmpOnly);
@ -457,6 +468,8 @@ protected:
// Running time as calculated by evalute. Used to detect changes. // Running time as calculated by evalute. Used to detect changes.
int tCachedRunningTime; int tCachedRunningTime;
mutable pair<int, int> classInstanceRev;
void clearOnChangedRunningTime(); void clearOnChangedRunningTime();
// Cached runner statistics // Cached runner statistics
@ -499,6 +512,8 @@ public:
/** Get a runner reference (drawing) */ /** Get a runner reference (drawing) */
pRunner getReference() const; pRunner getReference() const;
int classInstance() const override;
/**Set a runner reference*/ /**Set a runner reference*/
void setReference(int runnerId); void setReference(int runnerId);
@ -546,6 +561,9 @@ public:
int getLegNumber() const {return tLeg;} int getLegNumber() const {return tLeg;}
int getSpeakerPriority() const; int getSpeakerPriority() const;
RunnerStatus getTempStatus() const { return tempStatus; }
int getTempTime() const { return tempRT; }
void remove(); void remove();
bool canRemove() const; bool canRemove() const;
@ -703,7 +721,7 @@ public:
pCard getCard() const {return Card;} pCard getCard() const {return Card;}
int getCardId(){if (Card) return Card->Id; else return 0;} int getCardId(){if (Card) return Card->Id; else return 0;}
bool operator<(const oRunner &c); bool operator<(const oRunner &c) const;
bool static CompareSINumber(const oRunner &a, const oRunner &b){return a.CardNo<b.CardNo;} bool static CompareSINumber(const oRunner &a, const oRunner &b){return a.CardNo<b.CardNo;}
bool evaluateCard(bool applyTeam, vector<int> &missingPunches, int addpunch=0, bool synchronize=false); bool evaluateCard(bool applyTeam, vector<int> &missingPunches, int addpunch=0, bool synchronize=false);
@ -716,7 +734,7 @@ public:
int getCourseId() const {if (Course) return Course->Id; else return 0;} int getCourseId() const {if (Course) return Course->Id; else return 0;}
void setCourseId(int id); void setCourseId(int id);
int getCardNo() const {return tParentRunner ? tParentRunner->CardNo : CardNo;} int getCardNo() const {return tParentRunner && CardNo == 0 ? tParentRunner->CardNo : CardNo;}
void setCardNo(int card, bool matchCard, bool updateFromDatabase = false); void setCardNo(int card, bool matchCard, bool updateFromDatabase = false);
/** Sets the card to a given card. An existing card is marked as unpaired. /** Sets the card to a given card. An existing card is marked as unpaired.
CardNo is updated. Returns id of old card (or 0). CardNo is updated. Returns id of old card (or 0).

View File

@ -315,7 +315,7 @@ void oTeam::setRunnerInternal(int k, pRunner r)
Runners[k]->tInTeam = this; Runners[k]->tInTeam = this;
Runners[k]->tLeg = k; Runners[k]->tLeg = k;
if (Class && Class->getLegType(k) != LTGroup) if (Class && Class->getLegType(k) != LTGroup)
Runners[k]->setClassId(getClassId(), false); Runners[k]->setClassId(getClassId(false), false);
} }
updateChanged(); updateChanged();
} }
@ -698,7 +698,7 @@ bool oTeam::compareResult(const oTeam &a, const oTeam &b)
{ {
if (a.Class != b.Class) { if (a.Class != b.Class) {
if (a.Class) { if (a.Class) {
if (b.Class) return a.Class->tSortIndex < b.Class->tSortIndex; if (b.Class) return a.Class->tSortIndex < b.Class->tSortIndex || (a.Class->tSortIndex == b.Class->tSortIndex && a.Class->Id < b.Class->Id);
else return true; else return true;
} }
else return false; else return false;
@ -728,7 +728,8 @@ bool oTeam::compareStartTime(const oTeam &a, const oTeam &b)
{ {
if (a.Class != b.Class) { if (a.Class != b.Class) {
if (a.Class) { if (a.Class) {
if (b.Class) return a.Class->tSortIndex<b.Class->tSortIndex; if (b.Class)
return a.Class->tSortIndex<b.Class->tSortIndex || (a.Class->tSortIndex == b.Class->tSortIndex && a.Class->Id < b.Class->Id);
else return true; else return true;
} }
} }
@ -760,7 +761,8 @@ bool oTeam::compareSNO(const oTeam &a, const oTeam &b) {
} }
else if (a.Class != b.Class) { else if (a.Class != b.Class) {
if (a.Class) { if (a.Class) {
if (b.Class) return a.Class->tSortIndex<b.Class->tSortIndex; if (b.Class)
return a.Class->tSortIndex < b.Class->tSortIndex || (a.Class->tSortIndex == b.Class->tSortIndex && a.Class->Id < b.Class->Id);
else return true; else return true;
} }
} }
@ -928,6 +930,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
} }
if (Runners[i]) { if (Runners[i]) {
pClass actualClass = Runners[i]->getClassRef(true);
if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) {
Runners[i]->tInTeam->correctRemove(Runners[i]); Runners[i]->tInTeam->correctRemove(Runners[i]);
} }
@ -942,7 +945,8 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
Runners[i]->tLegEquClass = i; Runners[i]->tLegEquClass = i;
} }
Runners[i]->setStartNo(StartNo, setTmpOnly); if (actualClass == Class)
Runners[i]->setStartNo(StartNo, setTmpOnly);
if (!bib.empty() && Runners[i]->isChanged()) { if (!bib.empty() && Runners[i]->isChanged()) {
if (bibMode == -1 && Class) if (bibMode == -1 && Class)
bibMode = Class->getBibMode(); bibMode = Class->getBibMode();
@ -980,7 +984,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
else else
lastStatus = Runners[i]->getStatus(); lastStatus = Runners[i]->getStatus();
StartTypes st = pc->getStartType(i); StartTypes st = actualClass == pc ? pc->getStartType(i) : actualClass->getStartType(0);
LegTypes lt = legType; LegTypes lt = legType;
if ((lt==LTParallel || lt==LTParallelOptional) && i==0) { if ((lt==LTParallel || lt==LTParallelOptional) && i==0) {
@ -1016,9 +1020,12 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
} }
} }
if (!prs) { if (!prs) {
if (lt==LTNormal || lt==LTSum || lt == LTGroup) if (lt == LTNormal || lt == LTSum || lt == LTGroup) {
lastStartTime=pc->getStartData(i); if (actualClass == pc)
lastStartTime = pc->getStartData(i);
else
lastStartTime = actualClass->getStartData(0); // Qualification/final classes
}
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); Runners[i]->setStartTime(lastStartTime, false, setTmpOnly);
Runners[i]->tUseStartPunch=false; Runners[i]->tUseStartPunch=false;
} }
@ -1740,7 +1747,7 @@ void oEvent::getTeams(int classId, vector<pTeam> &t, bool sort) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (classId == 0 || it->getClassId() == classId) if (classId == 0 || it->getClassId(false) == classId)
t.push_back(&*it); t.push_back(&*it);
} }
} }
@ -1855,7 +1862,7 @@ void oTeam::addTableRow(Table &table) const {
table.set(row++, it, TID_MODIFIED, getTimeStamp(), false); table.set(row++, it, TID_MODIFIED, getTimeStamp(), false);
table.set(row++, it, TID_NAME, getName(), true); table.set(row++, it, TID_NAME, getName(), true);
table.set(row++, it, TID_CLASSNAME, getClass(), true, cellSelection); table.set(row++, it, TID_CLASSNAME, getClass(true), true, cellSelection);
table.set(row++, it, TID_CLUB, getClub(), true, cellCombo); table.set(row++, it, TID_CLUB, getClub(), true, cellCombo);
table.set(row++, it, TID_START, getStartTimeS(), true); table.set(row++, it, TID_START, getStartTimeS(), true);
@ -1920,7 +1927,7 @@ bool oTeam::inputData(int id, const wstring &input,
} }
else { else {
if (isName && !input.empty() && Class) { if (isName && !input.empty() && Class) {
pRunner r = oe->addRunner(input, getClubId(), getClassId(), 0, 0, false); pRunner r = oe->addRunner(input, getClubId(), getClassId(false), 0, 0, false);
setRunner(ix, r, true); setRunner(ix, r, true);
output = r->getName(); output = r->getName();
} }
@ -1968,7 +1975,7 @@ bool oTeam::inputData(int id, const wstring &input,
case TID_CLASSNAME: case TID_CLASSNAME:
setClassId(inputId, true); setClassId(inputId, true);
synchronize(true); synchronize(true);
output = getClass(); output = getClass(true);
break; break;
case TID_STATUS: { case TID_STATUS: {
@ -2033,7 +2040,7 @@ void oTeam::fillInput(int id, vector< pair<wstring, size_t> > &out, size_t &sele
else if (id==TID_CLASSNAME) { else if (id==TID_CLASSNAME) {
oe->fillClasses(out, oEvent::extraNone, oEvent::filterOnlyMulti); oe->fillClasses(out, oEvent::extraNone, oEvent::filterOnlyMulti);
out.push_back(make_pair(lang.tl(L"Ingen klass"), 0)); out.push_back(make_pair(lang.tl(L"Ingen klass"), 0));
selected = getClassId(); selected = getClassId(true);
} }
else if (id==TID_CLUB) { else if (id==TID_CLUB) {
oe->fillClubs(out); oe->fillClubs(out);

View File

@ -105,6 +105,10 @@ public:
int getRanking() const; int getRanking() const;
int classInstance() const override {
return 0; // Not supported
}
void resetResultCalcCache() const; void resetResultCalcCache() const;
vector< vector<int> > &getResultCache(ResultCalcCacheSymbol symb) const; vector< vector<int> > &getResultCache(ResultCalcCacheSymbol symb) const;
void setResultCache(ResultCalcCacheSymbol symb, int leg, vector<int> &data) const; void setResultCache(ResultCalcCacheSymbol symb, int leg, vector<int> &data) const;

View File

@ -102,7 +102,7 @@ const vector< pair<wstring, size_t> > &oEvent::fillTeams(vector< pair<wstring, s
tn = dashes + it->getName(); tn = dashes + it->getName();
} }
if (it->Class) if (it->Class)
out.push_back(make_pair(tn + L" (" + it->getClass() + L")", it->Id)); out.push_back(make_pair(tn + L" (" + it->getClass(true) + L")", it->Id));
else else
out.push_back(make_pair(tn, it->Id)); out.push_back(make_pair(tn, it->Id));
} }
@ -612,14 +612,14 @@ void oEvent::adjustTeamMultiRunners(pClass cls)
if (cls) { if (cls) {
bool multi = cls->getNumStages() > 1; bool multi = cls->getNumStages() > 1;
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) {
if (it->skip() || it->getClassId() != cls->getId()) if (it->skip() || it->getClassId(false) != cls->getId())
continue; continue;
if (multi && it->tInTeam == 0) { if (multi && it->tInTeam == 0) {
oe->autoAddTeam(&*it); oe->autoAddTeam(&*it);
} }
if (!multi && it->tInTeam) { if (!multi && it->tInTeam) {
assert( it->tInTeam->getClassId() == cls->getId()); assert( it->tInTeam->getClassId(false) == cls->getId());
removeTeam(it->tInTeam->getId()); removeTeam(it->tInTeam->getId());
} }
@ -628,7 +628,7 @@ void oEvent::adjustTeamMultiRunners(pClass cls)
vector<int> tr; vector<int> tr;
for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) { for (oTeamList::iterator it=Teams.begin(); it != Teams.end(); ++it) {
if (!multi && !it->isRemoved() && it->getClassId() == cls->getId()) { if (!multi && !it->isRemoved() && it->getClassId(false) == cls->getId()) {
tr.push_back(it->getId()); tr.push_back(it->getId());
} }
} }
@ -728,9 +728,9 @@ void oTeam::checkClassesWithReferences(oEvent &oe, std::set<int> &clsWithRef) {
map<int, pair<int, int> > pairedUnpairedPerClass; map<int, pair<int, int> > pairedUnpairedPerClass;
for (size_t k = 0; k < r.size(); k++) { for (size_t k = 0; k < r.size(); k++) {
if (r[k]->getReference()) if (r[k]->getReference())
++pairedUnpairedPerClass[r[k]->getClassId()].first; ++pairedUnpairedPerClass[r[k]->getClassId(false)].first;
else else
++pairedUnpairedPerClass[r[k]->getClassId()].second; ++pairedUnpairedPerClass[r[k]->getClassId(false)].second;
} }
for (auto &it : pairedUnpairedPerClass) { for (auto &it : pairedUnpairedPerClass) {
@ -744,8 +744,8 @@ void oTeam::convertClassWithReferenceToPatrol(oEvent &oe, const std::set<int> &c
oe.getRunners(-1, -1, r, true); oe.getRunners(-1, -1, r, true);
for(auto it : r) { for(auto it : r) {
if (clsWithRef.count(it->getClassId())) { if (clsWithRef.count(it->getClassId(false))) {
pClass cls = it->getClassRef(); pClass cls = it->getClassRef(false);
if (cls->getNumStages() == 0) { if (cls->getNumStages() == 0) {
pCourse crs = cls->getCourse(); pCourse crs = cls->getCourse();

View File

@ -45,11 +45,27 @@ class oSpeakerObject
{ {
public: public:
struct RunningTime { struct RunningTime {
void reset() { time = 0; preliminary = 0; }
int time; int time;
int preliminary; int preliminary;
RunningTime() : time(0), preliminary(0) {} RunningTime() : time(0), preliminary(0) {}
}; };
void reset() {
owner = 0;
bib.clear();
names.clear();
outgoingnames.clear();
resultRemark.clear();
club.clear();
startTimeS.clear();
status = StatusUnknown;
finishStatus = StatusUnknown;
useSinceLast = 0;
runningTime.reset();
runningTimeLeg.reset();
runningTimeSinceLast.reset();
}
oRunner *owner; oRunner *owner;
wstring bib; wstring bib;
vector<wstring> names; vector<wstring> names;

View File

@ -0,0 +1,298 @@
#include "StdAfx.h"
#include "qualification_final.h"
#include "meos_util.h"
#include "meosexception.h"
#include <set>
#include <algorithm>
#include "xmlparser.h"
pair<int, int> QualificationFinal::getNextFinal(int instance, int orderPlace, int numSharedPlaceNext) const {
pair<int, int> key(instance, orderPlace);
int iter = 0;
while (numSharedPlaceNext >= 0) {
auto res = sourcePlaceToFinalOrder.find(key);
if (res != sourcePlaceToFinalOrder.end()) {
if (iter >= 2) { // For three in a shared last place
pair<int, int> key2 = key;
int extraSub = ((iter + 1) % 2);
key2.second -= extraSub;
auto res2 = sourcePlaceToFinalOrder.find(key2);
if (res2 != sourcePlaceToFinalOrder.end()) {
auto ans = res2->second;
ans.second += iter + extraSub;
return ans;
}
}
auto ans = res->second;
ans.second += iter;
return ans;
}
--key.second;
--numSharedPlaceNext;
++iter;
}
return make_pair(0, -1);
}
bool QualificationFinal::noQualification(int instance) const {
if (size_t(instance) >= classDefinition.size())
return false;
return classDefinition[instance].qualificationMap.empty() &&
classDefinition[instance].timeQualifications.empty();
}
void QualificationFinal::getBaseClassInstances(set<int> &base) const {
for (size_t k = 0; k < classDefinition.size(); k++) {
if (noQualification(k))
base.insert(k+1);
else break;
}
}
void QualificationFinal::import(const wstring &file) {
xmlparser xml;
xml.read(file);
auto qr = xml.getObject("QualificationRules");
xmlList levels;
qr.getObjects("Level", levels);
map<int, int> idToIndex;
map<int, set<int> > qualificationRelations;
int numBaseLevels = 0;
int iLevel = 0;
for (size_t iLevel = 0; iLevel < levels.size(); iLevel++) {
auto &level = levels[iLevel];
xmlList classes;
level.getObjects("Class", classes);
for (auto &cls : classes) {
wstring name;
cls.getObjectString("Name", name);
if (name.empty())
throw meosException("Klassen måste ha ett namn.");
int classId = cls.getObjectInt("id");
if (!(classId>0))
throw meosException("Id must be a positive integer.");
if (idToIndex.count(classId))
throw meosException("Duplicate class with id " + itos(classId));
xmlList rules;
cls.getObjects("Qualification", rules);
if (rules.empty())
numBaseLevels = 1; // Instance zero is not used as qualification,
idToIndex[classId] = classDefinition.size() + numBaseLevels;
classDefinition.push_back(Class());
classDefinition.back().name = name;
for (auto &qf : rules) {
int place = qf.getObjectInt("place");
if (place > 0) {
int id = qf.getObjectInt("id");
if (id == 0 && iLevel == 0)
classDefinition.back().qualificationMap.push_back(make_pair(0, place));
else if (idToIndex.count(id)) {
classDefinition.back().qualificationMap.push_back(make_pair(idToIndex[id], place));
qualificationRelations[classId].insert(id);
}
else
throw meosException("Unknown class with id " + itos(id));
}
else {
string time;
qf.getObjectString("place", time);
if (time == "time") {
string ids;
qf.getObjectString("id", ids);
vector<string> vid;
split(ids, ",;", vid);
vector<int> ivid;
for (auto &s : vid) {
int i = atoi(s.c_str());
if (!idToIndex.count(i))
throw meosException("Unknown class with id " + itos(i));
ivid.push_back(idToIndex[i]);
}
if (ivid.empty())
throw meosException(L"Empty time qualification for " + name);
classDefinition.back().timeQualifications.push_back(ivid);
}
else throw meosException("Unknown classification rule " + time);
}
}
}
}
/*classDefinition.resize(3);
classDefinition[0].name = L"Semi A";
classDefinition[1].name = L"Semi B";
classDefinition[2].name = L"Final";
for (int i = 0; i < 4; i++) {
classDefinition[0].qualificationMap.push_back(make_pair(0, i * 2 + 1));
classDefinition[1].qualificationMap.push_back(make_pair(0, i * 2 + 2));
classDefinition[2].qualificationMap.push_back(make_pair(i%2+1, i/2 + 1));
}
*/
initgmap(true);
}
void QualificationFinal::init(const wstring &def) {
vector <wstring> races, rtdef, rdef;
split(def, L"|", races);
classDefinition.resize(races.size());
bool valid = true;
bool first = true;
for (size_t k = 0; k < races.size(); k++) {
split(races[k], L"T", rtdef);
classDefinition[k].qualificationMap.clear();
classDefinition[k].timeQualifications.clear();
if (first && rtdef.empty())
continue;
valid = rtdef.size() > 0;
if (!valid)
break;
first = false;
split(rtdef[0], L";", rdef);
valid = rdef.size() > 0 && rdef.size()%2 == 0;
if (!valid)
break;
for (size_t j = 0; j < rdef.size(); j+=2) {
size_t src = _wtoi(rdef[j].c_str());
if (src > k) {
valid = false;
break;
}
const wstring &rd = rdef[j + 1];
size_t d1 = _wtoi(rd.c_str());
size_t d2 = d1;
size_t range = rd.find_first_of('-', 0);
if (range < rd.size())
d2 = _wtoi(rd.c_str()+range+1);
if (d1 > d2) {
valid = false;
break;
}
while (d1 <= d2) {
classDefinition[k].qualificationMap.push_back(make_pair(int(src), int(d1)));
d1++;
}
}
for (size_t i = 1; valid && i < rtdef.size(); i++) {
split(rtdef[i], L";", rdef);
classDefinition[k].timeQualifications.push_back(vector<int>());
for (size_t j = 0; valid && j < rdef.size(); j += 2) {
size_t src = _wtoi(rdef[j].c_str());
if (src > k) {
valid = false;
break;
}
classDefinition[k].timeQualifications.back().push_back(src);
}
}
}
if (!valid)
classDefinition.clear();
initgmap(false);
}
void QualificationFinal::encode(wstring &output) const {
output.clear();
for (size_t k = 0; k < classDefinition.size(); k++) {
if (k > 0)
output.append(L"|");
auto &qm = classDefinition[k].qualificationMap;
for (size_t j = 0; j < qm.size(); j++) {
if (j > 0)
output.append(L";");
size_t i = j;
while ((i + 1) < qm.size() && qm[i + 1].first == qm[i].first
&& qm[i + 1].second == qm[i].second+1) {
i++;
}
output.append(itow(qm[j].first) + L";");
if (i <= j + 1) {
output.append(itow(qm[j].second));
}
else {
output.append(itow(qm[j].second) + L"-" + itow(qm[i].second));
j = i;
}
}
auto &tqm = classDefinition[k].timeQualifications;
for (auto &source : tqm) {
output.append(L"T");
for (size_t i = 0; i < source.size(); i++) {
if (i > 0)
output.append(L";");
output.append(itow(source[i]));
}
}
}
}
int QualificationFinal::getNumStages(int stage) const {
if (stage == 0 || classDefinition[stage-1].qualificationMap.empty())
return 1;
set<int> races;
for (auto &qm : classDefinition[stage - 1].qualificationMap) {
if (qm.first == stage)
throw meosException("Invalid qualification scheme");
races.insert(qm.first);
}
int def = 0;
for (int r : races)
def = max(def, 1 + getNumStages(r));
return def;
}
void QualificationFinal::initgmap(bool check) {
sourcePlaceToFinalOrder.clear();
for (int ix = 0; ix < (int)classDefinition.size(); ix++) {
auto &c = classDefinition[ix];
for (int k = 0; k < (int)c.qualificationMap.size(); k++) {
const pair<int, int> &sd = c.qualificationMap[k];
if (check && sourcePlaceToFinalOrder.count(sd))
throw meosException(L"Inconsistent qualification rule, X#" + c.name + + L"/" + itow(sd.first));
sourcePlaceToFinalOrder[sd] = make_pair(ix+1, k);
}
}
}
int QualificationFinal::getHeatFromClass(int finalClassId, int baseClassId) const {
if (baseClassId == baseId) {
int fci = (finalClassId - baseId) / maxClassId;
if (fci * maxClassId + baseClassId == finalClassId)
return fci;
}
return 0;
}

View File

@ -0,0 +1,84 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "stdafx.h"
#include <vector>
#include <map>
#include <set>
class QualificationFinal {
private:
int maxClassId;
int baseId;
struct Class {
wstring name;
vector< pair<int, int> > qualificationMap;
vector< vector<int> > timeQualifications;
};
vector<Class> classDefinition;
map<pair<int, int>, pair<int, int>> sourcePlaceToFinalOrder;
void initgmap(bool check);
// Recursive implementation
int getNumStages(int stage) const;
public:
QualificationFinal(int maxClassId, int baseId) : maxClassId(maxClassId), baseId(baseId) {}
int getNumClasses() const {
return classDefinition.size();
}
const wstring getInstanceName(int inst) {
return classDefinition.at(inst-1).name;
}
// Count number of stages
int getNumStages() const {
return getNumStages(classDefinition.size());
}
int getHeatFromClass(int finalClassId, int baseClassId) const;
void import(const wstring &file);
void init(const wstring &def);
void encode(wstring &output) const;
/** Retuns the final class and the order within that class. */
pair<int,int> getNextFinal(int instance, int orderPlace, int numSharedPlaceNext) const;
/** Returns true if all competitors are automatically qualified*/
bool noQualification(int instance) const;
/** Fills in the set of no-qualification classes*/
void getBaseClassInstances(set<int> &base) const;
};

View File

@ -10,6 +10,8 @@
#define IDI_SMALL 108 #define IDI_SMALL 108
#define IDC_MEOS 109 #define IDC_MEOS 109
#define IDR_MAINFRAME 128 #define IDR_MAINFRAME 128
#define IDB_ECO 131
#define IDR_HTML1 132
#define IDC_STATIC -1 #define IDC_STATIC -1
// Next default values for new objects // Next default values for new objects
@ -17,7 +19,7 @@
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1 #define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_RESOURCE_VALUE 133
#define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 110 #define _APS_NEXT_SYMED_VALUE 110

View File

@ -31,11 +31,14 @@ Eksoppsv
#include "infoserver.h" #include "infoserver.h"
#include <chrono> #include <chrono>
#include "oListInfo.h"
#include "TabList.h"
#include "generalresult.h"
using namespace restbed; using namespace restbed;
vector< shared_ptr<RestServer> > RestServer::startedServers; vector< shared_ptr<RestServer> > RestServer::startedServers;
shared_ptr<RestServer> RestServer::construct() { shared_ptr<RestServer> RestServer::construct() {
shared_ptr<RestServer> obj(new RestServer()); shared_ptr<RestServer> obj(new RestServer());
startedServers.push_back(obj); startedServers.push_back(obj);
@ -43,7 +46,13 @@ shared_ptr<RestServer> RestServer::construct() {
} }
void RestServer::remove(shared_ptr<RestServer> server) { void RestServer::remove(shared_ptr<RestServer> server) {
// xxx std::remove(startedServers.begin(), startedServers.end(), server); //std::remove(startedServers.begin(), startedServers.end(), server);
for (size_t k = 0; k < startedServers.size(); k++) {
if (startedServers[k] == server) {
startedServers.erase(startedServers.begin() + k);
break;
}
}
} }
RestServer::RestServer() : hasAnyRequest(false) { RestServer::RestServer() : hasAnyRequest(false) {
@ -142,21 +151,18 @@ void RestServer::compute(oEvent &ref) {
auto rq = getRequest(); auto rq = getRequest();
if (!rq) if (!rq)
return; return;
if (rq->parameters.empty()) {
rq->answer = "<html><head>" try {
"<title>MeOS Information Service</title>" computeInternal(ref, rq);
"</head>"
"<body>"
"<h2>MeOS</h2>"
"</body>"
"</html>";
} }
else if (rq->parameters.count("get") > 0) { catch (meosException &ex) {
string what = rq->parameters.find("get")->second; rq->answer = "Error (MeOS): Error: " + ref.gdiBase().toUTF8(lang.tl(ex.wwhat()));
getData(ref, what, rq->parameters, rq->answer);
} }
else { catch (std::exception &ex) {
rq->answer = "Error (MeOS): Unknown request"; rq->answer = "Error (MeOS): General Error: " + string(ex.what());
}
catch (...) {
rq->answer = "Error (MeOS): Unknown internal error.";
} }
{ {
@ -166,39 +172,594 @@ void RestServer::compute(oEvent &ref) {
waitForCompletion.notify_all(); waitForCompletion.notify_all();
} }
void RestServer::computeInternal(oEvent &ref, shared_ptr<RestServer::EventRequest> &rq) {
if (rq->parameters.empty()) {
rq->answer = "<html><head>"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset = UTF-8\">"
"<title>MeOS Information Service</title>"
"</head>"
"<body>"
"<h2>MeOS</h2><p>" + ref.gdiBase().toUTF8(lang.tl(getMeosFullVersion())) + "<p>"
"<ul>\n";
vector<oListParam> lists;
TabList::getPublicLists(ref, lists);
map<EStdListType, oListInfo> listMap;
ref.getListTypes(listMap, false);
for (auto &lp : lists) {
wstring n = lp.getName();
if (n.empty()) {
n = listMap[lp.listCode].getName();
}
lp.setName(n);
int keyCand = lp.listCode * 100;
bool done = false;
for (int i = 0; i < 100; i++) {
if (!listCache.count(keyCand + i)) {
keyCand += i;
listCache[keyCand].first = lp;
done = true;
break;
}
else if(listCache[keyCand + i].first == lp) {
keyCand = keyCand + i;
done = true;
break;
}
}
if (!done) {
listCache[keyCand].first = lp;
listCache[keyCand].second.reset();
}
rq->answer += "<li><a href=\"?html=1&type=" + itos(keyCand) + "\">" + ref.gdiBase().toUTF8(n) + "</a></li>\n";
}
// "<li><a href=\"?html=1&result=1\">Resultat</a></li>"
// "<li><a href=\"?html=1&startlist=1\">Startlista</a></li>"
rq->answer += "</ul>\n";
HINSTANCE hInst = GetModuleHandle(0);
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(132), RT_HTML);
HGLOBAL res = LoadResource(hInst, hRes);
char *html = (char *)LockResource(res);
int resSize = SizeofResource(hInst, hRes);
if (html) {
string htmlS;
while (*html != 0 && resSize > 0) {
if (*html == '*')
htmlS += "&lt;";
else if (*html == '#')
htmlS += "&amp;";
else
htmlS += *html;
++html;
resSize--;
}
rq->answer += htmlS;
}
rq->answer += "\n</body></html>\n";
}
else if (rq->parameters.count("get") > 0) {
string what = rq->parameters.find("get")->second;
getData(ref, what, rq->parameters, rq->answer);
}
else if (rq->parameters.count("html") > 0) {
string stype = rq->parameters.count("type") ? rq->parameters.find("type")->second : _EmptyString;
int type = atoi(stype.c_str());
auto res = listCache.find(type);
if (res != listCache.end()) {
gdioutput gdiPrint("print", ref.gdiBase().getScale(), ref.gdiBase().getCP());
gdiPrint.clearPage(false);
if (!res->second.second) {
res->second.second = make_shared<oListInfo>();
ref.generateListInfo(res->second.first, gdiPrint.getLineHeight(), *res->second.second);
}
ref.generateList(gdiPrint, true, *res->second.second, false);
wstring exportFile = getTempFile();
gdiPrint.writeHTML(exportFile, ref.getName(), 30);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
rq->answer += rbf;
}
removeTempFile(exportFile);
}
else {
rq->answer = "Error (MeOS): Unknown list";
}
}
else {
rq->answer = "Error (MeOS): Unknown request";
}
}
void writePerson(const GeneralResult::GeneralResultInfo &res,
xmlbuffer &reslist,
bool includeTeam,
bool includeCourse,
vector< pair<string, wstring> > &rProp) {
int clsId = res.src->getClassId(true);
rProp.push_back(make_pair("cls", itow(clsId)));
if (includeCourse) {
pRunner pr = dynamic_cast<pRunner>(res.src);
if (pr && pr->getCourse(false))
rProp.push_back(make_pair("course", itow(pr->getCourse(false)->getId())));
}
bool hasTeam = res.src->getTeam() != 0 &&
clsId == res.src->getClassId(false) && // No Qualification/Final
(clsId == 0 || res.src->getClassRef(false)->getQualificationFinal() == 0); // // No Qualification/Final
if (includeTeam && hasTeam)
rProp.push_back(make_pair("team", itow(res.src->getTeam()->getId())));
if (hasTeam)
rProp.push_back(make_pair("leg", itow(1+pRunner(res.src)->getLegNumber())));
rProp.push_back(make_pair("stat", itow(res.status)));
if (res.score > 0)
rProp.push_back(make_pair("score", itow(res.score)));
rProp.push_back(make_pair("st", itow(10 * (res.src->getStartTime() + res.src->getEvent()->getZeroTimeNum()))));
if (res.src->getClassRef(false) == 0 || !res.src->getClassRef(true)->getNoTiming()) {
if (res.time > 0)
rProp.push_back(make_pair("rt", itow(10 * res.time)));
if (res.place > 0)
rProp.push_back(make_pair("place", itow(res.place)));
}
auto &subTag = reslist.startTag("person", rProp);
rProp.clear();
rProp.push_back(make_pair("id", itow(res.src->getId())));
subTag.write("name", rProp, res.src->getName());
rProp.clear();
if (res.src->getClubRef()) {
rProp.push_back(make_pair("id", itow(res.src->getClubId())));
subTag.write("org", rProp, res.src->getClub());
rProp.clear();
}
subTag.endTag();
}
void RestServer::getData(oEvent &oe, const string &what, const multimap<string, string> &param, string &answer) { void RestServer::getData(oEvent &oe, const string &what, const multimap<string, string> &param, string &answer) {
xmlbuffer out; xmlbuffer out;
out.setComplete(true); out.setComplete(true);
bool okRequest = false;
if (what == "iofresult") {
wstring exportFile = getTempFile();
bool useUTC = false;
set<int> cls;
if (param.count("class") > 0)
getSelection(param.find("class")->second, cls);
if (what == "competition") { oe.exportIOFSplits(oEvent::IOF30, exportFile.c_str(), false, useUTC, cls, -1, false, false, true, false);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
answer += rbf;
}
removeTempFile(exportFile);
okRequest = true;
}
else if (what == "iofstart") {
wstring exportFile = getTempFile();
bool useUTC = false;
set<int> cls;
if (param.count("class") > 0)
getSelection(param.find("class")->second, cls);
oe.exportIOFStartlist(oEvent::IOF30, exportFile.c_str(), useUTC, cls, false, true, false);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
answer += rbf;
}
removeTempFile(exportFile);
okRequest = true;
}
else if (what == "competition") {
InfoCompetition cmp(0); InfoCompetition cmp(0);
cmp.synchronize(oe); cmp.synchronize(oe);
cmp.serialize(out, false); cmp.serialize(out, false);
okRequest = true;
} }
else if (what == "class") { else if (what == "class") {
vector<pClass> cls; vector<pClass> cls;
oe.getClasses(cls, true); oe.getClasses(cls, true);
set<int> ctrlW;
vector<pControl> ctrl;
oe.getControls(ctrl, true);
for (size_t k = 0; k < ctrl.size(); k++) {
if (ctrl[k]->isValidRadio()) {
vector<int> cc;
ctrl[k]->getCourseControls(cc);
ctrlW.insert(cc.begin(), cc.end());
}
}
for (auto c : cls) { for (auto c : cls) {
InfoClass iCls(c->getId()); InfoClass iCls(c->getId());
set<int> ctrl; iCls.synchronize(*c, ctrlW);
iCls.synchronize(*c, ctrl);
iCls.serialize(out, false); iCls.serialize(out, false);
} }
okRequest = true;
}
else if (what == "organization") {
vector<pClub> clb;
oe.getClubs(clb, true);
for (auto c : clb) {
InfoOrganization iClb(c->getId());
iClb.synchronize(*c);
iClb.serialize(out, false);
}
okRequest = true;
} }
else if (what == "competitor") { else if (what == "competitor") {
vector<pRunner> r; vector<pRunner> r;
set<int> selection; set<int> selection;
if (param.count("id") > 0) if (param.count("class") > 0)
getSelection(param.find("id")->second, selection); getSelection(param.find("class")->second, selection);
oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, true); oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, true);
{
vector<pRunner> r2;
r2.reserve(r.size());
for (pRunner tr : r) {
pClass cls = tr->getClassRef(true);
if (cls && cls->getQualificationFinal() && tr->getLegNumber() != 0)
continue;
if (selection.empty() || (cls && selection.count(cls->getId())))
r2.push_back(tr);
}
r.swap(r2);
}
for (auto c : r) { for (auto c : r) {
InfoCompetitor iR(c->getId()); InfoCompetitor iR(c->getId());
iR.synchronize(false, *c); iR.synchronize(false, *c);
iR.serialize(out, false); iR.serialize(out, false);
} }
okRequest = true;
}
else if (what == "team") {
vector<pTeam> teams;
set<int> selection;
if (param.count("class") > 0)
getSelection(param.find("class")->second, selection);
oe.getTeams(selection.size() == 1 ? *selection.begin() : 0, teams, true);
if (selection.size() > 1) {
vector<pTeam> r2;
r2.reserve(teams.size());
for (pTeam tr : teams) {
if (selection.count(tr->getClassId(false)))
r2.push_back(tr);
}
teams.swap(r2);
}
for (auto c : teams) {
InfoTeam iT(c->getId());
iT.synchronize(*c);
iT.serialize(out, false);
}
okRequest = true;
}
else if (what == "control") {
vector<pControl> ctrl;
oe.getControls(ctrl, true);
vector< pair<string, wstring> > prop(1);
prop[0].first = "id";
for (pControl c : ctrl) {
int nd = c->getNumberDuplicates();
for (int k = 0; k < nd; k++) {
prop[0].second = itow(oControl::getCourseControlIdFromIdIndex(c->getId(), k));
if (nd > 1)
out.write("control", prop, c->getName() + L"-" + itow(k+1));
else
out.write("control", prop, c->getName());
}
}
okRequest = true;
}
else if (what == "result") {
okRequest = true;
vector<pRunner> r;
set<int> selection;
pClass sampleClass = 0;
if (param.count("class") > 0) {
getSelection(param.find("class")->second, selection);
if (!selection.empty())
sampleClass = oe.getClass(*selection.begin());
}
if (sampleClass == 0) {
vector<pClass> tt;
oe.getClasses(tt, false);
if (!tt.empty())
sampleClass = tt[0];
}
string resTag;
if (param.count("module") > 0)
resTag = param.find("module")->second;
pair<int,int> controlId(oPunch::PunchStart, oPunch::PunchFinish);
bool totalResult = false;
if (param.count("total")) {
const string &tot = param.find("total")->second;
totalResult = atoi(tot.c_str()) > 0 || _stricmp(tot.c_str(), "true") == 0;
}
if (param.count("to")) {
const string &cid = param.find("to")->second;
controlId.second = atoi(cid.c_str());
if (controlId.second == 0)
controlId.second = oControl::getControlIdByName(oe, cid);
if (controlId.second == 0)
throw meosException("Unknown control: " + cid);
}
if (param.count("from")) {
const string &cid = param.find("from")->second;
controlId.first = atoi(cid.c_str());
if (controlId.first == 0)
controlId.first = oControl::getControlIdByName(oe, cid);
if (controlId.first == 0)
throw meosException("Unknown control: " + cid);
}
oListInfo::ResultType resType = oListInfo::Classwise;
wstring resTypeStr = L"classindividual";
ClassType ct = sampleClass ? sampleClass->getClassType() : ClassType::oClassIndividual;
bool team = ct == oClassPatrol || ct == oClassRelay;
int limit = 100000;
if (param.count("limit")) {
limit = atoi(param.find("limit")->second.c_str());
if (limit <= 0)
throw meosException("Invalid limit: " + param.find("limit")->second);
}
if (param.count("type")) {
string type = param.find("type")->second;
if (type == "GlobalIndividual") {
resType = oListInfo::Global;
team = false;
}
else if (type == "ClassIndividual") {
resType = oListInfo::Classwise;
team = false;
}
else if (type == "CourseIndividual") {
resType = oListInfo::Coursewise;
team = false;
}
else if (type == "LegIndividual") {
resType = oListInfo::Legwise;
team = false;
}
else if (type == "GlobalTeam") {
resType = oListInfo::Global;
team = true;
}
else if (type == "ClassTeam") {
resType = oListInfo::Classwise;
team = true;
}
else
throw meosException("Unknown type: " + type);
string2Wide(type, resTypeStr);
resTypeStr = canonizeName(resTypeStr.c_str());
}
else if (team) {
resTypeStr = L"classteam";
}
int inputNumber = 0;
if (param.count("argument")) {
const string &arg = param.find("argument")->second;
inputNumber = atoi(arg.c_str());
}
vector<GeneralResult::GeneralResultInfo> results;
vector< pair<string, wstring> > prop, noProp, rProp;
prop.push_back(make_pair("type", resTypeStr));
int leg = -1;
if (param.count("leg") > 0) {
string legs = param.find("leg")->second;
leg = atoi(legs.c_str())-1;
if (leg < 0 || leg > 32)
throw meosException("Invalid leg: " + legs);
}
if (ct == oClassRelay) {
if (leg == -1)
prop.push_back(make_pair("leg", L"Last"));
else
prop.push_back(make_pair("leg", itow(leg + 1)));
}
if (!resTag.empty())
prop.push_back(make_pair("module", oe.gdiBase().widen(resTag) + L"(" + itow(inputNumber) + L")"));
if (controlId.first != oPunch::PunchStart) {
pair<int, int> idIx = oControl::getIdIndexFromCourseControlId(controlId.first);
pControl ctrl = oe.getControl(idIx.first);
if (ctrl == 0)
throw meosException("Unknown control: " + itos(idIx.first));
wstring loc = ctrl->getName();
if (idIx.second > 0)
loc += L"-" + itow(idIx.second + 1);
prop.push_back(make_pair("from", loc));
}
if (controlId.second == oPunch::PunchFinish)
prop.push_back(make_pair("to", L"Finish"));
else {
pair<int, int> idIx = oControl::getIdIndexFromCourseControlId(controlId.second);
pControl ctrl = oe.getControl(idIx.first);
if (ctrl == 0)
throw meosException("Unknown control: " + itos(idIx.first));
wstring loc = ctrl->getName();
if (idIx.second > 0)
loc += L"-" + itow(idIx.second+1);
prop.push_back(make_pair("to", loc));
}
if (!team) {
oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, false);
{
vector<pRunner> r2;
r2.reserve(r.size());
for (pRunner tr : r) {
pClass cls = tr->getClassRef(true);
if (cls && cls->getQualificationFinal() && tr->getLegNumber() != 0)
continue;
if (selection.empty() || (cls && selection.count(cls->getId())))
r2.push_back(tr);
}
r.swap(r2);
}
GeneralResult::calculateIndividualResults(r, controlId, totalResult, resTag, resType, inputNumber, oe, results);
if (resType == oListInfo::Classwise)
sort(results.begin(), results.end());
/*else if (resType == oListInfo::Coursewise) {
sort(results.begin(), results.end(),
[](const GeneralResult::GeneralResultInfo &a, const GeneralResult::GeneralResultInfo &b)->
bool {
pCourse ac = dynamic_cast<const oRunner &>(*a.src).getCourse(false);
pCourse bc = dynamic_cast<const oRunner &>(*b.src).getCourse(false);
if (ac != bc)
return ac->getId() < bc->getId();
return a.compareResult(b);
}
);
}*/
auto &reslist = out.startTag("results", prop);
int place = -1;
int cClass = -1;
int counter = 0;
for (const auto &res : results) {
if (res.src->getClassId(true) != cClass) {
counter = 0;
place = 1;
cClass = res.src->getClassId(true);
}
if (++counter > limit && (place != res.place || res.status != StatusOK))
continue;
place = res.place;
writePerson(res, reslist, true, resType == oListInfo::Coursewise, rProp);
}
reslist.endTag();
}
else {
//Teams
vector<pTeam> teams;
oe.getTeams(selection.size() == 1 ? *selection.begin() : 0, teams, true);
if (selection.size() > 1) {
vector<pTeam> r2;
r2.reserve(teams.size());
for (pTeam tr : teams) {
if (selection.count(tr->getClassId(true)))
r2.push_back(tr);
}
teams.swap(r2);
}
auto context = GeneralResult::calculateTeamResults(teams, leg, controlId, totalResult, resTag, resType, inputNumber, oe, results);
sort(results.begin(), results.end());
auto &reslist = out.startTag("results", prop);
int place = -1;
int cClass = -1;
int counter = 0;
for (const auto &res : results) {
pTeam team = pTeam(res.src);
if (leg >= team->getNumRunners())
continue;
if (res.src->getClassId(true) != cClass) {
counter = 0;
place = 1;
cClass = res.src->getClassId(true);
}
if (++counter > limit && (place != res.place || res.status != StatusOK))
continue;
place = res.place;
rProp.push_back(make_pair("cls", itow(res.src->getClassId(true))));
rProp.push_back(make_pair("stat", itow(res.status)));
if (res.score > 0)
rProp.push_back(make_pair("score", itow(res.score)));
if (res.src->getStartTime() > 0)
rProp.push_back(make_pair("st", itow(10 * (res.src->getStartTime() + oe.getZeroTimeNum()))));
if (res.src->getClassRef(false) == 0 || !res.src->getClassRef(true)->getNoTiming()) {
if (res.time > 0)
rProp.push_back(make_pair("rt", itow(10 * res.time)));
if (res.place > 0)
rProp.push_back(make_pair("place", itow(res.place)));
}
auto &subTag = reslist.startTag("team", rProp);
rProp.clear();
rProp.push_back(make_pair("id", itow(res.src->getId())));
subTag.write("name", rProp, res.src->getName());
rProp.clear();
if (res.src->getClubRef()) {
rProp.push_back(make_pair("id", itow(res.src->getClubId())));
subTag.write("org", rProp, res.src->getClub());
rProp.clear();
}
int subRes = res.getNumSubresult(*context);
GeneralResult::GeneralResultInfo out;
for (int k = 0; k < subRes; k++) {
if (res.getSubResult(*context, k, out)) {
writePerson(out, subTag, false, false, rProp);
}
}
subTag.endTag();
}
reslist.endTag();
}
} }
if (out.size() > 0) { if (out.size() > 0) {
xmlparser mem; xmlparser mem;
@ -208,7 +769,7 @@ void RestServer::getData(oEvent &oe, const string &what, const multimap<string,
mem.endTag(); mem.endTag();
mem.getMemoryOutput(answer); mem.getMemoryOutput(answer);
} }
else { else if (!okRequest) {
answer = "Error (MeOS): Unknown command '" + what + "'"; answer = "Error (MeOS): Unknown command '" + what + "'";
} }
} }

View File

@ -75,6 +75,11 @@ private:
RestServer(const RestServer &); RestServer(const RestServer &);
RestServer & operator=(const RestServer &) const; RestServer & operator=(const RestServer &) const;
void computeInternal(oEvent &ref, shared_ptr<RestServer::EventRequest> &rq);
map<int, pair<oListParam, shared_ptr<oListInfo> > > listCache;
public: public:
~RestServer(); ~RestServer();

View File

@ -194,7 +194,7 @@ void SpeakerMonitor::renderResult(gdioutput &gdi,
int dx = 0; int dx = 0;
if (showClass) { if (showClass) {
pClass pc = res.r->getClassRef(); pClass pc = res.r->getClassRef(true);
if (pc) { if (pc) {
gdi.addStringUT(yp, xp + timeWidth, fontMediumPlus, pc->getName()); gdi.addStringUT(yp, xp + timeWidth, fontMediumPlus, pc->getName());
dx = classWidth; dx = classWidth;
@ -243,7 +243,7 @@ void SpeakerMonitor::renderResult(gdioutput &gdi,
} }
else { else {
if (showClass) { if (showClass) {
pClass pc = res.r->getClassRef(); pClass pc = res.r->getClassRef(true);
if (pc) if (pc)
msg += L" (" + pc->getName() + L") "; msg += L" (" + pc->getName() + L") ";
else else
@ -412,7 +412,7 @@ wstring getTimeDesc(int t1, int t2) {
void SpeakerMonitor::getMessage(const oEvent::ResultEvent &res, void SpeakerMonitor::getMessage(const oEvent::ResultEvent &res,
wstring &message, deque<wstring> &details) { wstring &message, deque<wstring> &details) {
pClass cls = res.r->getClassRef(); pClass cls = res.r->getClassRef(true);
if (!cls) if (!cls)
return; return;
@ -605,10 +605,10 @@ void SpeakerMonitor::getMessage(const oEvent::ResultEvent &res,
details.push_back(share); details.push_back(share);
} }
} }
if (changeover && res.r->getTeam() && res.r->getTeam()->getClassRef() != 0) { if (changeover && res.r->getTeam() && res.r->getTeam()->getClassRef(true) != 0) {
wstring vxl = L"skickar ut X.#"; wstring vxl = L"skickar ut X.#";
pTeam t = res.r->getTeam(); pTeam t = res.r->getTeam();
pClass cls = t->getClassRef(); pClass cls = t->getClassRef(true);
bool second = false; bool second = false;
int nextLeg = cls->getNextBaseLeg(res.r->getLegNumber()); int nextLeg = cls->getNextBaseLeg(res.r->getLegNumber());
if (nextLeg > 0) { if (nextLeg > 0) {

View File

@ -2279,3 +2279,19 @@ ask:updatetimes = Vill du behålla nuvarande starttider, om möjligt? Svara nej
X har en tid (Y) som inte är kompatibel med förändringen = X har en tid (Y) som inte är kompatibel med förändringen X har en tid (Y) som inte är kompatibel med förändringen = X har en tid (Y) som inte är kompatibel med förändringen
warn:latestarttime = Att använda starttider mer än X timmar efter nolltiden rekommenderas inte eftersom äldre SI brickor endast har en 12-timmarsklocka.\n\nVill du ändå använda starttiden? warn:latestarttime = Att använda starttider mer än X timmar efter nolltiden rekommenderas inte eftersom äldre SI brickor endast har en 12-timmarsklocka.\n\nVill du ändå använda starttiden?
Anm. tid = Anm. tid Anm. tid = Anm. tid
Ekonomihantering, X = Ekonomihantering, X
Manuellt gjorda justeringar = Manuellt gjorda justeringar
Antal förfrågningar: X = Antal förfrågningar: X
Genomsnittlig svarstid: X ms = Genomsnittlig svarstid: X ms
Informationsserver = Informationsserver
Längsta svarstid: X ms = Längsta svarstid: X ms
MeOS Informationsserver REST-API = MeOS Informationsserver REST-API
RestService = RestService
Server startad på port X = Server startad på port X
Testa servern = Testa servern
help:rest = MeOS REST API låter dig komma åt tävlingsdata via en webbanslutning. Du kan visa resultatlistor direkt i en webbläsare, men du kan också komma åt tävlingsdata och resultat i XML-format för vidare behandling andra program och appar.
Server startad på X = Server startad på X
Inconsistent qualification rule, X = Inkonsekvent kvalifikationsregel, X
help:LockStartList = MeOS uppdaterar inte löparna i en låst klass även om kvalificeringsresultaten ändras.
Kval-Final-Schema = Kval-Final-Schema
Lås startlista = Lås startlista