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 "meos_util.h"
#include "restserver.h"
#include "meosexception.h"
#include <ShellAPI.h>
int AutomaticCB(gdioutput *gdi, int type, void *data);
RestService::RestService() : AutoMachine("RestService"), port(-1) {
RestService::RestService() : AutoMachine("Informationsserver"), port(-1) {
}
RestService::~RestService() {
if (server) {
server->stop();
@ -17,14 +19,17 @@ RestService::~RestService() {
}
void RestService::save(oEvent &oe, gdioutput &gdi) {
if (!server)
if (!server) {
server = RestServer::construct();
int port = gdi.getTextNo("Port");
if (port > 0 && port < 65536)
int xport = gdi.getTextNo("Port");
if (xport > 0 && xport < 65536) {
port = xport;
server->startService(port);
}
else
throw std::exception("Invalid port number");
throw meosException("Invalid port number");
}
}
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"");
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
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) {
gdi.pushX();
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) {
gdi.addString("", 0, "Server startad på port X#" + itos(port));
gdi.addString("", 0, "Server startad på X#" + itos(port));
RestServer::Statistics rs;
server->getStatistics(rs);
gdi.addString("", 0, "Antal förfrågningar: X#" + itos(rs.numRequests));
gdi.addString("", 0, "Genomsnittlig svarstid: X ms#" + itos(rs.averageResponseTime));
gdi.addString("", 0, "Längsta svarstid: X ms#" + itos(rs.maxResponseTime));
gdi.addString("", 0, "Antal förfrågningar: X.#" + itos(rs.numRequests));
gdi.addString("", 0, "Genomsnittlig svarstid: X ms.#" + itos(rs.averageResponseTime));
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);
@ -87,6 +84,12 @@ void RestService::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
void RestService::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
if (type == GUI_BUTTON) {
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 <crtdbg.h>
#include <memory.h>
#include <memory>
#include <tchar.h>
#include <string>
#include <fstream>
#include <list>
#include <crtdbg.h>
using namespace std;
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)
gdi.addInput("Interval", intervalIn, 7, 0, L"Tidsintervall (sekunder):");
gdi.dropLine(1);
gdi.addButton(startCommand, "Starta automaten", AutomaticCB).setExtra(getId());
gdi.addButton(created ? "Stop":"Cancel", "Avbryt", AutomaticCB).setExtra(getId());
gdi.addButton(startCommand, created ? "Starta automaten" : "OK", 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.fillDown();

View File

@ -1325,6 +1325,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
return false;
DWORD cid=ClassId;
pClass pc = oe->getClass(cid);
DrawMethod method = DrawMethod(gdi.getSelectedItem("Method").first);
int interval = 0;
@ -1339,6 +1340,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (gdi.hasField("Leg")) {
leg = gdi.getSelectedItem("Leg").first;
}
else if (pc && pc->getParentClass() != 0)
leg = -1;
wstring bib;
bool doBibs = false;
@ -1536,6 +1539,19 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
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") {
save(gdi, true);
if (!checkClassSelected(gdi))
@ -1572,7 +1588,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.selectItemByData("BibSettings", bt);
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("Samma"), BibSame));
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);
pair<int, bool> teamBib = gdi.getSelectedItem("TeamBib");
pair<int, bool> teamBib = gdi.getSelectedItem("BibTeam");
if (teamBib.second) {
pc->setBibMode(BibMode(teamBib.first));
}
pc->getDI().setString("Bib", getBibCode(bt, gdi.getText("Bib")));
pc->synchronize();
int leg = pc->getParentClass() ? -1 : 0;
if (bt == AutoBibManual) {
oe->addBib(cid, 0, gdi.getText("Bib"));
oe->addBib(cid, leg, gdi.getText("Bib"));
}
else {
oe->setBibClassGap(gdi.getTextNo("BibGap"));
@ -1644,7 +1660,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
par.selection.insert(cid);
oListInfo info;
par.listCode = EStdStartList;
par.setLegNumberCoded(0);
par.setLegNumberCoded(leg);
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateList(gdi, false, info, true);
@ -2223,6 +2239,10 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
if (gdi.hasField("DirectResult"))
gdi.check("DirectResult", false);
if (gdi.hasField("LockStartList")) {
gdi.check("LockStartList", false);
gdi.setInputStatus("LockStartList", false);
}
gdi.check("NoTiming", false);
ClassId=cid;
@ -2274,6 +2294,11 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
if (gdi.hasField("DirectResult"))
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;
if (pc->hasTrueMultiCourse()) {
@ -2344,9 +2369,10 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
pCourse pcourse = pc->getCourse();
gdi.selectItemByData("Courses", pcourse ? pcourse->getId():-2);
}
if (gdi.hasField("QualificationFinal"))
gdi.setInputStatus("QualificationFinal", pc->getParentClass() == 0);
gdi.selectItemByData("Classes", cid);
ClassId=cid;
EditChanged=false;
}
@ -2672,6 +2698,12 @@ void TabClass::save(gdioutput &gdi, bool skipReload)
pc->setDirectResult(withDirect);
}
if (gdi.hasField("LockStartList")) {
bool locked = gdi.isChecked("LockStartList");
if (pc->getParentClass())
pc->lockedClassAssignment(locked);
}
int crs = gdi.getSelectedItem("Courses").first;
if (crs==0) {
@ -2893,11 +2925,28 @@ bool TabClass::loadPage(gdioutput &gdi)
gdi.addCheckbox("DirectResult", "Resultat vid målstämpling", 0, false,
"help:DirectResult");
}
gdi.dropLine(2);
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;
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList))
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));
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces))
func.push_back(ButtonData("QualificationFinal", "Kval-Final-Schema", false));
RECT funRect;
funRect.right = gdi.getCX() - 7;
funRect.top = gdi.getCY() - 2;
@ -3216,7 +3268,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
if (method != DMSimultaneous)
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);
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
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.addItem("BibTeam" + id, bibTeamOptions);
gdi.selectItemByData("BibTeam" + id, it->getBibMode());

View File

@ -528,7 +528,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
else
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")");
if (count % 5 == 0)

View File

@ -119,13 +119,14 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
gdi.setText("Date", oe->getDate());
return 0;
}
}
bool updateTimes = newZT != oldZT && oe->getNumRunners() > 0 && gdi.ask(L"ask:updatetimes");
if (updateTimes) {
int delta = oldZT - newZT;
oe->updateStartTimes(delta);
}
}
oe->setDate(date);
oe->useLongTimes(longTimes);
oe->setName(gdi.getText("Name"));
@ -3228,7 +3229,7 @@ void TabCompetition::welcomeToMeOS(gdioutput &gdi) {
void TabCompetition::displayRunners(gdioutput &gdi, const vector<pRunner> &changedClass) const {
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")");
}
}
@ -3991,7 +3992,7 @@ void TabCompetition::checkReadyForResultExport(gdioutput &gdi, const set<int> &c
int numVacant = 0;
for (pRunner r : runners) {
if (!classFilter.empty() && !classFilter.count(r->getClassId()))
if (!classFilter.empty() && !classFilter.count(r->getClassId(false)))
continue;
if (r->isVacant())

View File

@ -601,7 +601,6 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
lastSplitState = par.showSplitTimes;
lastLargeSize = par.useLargeSize;
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
generateList(gdi);
@ -635,10 +634,8 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oListParam par;
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
getResultIndividual(par, cnf);
cnf.getIndividual(par.selection);
par.listCode = EStdResultList;
par.showInterTimes = true;
par.setLegNumberCoded(-1);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
@ -667,12 +664,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="StartIndividual") {
oe->sanityCheck(gdi, false);
oListParam par;
par.listCode = EStdStartList;
par.setLegNumberCoded(-1);
par.pageBreak = gdi.isChecked("PageBreak");
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getIndividual(par.selection);
getStartIndividual(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
@ -681,33 +676,22 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="StartClub") {
oe->sanityCheck(gdi, false);
oListParam par;
par.listCode = EStdClubStartList;
getStartClub(par);
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);
currentList.setCallback(openRunnerTeamCB);
//currentList.addList(foo);
generateList(gdi);
gdi.refresh();
}
else if (bi.id=="ResultClub") {
oe->sanityCheck(gdi, false);
oListParam par;
par.listCode = EStdClubResultList;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.setLegNumberCoded(-1);
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getIndividual(par.selection);
cnf.getPatrol(par.selection);
getResultClub(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
@ -735,12 +719,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="TeamStartList") {
oe->sanityCheck(gdi, false);
oListParam par;
par.listCode = EStdTeamStartList;
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getRelay(par.selection);
getStartTeam(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
par.setLegNumberCoded(0);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
@ -779,11 +761,10 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="PatrolStartList") {
oe->sanityCheck(gdi, false);
oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.listCode = EStdPatrolStartList;
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getPatrol(par.selection);
getStartPatrol(par, cnf);
par.pageBreak = gdi.isChecked("PageBreak");
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
@ -792,15 +773,12 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="TeamResults") {
oe->sanityCheck(gdi, true);
oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = EStdTeamResultListAll;
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
ClassConfigInfo 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);
generateList(gdi);
gdi.refresh();
@ -823,7 +801,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
int race = int(bi.getExtra());
int race = bi.getExtraInt();
par.setLegNumberCoded(race);
par.listCode = EStdIndMultiResultListLeg;
ClassConfigInfo cnf;
@ -854,13 +832,11 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="PatrolResultList") {
oe->sanityCheck(gdi, false);
oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = EStdPatrolResultList;
ClassConfigInfo 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;
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
@ -871,13 +847,11 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="RogainingResultList") {
oe->sanityCheck(gdi, true);
oListParam par;
par.pageBreak = gdi.isChecked("PageBreak");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
par.listCode = ERogainingInd;
ClassConfigInfo 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;
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,
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*/
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:
/** Returns a collection of public lists. */
void static getPublicLists(oEvent &oe, vector<oListParam> &lists);
bool loadPage(gdioutput &gdi);
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) {
if (!r) {
runnerId=0;
runnerId = 0;
gdi.setText("Name", L"");
gdi.setText("Bib", L"");
gdi.selectItemByData("RCourse", 0);
@ -158,7 +158,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.enableEditControls(true);
disablePunchCourse(gdi);
pRunner parent=r->getMultiRunner(0);
pRunner parent = r->getMultiRunner(0);
r->synchronizeAll();
//r->apply(false);
@ -172,14 +172,14 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.selectItemByData("Runners", parent->getId());
runnerId=r->getId();
runnerId = r->getId();
gdi.setText("Name", r->getNameRaw());
wstring bib = r->getBib();
if (gdi.hasField("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);
}
@ -187,10 +187,10 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
gdi.selectItemByData("RClass", r->getClassId());
gdi.selectItemByData("RClass", r->getClassId(true));
if (gdi.hasField("EditTeam")) {
gdi.setInputStatus("EditTeam", r->getTeam()!=0);
gdi.setInputStatus("EditTeam", r->getTeam() != 0);
if (r->getTeam()) {
gdi.setText("Team", r->getTeam()->getName());
@ -217,19 +217,19 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
r->getLegPlacesAcc(placeAcc);
wstring out;
for (size_t k = 0; k<delta.size(); k++) {
for (size_t k = 0; k < delta.size(); k++) {
out += itow(place[k]);
if (k<placeAcc.size())
if (k < placeAcc.size())
out += L" (" + itow(placeAcc[k]) + L")";
if (after[k]>0)
out+= L" +" + getTimeMS(after[k]);
if (after[k] > 0)
out += L" +" + getTimeMS(after[k]);
if (k<afterAcc.size() && afterAcc[k]>0)
out+= L" (+" + getTimeMS(afterAcc[k]) + L")";
if (k < afterAcc.size() && afterAcc[k]>0)
out += L" (+" + getTimeMS(afterAcc[k]) + L")";
if (delta[k]>0)
out+= L" B: " + getTimeMS(delta[k]);
if (delta[k] > 0)
out += L" B: " + getTimeMS(delta[k]);
out += L" | ";
@ -241,18 +241,18 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
#endif
if (gdi.hasField("MultiR")) {
int numMulti=parent->getNumMulti();
if (numMulti==0) {
int numMulti = parent->getNumMulti();
if (numMulti == 0) {
gdi.clearList("MultiR");
gdi.disableInput("MultiR");
lastRace=0;
lastRace = 0;
}
else {
gdi.clearList("MultiR");
gdi.enableInput("MultiR");
for (int k=0;k<numMulti+1;k++) {
gdi.addItem("MultiR", lang.tl("Lopp X#" + itos(k+1)), k);
for (int k = 0; k < numMulti + 1; k++) {
gdi.addItem("MultiR", lang.tl("Lopp X#" + itos(k + 1)), k);
}
gdi.selectItemByData("MultiR", r->getRaceNo());
}
@ -264,7 +264,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
updateNumShort(gdi, r->getCourse(false), r);
int cno = parent->getCardNo();
gdi.setText("CardNo", cno>0 ? itow(cno) : L"");
gdi.setText("CardNo", cno > 0 ? itow(cno) : L"");
warnDuplicateCard(gdi, cno, r);
@ -316,9 +316,9 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
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) {
gdi.setTabStops("Punches", 70);
@ -337,6 +337,12 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.clearList("Course");
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)
@ -579,6 +585,12 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
if (gdi.hasField("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->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.");
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.");
classId = r->getTeam()->getClassId();
classId = r->getTeam()->getClassId(false);
}
}
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>?")) {
r->resetInputData();
readStatusIn = false;
@ -635,7 +647,7 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
vector<int> mp;
r->evaluateCard(true, mp, 0, true);
if (r->getClassId() != classId) {
if (r->getClassId(true) != classId) {
gdi.alert("Deltagarens klass styrs av laget.");
}
@ -652,11 +664,14 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
r->synchronizeAll();
if (r->getClassRef() && r->getClassRef()->hasClassGlobalDependance()) {
if (r->getClassRef(false) && r->getClassRef(false)->hasClassGlobalDependence()) {
set<int> cls;
cls.insert(r->getClassId());
cls.insert(r->getClassId(false));
oe->reEvaluateAll(cls, false);
}
if (r->getClassRef(false))
r->getClassRef(false)->updateFinalClasses(r, false);
}
else
runnerId=0;
@ -938,9 +953,11 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (!runnerId)
return 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") {
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->getStartTime()>0) {
pRunner newRunner = oe->addRunnerVacant(r->getClassId());
pRunner newRunner = oe->addRunnerVacant(r->getClassId(true));
newRunner->cloneStartTime(r);
newRunner->setStartNo(r->getStartNo(), false);
if (r->getCourseId())
@ -1045,12 +1062,18 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
if (gdi.isInputChanged("")) {
pRunner r = oe->getRunner(runnerId, 0);
bool newName = r && r->getName() != gdi.getText("Name");
save(gdi, runnerId, true);
if (newName)
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) {
fillRunnerList(gdi);
@ -1193,6 +1216,10 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
}
}
else if (type==GUI_CLEAR) {
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings)
gdi_settings->closeWindow();
if (runnerId>0 && currentMode == 0)
save(gdi, runnerId, true);
@ -1202,7 +1229,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
int id = static_cast<TextInfo*>(data)->getExtraInt();
oRunner *vacancy = oe->getRunner(id, 0);
if (vacancy==0 || vacancy->getClassId()==0)
if (vacancy==0 || vacancy->getClassId(false)==0)
return -1;
pRunner r = oe->getRunner(runnerId, 0);
@ -1215,7 +1242,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
wchar_t bf[1024];
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)) {
vacancy->synchronize();
@ -1226,11 +1253,11 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
temp.setTemporary();
temp.setBib(r->getBib(), 0, false, false);
temp.setStartNo(r->getStartNo(), false);
temp.setClassId(r->getClassId(), true);
temp.setClassId(r->getClassId(true), true);
temp.apply(false, 0, false);
temp.cloneStartTime(r);
r->setClassId(vacancy->getClassId(), true);
r->setClassId(vacancy->getClassId(true), true);
// Remove or create multi runners
r->createMultiRunner(true, true);
r->apply(false, 0, false);
@ -1243,7 +1270,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
r->resetInputData();
}
vacancy->setClassId(temp.getClassId(), true);
vacancy->setClassId(temp.getClassId(true), true);
// Remove or create multi runners
vacancy->createMultiRunner(true, true);
vacancy->apply(false, 0, false);
@ -1321,7 +1348,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
int birthYear = 0;
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->setCardNo(cardNo, true);
@ -1377,7 +1404,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
// Print start certificate
tsi.generateStartInfo(gdi, *r);
showVacancyList(gdi, "", r->getClassId());
showVacancyList(gdi, "", r->getClassId(true));
}
else if (type==GUI_INPUT) {
InputInfo ii=*(InputInfo *)data;
@ -1473,7 +1500,7 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
for (size_t k = 0; k < runnersToReport.size(); k++) {
pRunner r = oe->getRunner(runnersToReport[k].first, 0);
if (r && r->getTeam()) {
pClass cls = oe->getClass(r->getClassId());
pClass cls = r->getClassRef(true);
if (cls && cls->getClassType() == oClassPatrol)
continue;
@ -1511,7 +1538,7 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
tInfo += L" " + t->getStatusS();
}
gdi.addStringUT(fontMediumPlus, t->getClass());
gdi.addStringUT(fontMediumPlus, t->getClass(true));
gdi.addStringUT(boldLarge, tInfo);
gdi.dropLine();
@ -1542,19 +1569,19 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
pRunner r = oe->getRunner(id, 0);
if (!r || ! r->getClassRef())
if (!r || ! r->getClassRef(false))
return;
gdi.pushX();
gdi.fillDown();
if (r->getTeam() == 0) {
gdi.addStringUT(fontMediumPlus, r->getClass());
gdi.addStringUT(fontMediumPlus, r->getClass(true));
gdi.addStringUT(boldLarge, r->getCompleteIdentification());
}
else {
wstring s;
if (r->getTeam())
s += r->getClassRef()->getLegNumber(r->getLegNumber());
s += r->getClassRef(false)->getLegNumber(r->getLegNumber());
s += L": " + r->getName();
gdi.addStringUT(boldText, s);
@ -1573,7 +1600,7 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
if (r->statusOK()) {
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) {
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);
gdi.addStringUT(yp, xp, 0, bf);
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);
int c = r[k]->getCardNo();
if (c>0) {
@ -2224,6 +2251,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
card->synchronize();
r->synchronize(true);
r->evaluateCard(true, mp);
r->hasManuallyUpdatedTimeStatus();
card->fillPunches(gdi, "Punches", pc);
UpdateStatus(gdi, r);
}
@ -2246,6 +2274,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
r->synchronize(true);
r->evaluateCard(true, mp);
card->fillPunches(gdi, "Punches", r->getCourse(true));
r->hasManuallyUpdatedTimeStatus();
UpdateStatus(gdi, r);
}
else if (bi.id=="SaveC"){
@ -2274,6 +2303,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data)
card->synchronize();
r->synchronize();
r->evaluateCard(true, mp);
r->hasManuallyUpdatedTimeStatus();
card->fillPunches(gdi, "Punches", r->getCourse(true));
UpdateStatus(gdi, r);
gdi.selectItemByData("Punches", lbi.data);
@ -2380,14 +2410,17 @@ bool TabRunner::loadPage(gdioutput &gdi)
}
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);
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.addInput("Fee", L"", 4, 0, L"Avgift:");
//gdi.addButton("Economy", "@" + itos(131), RunnerCB, "Ekonomi...");
gdi.dropLine();
gdi.addButton("Economy", "Ekonomi...", RunnerCB, "");
}
else {
gdi.fillDown();
@ -2652,7 +2685,7 @@ void TabRunner::fillRunnerList(gdioutput &gdi) {
}
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) {
StartTypes st = pc->getStartType(r->getLegNumber());
@ -2778,3 +2811,138 @@ void TabRunner::autoGrowCourse(gdioutput &gdi) {
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);
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:
void clearCompetitionData();
@ -104,6 +119,8 @@ public:
bool loadPage(gdioutput &gdi);
bool loadPage(gdioutput &gdi, int runnerId);
TabRunner(oEvent *oe);
~TabRunner(void);

View File

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

View File

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

View File

@ -188,7 +188,7 @@ void TabTeam::selectTeam(gdioutput &gdi, pTeam t)
gdi.enableInput("Remove");
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.selectItemByData("RClass", t->getClassId());
gdi.selectItemByData("RClass", t->getClassId(false));
gdi.selectItemByData("Teams", t->getId());
if (gdi.hasField("StatusIn")) {
@ -353,14 +353,14 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
gdi.getSelectedItem("RClass", lbi);
int classId = lbi.data;
bool newClass = t->getClassId() != classId;
bool newClass = t->getClassId(false) != classId;
set<int> classes;
bool globalDep = false;
if (t->getClassRef())
globalDep = t->getClassRef()->hasClassGlobalDependance();
if (t->getClassRef(false))
globalDep = t->getClassRef(false)->hasClassGlobalDependence();
classes.insert(classId);
classes.insert(t->getClassId());
classes.insert(t->getClassId(false));
bool readStatusIn = true;
if (newClass && t->getInputStatus() != StatusNotCompetiting && t->hasInputData()) {
@ -402,7 +402,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
pClass pc=oe->getClass(classId);
if (pc) {
globalDep |= pc->hasClassGlobalDependance();
globalDep |= pc->hasClassGlobalDependence();
for (unsigned i=0;i<pc->getNumStages(); i++) {
char bf[16];
@ -428,7 +428,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
// Same runner set
if (oldId == r->getId()) {
if (newName) {
r->updateFromDB(name, r->getClubId(), r->getClassId(),
r->updateFromDB(name, r->getClubId(), r->getClassId(false),
cardNo, 0);
r->setName(name, true);
}
@ -447,12 +447,12 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
if (!t->getClub().empty())
r->setClub(t->getClub());
r->resetPersonalData();
r->updateFromDB(name, r->getClubId(), r->getClassId(),
r->updateFromDB(name, r->getClubId(), r->getClassId(false),
cardNo, 0);
}
}
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->setCardNo(cardNo, true);
@ -594,7 +594,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "DirOK") {
pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef())
if (!t || !t->getClassRef(false))
return 0;
int leg = bi.getExtraInt();
@ -632,7 +632,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
bool rent = gdi.isChecked("DirRent");
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)
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") {
pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef())
if (!t || !t->getClassRef(false))
return 0;
pClass pc = t->getClassRef();
pClass pc = t->getClassRef(false);
gdi.restore("ChangeKey", false);
gdi.fillRight();
gdi.pushX();
@ -695,10 +695,10 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "SaveKey") {
pTeam t = oe->getTeam(teamId);
if (!t || !t->getClassRef())
if (!t || !t->getClassRef(false))
return 0;
pClass pc = t->getClassRef();
pClass pc = t->getClassRef(false);
int nf = pc->getNumForks();
ListBoxInfo lbi;
gdi.getSelectedItem("ForkKey", lbi);
@ -752,7 +752,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
pTeam t = oe->getTeam(teamId);
if (t == 0)
return 0;
pClass pc = t->getClassRef();
pClass pc = t->getClassRef(false);
if (pc == 0)
return 0;
@ -806,7 +806,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
continue;
if (clubs.count(clsR[i]->getClubId()) == 0)
continue;
if (clsR[i]->getClassId() != t->getClassId())
if (clsR[i]->getClassId(false) != t->getClassId(false))
continue;
if (clsR[i]->getName() == anon)
continue;
@ -839,7 +839,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
if (usedR.count(clsR[i]->getId()))
continue;
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())
id += L" (" + club + L")";
@ -999,7 +999,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
pc->getNumStages() == shownRunners) {
// 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()) )
loadTeamMembers(gdi, 0,0,t);
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)
{
if (ClassId==0)
if (t) ClassId=t->getClassId();
if (t) ClassId=t->getClassId(false);
classId=ClassId;
gdi.restore("",false);
@ -1696,7 +1696,7 @@ void TabTeam::doAddTeamMembers(gdioutput &gdi) {
for (size_t k = 0; k < t.size(); k++) {
pTeam mt = t[k];
pClass cls = mt->getClassRef();
pClass cls = mt->getClassRef(false);
if (cls == 0)
continue;
bool ch = false;
@ -1845,7 +1845,7 @@ void TabTeam::switchRunners(pTeam t, int leg, pRunner r, pRunner oldR) {
else if (oldR) {
t->setRunner(leg, 0, false);
t->synchronize(true);
oldR->setClassId(r->getClassId(), true);
oldR->setClassId(r->getClassId(false), true);
oldR->evaluateCard(true, mp, 0, 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) {
pc->synchronize();
if (pr->getClassId() == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass))
if (pr->getClassId(false) == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass))
pr->setClassId(pc->getId(), false);
}
}
@ -397,8 +397,8 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
course->synchronize();
}
if (course) {
if (pr->getClassId() != 0)
event.getClass(pr->getClassId())->setCourse(course);
if (pr->getClassId(false) != 0)
event.getClass(pr->getClassId(false))->setCourse(course);
else
pr->setCourseId(course->getId());
}
@ -1253,23 +1253,71 @@ void csvparser::parse(const wstring &file, list< vector<string> > &data) {
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) {
data.clear();
fin.open(file);
// const size_t bf_size = 8192;
fin.seekg(0, ios_base::end);
auto len = fin.tellg();
fin.seekg(0);
string rbf;
if (!fin.good())
throw meosException("Failed to read file");
bool isUTF8 = false;
bool isUnicode = false;
bool firstLine = true;
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;
while(std::getline(fin, rbf)) {
const char *bf = rbf.c_str();
if (firstLine) {
@ -1278,27 +1326,23 @@ void csvparser::parse(const wstring &file, list< vector<wstring> > &data) {
bf += 3;
}
else if (bf[0] == -1 && bf[1] == -2) {
isUnicode = true;
bf += 2;
fin.close();
vector<wchar_t>().swap(wbf_a);
parseUnicode(file, data);
return;
}
}
if (isUnicode) {
int len = 0;
if (bf[len] == 0 && bf[len+1] != 0)
len++;
split((wchar_t*)&bf[len], sp);
}
else if (isUTF8) {
if (isUTF8) {
int len = strlen(bf);
int wlen = MultiByteToWideChar(CP_UTF8, 0, bf, len, wbf, buff_pre_alloc);
wbf[wlen] = 0;
split(wbf, sp);
split(&wbf[0], sp);
}
else {
w = gdi_main->recodeToWide(bf);
wchar_t *wbf = const_cast<wchar_t *>(w.c_str());
split(wbf, sp);
wchar_t *wbfL = const_cast<wchar_t *>(w.c_str());
split(wbfL, sp);
}
firstLine = false;

View File

@ -99,6 +99,8 @@ protected:
map<SIConfigFields, int> siconfigmap;
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
static int selectPunchIndex(const wstring &competitionDate, const vector<wstring> &sp,
int &cardIndex, int &timeIndex, int &dateIndex,

View File

@ -2284,3 +2284,17 @@ RunnerEntryTime = Competitor's entry time
RunnerPaid = Paid amount
RunnerPayMethod = Payment method
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;
if (!hDC) {
assert(hWndTarget!=0);
// assert(hWndTarget!=0);
hDC=GetDC(hWndTarget);
}
RECT rc;

View File

@ -78,6 +78,7 @@ GeneralResult::GeneralResult(void) {
GeneralResult::~GeneralResult(void) {
}
// Needed to generate template instances
void GRINSTANCE() {
vector<oRunner *> a;
vector<oTeam *> b;
@ -86,6 +87,7 @@ void GRINSTANCE() {
gr.sort(b, SortByFinishTime);
}
void GeneralResult::setContext(const oListParam *contextIn) {
context = contextIn;
}
@ -230,8 +232,10 @@ template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const
const int maxT = 3600 * 100;
for(size_t k = 0; k < rt.size(); k++) {
arr[k].first = 0;
if (ps == ClassWise)
arr[k].first = rt[k]->getClassRef() ? rt[k]->getClassRef()->getSortIndex() : 0;
if (ps == ClassWise) {
pClass sclass = rt[k]->getClassRef(true);
arr[k].first = sclass ? sclass->getSortIndex() : 0;
}
else if (ps == CourseWise) {
oRunner *r = dynamic_cast<oRunner *>(rt[k]);
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())
return;
@ -286,7 +293,7 @@ void GeneralResult::calculateIndividualResults(vector<oRunner *> &runners, oList
int ln = r->getLegNumber();
const oTeam *pt = r->getTeam();
if (pt) {
const oClass *tcls = pt->getClassRef();
const oClass *tcls = pt->getClassRef(false);
if (tcls && tcls->getClassType() == oClassRelay) {
int 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;
}
else if (resType == oListInfo::Coursewise) {
pCourse crs = r->getCourse(false);
runnerScore[k].principalSort = crs ? crs->getId() : 0;
}
else
runnerScore[k].principalSort = 0;
@ -474,10 +485,10 @@ RunnerStatus TotalResultAtControl::deduceStatus(oRunner &runner) const {
if (runner.getTeam() && getListParamTimeFromControl() <= 0) {
// Only use input time when start time is used
const pTeam t = runner.getTeam();
if (runner.getLegNumber()>0 && t->getClassRef()) {
if (runner.getLegNumber()>0 && t->getClassRef(false)) {
// Find base leg
int legIx = runner.getLegNumber();
const pClass cls = t->getClassRef();
const pClass cls = t->getClassRef(false);
while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx)))
legIx--;
if (legIx > 0)
@ -504,10 +515,10 @@ int TotalResultAtControl::deduceTime(oRunner &runner, int startTime) const {
if (runner.getTeam() && getListParamTimeFromControl() <= 0) {
// Only use input time when start time is used
const pTeam t = runner.getTeam();
if (runner.getLegNumber()>0 && t->getClassRef()) {
if (runner.getLegNumber()>0 && t->getClassRef(false)) {
// Find base leg
int legIx = runner.getLegNumber();
const pClass cls = t->getClassRef();
const pClass cls = t->getClassRef(false);
while (legIx > 0 && (cls->isParallel(legIx) || cls->isOptional(legIx)))
legIx--;
if (legIx > 0)
@ -1125,11 +1136,10 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.addSymbol("RunnerCourse", team.getResultCache(oTeam::RCCCourse));
parser.addSymbol("RunnerSplitTimes", team.getResultCache(oTeam::RCCSplitTime));
pClass cls = team.getClassRef();
pClass cls = team.getClassRef(true);
if (cls) {
int nl = max<int>(1, cls->getNumStages()-1);
parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(nl, false));
}
}
@ -1237,7 +1247,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
parser.addSymbol("SplitTimesAccumulated", e);
}
pClass cls = runner.getClassRef();
pClass cls = runner.getClassRef(true);
if (cls) {
int nl = runner.getLegNumber();
parser.addSymbol("ShortestClassTime", cls->getBestLegTime(nl));
@ -1303,3 +1313,294 @@ void DynamicResult::debugDumpVariables(gdioutput &gdi, bool includeSymbols) cons
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};
virtual PrincipalSort getPrincipalSort() const {return ClassWise;}
virtual int score(oTeam &team, RunnerStatus st, int time, int points) const;
virtual RunnerStatus deduceStatus(oTeam &team) const;
virtual int deduceTime(oTeam &team) const;
@ -64,6 +62,82 @@ protected:
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 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;
oe.getTeams(0, t, false);
for (size_t k = 0; k < t.size(); k++) {
if (!includeCls.count(t[k]->getClassId()))
if (!includeCls.count(t[k]->getClassId(true)))
continue;
int wid = t[k]->getId();
knownId.insert(wid);
@ -228,7 +228,7 @@ bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set<int> &incl
vector<pRunner> r;
oe.getRunners(0, 0, r, false);
for (size_t k = 0; k < r.size(); k++) {
if (!includeCls.count(r[k]->getClassId()))
if (!includeCls.count(r[k]->getClassId(true)))
continue;
int wid = r[k]->getId();
knownId.insert(wid);
@ -397,7 +397,7 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
ch = true;
}
int cls = bc.getClassId();
int cls = bc.getClassId(true);
if (cls != classId) {
classId = cls;
ch = true;
@ -463,8 +463,8 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
bool ch = synchronize(useTotalResults, r);
vector<RadioTime> newRT;
if (r.getClassId() > 0) {
const vector<int> &radios = cmp.getControls(r.getClassId(), r.getLegNumber());
if (r.getClassId(false) > 0) {
const vector<int> &radios = cmp.getControls(r.getClassId(false), r.getLegNumber());
for (size_t k = 0; k < radios.size(); k++) {
RadioTime radioTime;
RunnerStatus s_split;
@ -520,7 +520,7 @@ void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
bool InfoTeam::synchronize(oTeam &t) {
bool ch = synchronizeBase(t);
const pClass cls = t.getClassRef();
const pClass cls = t.getClassRef(true);
if (cls) {
vector< vector<int> > r;

View File

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

View File

@ -335,7 +335,7 @@ void IOF30Interface::personCourseAssignment(gdioutput &gdi, xmlList &xAssignment
xPAssignment.getObjectString("ClassName", cls);
multimap<wstring, pRunner>::const_iterator res = name2Runner.find(person);
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;
break;
}
@ -386,7 +386,7 @@ void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
if (!bib.empty())
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++) {
@ -426,7 +426,7 @@ void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAssignment,
const map<wstring, pCourse> &courses) {
if (!team.getClassRef())
if (!team.getClassRef(false))
return;
for (size_t k = 0; k <xAssignment.size(); k++) {
@ -443,11 +443,11 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
if (xLegOrder)
legorder = xLegOrder.getInt() - 1;
int legId = team.getClassRef()->getLegNumberLinear(leg, legorder);
int legId = team.getClassRef(false)->getLegNumberLinear(leg, legorder);
if (legId>=0) {
pRunner r = team.getRunner(legId);
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) {
r->setEntrySource(entrySourceId);
r->flagEntryTouched(true);
@ -460,7 +460,7 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
}
}
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 {
wstring name;
@ -543,8 +543,8 @@ void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignmen
for (bibIterT it = range.first; it != range.second; ++it) {
int ln = it->second->getLegNumber();
int rLegNumber = 0, rLegOrder = 0;
if (it->second->getClassRef())
it->second->getClassRef()->splitLegNumberParallel(ln, rLegNumber, rLegOrder);
if (it->second->getClassRef(false))
it->second->getClassRef(false)->splitLegNumberParallel(ln, rLegNumber, rLegOrder);
bool match = true;
if (leg != 0 && leg != rLegNumber+1)
match = false;
@ -569,14 +569,14 @@ void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignmen
vector<pTeam> t;
oe.getTeams(0, t);
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;
}
teamIterT res = clsName2Team.find(make_pair(className, teamName));
if (res != clsName2Team.end()) {
pClass cls = res->second->getClassRef();
pClass cls = res->second->getClassRef(false);
if (cls) {
int ln = cls->getLegNumberLinear(leg, legOrder);
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;
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;
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);
}
wstring bib;
@ -1392,7 +1392,7 @@ pTeam IOF30Interface::readTeamStart(gdioutput &gdi, pClass pc, xmlobject &xTeam,
return 0;
// 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);
wstring bib;
@ -1534,7 +1534,7 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
if (cardNo > 0 && r == 0 && team) {
// 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->setEntrySource(entrySourceId);
r->synchronize();
@ -1555,21 +1555,21 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
map<int, vector<LegInfo> > 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);
if (team) {
int leg = xo.getObjectInt("Leg");
int legorder = xo.getObjectInt("LegOrder");
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()) {
legindex = getIndexFromLegPos(leg, legorder, res->second);
}
if (personId2TeamLeg.find(r->getId()) == personId2TeamLeg.end()) {
if (team->getClassRef())
legindex = team->getClassRef()->getLegRunner(legindex);
if (team->getClassRef(false))
legindex = team->getClassRef(false)->getLegRunner(legindex);
// Ensure unique
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 legorder = starts[k].getObjectInt("LegOrder");
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()) {
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->synchronize();
@ -1961,7 +1961,7 @@ void IOF30Interface::writeAssignedFee(xmlparser &xml, const oAbstractRunner &tr,
if (paid >= paidForCard) {
paid -= paidForCard; // Included in card service fee
}
const pClass pc = tr.getClassRef();
const oClass *pc = tr.getClassRef(false);
if (!splitLateFee || !pc || !tr.hasLateEntryFee()) {
xml.startTag("AssignedFee");
string type = tr.hasLateEntryFee() ? "Late" : "Normal";
@ -2476,7 +2476,6 @@ void IOF30Interface::writeClass(xmlparser &xml, const oClass &c) {
else if (stat == oClass::InvalidRefund)
xml.write("Status", L"InvalidatedNoFee");
xml.endTag();
}
@ -2537,7 +2536,7 @@ void IOF30Interface::writePersonResult(xmlparser &xml, const oRunner &r,
if (teamMember) {
oRunner const *resultHolder = &r;
cTeam t = r.getTeam();
pClass cls = r.getClassRef();
const oClass *cls = r.getClassRef(false);
if (t && cls) {
int leg = r.getLegNumber();
@ -2614,9 +2613,9 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
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) {
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()));
if ( (r.getTeam() && r.getClassRef()->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult");
int rt = r.getTotalRunningTime();
if (rt > 0)
xml.write("Time", rt);
bool hasTiming = r.getClassRef()->getNoTiming() == false;
bool hasTiming = r.getClassRef(false)->getNoTiming() == false;
RunnerStatus stat = r.getTotalStatus();
int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0;
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)
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 {
// Team member race result
int legNumber, legOrder;
const pClass pc = r.getClassRef();
const oClass *pc = r.getClassRef(false);
if (pc) {
bool par = pc->splitLegNumberParallel(r.getLegNumber(), legNumber, legOrder);
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());
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
if (pp[k]->getTypeCode() == fromPunch) {
@ -182,7 +182,7 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
if (!r)
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
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;
gSI=0;
for (size_t k = 0; k < gdi_extra.size(); k++) {
if (gdi_extra[k])
gdi_extra[k]->clearPage(false, false);
}
if (gEvent) {
try {
gEvent->save();

View File

@ -28,10 +28,29 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
//
BMP_TEST BITMAP "bitmap1.bmp"
#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
@ -48,6 +67,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// remains consistent on all systems.
IDI_MEOS ICON "meos.ICO"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
@ -160,6 +180,14 @@ BEGIN
END
END
/////////////////////////////////////////////////////////////////////////////
//
// HTML
//
IDR_HTML1 HTML "html1.htm"
#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++) {
int bchar = toLowerStripped(name[i]);
if (isspace(bchar) || bchar == '-' || bchar == 160) {
if (myIsSpace(bchar) || bchar == '-' || bchar == 160) {
if (!dec.back().empty())
dec.push_back(wstring());
continue;
@ -1823,7 +1823,7 @@ void capitalize(wstring &str) {
int getTimeZoneInfo(const wstring &date) {
static wchar_t lastDate[16] = {0};
static int lastValue = -1;
// Local cacheing
// Local caching
if (lastValue != -1 && lastDate == date) {
return lastValue;
}
@ -2161,8 +2161,14 @@ void processGeneralTime(const wstring &generalTime, wstring &meosTime, wstring &
}
void string2Wide(const string &in, wstring &out) {
out.clear();
out.insert(out.begin(), in.begin(), in.end());// XXX Simple extend
int cp = 1252;
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) {

View File

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

View File

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

View File

@ -27,9 +27,9 @@
//V2: ABCDEFGHIHJKMN
//V31: a
//V33: abcde
//V35: abc
//V35: abcde
int getMeosBuild() {
string revision("$Rev: 621 $");
string revision("$Rev: 634 $");
return 174 + atoi(revision.substr(5, string::npos).c_str());
}
@ -41,7 +41,7 @@ int getMeosBuild() {
//V33: abcdefghij
//V34: abcdfg
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);
}
@ -109,7 +109,7 @@ void getSupporters(vector<string> &supp)
supp.push_back("Oskarström OK");
supp.push_back("Skogslöparna");
supp.push_back("OK Milan");
supp.push_back("GoIF Tjalve");
supp.push_back("Tjalve IF");
supp.push_back("OK Skärmen");
supp.push_back("Østkredsen");
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("Avesta OK");
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;
Modified.update();
correctionNeeded = true;
localObject = false;
}
oBase::~oBase()
@ -68,6 +69,8 @@ bool oBase::synchronize(bool writeOnly)
}
if (oe && oe->HasDBConnection && (changed || !writeOnly)) {
correctionNeeded = false;
if (localObject)
return false;
return oe->msSynchronize(this);
}
else {
@ -79,17 +82,6 @@ bool oBase::synchronize(bool writeOnly)
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)
{
getDI().setInt64("ExtId", id);

View File

@ -75,7 +75,7 @@ private:
void resetChangeStatus() {changed &= reChanged;}
bool reChanged;
bool changed;
bool localObject;
const static unsigned long long BaseGenStringFlag = 1ull << 63;
const static unsigned long long Base36StringFlag = 1ull << 62;
const static unsigned long long ExtStringMask = ~(BaseGenStringFlag|Base36StringFlag);
@ -106,15 +106,17 @@ protected:
/** Change the id of the object */
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 */
virtual oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const = 0;
virtual int getDISize() const = 0;
void setLocalObject() { localObject = true; }
public:
// Returns true if the object is local, not stored in DB/On disc
bool isLocalObject() { return localObject; }
/// Returns textual information on the object
virtual wstring getInfo() const = 0;

View File

@ -43,6 +43,8 @@
#include "gdistructures.h"
#include "meosexception.h"
#include "random.h"
#include "qualification_final.h"
#include "generalresult.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
@ -64,6 +66,7 @@ oClass::oClass(oEvent *poe): oBase(poe)
tCoursesChanged = false;
tStatusRevision = 0;
tShowMultiDialog = false;
parentClass = 0;
}
oClass::oClass(oEvent *poe, int id): oBase(poe)
@ -73,7 +76,7 @@ oClass::oClass(oEvent *poe, int id): oBase(poe)
if (id == 0)
id = oe->getFreeClassId();
Id=id;
oe->qFreeClassId = max(id, oe->qFreeClassId);
oe->qFreeClassId = max(id % MaxClassId, oe->qFreeClassId);
tLeaderTime.resize(1);
tNoTiming = -1;
tIgnoreStartPunch = -1;
@ -85,6 +88,8 @@ oClass::oClass(oEvent *poe, int id): oBase(poe)
tCoursesChanged = false;
tStatusRevision = 0;
tShowMultiDialog = false;
parentClass = 0;
}
oClass::~oClass()
@ -359,7 +364,7 @@ int oClass::getNumRunners(bool checkFirstLeg, bool noCountVacant, bool noCountNo
oRunnerList::iterator it;
for (it=oe->Runners.begin(); it != oe->Runners.end(); ++it) {
if (it->getClassId()==Id) {
if (it->getClassId(true)==Id) {
if (it->skip())
continue;
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 {
data = (pvoid)oData;
olddata = (pvoid)oDataOld;
strData = 0;
strData = const_cast< vector <vector<wstring> >* >(&oDataStr);
return *oe->oClassData;
}
@ -1067,13 +1072,14 @@ const vector< pair<wstring, size_t> > &oEvent::fillClasses(vector< pair<wstring,
if (rit->isRemoved())
continue;
if (rit->Class) {
if (rit->Class->getNumStages() > 0 && rit->Class->getStartType(rit->tLeg) != STDrawn)
pClass pc = rit->getClassRef(true);
if (pc) {
if (pc->getNumStages() > 0 && pc->getStartType(rit->tLeg) != STDrawn)
needTime = false;
}
if (rit->tStartTime==0 && needTime)
undrawn.insert(rit->getClassId());
hasRunner.insert(rit->getClassId());
undrawn.insert(rit->getClassId(true));
hasRunner.insert(rit->getClassId(true));
}
}
else if (extended == extraNumMaps)
@ -1137,9 +1143,9 @@ void oEvent::getNotDrawnClasses(set<int> &classes, bool someMissing)
synchronizeList(oLRunnerId);
for (rit=Runners.begin(); rit != Runners.end(); ++rit) {
if (rit->tStartTime>0)
drawn.insert(rit->getClassId());
drawn.insert(rit->getClassId(true));
else if (someMissing)
classes.insert(rit->getClassId());
classes.insert(rit->getClassId(true));
}
// Return all classe where some runner has no start time
@ -1231,28 +1237,6 @@ bool oClass::isCourseUsed(int Id) const
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 {
if (MultiCourse.empty())
return false;
@ -1516,7 +1500,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
int maxleg = pc->getLastStageIndex();
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) {
total++;
@ -1543,7 +1527,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
oTeamList::const_iterator it;
for (it=Teams.begin(); it != Teams.end(); ++it) {
if (it->getClassId()==id) {
if (it->getClassId(true)==id) {
total++;
if (it->tStatus!=StatusUnknown ||
@ -2695,7 +2679,7 @@ void oClass::getStatistics(const set<int> &feeLock, int &entries, int &started)
if (it->getStatus() == StatusNotCompetiting)
continue;
if (it->getClassId()==Id) {
if (it->getClassId(false)==Id) {
if (feeLock.empty() || feeLock.count(it->getDCI().getInt("Fee"))) {
entries++;
if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS && it->tStatus != StatusCANCEL)
@ -2789,6 +2773,22 @@ void oClass::reinitialize()
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;
tIgnoreStartPunch = -1;
}
@ -3787,7 +3787,7 @@ void oClass::extractBibPatterns(oEvent &oe, map<int, pair<wstring, int> > &patte
patterns.clear();
wchar_t pattern[32];
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)
continue;
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--) {
if (r[k-1]->getTeam() != 0)
continue;
int cls = r[k-1]->getClassId();
int cls = r[k-1]->getClassId(true);
if (cls == 0)
continue;
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++) {
if (legInfo[k].startMethod == STHunting)
return true;
@ -4139,6 +4139,8 @@ int oClass::getNextBaseLeg(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--) {
if (!(legInfo[k].isParallel() || legInfo[k].isOptional()))
return k-1;
@ -4147,9 +4149,242 @@ int oClass::getPreceedingLeg(int leg) const {
}
bool oClass::lockedForking() const {
return getDCI().getInt("Locked") != 0;
return (getDCI().getInt("Locked") & 1) == 1;
}
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;
class oDataInterface;
const int MaxClassId = 1000000;
enum PersonSex;
enum StartTypes {
@ -132,6 +134,7 @@ struct ClassResultInfo {
int lastStartTime;
};
class QualificationFinal;
enum ClassType {oClassIndividual=1, oClassPatrol=2,
oClassRelay=3, oClassIndividRelay=4};
@ -206,7 +209,7 @@ protected:
BYTE oData[dataSize];
BYTE oDataOld[dataSize];
vector< vector<wstring> > oDataStr;
//Multicourse data
string codeMultiCourse() const;
//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);
mutable vector<pClass> virtualClasses;
pClass parentClass;
shared_ptr<QualificationFinal> qualificatonFinal;
void configureInstance(int instance, bool allowCreation) const;
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);
// Return true if forking in the class is locked
bool lockedForking() const;
void lockedForking(bool locked);
bool lockedClassAssignment() const;
void lockedClassAssignment(bool locked);
// Draw data
int getDrawFirstStart() const;
void setDrawFirstStart(int st);
@ -286,7 +309,7 @@ public:
void drawSeeded(ClassSeedMethod seed, int leg, int firstStart, int interval, const vector<int> &groups,
bool noClubNb, bool reverse, int pairSize);
/** 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
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)
@ -315,6 +338,9 @@ public:
return false;
}
oClass *getVirtualClass(int instance, bool allowCreation);
const oClass *getVirtualClass(int instance) const;
ClassStatus getClassStatus() const;
ClassMetaType interpretClassType() const;
@ -441,9 +467,6 @@ public:
void setDirectResult(bool directResult);
bool hasDirectResult() const;
string getClassResultStatus() const;
bool isCourseUsed(int Id) const;
wstring getLength(int leg) const;
@ -472,7 +495,7 @@ public:
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.
// 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)
{
sortRunners(ClassStartTime);
@ -440,10 +439,12 @@ void oEvent::viewClubMembers(gdioutput &gdi, int clubId)
int nt = 0;
// Update teams
for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) {
if (it->skip())
continue;
if (it->getClubId() == clubId) {
if (nt==0)
gdi.addString("", 1, "Lag(flera)");
gdi.addStringUT(0, it->getName() + L", " + it->getClass() );
gdi.addStringUT(0, it->getName() + L", " + it->getClass(false) );
nt++;
}
}
@ -451,10 +452,12 @@ void oEvent::viewClubMembers(gdioutput &gdi, int clubId)
gdi.dropLine();
// Update runners
for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) {
if (it->skip())
continue;
if (it->getClubId() == clubId) {
if (nr==0)
gdi.addString("", 1, "Löpare:");
gdi.addStringUT(0, it->getName() + L", " + it->getClass() );
gdi.addStringUT(0, it->getName() + L", " + it->getClass(true) );
nr++;
}
}
@ -496,7 +499,7 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
wstring ts;
if (!inTeam)
line.addString(xs+data.clsPos, r->getClass());
line.addString(xs+data.clsPos, r->getClass(true));
if (r->getStatus() == StatusUnknown)
ts = L"-";
@ -504,8 +507,8 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
if (r->getStatus()==StatusOK) {
ClassType type = oClassIndividual;
cTeam t = r->getTeam();
if (t && r->getClassRef())
type = r->getClassRef()->getClassType();
if (t && r->getClassRef(false))
type = r->getClassRef(false)->getClassType();
if (type == oClassIndividRelay || type == oClassRelay) {
int leg = r->getLegNumber();
@ -541,7 +544,7 @@ void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam,
if (res != definedPayModes.end())
payMode = ", " + res->second;
*/
if (r->getClassRef() && r->getClassRef()->getClassStatus() == oClass::InvalidRefund) {
if (r->getClassRef(false) && r->getClassRef(false)->getClassStatus() == oClass::InvalidRefund) {
fee = 0;
card = 0;
}
@ -574,7 +577,7 @@ void oClub::addTeamInvoiceLine(const pTeam t, const map<int, wstring> &definedPa
return;
line.addString(xs, t->getName());
line.addString(xs+data.clsPos, t->getClass());
line.addString(xs+data.clsPos, t->getClass(false));
wstring ts;
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;
}

View File

@ -998,3 +998,21 @@ void oControl::getClasses(vector<pClass> &cls) const {
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();
public:
static int getControlIdByName(const oEvent &oe, const string &name);
// Returns true if controls is considered a radio control.
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);
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("Heat", oDataContainer::oIS8U, "Heat");
oClassData->addVariableInt("Locked", oDataContainer::oIS8U, "Låst gaffling");
oClassData->addVariableString("Qualification", "Kvalschema");
oTeamData = new oDataContainer(oTeam::dataSize);
oTeamData->addVariableCurrency("Fee", "Anm. avgift");
@ -1210,6 +1211,7 @@ bool oEvent::open(const xmlparser &xml) {
}
toc("class");
reinitializeClasses();
//Get clubs
xo=xml.getObject("ClubList");
@ -1839,7 +1841,7 @@ void oEvent::updateFreeId(oBase *obj)
qFreeRunnerId=max(obj->Id, qFreeRunnerId);
}
else if (typeid(*obj)==typeid(oClass)){
qFreeClassId=max(obj->Id, qFreeClassId);
qFreeClassId=max(obj->Id % MaxClassId, qFreeClassId);
}
else if (typeid(*obj)==typeid(oCourse)){
qFreeCourseId=max(obj->Id, qFreeCourseId);
@ -1881,7 +1883,7 @@ void oEvent::updateFreeId()
oClassList::iterator it;
qFreeClassId=0;
for (it=Classes.begin(); it != Classes.end(); ++it)
qFreeClassId=max(qFreeClassId, it->Id);
qFreeClassId=max(qFreeClassId, it->Id % MaxClassId);
}
{
oCourseList::iterator it;
@ -2553,17 +2555,27 @@ void oEvent::removeCourse(int Id)
void oEvent::removeClass(int Id)
{
oClassList::iterator it;
for (it=Classes.begin(); it != Classes.end(); ++it){
vector<int> subRemove;
for (it = Classes.begin(); it != Classes.end(); ++it){
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)
msRemove(&*it);
Classes.erase(it);
dataRevision++;
updateTabs();
return;
break;
}
}
for (int id : subRemove) {
removeClass(id);
}
}
void oEvent::removeControl(int Id)
@ -2642,17 +2654,33 @@ bool oEvent::isCourseUsed(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
oRunnerList::const_iterator 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;
}
//Search teams
oTeamList::const_iterator 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 false;
@ -2713,7 +2741,7 @@ bool oEvent::classHasResults(int Id) const
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved())
continue;
if ( (Id == 0 || it->getClassId() == Id) && (it->getCard() || it->FinishTime))
if ( (Id == 0 || it->getClassId(true) == Id) && (it->getCard() || it->FinishTime))
return true;
}
@ -2722,10 +2750,16 @@ bool oEvent::classHasResults(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)
if (it->getClassId()==Id)
if (!it->isRemoved() && it->getClassId(false)==Id)
return true;
return false;
@ -2768,8 +2802,8 @@ void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb)
if (it->skip() || !it->isVacant())
continue;
if (it->getClassId() != Id) {
Id=it->getClassId();
if (it->getClassId(true) != Id) {
Id=it->getClassId(true);
y+=lh/2;
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;
}
@ -2865,7 +2899,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
}
if (unknown) {
if (id != it->getClassId()) {
if (id != it->getClassId(false)) {
if (nr>0) {
gdi.addString("", y, x, 0, "Antal: X#"+itos(nr));
y+=lh;
@ -2876,11 +2910,11 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
y += lh;
}
y += lh;
id = it->getClassId();
gdi.addStringUT(y, x, 1, it->getClass());
id = it->getClassId(false);
gdi.addStringUT(y, x, 1, it->getClass(false));
y += lh;
}
gdi.addStringUT(y, x, 0, it->getClass());
gdi.addStringUT(y, x, 0, it->getClass(false));
nr++;
gdi.addStringUT(y, x+100, 0, it->getName(), 0, cb).setExtra(it->getId()).id = "T";
y+=lh;
@ -2920,15 +2954,15 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
if (it->tStatus == StatusUnknown) {
if (id != it->getClassId()) {
if (id != it->getClassId(true)) {
if (nr>0) {
gdi.addString("", y, x, 0, "Antal: X#"+itos(nr));
y+=lh;
nr=0;
}
y += lh;
id = it->getClassId();
gdi.addStringUT(y, x, 1, it->getClass());
id = it->getClassId(true);
gdi.addStringUT(y, x, 1, it->getClass(true));
y += lh;
}
@ -2982,7 +3016,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
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;
}
}
@ -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[3], fontMedium, r[0]->getClass());
gdi.addStringUT(src_y, x+dx[3], fontMedium, r[0]->getClass(true));
y+=lh;
}
}
@ -3689,7 +3723,7 @@ void oEvent::reEvaluateCourse(int CourseId, bool DoSync)
set<int> classes;
for(it=Runners.begin(); it != Runners.end(); ++it){
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) {
if (!cls.empty() && cls.count(tit->getClassId()) == 0)
if (!cls.empty() && cls.count(tit->getClassId(false)) == 0)
continue;
tit->resetTmpStore();
@ -3727,7 +3761,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
oRunnerList::iterator 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;
if (!it->tInTeam) {
@ -3742,7 +3776,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
while (needupdate) {
needupdate = false;
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;
if (!it->isRemoved()) {
@ -3760,7 +3794,7 @@ void oEvent::reEvaluateAll(const set<int> &cls, bool doSync)
// Update team start times etc.
for(oTeamList::iterator tit=Teams.begin();tit!=Teams.end();++tit) {
if (!tit->isRemoved()) {
if (!cls.empty() && cls.count(tit->getClassId()) == 0)
if (!cls.empty() && cls.count(tit->getClassId(true)) == 0)
continue;
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) {
if (!it->isRemoved()) {
if (!cls.empty() && cls.count(it->getClassId()) == 0)
if (!cls.empty() && cls.count(it->getClassId(true)) == 0)
continue;
if (!it->tInTeam)
@ -3805,7 +3839,7 @@ void oEvent::reEvaluateChanged()
it->clearSplitAnalysis();
it->resetLeaderTime();
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) {
if (it->isRemoved())
continue;
if (resetClasses.count(it->getClassId()))
int clz = it->getClassId(true);
if (resetClasses.count(clz))
it->storeTimes();
if (!it->wasSQLChanged() && !resetClasses[it->getClassId()])
if (!it->wasSQLChanged() && !resetClasses[clz])
continue;
pTeam t = it->tInTeam;
@ -3926,7 +3960,7 @@ void oEvent::reCalculateLeaderTimes(int classId)
while (needupdate) {
needupdate = false;
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)
it->storeTimes();
else if (it->tLeg>leg)
@ -4097,7 +4131,7 @@ int oEvent::getFirstStart(int classId) const {
int minTime=3600*24;
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)
minTime = it->tStartTime;
++it;
@ -4168,17 +4202,26 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
sortRunners(ClassStartTimeClub);
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()) {
cls->setBibMode(BibFree);
wchar_t pattern[32];
int num = oClass::extractBibPattern(firstNumber, pattern);
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved())
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];
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++;
it->synchronize();
}
@ -4188,7 +4231,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
for(it=Runners.begin(); it != Runners.end(); ++it){
if (it->isRemoved())
continue;
if (ClassId==0 || it->getClassId()==ClassId) {
if (ClassId==0 || it->getClassId(true)==ClassId) {
it->getDI().setString("Bib", L"");//Update only bib
it->synchronize();
}
@ -4206,8 +4249,8 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
for (it=Teams.begin(); it != Teams.end(); ++it) {
if (it->isRemoved())
continue;
if (ClassId==0 || it->getClassId()==ClassId) {
if (it->getClassRef() && it->getClassRef()->getBibMode() != BibFree) {
if (ClassId==0 || it->getClassId(false)==ClassId) {
if (it->getClassRef(false) && it->getClassRef(false)->getBibMode() != BibFree) {
for (size_t i = 0; i < it->Runners.size(); i++) {
if (it->Runners[i]) {
//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())
continue;
if (ClassId == 0 || it->getClassId() == ClassId) {
if (ClassId == 0 || it->getClassId(false) == ClassId) {
wchar_t bib[32];
swprintf_s(bib, pattern, num);
bool lockedStartNo = it->Class && it->Class->lockedForking();
@ -4250,7 +4293,7 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
}
else {
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->apply(true, 0, false);
}
@ -4265,7 +4308,7 @@ void oEvent::addAutoBib() {
int clsId = -1;
int bibGap = oe->getBibClassGap();
int interval = 1;
set<int> isTeamCls;
wchar_t pattern[32] = {0};
wchar_t storedPattern[32];
wcscpy_s(storedPattern, L"%d");
@ -4283,24 +4326,26 @@ void oEvent::addAutoBib() {
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
if (tit->skip())
continue;
pClass cls = tit->getClassRef();
pClass cls = tit->getClassRef(false);
if (cls == 0)
continue;
teamStartNo[tit->getId()] = tit->getStartNo();
wstring bibInfo = cls->getDCI().getString("Bib");
bool teamAssign = !bibInfo.empty();
bool teamAssign = !bibInfo.empty() && cls->getNumStages() > 1;
bool freeMode = cls->getBibMode()==BibFree;
if (!teamAssign && freeMode)
continue; // Manul or none
isTeamCls.insert(cls->getId());
bool addBib = bibInfo != L"-";
if (addBib && teamAssign)
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++) {
if (tit->Runners[i]) {
if (addBib && teamAssign)
@ -4318,15 +4363,15 @@ void oEvent::addAutoBib() {
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
if (tit->skip())
continue;
int clsId = tit->getClassId();
int clsId = tit->getClassId(false);
cls2TeamList[clsId].push_back(&*tit);
}
map<int, vector<pRunner> > cls2RunnerList;
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->skip() || !it->getClassId())
if (it->isRemoved() || !it->getClassId(false))
continue;
int clsId = it->getClassId();
int clsId = it->getClassId(true);
cls2RunnerList[clsId].push_back(&*it);
}
@ -4362,7 +4407,7 @@ void oEvent::addAutoBib() {
number = oClass::extractBibPattern(bibInfo, pattern);
}
if (cls->getNumStages() > 1) {
if (isTeamCls.count(clsId)) {
vector<pTeam> &tl = cls2TeamList[clsId];
if (cls->getBibMode() == BibAdd) {
@ -4405,18 +4450,23 @@ void oEvent::addAutoBib() {
tl[k]->apply(true, 0, false);
}
}
continue;
}
else {
interval = 1;
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++) {
if (pattern[0]) {
wchar_t buff[32];
swprintf_s(buff, pattern, number);
rl[k]->setBib(buff, number, true, false);
rl[k]->setBib(buff, number, !locked, false);
number += interval;
}
else {
@ -4436,7 +4486,7 @@ void oEvent::checkOrderIdMultipleCourses(int ClassId)
//Find first free order
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
order=max(order, it->StartNo);
}
@ -4444,7 +4494,7 @@ void oEvent::checkOrderIdMultipleCourses(int ClassId)
//Assign orders
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){
it->StartNo=++order;
it->updateChanged(); //Mark as changed.
@ -4610,7 +4660,7 @@ void oEvent::loadProperties(const wchar_t *file) {
bool compareClubClassTeamName(const oRunner &a, const oRunner &b)
{
if (a.Club==b.Club) {
if (a.Class==b.Class) {
if (a.getClassId(true) == b.getClassId(true)) {
if (a.tInTeam==b.tInTeam)
return a.tRealName<b.tRealName;
else if (a.tInTeam) {
@ -4621,11 +4671,10 @@ bool compareClubClassTeamName(const oRunner &a, const oRunner &b)
return b.tInTeam!=0;
}
else
return a.getClass()<b.getClass();
return a.getClass(true)<b.getClass(true);
}
else
return a.getClub()<b.getClub();
}
void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
@ -4656,7 +4705,7 @@ void oEvent::assignCardInteractive(gdioutput &gdi, GUICALLBACK cb)
wstring r;
if (it->Class)
r+=it->getClass()+L", ";
r+=it->getClass(false)+L", ";
if (it->tInTeam) {
r+=itow(it->tInTeam->getStartNo()); + L" " + it->tInTeam->getName();
@ -5345,7 +5394,7 @@ void oEvent::applyEventFees(bool updateClassFromEvent,
if (it->skip())
continue;
if (allClass || classFilter.count(it->getClassId())) {
if (allClass || classFilter.count(it->getClassId(true))) {
it->addClassDefaultFee(true);
it->synchronize(true);
}
@ -5451,7 +5500,7 @@ void oEvent::removeVacanies(int classId) {
if (it->skip() || !it->isVacant())
continue;
if (classId!=0 && it->getClassId()!=classId)
if (classId!=0 && it->getClassId(false)!=classId)
continue;
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) {
if (it->isRemoved())
continue;
if (onlyThisClass > 0 && it->getClassId() != onlyThisClass)
if (onlyThisClass > 0 && it->getClassId(false) != onlyThisClass)
continue;
if (it->sName.empty()) {
if (!warnNoName) {
@ -5502,7 +5551,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (!warnNoTeam) {
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"#" + it->getClass());
L"#" + it->getClass(false));
warnNoTeam = true;
}
}
@ -5510,7 +5559,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (!warnNoPatrol) {
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"#" + it->getClass());
+ L"#" + it->getClass(false));
warnNoPatrol = true;
}
}
@ -5524,7 +5573,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (it->isRemoved())
continue;
if (onlyThisClass > 0 && it->getClassId() != onlyThisClass)
if (onlyThisClass > 0 && it->getClassId(false) != onlyThisClass)
continue;
if (it->sName.empty()) {
@ -5549,7 +5598,7 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (type == oClassIndividual) {
if (!warnIndividualTeam) {
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;
}
}
@ -5571,6 +5620,9 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
if (onlyThisClass > 0 && it->getId() != onlyThisClass)
continue;
if (it->getQualificationFinal())
continue;
if (it->hasMultiCourse()) {
for (unsigned k=0;k<it->getNumStages(); k++) {
StartTypes st = it->getStartType(k);
@ -5786,7 +5838,7 @@ wstring oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes,
r.StartNo = it->StartNo;
r.CardNo = it->CardNo;
r.Club = ce.getClub(it->getClubId());
r.Class = ce.getClass(it->getClassId());
r.Class = ce.getClass(it->getClassId(false));
if (cloneCourses)
r.Course = ce.getCourse(it->getCourseId());
@ -5819,7 +5871,7 @@ wstring oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes,
t.sName = it->sName;
t.StartNo = it->StartNo;
t.Club = ce.getClub(it->getClubId());
t.Class = ce.getClass(it->getClassId());
t.Class = ce.getClass(it->getClassId(false));
if (cloneTimes)
t.startTime = it->startTime;
@ -5879,7 +5931,7 @@ bool checkTargetClass(pRunner target, pRunner source,
if (changeClassMethod == oEvent::TransferAnyway)
return true;
if (!compareClassName(target->getClass(), source->getClass())) {
if (!compareClassName(target->getClass(false), source->getClass(false))) {
// Store all vacant positions in the right class
int targetClass = -1;
@ -5894,10 +5946,10 @@ bool checkTargetClass(pRunner target, pRunner source,
for (oClassList::const_iterator cit = Classes.begin(); cit != Classes.end(); ++cit) {
if (cit->isRemoved())
continue;
if (compareClassName(cit->getName(), source->getClass())) {
if (compareClassName(cit->getName(), source->getClass(false))) {
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
}
}
@ -5907,7 +5959,7 @@ bool checkTargetClass(pRunner target, pRunner source,
for (size_t j = 0; j < targetVacant.size(); j++) {
if (!targetVacant[j])
continue;
if (targetVacant[j]->getClassId() == targetClass)
if (targetVacant[j]->getClassId(false) == targetClass)
vacantIx.insert(j);
}
int posToUse = -1;
@ -5935,12 +5987,12 @@ bool checkTargetClass(pRunner target, pRunner source,
int oldStart = target->getStartTime();
wstring oldBib = target->getBib();
int oldSN = target->getStartNo();
int oldClass = target->getClassId();
int oldClass = target->getClassId(false);
pRunner tgt = targetVacant[posToUse];
target->cloneStartTime(tgt);
target->setBib(tgt->getBib(), 0, false, false);
target->setStartNo(tgt->getStartNo(), false);
target->setClassId(tgt->getClassId(), false);
target->setClassId(tgt->getClassId(false), false);
tgt->setStartTime(oldStart, true, 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++) {
pRunner src = remainingRunners[cnd[j]];
int p = 0;
if (src->getClass() == it->getClass())
if (src->getClass(false) == it->getClass(false))
p += 1;
if (src->getBirthYear() == it->getBirthYear())
p += 2;
@ -6165,7 +6217,7 @@ void oEvent::transferResult(oEvent &ce,
}
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->setClub(src->getClub());
targetVacant->setCardNo(src->getCardNo(), false);
@ -6173,13 +6225,13 @@ void oEvent::transferResult(oEvent &ce,
assignedVacant.push_back(targetVacant);
}
else {
pClass dstClass = ce.getClass(src->getClassId());
if (dstClass && compareClassName(dstClass->getName(), src->getClass())) {
if ( (!src->hasFlag(oAbstractRunner::FlagTransferSpecified) && allowNewEntries.count(src->getClassId()))
pClass dstClass = ce.getClass(src->getClassId(false));
if (dstClass && compareClassName(dstClass->getName(), src->getClass(false))) {
if ( (!src->hasFlag(oAbstractRunner::FlagTransferSpecified) && allowNewEntries.count(src->getClassId(false)))
|| src->hasFlag(oAbstractRunner::FlagTransferNew)) {
if (src->getClubId() > 0)
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);
dst->cloneData(src);
dst->setInputData(*src);
@ -6188,7 +6240,7 @@ void oEvent::transferResult(oEvent &ce,
else if (transferAllNoCompete) {
if (src->getClubId() > 0)
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);
dst->cloneData(src);
dst->setInputData(*src);
@ -6313,7 +6365,7 @@ void oEvent::transferResult(oEvent &ce,
for (size_t j = 0; j < cnd.size(); j++) {
pTeam src = remainingTeams[cnd[j]];
int p = 0;
if (src->getClass() == it->getClass())
if (src->getClass(false) == it->getClass(false))
p += 1;
if (p > point) {
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 exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldStylePatrol);
/** Set up transient data in cassss */
/** Set up transient data in classes */
void reinitializeClasses();
/** Analyze the result status of each class*/
@ -779,7 +779,7 @@ public:
short partialCount;
short legNumber;
inline int classId() const {return r->getClassId();}
inline int classId() const {return r->getClassId(true);}
inline int leg() const {return legNumber;}
};
@ -917,7 +917,6 @@ public:
bool empty() const;
void generateMinuteStartlist(gdioutput &gdi);
void generateMinuteStartlist(const string &file);
bool classHasTeams(int Id) const;
bool classHasResults(int Id) const;
@ -982,12 +981,14 @@ public:
bool saveRunnerDatabase(const wchar_t *file, bool onlyLocal);
enum ResultType {RTClassResult, RTTotalResult, RTCourseResult, RTClassCourseResult};
void calculateResults(ResultType result);
void calculateResults(ResultType result, bool includePreliminary = false);
void calculateRogainingResults();
void calculateResults(list<oSpeakerObject> &rl);
void calculateTeamResults(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);
/** 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;
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;
if (!di.startName.empty() && it->Class && it->Class->getStart()!=di.startName)
continue;
ClassInfo &ci = otherClasses[it->getClassId()];
ClassInfo &ci = otherClasses[it->getClassId(false)];
int k = 0;
while(true) {
if (k==StartField.size()) {
@ -688,14 +688,18 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
if (spec[k].vacances>0 && pc->getClassType()==oClassRelay)
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.");
if (size_t(spec[k].leg) < pc->legInfo.size()) {
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;
if (!multiDay && spec[k].leg == 0)
if (!multiDay && spec[k].leg == 0 && pc->getParentClass() == 0)
clsIdClearVac.insert(spec[k].classID);
}
@ -709,7 +713,7 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
vector<int> toRemove;
//Remove old vacances
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (clsIdClearVac.count(it->getClassId())) {
if (clsIdClearVac.count(it->getClassId(true))) {
if (it->isRemoved())
continue;
if (it->tInTeam)
@ -734,11 +738,12 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
}
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)
continue;
int ix = clsId2Ix[it->getClassId()];
if (it->legToRun() == spec[ix].leg ) {
int ix = clsId2Ix[cid];
if (it->legToRun() == spec[ix].leg || spec[ix].leg == -1) {
runners.push_back(&*it);
spec[ix].ntimes++;
}
@ -753,12 +758,12 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
int baseInterval = 10*60;
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)
continue;
int st = it->getStartTime();
int ix = clsId2Ix[it->getClassId()];
int ix = clsId2Ix[it->getClassId(false)];
if (st>0) {
first[ix] = min(first[ix], st);
@ -839,7 +844,6 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
nextFreeStartNo = max<int>(nextFreeStartNo, minStartNo + stimes.size());
}
void getLargestClub(map<int, vector<pRunner> > &clubRunner, vector<pRunner> &largest)
{
size_t maxClub=0;
@ -1176,7 +1180,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
continue;
if (it->tLeg != leg)
continue;
if (it->isVacant() && notDrawn.count(it->getClassId())==1)
if (it->isVacant() && notDrawn.count(it->getClassId(false))==1)
continue;
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) {
int st = 0;
if (controlIdFrom > 0) {
if (controlIdFrom > 0 && controlIdFrom != oPunch::PunchStart) {
RunnerStatus stat;
it->getSplitTime(controlIdFrom, stat, st);
if (stat != StatusOK) {
@ -56,7 +56,7 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
continue;
}
}
if (controlIdTo == 0) {
if (controlIdTo == 0 || controlIdTo == oPunch::PunchFinish) {
it->tempRT = max(0, it->FinishTime - (st + it->tStartTime) );
if (it->tempRT > 0)
it->tempRT += it->getTimeAdjustment();
@ -79,8 +79,8 @@ void oEvent::calculateSplitResults(int controlIdFrom, int controlIdTo)
int cTime=0;
for (it=Runners.begin(); it != Runners.end(); ++it){
if (it->getClassId()!=cClassId){
cClassId=it->getClassId();
if (it->getClassId(true)!=cClassId){
cClassId=it->getClassId(true);
cPlace=0;
vPlace=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 courseResults = resultType == RTCourseResult;
const bool classCourseResults = resultType == RTClassCourseResult;
@ -135,7 +135,7 @@ void oEvent::calculateResults(ResultType resultType) {
// Start new "class"
if (classCourseResults) {
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) {
cClassId = crsId;
cPlace=0;
@ -156,8 +156,8 @@ void oEvent::calculateResults(ResultType resultType) {
cTime=0;
}
}
else if (it->getClassId() != cClassId || it->tDuplicateLeg!=cDuplicateLeg || it->tLegEquClass != cLegEquClass) {
cClassId=it->getClassId();
else if (it->getClassId(true) != cClassId || it->tDuplicateLeg!=cDuplicateLeg || it->tLegEquClass != cLegEquClass) {
cClassId=it->getClassId(true);
useResults = it->Class ? !it->Class->getNoTiming() : false;
cPlace=0;
vPlace=0;
@ -176,7 +176,7 @@ void oEvent::calculateResults(ResultType resultType) {
else if (!totalResults) {
int tPlace = 0;
if (it->tStatus==StatusOK){
if (it->tStatus==StatusOK || (includePreliminary && it->tStatus == StatusUnknown && it->FinishTime > 0)){
cPlace++;
int rt = it->getRunningTime() + it->getNumShortening() * 3600 * 24* 8;
@ -200,7 +200,8 @@ void oEvent::calculateResults(ResultType resultType) {
else {
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++;
if (tt > cTime)
@ -236,8 +237,8 @@ void oEvent::calculateRogainingResults() {
if (it->isRemoved())
continue;
if (it->getClassId()!=cClassId || it->tDuplicateLeg!=cDuplicateLeg) {
cClassId = it->getClassId();
if (it->getClassId(true)!=cClassId || it->tDuplicateLeg!=cDuplicateLeg) {
cClassId = it->getClassId(true);
useResults = it->Class ? !it->Class->getNoTiming() : false;
cPlace = 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();
if (postSyncEvent) {
reinitializeClasses();
reEvaluateChanged();
resetChangeStatus();
return true;

View File

@ -561,7 +561,7 @@ void oEvent::speakerList(gdioutput &gdi, int ClassId, int leg, int ControlId,
if (classHasTeams(ClassId)) {
oTeamList::iterator it=Teams.begin();
while(it!=Teams.end()){
if (it->getClassId()==ClassId && !it->skip()) {
if (it->getClassId(true)==ClassId && !it->skip()) {
oSpeakerObject so;
it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so);
if (so.owner)
@ -571,15 +571,23 @@ void oEvent::speakerList(gdioutput &gdi, int ClassId, int leg, int ControlId,
}
}
else {
oRunnerList::iterator it=Runners.begin();
while(it!=Runners.end()){
if (it->getClassId()==ClassId && !it->skip()) {
pClass pc = getClass(ClassId);
bool qfBaseClass = pc && pc->getQualificationFinal();
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;
it->fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so);
it.fillSpeakerObject(leg, ControlId, PreviousControlId, totalResults, so);
if (so.owner)
speakerList.push_back(so);
}
++it;
}
}
if (speakerList.empty()) {
@ -1089,9 +1097,9 @@ int oEvent::setupTimeLineEvents(int classId, int currentTime)
if (false && startTimes.size() == 1) {
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));
it->second.setMessage(L"X har startat.#" + r.getClass());
it->second.setMessage(L"X har startat.#" + r.getClass(true));
}
else {
for (size_t j = 0; j<started.size(); j++) {
@ -1106,15 +1114,15 @@ int oEvent::setupTimeLineEvents(int classId, int currentTime)
prio = oTimeLine::PHigh;
else if (p == 1)
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));
it->second.setMessage(L"har startat.");
}
else if (!startedClass) {
// 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));
it->second.setMessage(L"X har startat.#" + r.getClass());
it->second.setMessage(L"X har startat.#" + r.getClass(true));
startedClass = true;
}
}
@ -1203,7 +1211,7 @@ void oEvent::timeLinePrognose(TempResultMap &results, TimeRunner &tr, int prelT,
else if (p>6 + prio * 5)
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));
tlit->second.setMessage(msg);
}
@ -1411,7 +1419,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 10)
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));
tlit->second.setMessage(msg).setDetail(detail);
}
@ -1509,7 +1517,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 20)
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));
tlit->second.setMessage(msg).setDetail(detail);
}
@ -1535,7 +1543,7 @@ int oEvent::setupTimeLineEvents(vector<pRunner> &started, const vector< pair<int
else if (place <= 20)
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));
wstring msg;
if (r.getStatus() != StatusDQ)
@ -1558,7 +1566,7 @@ void oEvent::renderTimeLineEvents(gdioutput &gdi) const
wstring msg = t>0 ? getAbsTime(t) : makeDash(L"--:--:--");
oAbstractRunner *r = it->second.getSource(*this);
if (r) {
msg += L" (" + r->getClass() + L") ";
msg += L" (" + r->getClass(true) + L") ";
msg += r->getName() + L", " + r->getClub();
}
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);
map<int, int> teamStatusPos;
for (oTeamList::const_iterator it = Teams.begin(); it != Teams.end(); ++it) {
if (!classFilter.count(it->getClassId()))
if (!classFilter.count(it->getClassId(false)))
continue;
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) {
const oRunner &r = *it;
if (r.isRemoved() || !classFilter.count(r.getClassId()))
if (r.isRemoved() || !classFilter.count(r.getClassId(true)))
continue;
if (r.prelStatusOK() || r.getStatus() != StatusUnknown) {
RunnerStatus stat = r.prelStatusOK() ? StatusOK : r.getStatus();
@ -1738,7 +1746,7 @@ void oEvent::getResultEvents(const set<int> &classFilter, const set<int> &punchF
continue;
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;
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)
continue;
pRunner r = getRunner(fp.tRunnerId, 0);
if (r == 0 || !classFilter.count(r->getClassId()))
if (r == 0 || !classFilter.count(r->getClassId(true)))
continue;
int courseControlId = oFreePunch::getControlIdFromHash(fp.iHashType, true);
int ctrl = oControl::getIdIndexFromCourseControlId(courseControlId).first;

View File

@ -1037,7 +1037,7 @@ void oFreeImport::test(const oRunnerList &li)
givenDB.insert(it->getGivenName().c_str());
familyDB.insert(it->getFamilyName().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) {
tr->synchronize();
if (type == oPunch::PunchStart) {
if (tr->getClassRef() && !tr->getClassRef()->ignoreStartPunch())
if (tr->getClassRef(false) && !tr->getClassRef(true)->ignoreStartPunch())
tr->setStartTime(time, true, false);
}
else
tr->setFinishTime(time);
// 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) {
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[OEnat] = gdibase.recodeToNarrow(di.getString("Nationality"));
row[OEclassno] = conv_is(it->getClassId());
row[OEclassshortname] = gdibase.recodeToNarrow(it->getClass());
row[OEclassname] = gdibase.recodeToNarrow(it->getClass());
row[OEclassno] = conv_is(it->getClassId(true));
row[OEclassshortname] = gdibase.recodeToNarrow(it->getClass(true));
row[OEclassname] = gdibase.recodeToNarrow(it->getClass(true));
row[OErent] = conv_is(di.getInt("CardFee"));
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;
for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) {
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 classId = runnersInTeam[k].second;
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());
}
}
@ -2048,7 +2048,7 @@ void oClass::exportIOFStart(xmlparser &xml) {
if (getClassType() == oClassIndividual || getClassType() == oClassIndividRelay) {
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;
xml.startTag("PersonStart");
@ -2096,7 +2096,7 @@ void oClass::exportIOFStart(xmlparser &xml) {
bool writeTeamName = !useEventor || getClassType() != oClassPatrol;
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;
xml.startTag("TeamStart");
@ -2218,7 +2218,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
if (it->isRemoved())
continue;
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 (!it->Class || it->Class->getClassType()!=oClassPatrol) {
@ -2227,7 +2227,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
continue;
}
if ((!classes.empty() && classes.count(it->getClassId()) == 0) || leg != -1) {
if ((!classes.empty() && classes.count(it->getClassId(true)) == 0) || leg != -1) {
skipClass=true;
ClassStarted=false;
continue;
@ -2236,9 +2236,9 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
skipClass=false;
xml.startTag("ClassResult");
ClassStarted=true;
Id=it->getClassId();
Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass());
xml.write("ClassShortName", it->getClass(true));
}
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())
continue;
if (it->getClassId()!=Id) {
if (it->getClassId(true)!=Id) {
if (ClassStarted) xml.endTag();
if (!it->Class) {
@ -2332,7 +2332,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
continue;
}
if ( (!classes.empty() && classes.count(it->getClassId()) == 0) ) {
if ( (!classes.empty() && classes.count(it->getClassId(true)) == 0) ) {
skipClass=true;
ClassStarted=false;
continue;
@ -2341,9 +2341,9 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set<int>
xml.startTag("ClassResult");
ClassStarted=true;
skipClass=false;
Id=it->getClassId();
Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass());
xml.write("ClassShortName", it->getClass(true));
}
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) {
if (it->isRemoved())
continue;
if (it->getClassId()!=Id) {
if (it->getClassId(true)!=Id) {
if (ClassStarted) {
xml.endTag();
ClassStarted = false;
@ -2442,7 +2442,7 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
continue;
}
if (!classes.empty() && classes.count(it->getClassId()) == 0) {
if (!classes.empty() && classes.count(it->getClassId(true)) == 0) {
skipClass=true;
continue;
}
@ -2450,9 +2450,9 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set<int> &classes, bool oldS
skipClass=false;
xml.startTag("ClassResult");
ClassStarted=true;
Id=it->getClassId();
Id=it->getClassId(true);
xml.write("ClassShortName", it->getClass());
xml.write("ClassShortName", it->getClass(true));
}
if (skipClass)

View File

@ -396,9 +396,9 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
continue;
// 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;
totWord.clear();
@ -417,7 +417,7 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
}
rout.clear();
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()));
if (out.length() > rout.length())
rout = out;
@ -474,7 +474,7 @@ const wstring & oEvent::formatListString(EPostType type, const pRunner r) const
oListParam par;
par.setLegNumberCoded(r->tLeg);
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,
@ -485,7 +485,7 @@ const wstring & oEvent::formatListString(EPostType type, const pRunner r,
par.setLegNumberCoded(r->tLeg);
pp.type = type;
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;
case lRunnerLegNumberAlpha:
if (t && t->getClassRef() && legIndex >= 0) {
wstring legStr = t->getClassRef()->getLegNumber(legIndex);
if (t && t->getClassRef(false) && legIndex >= 0) {
wstring legStr = t->getClassRef(false)->getLegNumber(legIndex);
wcscpy_s(bfw, legStr.c_str());
}
break;
case lRunnerLegNumber:
if (t && t->getClassRef() && legIndex >= 0) {
if (t && t->getClassRef(false) && legIndex >= 0) {
int legNumber, legOrder;
t->getClassRef()->splitLegNumberParallel(legIndex, legNumber, legOrder);
t->getClassRef(false)->splitLegNumberParallel(legIndex, legNumber, legOrder);
wsptr = &itow(legNumber+1);
}
break;
@ -727,7 +727,7 @@ const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListP
try {
const wstring &res = formatListStringAux(pp, par, t, t ? t->getRunner(legIndex) : 0,
t ? t->getClubRef() : 0,
t ? t->getClassRef() : 0, counter);
t ? t->getClassRef(false) : 0, counter);
reentrantLock = false;
return res;
}
@ -928,7 +928,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
if (t) {
pRunner r1 = t->getRunner(0);
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());
}
else if (r1) {
@ -1375,7 +1375,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
break;
case lRunnerCard:
if (r && r->CardNo > 0)
if (r && r->getCardNo() > 0)
swprintf_s(wbf, L"%d", r->getCardNo());
break;
case lRunnerRank:
@ -2212,7 +2212,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
if (it->isRemoved() || it->tStatus == StatusNotCompetiting)
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;
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)
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;
//if (it->legToRun() != li.lp.legNumber && li.lp.legNumber!=-1)
if (!li.lp.matchLegNumber(it->getClassRef(), it->legToRun()))
if (!li.lp.matchLegNumber(it->getClassRef(false), it->legToRun()))
continue;
if (li.filter(EFilterExcludeDNS))
@ -2348,29 +2347,29 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
wstring newKey;
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 (li.lp.pageBreak) {
if (!oldKey.empty())
gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, "");
}
gdi.addStringUT(pagePageInfo, it->getClass());
gdi.addStringUT(pagePageInfo, it->getClass(true));
oldKey.swap(newKey);
printPostInfo.counter.level2=0;
printPostInfo.counter.level3=0;
printPostInfo.reset();
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) {
printPostInfo.reset();
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) {
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;
@ -2397,7 +2396,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
if (it->isRemoved() || it->tStatus == StatusNotCompetiting)
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;
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++) {
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)
continue;
@ -2475,12 +2474,12 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
gdi.addStringUT(gdi.getCY()-1, 0, pageNewPage, "");
}
wstring legInfo;
if (linearLegSpec >= 0 && it->getClassRef()) {
if (linearLegSpec >= 0 && it->getClassRef(false)) {
// Specified leg
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);
printPostInfo.counter.level2=0;
@ -2561,7 +2560,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
printPostInfo.keepToghether = suitableBreak;
printPostInfo.par.relayLegIndex = tr[k] ? tr[k]->tLeg : -1;
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++;
}
}
@ -2579,7 +2578,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
}
else {
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++;
}
@ -2632,16 +2631,15 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
}
bool startClub = false;
pRunner pLeader = 0;
for (rit = Runners.begin(); rit != Runners.end(); ++rit) {
if (rit->isRemoved() || rit->tStatus == StatusNotCompetiting)
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;
if (!li.lp.matchLegNumber(rit->getClassRef(), rit->legToRun()))
if (!li.lp.matchLegNumber(rit->getClassRef(false), rit->legToRun()))
continue;
if (li.filter(EFilterExcludeDNS))
@ -2657,8 +2655,6 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
continue;
}
if (!pLeader || pLeader->Class != rit->Class)
pLeader = &*rit;
if (rit->Club == &*it) {
if (!startClub) {
if (li.lp.pageBreak) {
@ -2680,7 +2676,7 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
printPostInfo.counter.level3=0;
printPostInfo.reset();
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())
continue;
}

View File

@ -294,6 +294,24 @@ class MetaListContainer;
struct 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;
GUICALLBACK cb;
set<int> selection;
@ -389,6 +407,7 @@ public:
Global,
Classwise,
Legwise,
Coursewise
};
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);
}
if (r_it->getClassId()==0)
if (r_it->getClassId(false)==0)
no_class.push_back(&*r_it);
else if (needCourse && r_it->getCourse(false)==0)
no_course.push_back(&*r_it);
@ -481,7 +481,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_course.empty() && ++i<20){
pRunner r=no_course.front();
no_course.pop_front();
wstring name = r->getClass() + L": " + r->getName();
wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty())
name += L" ("+ r->getClub()+ L")";
gdi.addStringUT(0, name);
@ -497,7 +497,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_club.empty() && ++i<20){
pRunner r=no_club.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);
}
@ -510,7 +510,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_start.empty() && ++i<20){
pRunner r=no_start.front();
no_start.pop_front();
wstring name = r->getClass() + L": " + r->getName();
wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty())
name += L" (" + r->getClub() + L")";
@ -526,7 +526,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!no_card.empty() && ++i<20){
pRunner r=no_card.front();
no_card.pop_front();
wstring name = r->getClass() + L": " + r->getName();
wstring name = r->getClass(true) + L": " + r->getName();
if (!r->getClub().empty())
name += L" (" + r->getClub() + L")";
@ -543,7 +543,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
while(!si_duplicate.empty() && ++i<50){
pRunner r=si_duplicate.front();
si_duplicate.pop_front();
wstring name = r->getClass() + L" / " + r->getName();
wstring name = r->getClass(true) + L" / " + r->getName();
if (!r->getClub().empty())
name += L" (" + r->getClub() + L")";
name += L": " + itow(r->getCardNo());
@ -566,7 +566,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
header = true;
}
wstring name = r->getClass() + L" / " + r->getName();
wstring name = r->getClass(true) + L" / " + r->getName();
if (!r->getClub().empty())
name += L" (" + r->getClub() + L")";
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) {
if (t_it->isRemoved())
continue;
pClass pc=getClass(t_it->getClassId());
pClass pc=getClass(t_it->getClassId(true));
if (pc){
for(unsigned i=0;i<pc->getNumStages();i++){
@ -604,7 +604,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
bool any = false;
for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){
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())
name += L" (" + r_it->getClub() + L")";
@ -626,7 +626,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
if (r_it->isRemoved())
continue;
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();
if (!r_it->getClub().empty())
name += L" (" + r_it->getClub() + L")";
@ -650,9 +650,9 @@ void oEvent::generatePreReport(gdioutput &gdi) {
gdi.addString("", 1, "Lag(flera)");
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){
for(unsigned i=0;i<pc->getNumStages();i++){

View File

@ -44,6 +44,7 @@
#include "socket.h"
#include "MeOSFeatures.h"
#include "oListInfo.h"
#include "qualification_final.h"
oRunner::RaceIdFormatter oRunner::raceIdFormatter;
@ -420,8 +421,27 @@ void oAbstractRunner::setClassId(int id, bool isManualUpdate) {
// Update all classes (for multirunner)
void oRunner::setClassId(int id, bool isManualUpdate)
{
if (tParentRunner)
tParentRunner->setClassId(id, isManualUpdate);
if (Class && Class->getQualificationFinal() && 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 {
pClass pc = Class;
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 &&
Class->isSingleRunnerMultiStage()) {
if (!isTemporaryObject) {
pTeam t = oe->addTeam(getName(), getClubId(), getClassId());
pTeam t = oe->addTeam(getName(), getClubId(), getClassId(false));
t->setStartNo(StartNo, false);
t->setRunner(0, this, true);
}
@ -765,13 +785,16 @@ pCourse oRunner::getCourse(bool useAdaptedCourse) const {
if (Course)
tCrs = Course;
else if (Class) {
if (Class->hasMultiCourse()) {
const oClass *cls = getClassRef(true);
if (cls->hasMultiCourse()) {
if (tInTeam) {
if (size_t(tLeg) >= tInTeam->Runners.size() || tInTeam->Runners[tLeg] != this) {
tInTeam->quickApply();
}
}
if (Class == cls) {
if (tInTeam && Class->hasUnorderedLegs()) {
vector< pair<int, pCourse> > group;
Class->getParallelCourseGroup(tLeg, StartNo, group);
@ -825,31 +848,26 @@ pCourse oRunner::getCourse(bool useAdaptedCourse) const {
}
}
else if (tInTeam) {
unsigned leg=legToRun();
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 {
if (unsigned(tDuplicateLeg)<Class->MultiCourse.size()) {
vector<pCourse> &courses=Class->MultiCourse[tDuplicateLeg];
if (courses.size()>0) {
int index=StartNo % courses.size();
if (unsigned(tDuplicateLeg) < Class->MultiCourse.size()) {
vector<pCourse> &courses = Class->MultiCourse[tDuplicateLeg];
if (courses.size() > 0) {
int index = StartNo % courses.size();
tCrs = courses[index];
}
}
}
}
else {
// Final / qualification classes
tCrs = cls->getCourse(0, StartNo);
}
}
else
tCrs = Class->Course;
tCrs = cls->Course;
}
if (tCrs && useAdaptedCourse) {
@ -1329,6 +1347,19 @@ bool oRunner::evaluateCard(bool doApply, vector<int> & MissingPunches,
doAdjustTimes(course);
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) {
int rt = getRunningTime();
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
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)
{
int acid=a.getClassId();
int bcid=b.getClassId();
int acid=a.getClassId(true);
int bcid=b.getClassId(true);
if (acid!=bcid)
return acid<bcid;
else if (a.tempStatus != b.tempStatus)
@ -1661,21 +1682,29 @@ bool oRunner::sortSplit(const oRunner &a, const oRunner &b)
if (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) {
if (!Class || !c.Class)
return size_t(Class)<size_t(c.Class);
else if (Class == c.Class && Class->getClassStatus() != oClass::Normal)
bool oRunner::operator<(const oRunner &c) const {
const oClass * myClass = getClassRef(true);
const oClass * cClass = c.getClassRef(true);
if (!myClass || !cClass)
return size_t(myClass)<size_t(cClass);
else if (Class == cClass && Class->getClassStatus() != oClass::Normal)
return CompareString(LOCALE_USER_DEFAULT, 0,
tRealName.c_str(), tRealName.length(),
c.tRealName.c_str(), c.tRealName.length()) == CSTR_LESS_THAN;
if (oe->CurrentSortOrder==ClassStartTime) {
if (Class->Id != c.Class->Id)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass->Id != cClass->Id) {
if (myClass->tSortIndex != cClass->tSortIndex)
return myClass->tSortIndex < cClass->tSortIndex;
else
return myClass->Id < cClass->Id;
}
else if (tStartTime != c.tStartTime) {
if (tStartTime <= 0 && c.tStartTime > 0)
return false;
@ -1697,8 +1726,8 @@ bool oRunner::operator <(const oRunner &c) {
RunnerStatus stat = tStatus == StatusUnknown ? StatusOK : tStatus;
RunnerStatus cstat = c.tStatus == StatusUnknown ? StatusOK : c.tStatus;
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tLegEquClass != c.tLegEquClass)
return tLegEquClass < c.tLegEquClass;
else if (tDuplicateLeg != c.tDuplicateLeg)
@ -1730,8 +1759,8 @@ bool oRunner::operator <(const oRunner &c) {
}
}
else if (oe->CurrentSortOrder == ClassCourseResult) {
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex;
const pCourse crs1 = getCourse(false);
const pCourse crs2 = c.getCourse(false);
@ -1805,8 +1834,8 @@ bool oRunner::operator <(const oRunner &c) {
return ft > cft;
}
else if (oe->CurrentSortOrder == ClassFinishTime){
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
if (tStatus != c.tStatus)
return RunnerStatusOrderMap[tStatus] < RunnerStatusOrderMap[c.tStatus];
else{
@ -1834,8 +1863,8 @@ bool oRunner::operator <(const oRunner &c) {
return et > cet;
}
else if (oe->CurrentSortOrder == ClassPoints) {
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tDuplicateLeg != c.tDuplicateLeg)
return tDuplicateLeg < c.tDuplicateLeg;
else if (tStatus != c.tStatus)
@ -1852,8 +1881,8 @@ bool oRunner::operator <(const oRunner &c) {
}
}
else if (oe->CurrentSortOrder==ClassTotalResult) {
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tDuplicateLeg != c.tDuplicateLeg)
return tDuplicateLeg < c.tDuplicateLeg;
else {
@ -1902,8 +1931,8 @@ bool oRunner::operator <(const oRunner &c) {
}
}
else if (oe->CurrentSortOrder==ClassStartTimeClub) {
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass != cClass)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tStartTime != c.tStartTime) {
if (tStartTime <= 0 && c.tStartTime > 0)
return false;
@ -1916,8 +1945,8 @@ bool oRunner::operator <(const oRunner &c) {
}
}
else if (oe->CurrentSortOrder==ClassTeamLeg) {
if (Class->Id != c.Class->Id)
return Class->tSortIndex < c.Class->tSortIndex;
if (myClass->Id != cClass->Id)
return myClass->tSortIndex < cClass->tSortIndex || (myClass->tSortIndex == cClass->tSortIndex && myClass->Id < cClass->Id);
else if (tInTeam != c.tInTeam) {
if (tInTeam == 0)
return true;
@ -1959,7 +1988,7 @@ void oAbstractRunner::setClub(const wstring &clubName)
updateChanged();
if (Class) {
// Vacant clubs have special logic
Class->tResultInfo.clear();
getClassRef(true)->tResultInfo.clear();
}
if (Club && Club->isVacant()) { // Clear entry date/time for vacant
getDI().setInt("EntryDate", 0);
@ -2326,7 +2355,7 @@ void oEvent::getRunners(int classId, int courseId, vector<pRunner> &r, bool sort
continue;
}
if (classId <= 0 || it->getClassId() == classId)
if (classId <= 0 || it->getClassId(true) == classId)
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 (size_t k = 0; k < tInTeam->Runners.size(); 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;
}
}
@ -2432,9 +2461,11 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
}
else {
if (time <= 0) { //No time specified. Card readout search
pRunner secondTry = 0;
//First try runners with no card read or a different card read.
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->skip())
if (it->isRemoved())
continue;
if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL))
continue;
@ -2442,10 +2473,16 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
continue;
pRunner ret;
if (it->CardNo==cardNo && (ret = it->nextNeedReadout()) != 0)
if (it->CardNo == cardNo && (ret = it->nextNeedReadout()) != 0) {
if (!it->skip())
return ret;
else if (secondTry == 0 || secondTry->tLeg > ret->tLeg)
secondTry = ret;
}
}
if (secondTry)
return secondTry;
}
else {
for (it=Runners.begin(); it != Runners.end(); ++it) {
pRunner r = pRunner(&*it);
@ -2745,11 +2782,11 @@ const vector< pair<wstring, size_t> > &oEvent::fillRunners(vector< pair<wstring,
if (compact) {
swprintf_s(bf, L"%s, %s (%s)", it->getNameAndRace(true).c_str(),
it->getClub().c_str(),
it->getClass().c_str());
it->getClass(true).c_str());
} else {
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());
}
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)
out.push_back(make_pair(it->getUIName(), it->Id));
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));
}
}
@ -2879,7 +2916,7 @@ void oRunner::createMultiRunner(bool createMaster, bool sync)
if (!multiRunner[k-1]) {
update = true;
multiRunner[k-1]=oe->addRunner(sName, getClubId(),
getClassId(), 0, 0, false);
getClassId(false), 0, 0, false);
multiRunner[k-1]->tDuplicateLeg=k;
multiRunner[k-1]->tParentRunner=this;
@ -2909,6 +2946,12 @@ pRunner oRunner::getPredecessor() const
bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) {
createMultiRunner(false, sync);
if (sync) {
for (size_t k = 0; k < multiRunner.size(); k++) {
if (multiRunner[k])
multiRunner[k]->synchronize(true);
}
}
tLeg = -1;
tLegEquClass = 0;
tUseStartPunch=true;
@ -3045,7 +3088,7 @@ void oEvent::generateRunnerTableData(Table &table, oRunner *addRunner)
oRunnerList::iterator it;
table.reserve(Runners.size());
for (it=Runners.begin(); it != Runners.end(); ++it){
if (!it->skip()){
if (!it->isRemoved()){
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_MODIFIED, getTimeStamp(), false);
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_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_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.");
if (sName != input && tRealName != input) {
updateFromDB(input, getClubId(), getClassId(), getCardNo(), getBirthYear());
updateFromDB(input, getClubId(), getClassId(false), getCardNo(), getBirthYear());
setName(input, true);
synchronizeAll();
}
@ -3184,7 +3229,7 @@ bool oRunner::inputData(int id, const wstring &input,
else
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"");
synchronize(true);
@ -3195,7 +3240,7 @@ bool oRunner::inputData(int id, const wstring &input,
case TID_CLASSNAME:
setClassId(inputId, true);
synchronize(true);
output = getClass();
output = getClass(true);
break;
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) {
oe->fillClasses(out, oEvent::extraNone, oEvent::filterNone);
out.push_back(make_pair(lang.tl(L"Ingen klass"), 0));
selected = getClassId();
selected = getClassId(true);
}
else if (id==TID_CLUB) {
oe->fillClubs(out);
@ -3378,7 +3423,7 @@ void oRunner::getSplitTime(int courseControlId, RunnerStatus &stat, int &rt) con
{
rt = 0;
stat = StatusUnknown;
int cardno = tParentRunner ? tParentRunner->CardNo : CardNo;
int cardno = getCardNo();
if (courseControlId==oPunch::PunchFinish &&
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) {
if (tParentRunner)
const bool freeBib = !Class || Class->getBibMode() == BibMode::BibFree;
if (tParentRunner && !freeBib)
tParentRunner->setBib(bib, bibNumerical, updateStartNo, tmpOnly);
else {
if (updateStartNo)
@ -3657,13 +3704,14 @@ void oRunner::setBib(const wstring &bib, int bibNumerical, bool updateStartNo, b
if (oe)
oe->bibStartNoToRunnerTeam.clear();
}
for (size_t k=0;k<multiRunner.size();k++) {
if (!freeBib) {
for (size_t k = 0; k < multiRunner.size(); k++) {
if (multiRunner[k]) {
multiRunner[k]->getDI().setString("Bib", bib);
}
}
}
}
}
@ -3848,7 +3896,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
gdi.dropLine(0.5);
pCourse pc = getCourse(true);
gdi.addStringUT(bnormal, getName() + L", " + getClass());
gdi.addStringUT(bnormal, getName() + L", " + getClass(true));
gdi.addStringUT(normal, getClub());
gdi.dropLine(0.5);
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())
bib = bib + L": ";
gdi.addStringUT(boldSmall, bib + getName() + L", " + getClass());
gdi.addStringUT(boldSmall, bib + getName() + L", " + getClass(true));
gdi.addStringUT(fontSmall, getClub());
gdi.dropLine(0.5);
@ -4274,7 +4322,7 @@ void oEvent::updateRunnersFromDB()
for (it=Runners.begin(); it != Runners.end(); ++it) {
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);
if (Class) {
Class->markSQLChanged(tLeg, controlId);
pClass cls2 = getClassRef(true);
if (cls2 != Class)
cls2->markSQLChanged(-1, controlId);
if (tInTeam && tInTeam->Class != Class && tInTeam->Class) {
tInTeam->Class->markSQLChanged(tLeg, controlId);
}
@ -5535,10 +5587,13 @@ int oRunner::getRanking() const {
}
void oAbstractRunner::hasManuallyUpdatedTimeStatus() {
if (Class && Class->hasClassGlobalDependance()) {
if (Class && Class->hasClassGlobalDependence()) {
set<int> cls;
oe->reEvaluateAll(cls, false);
}
if (Class) {
Class->updateFinalClasses(dynamic_cast<oRunner *>(this), false);
}
}
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())
return false;
pClass tCls = getTeam()->getClassRef();
const oClass * tCls = getTeam()->getClassRef(false);
if (!tCls || tCls != Class)
return false;
@ -5598,3 +5653,24 @@ bool oAbstractRunner::hasLateEntryFee() const {
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;}
pClub getClubRef() {return Club;}
virtual int classInstance() const = 0;
const pClass getClassRef() const {return Class;}
pClass getClassRef() {return Class;}
const oClass *getClassRef(bool virtualClass) const {
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 int getClubId() const {if (Club) return Club->Id; else return 0;}
virtual void setClub(const wstring &clubName);
virtual pClub setClubId(int clubId);
virtual const wstring &getClass() const {if (Class) return Class->Name; else return _EmptyWString;}
virtual int getClassId() const {if (Class) return Class->Id; else return 0;}
const wstring &getClass(bool virtualClass) const;
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 int getStartNo() const {return StartNo;}
virtual void setStartNo(int no, bool storeTmpOnly);
@ -457,6 +468,8 @@ protected:
// Running time as calculated by evalute. Used to detect changes.
int tCachedRunningTime;
mutable pair<int, int> classInstanceRev;
void clearOnChangedRunningTime();
// Cached runner statistics
@ -499,6 +512,8 @@ public:
/** Get a runner reference (drawing) */
pRunner getReference() const;
int classInstance() const override;
/**Set a runner reference*/
void setReference(int runnerId);
@ -546,6 +561,9 @@ public:
int getLegNumber() const {return tLeg;}
int getSpeakerPriority() const;
RunnerStatus getTempStatus() const { return tempStatus; }
int getTempTime() const { return tempRT; }
void remove();
bool canRemove() const;
@ -703,7 +721,7 @@ public:
pCard getCard() const {return Card;}
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 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;}
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);
/** Sets the card to a given card. An existing card is marked as unpaired.
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]->tLeg = k;
if (Class && Class->getLegType(k) != LTGroup)
Runners[k]->setClassId(getClassId(), false);
Runners[k]->setClassId(getClassId(false), false);
}
updateChanged();
}
@ -698,7 +698,7 @@ bool oTeam::compareResult(const oTeam &a, const oTeam &b)
{
if (a.Class != b.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 false;
@ -728,7 +728,8 @@ bool oTeam::compareStartTime(const oTeam &a, const oTeam &b)
{
if (a.Class != b.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;
}
}
@ -760,7 +761,8 @@ bool oTeam::compareSNO(const oTeam &a, const oTeam &b) {
}
else if (a.Class != b.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;
}
}
@ -928,6 +930,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
}
if (Runners[i]) {
pClass actualClass = Runners[i]->getClassRef(true);
if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) {
Runners[i]->tInTeam->correctRemove(Runners[i]);
}
@ -942,6 +945,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
Runners[i]->tLegEquClass = i;
}
if (actualClass == Class)
Runners[i]->setStartNo(StartNo, setTmpOnly);
if (!bib.empty() && Runners[i]->isChanged()) {
if (bibMode == -1 && Class)
@ -980,7 +984,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
else
lastStatus = Runners[i]->getStatus();
StartTypes st = pc->getStartType(i);
StartTypes st = actualClass == pc ? pc->getStartType(i) : actualClass->getStartType(0);
LegTypes lt = legType;
if ((lt==LTParallel || lt==LTParallelOptional) && i==0) {
@ -1016,9 +1020,12 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
}
}
if (!prs) {
if (lt==LTNormal || lt==LTSum || lt == LTGroup)
lastStartTime=pc->getStartData(i);
if (lt == LTNormal || lt == LTSum || lt == LTGroup) {
if (actualClass == pc)
lastStartTime = pc->getStartData(i);
else
lastStartTime = actualClass->getStartData(0); // Qualification/final classes
}
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly);
Runners[i]->tUseStartPunch=false;
}
@ -1740,7 +1747,7 @@ void oEvent::getTeams(int classId, vector<pTeam> &t, bool sort) {
if (it->isRemoved())
continue;
if (classId == 0 || it->getClassId() == classId)
if (classId == 0 || it->getClassId(false) == classId)
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_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_START, getStartTimeS(), true);
@ -1920,7 +1927,7 @@ bool oTeam::inputData(int id, const wstring &input,
}
else {
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);
output = r->getName();
}
@ -1968,7 +1975,7 @@ bool oTeam::inputData(int id, const wstring &input,
case TID_CLASSNAME:
setClassId(inputId, true);
synchronize(true);
output = getClass();
output = getClass(true);
break;
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) {
oe->fillClasses(out, oEvent::extraNone, oEvent::filterOnlyMulti);
out.push_back(make_pair(lang.tl(L"Ingen klass"), 0));
selected = getClassId();
selected = getClassId(true);
}
else if (id==TID_CLUB) {
oe->fillClubs(out);

View File

@ -105,6 +105,10 @@ public:
int getRanking() const;
int classInstance() const override {
return 0; // Not supported
}
void resetResultCalcCache() const;
vector< vector<int> > &getResultCache(ResultCalcCacheSymbol symb) 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();
}
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
out.push_back(make_pair(tn, it->Id));
}
@ -612,14 +612,14 @@ void oEvent::adjustTeamMultiRunners(pClass cls)
if (cls) {
bool multi = cls->getNumStages() > 1;
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;
if (multi && it->tInTeam == 0) {
oe->autoAddTeam(&*it);
}
if (!multi && it->tInTeam) {
assert( it->tInTeam->getClassId() == cls->getId());
assert( it->tInTeam->getClassId(false) == cls->getId());
removeTeam(it->tInTeam->getId());
}
@ -628,7 +628,7 @@ void oEvent::adjustTeamMultiRunners(pClass cls)
vector<int> tr;
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());
}
}
@ -728,9 +728,9 @@ void oTeam::checkClassesWithReferences(oEvent &oe, std::set<int> &clsWithRef) {
map<int, pair<int, int> > pairedUnpairedPerClass;
for (size_t k = 0; k < r.size(); k++) {
if (r[k]->getReference())
++pairedUnpairedPerClass[r[k]->getClassId()].first;
++pairedUnpairedPerClass[r[k]->getClassId(false)].first;
else
++pairedUnpairedPerClass[r[k]->getClassId()].second;
++pairedUnpairedPerClass[r[k]->getClassId(false)].second;
}
for (auto &it : pairedUnpairedPerClass) {
@ -744,8 +744,8 @@ void oTeam::convertClassWithReferenceToPatrol(oEvent &oe, const std::set<int> &c
oe.getRunners(-1, -1, r, true);
for(auto it : r) {
if (clsWithRef.count(it->getClassId())) {
pClass cls = it->getClassRef();
if (clsWithRef.count(it->getClassId(false))) {
pClass cls = it->getClassRef(false);
if (cls->getNumStages() == 0) {
pCourse crs = cls->getCourse();

View File

@ -45,11 +45,27 @@ class oSpeakerObject
{
public:
struct RunningTime {
void reset() { time = 0; preliminary = 0; }
int time;
int preliminary;
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;
wstring bib;
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 IDC_MEOS 109
#define IDR_MAINFRAME 128
#define IDB_ECO 131
#define IDR_HTML1 132
#define IDC_STATIC -1
// Next default values for new objects
@ -17,7 +19,7 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#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_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 110

View File

@ -31,11 +31,14 @@ Eksoppsv
#include "infoserver.h"
#include <chrono>
#include "oListInfo.h"
#include "TabList.h"
#include "generalresult.h"
using namespace restbed;
vector< shared_ptr<RestServer> > RestServer::startedServers;
shared_ptr<RestServer> RestServer::construct() {
shared_ptr<RestServer> obj(new RestServer());
startedServers.push_back(obj);
@ -43,7 +46,13 @@ shared_ptr<RestServer> RestServer::construct() {
}
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) {
@ -142,21 +151,18 @@ void RestServer::compute(oEvent &ref) {
auto rq = getRequest();
if (!rq)
return;
if (rq->parameters.empty()) {
rq->answer = "<html><head>"
"<title>MeOS Information Service</title>"
"</head>"
"<body>"
"<h2>MeOS</h2>"
"</body>"
"</html>";
try {
computeInternal(ref, rq);
}
else if (rq->parameters.count("get") > 0) {
string what = rq->parameters.find("get")->second;
getData(ref, what, rq->parameters, rq->answer);
catch (meosException &ex) {
rq->answer = "Error (MeOS): Error: " + ref.gdiBase().toUTF8(lang.tl(ex.wwhat()));
}
else {
rq->answer = "Error (MeOS): Unknown request";
catch (std::exception &ex) {
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();
}
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) {
xmlbuffer out;
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);
cmp.synchronize(oe);
cmp.serialize(out, false);
okRequest = true;
}
else if (what == "class") {
vector<pClass> cls;
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) {
InfoClass iCls(c->getId());
set<int> ctrl;
iCls.synchronize(*c, ctrl);
iCls.synchronize(*c, ctrlW);
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") {
vector<pRunner> r;
set<int> selection;
if (param.count("id") > 0)
getSelection(param.find("id")->second, selection);
if (param.count("class") > 0)
getSelection(param.find("class")->second, selection);
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) {
InfoCompetitor iR(c->getId());
iR.synchronize(false, *c);
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) {
xmlparser mem;
@ -208,7 +769,7 @@ void RestServer::getData(oEvent &oe, const string &what, const multimap<string,
mem.endTag();
mem.getMemoryOutput(answer);
}
else {
else if (!okRequest) {
answer = "Error (MeOS): Unknown command '" + what + "'";
}
}

View File

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

View File

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