MeOS version 3.6.1089

This commit is contained in:
Erik Melin 2019-07-31 13:14:41 +02:00
parent a4e2689418
commit 06a6c4ff67
23 changed files with 632 additions and 369 deletions

View File

@ -7,7 +7,6 @@
const wstring _EmptyWString=L""; const wstring _EmptyWString=L"";
const string _EmptyString=""; const string _EmptyString="";
const string _VacantName="Vakant"; const string _VacantName="Vakant";
const string _UnkownName="N.N.";
// TODO: reference any additional headers you need in STDAFX.H // TODO: reference any additional headers you need in STDAFX.H
// and not in this file // and not in this file

View File

@ -1252,6 +1252,7 @@ X (Y deltagare, grupp Z, W) = X (Y závodníků, skupina Z, W)
X har startat = X odstartovalo X har startat = X odstartovalo
X kontroller = X kontrol X kontroller = X kontrol
X meter = X metrů X meter = X metrů
X m = X m
X poäng fattas = X bodů chybí X poäng fattas = X bodů chybí
X rader kunde inte raderas = X řádků nemůže být smazáno X rader kunde inte raderas = X řádků nemůže být smazáno
X senaste = X nejnovějších X senaste = X nejnovějších

View File

@ -2303,6 +2303,7 @@ X har redan ett resultat. Vi du fortsätta? = X har allerede et resultat. Vil du
X har startat = X er startet X har startat = X er startet
X kontroller = X poster X kontroller = X poster
X meter = X meter X meter = X meter
X m = X m
X och Y[N by N] = X og Y X och Y[N by N] = X og Y
X p = X p X p = X p
X platser. Startar Y = X pladser. Starter Y X platser. Startar Y = X pladser. Starter Y

View File

@ -1252,7 +1252,8 @@ X (Saknar e-post) = X (Has no e-mail)
X (Y deltagare, grupp Z, W) = X (Y competitors, group Z, W) X (Y deltagare, grupp Z, W) = X (Y competitors, group Z, W)
X har startat = X started X har startat = X started
X kontroller = X controls X kontroller = X controls
X meter = X meter X meter = X meters
X m = X m
X poäng fattas = X points missing X poäng fattas = X points missing
X rader kunde inte raderas = X row(s) could not be deleted X rader kunde inte raderas = X row(s) could not be deleted
X senaste = X latest X senaste = X latest
@ -2432,3 +2433,6 @@ Kunde inte öppna databasen (X) = Could not connect to database (X)
Kunde inte ladda upp löpardatabasen (X) = Could not upload runner database (X) Kunde inte ladda upp löpardatabasen (X) = Could not upload runner database (X)
Runner check time = Runner check time Runner check time = Runner check time
ClassNumEntries = Number of entries in class ClassNumEntries = Number of entries in class
Flera lopp i valfri ordning = Several races in any order
Knockout sammanställning = Knock-out summary
X anmälda = X entries

View File

@ -1254,6 +1254,7 @@ X (Y deltagare, grupp Z, W) = X (Y coureurs, groupe Z, W)
X har startat = X est parti X har startat = X est parti
X kontroller = X postes X kontroller = X postes
X meter = X mètres X meter = X mètres
X m = X m
X poäng fattas = X points manquant X poäng fattas = X points manquant
X rader kunde inte raderas = X lignes ne peuvent être effacées X rader kunde inte raderas = X lignes ne peuvent être effacées
X senaste = X derniers X senaste = X derniers

View File

@ -390,9 +390,9 @@ void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) {
query.execute(sql); query.execute(sql);
} }
} }
else if (db == "oRunner") { else if (db == "oRunner" || db == "oTeam") {
if (!eCol.count("InputTime")) { if (!eCol.count("InputTime")) {
string sql = "ALTER TABLE oRunner "; string sql = "ALTER TABLE " + db + " ";
sql += "ADD COLUMN " + C_INT("InputTime"); sql += "ADD COLUMN " + C_INT("InputTime");
sql += "ADD COLUMN " + C_INT("InputStatus"); sql += "ADD COLUMN " + C_INT("InputStatus");
sql += "ADD COLUMN " + C_INT("InputPoints"); sql += "ADD COLUMN " + C_INT("InputPoints");
@ -522,7 +522,7 @@ bool MeosSQL::openDB(oEvent *oe)
query << C_START("oCard") query << C_START("oCard")
<< C_INT("CardNo") << C_INT("CardNo")
<< C_UINT("ReadId") << C_UINT("ReadId")
<< C_STRING("Punches", 1024) << C_END(); << C_STRING("Punches", 16*190) << C_END();
query.execute(); query.execute();
@ -558,7 +558,6 @@ bool MeosSQL::openDB(oEvent *oe)
// Ugrade oRunner // Ugrade oRunner
upgradeDB("oControl", oe->oControlData); upgradeDB("oControl", oe->oControlData);
query.reset(); query.reset();
query << C_START("oCourse") query << C_START("oCourse")
<< C_STRING("Name") << C_STRING("Name")
@ -577,6 +576,7 @@ bool MeosSQL::openDB(oEvent *oe)
<< C_INT("Club") << C_INT("Class") << C_INT("Club") << C_INT("Class")
<< C_INT("StartTime") << C_INT("FinishTime") << C_INT("StartTime") << C_INT("FinishTime")
<< C_INT("Status") << C_INT("StartNo") << C_INT("Status") << C_INT("StartNo")
<< C_INT("InputTime") << C_INT("InputStatus") << C_INT("InputPoints") << C_INT("InputPlace")
<< oe->oTeamData->generateSQLDefinition() << C_END(); << oe->oTeamData->generateSQLDefinition() << C_END();
query.execute(); query.execute();
@ -1165,7 +1165,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
while (row = res.fetch_row()) { while (row = res.fetch_row()) {
oControl c(oe, row["Id"]); oControl c(oe, row["Id"]);
storeControl(row, c); storeControl(row, c);
oe->Controls.push_back(c); oe->addControl(c);
oe->sqlUpdateControls = max(c.sqlUpdated, oe->sqlUpdateControls); oe->sqlUpdateControls = max(c.sqlUpdated, oe->sqlUpdateControls);
oe->sqlCounterControls = max(c.counter, oe->sqlCounterControls); oe->sqlCounterControls = max(c.counter, oe->sqlCounterControls);
@ -1191,7 +1191,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
set<int> tmp; set<int> tmp;
while (row = res.fetch_row()) { while (row = res.fetch_row()) {
oCourse c(oe, row["Id"]); oCourse c(oe, row["Id"]);
storeCourse(row, c, tmp); storeCourse(row, c, tmp, false);
oe->addCourse(c); oe->addCourse(c);
oe->sqlUpdateCourses = max(c.sqlUpdated, oe->sqlUpdateCourses); oe->sqlUpdateCourses = max(c.sqlUpdated, oe->sqlUpdateCourses);
@ -1216,7 +1216,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
Row row; Row row;
while (row = res.fetch_row()) { while (row = res.fetch_row()) {
oClass c(oe, row["Id"]); oClass c(oe, row["Id"]);
storeClass(row, c, false); storeClass(row, c, false, false);
c.changed = false; c.changed = false;
c.reChanged = false; c.reChanged = false;
@ -1277,7 +1277,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
Row row; Row row;
while (row = res.fetch_row()) { while (row = res.fetch_row()) {
oRunner r(oe, row["Id"]); oRunner r(oe, row["Id"]);
storeRunner(row, r, false, false, false); storeRunner(row, r, false, false, false, false);
assert(!r.changed); assert(!r.changed);
oe->addRunner(r, false); oe->addRunner(r, false);
@ -1309,7 +1309,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
while (row = res.fetch_row()) { while (row = res.fetch_row()) {
oTeam t(oe, row["Id"]); oTeam t(oe, row["Id"]);
storeTeam(row, t, false); storeTeam(row, t, false, false);
pTeam at = oe->addTeam(t, false); pTeam at = oe->addTeam(t, false);
@ -1427,6 +1427,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
} }
oe->runnerDB->setDataDate(dateTime); oe->runnerDB->setDataDate(dateTime);
processMissingObjects();
return retValue; return retValue;
} }
@ -1512,7 +1513,7 @@ void MeosSQL::storePunch(const Row &row, oFreePunch &p, bool rehash)
} }
OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c,
bool readCourses) bool readCourses, bool allowSubRead)
{ {
OpFailStatus success = opStatusOK; OpFailStatus success = opStatusOK;
@ -1523,11 +1524,13 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c,
c.importLegMethod(lm); c.importLegMethod(lm);
set<int> cid; set<int> cid;
vector< vector<int> > multip; vector<vector<int>> multip;
oClass::parseCourses(multi, multip, cid); oClass::parseCourses(multi, multip, cid);
int classCourse = row["Course"]; int classCourse = row["Course"];
if (classCourse != 0) if (classCourse != 0)
cid.insert(classCourse); cid.insert(classCourse);
if (!readCourses) { if (!readCourses) {
for (set<int>::iterator clsIt = cid.begin(); clsIt != cid.end(); ++clsIt) { for (set<int>::iterator clsIt = cid.begin(); clsIt != cid.end(); ++clsIt) {
if (!c.oe->getCourse(*clsIt)) if (!c.oe->getCourse(*clsIt))
@ -1535,12 +1538,26 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c,
} }
} }
if (readCourses) if (readCourses) {
if (allowSubRead) {
success = min(success, syncReadClassCourses(&c, cid, readCourses)); success = min(success, syncReadClassCourses(&c, cid, readCourses));
}
else {
// Cannot read from database here. Add implicitly added courses
for (int x : cid) {
if (c.oe->getCourse(x) == nullptr) {
oCourse oc(c.oe, x);
oc.setImplicitlyCreated();
addedFromDatabase(c.oe->addCourse(oc));
}
}
}
}
if (classCourse != 0) if (classCourse != 0)
c.Course = c.oe->getCourse(classCourse); c.Course = c.oe->getCourse(classCourse);
else else
c.Course = 0; c.Course = nullptr;
c.importCourses(multip); c.importCourses(multip);
@ -1559,8 +1576,8 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c,
} }
OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c, OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c,
set<int> &readControls) set<int> &readControls,
{ bool allowSubRead) {
OpFailStatus success = opStatusOK; OpFailStatus success = opStatusOK;
c.Name = fromUTF((string)row["Name"]); c.Name = fromUTF((string)row["Name"]);
@ -1573,12 +1590,16 @@ OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c,
// Might have been created during last call. // Might have been created during last call.
// Then just read to update // Then just read to update
if (!c.Controls[i]->existInDB()) { if (!c.Controls[i]->existInDB()) {
c.Controls[i]->setImplicitlyCreated();
if (allowSubRead) {
c.Controls[i]->changed = false; c.Controls[i]->changed = false;
success = min(success, syncRead(true, c.Controls[i])); success = min(success, syncRead(true, c.Controls[i]));
} }
else addedFromDatabase(c.Controls[i]);
}
else {
readControls.insert(c.Controls[i]->getId()); readControls.insert(c.Controls[i]->getId());
//success = min(success, syncRead(false, c.Controls[i])); }
} }
} }
@ -1598,7 +1619,8 @@ OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c,
OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
bool readCourseCard, bool readCourseCard,
bool readClassClub, bool readClassClub,
bool readRunners) bool readRunners,
bool allowSubRead)
{ {
OpFailStatus success = opStatusOK; OpFailStatus success = opStatusOK;
oEvent *oe=r.oe; oEvent *oe=r.oe;
@ -1637,10 +1659,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
set<int> controlIds; set<int> controlIds;
if (!r.Course) { if (!r.Course) {
oCourse oc(oe, row["Course"]); oCourse oc(oe, row["Course"]);
oc.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncReadCourse(true, &oc, controlIds)); success = min(success, syncReadCourse(true, &oc, controlIds));
if (!oc.isRemoved()) {
r.Course = oe->addCourse(oc); r.Course = oe->addCourse(oc);
addedFromDatabase(r.Course);
} }
else if (readCourseCard) }
else if (readCourseCard && allowSubRead)
success = min(success, syncReadCourse(false, r.Course, controlIds)); success = min(success, syncReadCourse(false, r.Course, controlIds));
if (readCourseCard) if (readCourseCard)
@ -1653,10 +1680,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
if (!r.Class) { if (!r.Class) {
oClass oc(oe, row["Class"]); oClass oc(oe, row["Class"]);
oc.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &oc, readClassClub)); success = min(success, syncRead(true, &oc, readClassClub));
if (!oc.isRemoved()) {
r.Class = oe->addClass(oc); r.Class = oe->addClass(oc);
addedFromDatabase(r.Class);
} }
else if (readClassClub) }
else if (readClassClub && allowSubRead)
success = min(success, syncRead(false, r.Class, true)); success = min(success, syncRead(false, r.Class, true));
if (r.tInTeam && r.tInTeam->Class!=r.Class) if (r.tInTeam && r.tInTeam->Class!=r.Class)
@ -1669,10 +1701,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
if (!r.Club) { if (!r.Club) {
oClub oc(oe, row["Club"]); oClub oc(oe, row["Club"]);
oc.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &oc)); success = min(success, syncRead(true, &oc));
if (!oc.isRemoved()) {
r.Club = oe->addClub(oc); r.Club = oe->addClub(oc);
addedFromDatabase(r.Club);
} }
else if (readClassClub) }
else if (readClassClub && allowSubRead)
success = min(success, syncRead(false, r.Club)); success = min(success, syncRead(false, r.Club));
} }
else r.Club=0; else r.Club=0;
@ -1684,12 +1721,18 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
if (!r.Card){ if (!r.Card){
oCard oc(oe, row["Card"]); oCard oc(oe, row["Card"]);
oe->Cards.push_back(oc); oc.setImplicitlyCreated();
r.Card = &oe->Cards.back(); if (allowSubRead)
success = min(success, syncRead(true, &oc));
if (!oc.isRemoved()) {
r.Card = oe->addCard(oc);
r.Card->changed = false; r.Card->changed = false;
success = min(success, syncRead(true, r.Card));
} }
else if (readCourseCard) else {
addedFromDatabase(r.Card);
}
}
else if (readCourseCard && allowSubRead)
success = min(success, syncRead(false, r.Card)); success = min(success, syncRead(false, r.Card));
} }
else r.Card=0; else r.Card=0;
@ -1713,10 +1756,18 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
pRunner pr = oe->getRunner(rid, 0); pRunner pr = oe->getRunner(rid, 0);
if (pr==0) { if (pr==0) {
oRunner or(oe, rid); oRunner or(oe, rid);
or.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &or, false, readCourseCard)); success = min(success, syncRead(true, &or, false, readCourseCard));
pr = oe->addRunner(or, false); if (!or.isRemoved()) {
pr = oe->addRunner(or , false);
addedFromDatabase(pr);
} }
else else {
r.multiRunnerId[i] = 0;
}
}
else if (allowSubRead)
success = min(success, syncRead(false, pr, false, readCourseCard)); success = min(success, syncRead(false, pr, false, readCourseCard));
} }
} }
@ -1732,7 +1783,7 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r,
} }
OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t,
bool readRecursive) bool readRecursive, bool allowSubRead)
{ {
oEvent *oe=t.oe; oEvent *oe=t.oe;
OpFailStatus success = opStatusOK; OpFailStatus success = opStatusOK;
@ -1747,8 +1798,14 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t,
t.sName=fromUTF((string)row["Name"]); t.sName=fromUTF((string)row["Name"]);
t.StartNo=row["StartNo"]; t.StartNo=row["StartNo"];
t.tStartTime = t.startTime = row["StartTime"]; t.tStartTime = t.startTime = row["StartTime"];
t.FinishTime=row["FinishTime"]; t.FinishTime = row["FinishTime"];
t.tStatus = t.status = RunnerStatus(int(row["Status"])); t.tStatus = t.status = RunnerStatus(int(row["Status"]));
t.inputTime = row["InputTime"];
t.inputPoints = row["InputPoints"];
t.inputStatus = RunnerStatus(int(row["InputStatus"]));
t.inputPlace = row["InputPlace"];
storeData(t.getDI(), row, oe->dataRevision); storeData(t.getDI(), row, oe->dataRevision);
if (oldSno != t.StartNo || oldBib != t.getBib()) if (oldSno != t.StartNo || oldBib != t.getBib())
@ -1768,10 +1825,15 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t,
if (!t.Class) { if (!t.Class) {
oClass oc(oe, classId); oClass oc(oe, classId);
oc.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &oc, readRecursive)); success = min(success, syncRead(true, &oc, readRecursive));
if (!oc.isRemoved()) {
t.Class = oe->addClass(oc); t.Class = oe->addClass(oc);
addedFromDatabase(t.Class);
} }
else if (readRecursive) }
else if (readRecursive && allowSubRead)
success = min(success, syncRead(false, t.Class, readRecursive)); success = min(success, syncRead(false, t.Class, readRecursive));
} }
else t.Class=0; else t.Class=0;
@ -1782,10 +1844,15 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t,
if (!t.Club) { if (!t.Club) {
oClub oc(oe, clubId); oClub oc(oe, clubId);
oc.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &oc)); success = min(success, syncRead(true, &oc));
if (!oc.isRemoved()) {
t.Club = oe->addClub(oc); t.Club = oe->addClub(oc);
addedFromDatabase(t.Club);
} }
else if (readRecursive) }
else if (readRecursive && allowSubRead)
success = min(success, syncRead(false, t.Club)); success = min(success, syncRead(false, t.Club));
} }
else t.Club = 0; else t.Club = 0;
@ -1798,19 +1865,24 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t,
for (size_t k=0;k<rns.size(); k++) { for (size_t k=0;k<rns.size(); k++) {
if (rns[k]>0) { if (rns[k]>0) {
pRns[k] = oe->getRunner(rns[k], 0); pRns[k] = oe->getRunner(rns[k], 0);
if (!pRns[k]) { if (!pRns[k]) {
oRunner or(oe, rns[k]); oRunner or(oe, rns[k]);
or.setImplicitlyCreated();
if (allowSubRead)
success = min(success, syncRead(true, &or, readRecursive, readRecursive)); success = min(success, syncRead(true, &or, readRecursive, readRecursive));
if (or.sName.empty()) { if (or.sName.empty()) {
or.sName = L"@AutoCorrection"; or.sName = L"@AutoCorrection";
oRunner::getRealName(or.sName, or.tRealName); oRunner::getRealName(or.sName, or.tRealName);
} }
pRns[k] = oe->addRunner(or, false);
if (!or.isRemoved()) {
pRns[k] = oe->addRunner(or , false);
addedFromDatabase(pRns[k]);
assert(pRns[k] && !pRns[k]->changed); assert(pRns[k] && !pRns[k]->changed);
} }
else if (readRecursive) }
else if (readRecursive && allowSubRead)
success = min(success, syncRead(false, pRns[k])); success = min(success, syncRead(false, pRns[k]));
} }
} }
@ -1936,6 +2008,9 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r)
} }
string MeosSQL::andWhereOld(oBase *ob) { string MeosSQL::andWhereOld(oBase *ob) {
if (ob->sqlUpdated.empty())
return " AND Counter!=" + itos(ob->counter);
else
return " AND (Counter!=" + itos(ob->counter) + " OR Modified!='" + ob->sqlUpdated + "')"; return " AND (Counter!=" + itos(ob->counter) + " OR Modified!='" + ob->sqlUpdated + "')";
} }
@ -1967,7 +2042,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r, bool readClassClub, b
if (r->changed) if (r->changed)
success=opStatusWarning; success=opStatusWarning;
success = min (success, storeRunner(row, *r, readCourseCard, readClassClub, true)); success = min (success, storeRunner(row, *r, readCourseCard, readClassClub, true, true));
r->oe->dataRevision++; r->oe->dataRevision++;
r->Modified.update(); r->Modified.update();
@ -2105,7 +2180,11 @@ OpFailStatus MeosSQL::syncUpdate(oTeam *t, bool forceWriteAll) {
<< " Class=" << t->getClassId(false) << ", " << " Class=" << t->getClassId(false) << ", "
<< " Club=" << t->getClubId() << ", " << " Club=" << t->getClubId() << ", "
<< " StartNo=" << t->getStartNo() << ", " << " StartNo=" << t->getStartNo() << ", "
<< " Status=" << t->status << " Status=" << t->status << ", "
<< " InputTime=" << t->inputTime << ", "
<< " InputStatus=" << t->inputStatus << ", "
<< " InputPoints=" << t->inputPoints << ", "
<< " InputPlace=" << t->inputPlace
<< t->getDI().generateSQLSet(forceWriteAll); << t->getDI().generateSQLSet(forceWriteAll);
//wstring str = L"write team " + t->sName + L"\n"; //wstring str = L"write team " + t->sName + L"\n";
@ -2147,7 +2226,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t, bool readRecursive)
if (t->changed) if (t->changed)
success=opStatusWarning; success=opStatusWarning;
storeTeam(row, *t, readRecursive); storeTeam(row, *t, readRecursive, true);
t->oe->dataRevision++; t->oe->dataRevision++;
t->Modified.update(); t->Modified.update();
t->changed = false; t->changed = false;
@ -2236,7 +2315,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oClass *c, bool readCourses)
if (c->changed) if (c->changed)
success=opStatusWarning; success=opStatusWarning;
storeClass(row, *c, readCourses); storeClass(row, *c, readCourses, true);
c->oe->dataRevision++; c->oe->dataRevision++;
c->Modified.update(); c->Modified.update();
c->changed = false; c->changed = false;
@ -2296,8 +2375,10 @@ OpFailStatus MeosSQL::syncReadClassCourses(oClass *c, const set<int> &courses,
pCourse pc = oe->getCourse(id); pCourse pc = oe->getCourse(id);
if (!pc) { if (!pc) {
oCourse oc(oe, id); oCourse oc(oe, id);
oc.setImplicitlyCreated();
success = min(success, syncReadCourse(true, &oc, controlIds)); success = min(success, syncReadCourse(true, &oc, controlIds));
oe->addCourse(oc); if (!oc.isRemoved())
addedFromDatabase(oe->addCourse(oc));
} }
else if (pc->changed || isOld(counter, modified, pc)) { else if (pc->changed || isOld(counter, modified, pc)) {
success = min(success, syncReadCourse(false, pc, controlIds)); success = min(success, syncReadCourse(false, pc, controlIds));
@ -2576,7 +2657,7 @@ OpFailStatus MeosSQL::syncReadCourse(bool forceRead, oCourse *c, set<int> &readC
if (c->changed) if (c->changed)
success = opStatusWarning; success = opStatusWarning;
storeCourse(row, *c, readControls); storeCourse(row, *c, readControls, true);
c->oe->dataRevision++; c->oe->dataRevision++;
c->Modified.update(); c->Modified.update();
c->changed=false; c->changed=false;
@ -2771,6 +2852,12 @@ OpFailStatus MeosSQL::syncUpdate(mysqlpp::Query &updateqry,
Result res=query.store(); Result res=query.store();
if (res && res.num_rows()==0) if (res && res.num_rows()==0)
setId = true; setId = true;
else if (ob->isImplicitlyCreated()) {
return opStatusWarning;//XXX Should we read this object?
}
}
else {
assert(!ob->isImplicitlyCreated());
} }
query.reset(); query.reset();
@ -3729,3 +3816,97 @@ int MeosSQL::getModifiedMask(oEvent &oe) {
} }
return -1; return -1;
} }
void MeosSQL::addedFromDatabase(oBase *object) {
assert(object);
if (object && !object->existInDB()) {
missingObjects.push_back(object);
}
}
void MeosSQL::processMissingObjects() {
if (!missingObjects.empty()) {
auto cpyMissing = missingObjects;
missingObjects.clear();
for (oBase *obj : cpyMissing) {
obj->changed = true;
syncRead(true, obj);
obj->changed = false;
assert(obj->existInDB());
{
oRunner *r = dynamic_cast<oRunner *>(obj);
if (r && r->getName().empty()) {
r->setName(L"@AutoCorrection", false);
syncUpdate(r, false);
}
}
{
oTeam *t = dynamic_cast<oTeam *>(obj);
if (t && t->getName().empty()) {
t->setName(L"@AutoCorrection", false);
syncUpdate(t, false);
}
}
{
oClass *cls = dynamic_cast<oClass *>(obj);
if (cls && cls->getName().empty()) {
cls->setName(L"@AutoCorrection");
syncUpdate(cls, false);
}
}
{
oCourse *crs = dynamic_cast<oCourse *>(obj);
if (crs && crs->getName().empty()) {
crs->setName(L"@AutoCorrection");
syncUpdate(crs, false);
}
}
{
oClub *clb = dynamic_cast<oClub *>(obj);
if (clb && clb->getName().empty()) {
clb->setName(L"@AutoCorrection");
syncUpdate(clb, false);
}
}
}
}
missingObjects.clear();
}
OpFailStatus MeosSQL::syncRead(bool forceRead, oBase *obj) {
OpFailStatus ret = OpFailStatus::opStatusFail;
if (typeid(*obj) == typeid(oRunner)) {
ret = syncRead(forceRead, (oRunner *)obj);
}
else if (typeid(*obj) == typeid(oClass)) {
ret = syncRead(forceRead, (oClass *)obj);
}
else if (typeid(*obj) == typeid(oCourse)) {
ret = syncRead(forceRead, (oCourse *)obj);
}
else if (typeid(*obj) == typeid(oControl)) {
ret = syncRead(forceRead, (oControl *)obj);
}
else if (typeid(*obj) == typeid(oClub)) {
ret = syncRead(forceRead, (oClub *)obj);
}
else if (typeid(*obj) == typeid(oCard)) {
ret = syncRead(forceRead, (oCard *)obj);
}
else if (typeid(*obj) == typeid(oFreePunch)) {
ret = syncRead(forceRead, (oFreePunch *)obj, true);
}
else if (typeid(*obj) == typeid(oTeam)) {
ret = syncRead(forceRead, (oTeam *)obj);
}
else if (typeid(*obj) == typeid(oEvent)) {
ret = SyncRead((oEvent *)obj);
}
else
throw std::exception("Database error");
processMissingObjects();
return ret;
}

View File

@ -58,6 +58,8 @@ protected:
string CmpDataBase; string CmpDataBase;
void alert(const string &s); void alert(const string &s);
vector<oBase *> missingObjects;
string errorMessage; string errorMessage;
string serverName; string serverName;
@ -94,16 +96,19 @@ protected:
void storePunch(const mysqlpp::Row &row, oFreePunch &p, bool rehash); void storePunch(const mysqlpp::Row &row, oFreePunch &p, bool rehash);
OpFailStatus storeTeam(const mysqlpp::Row &row, oTeam &t, OpFailStatus storeTeam(const mysqlpp::Row &row, oTeam &t,
bool readRecursive); bool readRecursive, bool allowSubRead);
OpFailStatus storeRunner(const mysqlpp::Row &row, oRunner &r, OpFailStatus storeRunner(const mysqlpp::Row &row, oRunner &r,
bool readCourseCard, bool readCourseCard,
bool readClassClub, bool readClassClub,
bool readRunners); bool readRunners,
bool allowSubRead);
OpFailStatus storeCourse(const mysqlpp::Row &row, oCourse &c, OpFailStatus storeCourse(const mysqlpp::Row &row, oCourse &c,
set<int> &readControls); set<int> &readControls,
bool allowSubRead);
OpFailStatus storeClass(const mysqlpp::Row &row, oClass &c, OpFailStatus storeClass(const mysqlpp::Row &row, oClass &c,
bool readCourses); bool readCourses,
bool allowSubRead);
void getColumns(const string &table, set<string> &output); void getColumns(const string &table, set<string> &output);
@ -120,9 +125,13 @@ protected:
mysqlpp::ResNSel updateCounter(const char *oTable, int id, mysqlpp::Query *updateqry); mysqlpp::ResNSel updateCounter(const char *oTable, int id, mysqlpp::Query *updateqry);
string selectUpdated(const char *oTable, const string &updated, int counter); string selectUpdated(const char *oTable, const string &updated, int counter);
void addedFromDatabase(oBase *object);
public: public:
bool dropDatabase(oEvent *oe); bool dropDatabase(oEvent *oe);
bool checkConnection(oEvent *oe); bool checkConnection(oEvent *oe);
void processMissingObjects();
bool repairTables(const string &db, vector<string> &output); bool repairTables(const string &db, vector<string> &output);
@ -179,6 +188,10 @@ public:
OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll); OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll);
OpFailStatus syncRead(bool forceRead, oTeam *t); OpFailStatus syncRead(bool forceRead, oTeam *t);
/** General interface. TypeId lookup */
OpFailStatus syncRead(bool forceRead, oBase *c);
int getModifiedMask(oEvent &oe); int getModifiedMask(oEvent &oe);
MeosSQL(void); MeosSQL(void);

View File

@ -74,25 +74,36 @@ bool MEOSDB_API msSynchronizeList(oEvent *oe, oListId lid)
nSynchList++; nSynchList++;
if (nSynchList % 100 == 99) if (nSynchList % 100 == 99)
OutputDebugString(L"Synchronized 100 lists\n"); OutputDebugString(L"Synchronized 100 lists\n");
bool ret = false;
switch (lid) {
case oListId::oLRunnerId:
ret = msql.syncListRunner(oe);
break;
case oListId::oLClassId:
ret = msql.syncListClass(oe);
break;
case oListId::oLCourseId:
ret = msql.syncListCourse(oe);
break;
case oListId::oLControlId:
ret = msql.syncListControl(oe);
break;
case oListId::oLClubId:
ret = msql.syncListClub(oe);
break;
case oListId::oLCardId:
ret = msql.syncListCard(oe);
break;
case oListId::oLPunchId:
ret = msql.syncListPunch(oe);
break;
case oListId::oLTeamId:
ret = msql.syncListTeam(oe);
break;
}
if (lid == oListId::oLRunnerId) msql.processMissingObjects();
return msql.syncListRunner(oe); return ret;
else if (lid == oListId::oLClassId)
return msql.syncListClass(oe);
else if (lid == oListId::oLCourseId)
return msql.syncListCourse(oe);
else if (lid == oListId::oLControlId)
return msql.syncListControl(oe);
else if (lid == oListId::oLClubId)
return msql.syncListClub(oe);
else if (lid == oListId::oLCardId)
return msql.syncListCard(oe);
else if (lid == oListId::oLPunchId)
return msql.syncListPunch(oe);
else if (lid == oListId::oLTeamId)
return msql.syncListTeam(oe);
return false;
} }
int MEOSDB_API msSynchronizeUpdate(oBase *obj) int MEOSDB_API msSynchronizeUpdate(oBase *obj)
@ -134,34 +145,7 @@ int MEOSDB_API msSynchronizeRead(oBase *obj)
if (nSynchEnt % 100 == 99) if (nSynchEnt % 100 == 99)
OutputDebugString(L"Synchronized 100 entities\n"); OutputDebugString(L"Synchronized 100 entities\n");
if (typeid(*obj)==typeid(oRunner)){ return msql.syncRead(false, obj);
return msql.syncRead(false, (oRunner *) obj );
}
else if (typeid(*obj)==typeid(oClass)){
return msql.syncRead(false, (oClass *) obj);
}
else if (typeid(*obj)==typeid(oCourse)){
return msql.syncRead(false, (oCourse *) obj);
}
else if (typeid(*obj)==typeid(oControl)){
return msql.syncRead(false, (oControl *) obj);
}
else if (typeid(*obj)==typeid(oClub)){
return msql.syncRead(false, (oClub *) obj);
}
else if (typeid(*obj)==typeid(oCard)){
return msql.syncRead(false, (oCard *) obj);
}
else if (typeid(*obj)==typeid(oFreePunch)){
return msql.syncRead(false, (oFreePunch *) obj, true);
}
else if (typeid(*obj)==typeid(oTeam)){
return msql.syncRead(false, (oTeam *) obj);
}
else if (typeid(*obj)==typeid(oEvent)){
return msql.SyncRead((oEvent *) obj);
}
return 0;
} }
// Removes (marks it as removed) an entry from the database. // Removes (marks it as removed) an entry from the database.

View File

@ -30,7 +30,7 @@
//V35: abcdef //V35: abcdef
//V36: abcdef //V36: abcdef
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 912 $"); string revision("$Rev: 915 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
@ -42,12 +42,12 @@ int getMeosBuild() {
//V33: abcdefghij //V33: abcdefghij
//V34: abcdfge //V34: abcdfge
wstring getMeosDate() { wstring getMeosDate() {
wstring date(L"$Date: 2019-06-16 10:37:59 +0200 (sö, 16 jun 2019) $"); wstring date(L"$Date: 2019-07-30 07:05:51 +0200 (ti, 30 jul 2019) $");
return date.substr(7,10); return date.substr(7,10);
} }
wstring getBuildType() { wstring getBuildType() {
return L"Update 1"; // No parantheses (...) return L"Update 2"; // No parantheses (...)
} }
wstring getMajorVersion() { wstring getMajorVersion() {
@ -60,7 +60,7 @@ wstring getMeosFullVersion() {
if (getBuildType().empty()) if (getBuildType().empty())
swprintf_s(bf, L"Version X#%s.%d, %s", maj.c_str(), getMeosBuild(), getMeosDate().c_str()); swprintf_s(bf, L"Version X#%s.%d, %s", maj.c_str(), getMeosBuild(), getMeosDate().c_str());
else else
swprintf_s(bf, L"Version X#%s.%d, %s %s", maj.c_str(), getMeosBuild(), getBuildType().c_str(), getMeosDate().c_str()); swprintf_s(bf, L"Version X#%s.%d, %s, %s", maj.c_str(), getMeosBuild(), getBuildType().c_str(), getMeosDate().c_str());
return bf; return bf;
} }
@ -133,5 +133,8 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
supp.emplace_back(L"Kexholm SK"); supp.emplace_back(L"Kexholm SK");
supp.emplace_back(L"Utby IK"); supp.emplace_back(L"Utby IK");
supp.emplace_back(L"JWOC 2019"); supp.emplace_back(L"JWOC 2019");
developSupp.emplace_back(L"OK Nackhe");
supp.emplace_back(L"OK Rodhen");
reverse(supp.begin(), supp.end()); reverse(supp.begin(), supp.end());
} }

View File

@ -101,17 +101,20 @@ protected:
TimeStamp Modified; TimeStamp Modified;
string sqlUpdated; //SQL TIMESTAMP string sqlUpdated; //SQL TIMESTAMP
int counter; int counter;
oEvent *oe;
bool Removed;
// True if the object is incorrect and needs correction // True if the object is incorrect and needs correction
// An example is if id changed as we wrote. Then owner // An example is if id changed as we wrote. Then owner
// needs to be updated. // needs to be updated.
bool correctionNeeded; bool correctionNeeded = false;
oEvent *oe; private:
bool Removed;
//Used for selections, etc. bool implicitlyAdded = false;
int _objectmarker; bool addedToEvent = false;
protected:
/// Mark the object as changed (on client) and that it needs synchronize to server /// Mark the object as changed (on client) and that it needs synchronize to server
virtual void updateChanged(); virtual void updateChanged();
@ -165,6 +168,11 @@ public:
bool existInDB() const { return !sqlUpdated.empty(); } bool existInDB() const { return !sqlUpdated.empty(); }
void setImplicitlyCreated() { implicitlyAdded = true; }
bool isImplicitlyCreated() const { return implicitlyAdded; }
bool isAddedToEvent() const { return addedToEvent; }
void addToEvent() { addedToEvent = true; }
oDataInterface getDI(); oDataInterface getDI();
oDataConstInterface getDCI() const; oDataConstInterface getDCI() const;

View File

@ -487,7 +487,7 @@ bool oCard::setPunchTime(const pPunch punch, const wstring &time)
pCard oEvent::getCard(int Id) const pCard oEvent::getCard(int Id) const
{ { // Do allow removed cards
if (Id < int(Cards.size() / 2)) { if (Id < int(Cards.size() / 2)) {
for (oCardList::const_iterator it = Cards.begin(); it != Cards.end(); ++it){ for (oCardList::const_iterator it = Cards.begin(); it != Cards.end(); ++it){
if (it->Id==Id) if (it->Id==Id)
@ -514,18 +514,17 @@ void oEvent::getCards(vector<pCard> &c) {
} }
} }
pCard oEvent::addCard(const oCard &oc) pCard oEvent::addCard(const oCard &oc)
{ {
if (oc.Id<=0) if (oc.Id<=0)
return 0; return 0;
Cards.push_back(oc); Cards.push_back(oc);
Cards.back().addToEvent();
return &Cards.back(); return &Cards.back();
} }
pCard oEvent::getCardByNumber(int cno) const pCard oEvent::getCardByNumber(int cno) const
{ {
oCardList::const_reverse_iterator it; oCardList::const_reverse_iterator it;

View File

@ -716,6 +716,7 @@ pClass oEvent::addClass(const wstring &pname, int CourseId, int classId)
c.Course=getCourse(CourseId); c.Course=getCourse(CourseId);
Classes.push_back(c); Classes.push_back(c);
Classes.back().addToEvent();
Classes.back().synchronize(); Classes.back().synchronize();
updateTabs(); updateTabs();
return &Classes.back(); return &Classes.back();
@ -732,8 +733,9 @@ pClass oEvent::addClass(oClass &c)
} }
Classes.push_back(c); Classes.push_back(c);
Classes.back().addToEvent();
if (!Classes.back().existInDB()) { if (!Classes.back().existInDB() && !c.isImplicitlyCreated()) {
Classes.back().changed = true; Classes.back().changed = true;
Classes.back().synchronize(); Classes.back().synchronize();
} }

View File

@ -233,7 +233,7 @@ pClub oEvent::addClub(const wstring &pname, int createId) {
oClub c(this, createId); oClub c(this, createId);
c = *dbClub; c = *dbClub;
c.Id = createId; c.Id = createId;
Clubs.push_back(c); return addClub(c);
} }
else { else {
if (createId==0) if (createId==0)
@ -241,11 +241,8 @@ pClub oEvent::addClub(const wstring &pname, int createId) {
oClub c(this, createId); oClub c(this, createId);
c.setName(pname); c.setName(pname);
Clubs.push_back(c); return addClub(c);
} }
Clubs.back().synchronize();
clubIdIndex[Clubs.back().Id]=&Clubs.back();
return &Clubs.back();
} }
pClub oEvent::addClub(const oClub &oc) pClub oEvent::addClub(const oClub &oc)
@ -254,6 +251,8 @@ pClub oEvent::addClub(const oClub &oc)
return clubIdIndex[oc.Id]; return clubIdIndex[oc.Id];
Clubs.push_back(oc); Clubs.push_back(oc);
Clubs.back().addToEvent();
if (!oc.existInDB()) if (!oc.existInDB())
Clubs.back().synchronize(); Clubs.back().synchronize();

View File

@ -64,7 +64,7 @@
#include "Table.h" #include "Table.h"
//Version of database //Version of database
int oEvent::dbVersion = 82; int oEvent::dbVersion = 83;
class RelativeTimeFormatter : public oDataDefiner { class RelativeTimeFormatter : public oDataDefiner {
string name; string name;
@ -610,7 +610,7 @@ pControl oEvent::addControl(int Id, int Number, const wstring &Name)
oControl c(this); oControl c(this);
c.set(Id, Number, Name); c.set(Id, Number, Name);
Controls.push_back(c); addControl(c);
oe->updateTabs(); oe->updateTabs();
return &Controls.back(); return &Controls.back();
@ -636,6 +636,8 @@ pControl oEvent::addControl(const oControl &oc)
qFreeControlId = max (qFreeControlId, Id); qFreeControlId = max (qFreeControlId, Id);
Controls.push_back(oc); Controls.push_back(oc);
oe->Controls.back().addToEvent();
return &Controls.back(); return &Controls.back();
} }
@ -1181,9 +1183,8 @@ bool oEvent::open(const xmlparser &xml) {
oControl c(this); oControl c(this);
c.set(&*it); c.set(&*it);
if (c.Id>0 && knownControls.count(c.Id) == 0) { if (c.Id>0 && knownControls.insert(c.Id).second) {
Controls.push_back(c); addControl(c);
knownControls.insert(c.Id);
} }
} }
} }
@ -1227,6 +1228,7 @@ bool oEvent::open(const xmlparser &xml) {
c.Set(&*it); c.Set(&*it);
if (c.Id>0 && knownClass.count(c.Id) == 0) { if (c.Id>0 && knownClass.count(c.Id) == 0) {
Classes.push_back(c); Classes.push_back(c);
Classes.back().addToEvent();
knownClass.insert(c.Id); knownClass.insert(c.Id);
} }
} }
@ -1249,7 +1251,7 @@ bool oEvent::open(const xmlparser &xml) {
oClub c(this); oClub c(this);
c.set(*it); c.set(*it);
if (c.Id>0) if (c.Id>0)
addClub(c);//Clubs.push_back(c); addClub(c);
} }
} }
} }
@ -1341,7 +1343,7 @@ bool oEvent::open(const xmlparser &xml) {
oCard c(this); oCard c(this);
c.Set(*it); c.Set(*it);
assert(c.Id>=0); assert(c.Id>=0);
Cards.push_back(c); addCard(c);
} }
} }
} }
@ -1576,8 +1578,9 @@ pCourse oEvent::addCourse(const oCourse &oc)
qFreeCourseId=max(qFreeCourseId, oc.getId()); qFreeCourseId=max(qFreeCourseId, oc.getId());
pCourse pc = &Courses.back(); pCourse pc = &Courses.back();
pc->addToEvent();
if (!pc->existInDB()) { if (!pc->existInDB() && !pc->isImplicitlyCreated()) {
pc->updateChanged(); pc->updateChanged();
pc->synchronize(); pc->synchronize();
} }
@ -1609,7 +1612,7 @@ void oEvent::autoRemoveTeam(pRunner pr)
if (pr->tInTeam) { if (pr->tInTeam) {
// A team may have more than this runner -> do not remove // A team may have more than this runner -> do not remove
bool canRemove = true; bool canRemove = true;
const vector<pRunner> &runners = pr->tInTeam->Runners; const auto &runners = pr->tInTeam->Runners;
for (size_t k = 0; k<runners.size(); k++) { for (size_t k = 0; k<runners.size(); k++) {
if (runners[k] && runners[k]->sName != pr->sName) if (runners[k] && runners[k]->sName != pr->sName)
canRemove = false; canRemove = false;
@ -1726,6 +1729,14 @@ pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) {
Runners.push_back(r); Runners.push_back(r);
pRunner pr=&Runners.back(); pRunner pr=&Runners.back();
pr->addToEvent();
for (size_t i = 0; i < pr->multiRunner.size(); i++) {
if (pr->multiRunner[i]) {
assert(pr->multiRunner[i]->tParentRunner == nullptr || pr->multiRunner[i]->tParentRunner == &r);
pr->multiRunner[i]->tParentRunner = pr;
}
}
//cardToRunnerHash.reset(); //cardToRunnerHash.reset();
if (cardToRunnerHash && r.getCardNo() != 0) { if (cardToRunnerHash && r.getCardNo() != 0) {
@ -1743,7 +1754,7 @@ pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) {
pr->Card->tOwner = pr; pr->Card->tOwner = pr;
if (HasDBConnection) { if (HasDBConnection) {
if (!pr->existInDB()) if (!pr->existInDB() && !pr->isImplicitlyCreated())
pr->synchronize(); pr->synchronize();
} }
if (needUpdate) if (needUpdate)
@ -2041,6 +2052,7 @@ pCard oEvent::allocateCard(pRunner owner)
c.tOwner = owner; c.tOwner = owner;
Cards.push_back(c); Cards.push_back(c);
pCard newCard = &Cards.back(); pCard newCard = &Cards.back();
newCard->addToEvent();
return newCard; return newCard;
} }
@ -2152,7 +2164,7 @@ bool oEvent::sortTeams(SortOrder so, int leg, bool linearLeg) {
// Count number of races with results // Count number of races with results
int numResult = 0; int numResult = 0;
int lastClassHeat = 0; int lastClassHeat = 0;
for (pRunner r : it->Runners) { for (auto &r : it->Runners) {
if (r && (r->prelStatusOK() || if (r && (r->prelStatusOK() ||
(r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) { (r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) {
@ -2266,7 +2278,7 @@ bool oEvent::sortTeams(SortOrder so, int leg, bool linearLeg, vector<const oTeam
// Count number of races with results // Count number of races with results
int numResult = 0; int numResult = 0;
int lastClassHeat = 0; int lastClassHeat = 0;
for (pRunner r : it->Runners) { for (auto &r : it->Runners) {
if (r && (r->prelStatusOK() || if (r && (r->prelStatusOK() ||
(r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) { (r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) {
@ -2675,7 +2687,7 @@ void oEvent::removeRunner(const vector<int> &ids)
// Reset team runner (this should not happen) // Reset team runner (this should not happen)
if (it->tInTeam) { if (it->tInTeam) {
if (it->tInTeam->Runners[it->tLeg]==&*it) if (it->tInTeam->Runners[it->tLeg]==&*it)
it->tInTeam->Runners[it->tLeg] = 0; it->tInTeam->Runners[it->tLeg] = nullptr;
} }
oRunnerList::iterator next = it; oRunnerList::iterator next = it;
@ -4451,10 +4463,10 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
if (!firstNumber.empty()) { if (!firstNumber.empty()) {
// Clear out start number temporarily, to not use it for sorting // Clear out start number temporarily, to not use it for sorting
for (it=Teams.begin(); it != Teams.end(); ++it) { for (it = Teams.begin(); it != Teams.end(); ++it) {
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
if (ClassId==0 || it->getClassId(false)==ClassId) { if (ClassId == 0 || it->getClassId(false) == ClassId) {
if (it->getClassRef(false) && it->getClassRef(false)->getBibMode() != BibFree) { if (it->getClassRef(false) && it->getClassRef(false)->getBibMode() != BibFree) {
for (size_t i = 0; i < it->Runners.size(); i++) { for (size_t i = 0; i < it->Runners.size(); i++) {
if (it->Runners[i]) { if (it->Runners[i]) {

View File

@ -629,7 +629,7 @@ public:
enum PredefinedTypes {PNoSettings, PPool, PForking, PPoolDrawn, PHunting, enum PredefinedTypes {PNoSettings, PPool, PForking, PPoolDrawn, PHunting,
PPatrol, PPatrolOptional, PPatrolOneSI, PRelay, PTwinRelay, PPatrol, PPatrolOptional, PPatrolOneSI, PRelay, PTwinRelay,
PYouthRelay, PNoMulti}; PYouthRelay, PTwoRacesNoOrder, PNoMulti};
void fillPredefinedCmp(gdioutput &gdi, const string &name) const; void fillPredefinedCmp(gdioutput &gdi, const string &name) const;

View File

@ -651,7 +651,7 @@ bool oEvent::readSynchronize(const CompetitionInfo &ci)
pRunner r = it->Runners[i]; pRunner r = it->Runners[i];
if (r != 0) { if (r != 0) {
if (usedInTeam[r->Id]) { if (usedInTeam[r->Id]) {
it->Runners[i] = 0; // Reset duplicate runners it->Runners[i] = nullptr; // Reset duplicate runners
it->updateChanged(); it->updateChanged();
teamCorrected = true; teamCorrected = true;
if (r->tInTeam == &*it) if (r->tInTeam == &*it)

View File

@ -442,7 +442,6 @@ bool oEvent::isInPunchHash(int card, int code, int time) {
return readPunchHash.count(make_pair(p1, p2)) > 0; return readPunchHash.count(make_pair(p1, p2)) > 0;
} }
pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFinish) { pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFinish) {
if (time > 0 && isInPunchHash(card, type, time)) if (time > 0 && isInPunchHash(card, type, time))
return 0; return 0;
@ -450,6 +449,7 @@ pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFi
punches.push_back(ofp); punches.push_back(ofp);
pFreePunch fp=&punches.back(); pFreePunch fp=&punches.back();
fp->addToEvent();
oFreePunch::rehashPunches(*this, card, fp); oFreePunch::rehashPunches(*this, card, fp);
insertIntoPunchHash(card, type, time); insertIntoPunchHash(card, type, time);
@ -519,6 +519,7 @@ pFreePunch oEvent::addFreePunch(oFreePunch &fp) {
insertIntoPunchHash(fp.CardNo, fp.Type, fp.Time); insertIntoPunchHash(fp.CardNo, fp.Type, fp.Time);
punches.push_back(fp); punches.push_back(fp);
pFreePunch fpz=&punches.back(); pFreePunch fpz=&punches.back();
fpz->addToEvent();
oFreePunch::rehashPunches(*this, fp.CardNo, fpz); oFreePunch::rehashPunches(*this, fp.CardNo, fpz);
if (!fpz->existInDB() && HasDBConnection) { if (!fpz->existInDB() && HasDBConnection) {
@ -618,43 +619,6 @@ void oEvent::getPunchesForRunner(int runnerId, bool doSort, vector<pFreePunch> &
pRunner r = getRunner(runnerId, 0); pRunner r = getRunner(runnerId, 0);
if (r == 0) if (r == 0)
return; return;
/*
// Get times for when other runners used this card
vector< pair<int, int> > times;
int refCno = r->getCardNo();
for (auto it = Runners.begin(); it != Runners.end(); ++it) {
if (it->Id == runnerId)
continue;
if (it->Card && it->getCardNo() == refCno) {
pair<int, int> t = it->Card->getTimeRange();
if (it->getStartTime() > 0)
t.first = min(it->getStartTime(), t.first);
if (it->getFinishTime() > 0)
t.second = max(it->getFinishTime(), t.second);
times.push_back(t);
}
}
for (oFreePunchList::const_iterator it = punches.begin(); it != punches.end(); ++it) {
if (it->CardNo == refCno) {
if (it->isRemoved() || it->isHiredCard())
continue;
bool other = false;
int t = it->Time;
for (size_t k = 0; k<times.size(); k++) {
if (t >= times[k].first && t <= times[k].second)
other = true;
}
if (!other)
runnerPunches.push_back(pFreePunch(&*it));
}
}
*/
//Lazy setup //Lazy setup
oFreePunch::rehashPunches(*oe, 0, 0); oFreePunch::rehashPunches(*oe, 0, 0);

View File

@ -582,9 +582,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
} }
} }
// Clear markers map<int, int> objectMarkers;
for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it)
r_it->_objectmarker=0;
//List all competitors not in a team. //List all competitors not in a team.
if (oe->hasTeam()) { if (oe->hasTeam()) {
@ -596,7 +594,9 @@ void oEvent::generatePreReport(gdioutput &gdi) {
if (pc){ if (pc){
for(unsigned i=0;i<pc->getNumStages();i++){ for(unsigned i=0;i<pc->getNumStages();i++){
pRunner r=t_it->getRunner(i); pRunner r=t_it->getRunner(i);
if (r) r->_objectmarker++; if (r) {
++objectMarkers[r->getId()];
}
} }
} }
} }
@ -605,7 +605,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
gdi.addString("", 1, "Löpare som förekommer i mer än ett lag:"); gdi.addString("", 1, "Löpare som förekommer i mer än ett lag:");
bool any = false; bool any = false;
for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){ for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it){
if (r_it->_objectmarker>1) { if (objectMarkers[r_it->getId()] > 1) {
wstring name = r_it->getClass(true) + L": " + r_it->getName(); wstring name = r_it->getClass(true) + L": " + r_it->getName();
if (!r_it->getClub().empty()) if (!r_it->getClub().empty())
name += L" (" + r_it->getClub() + L")"; name += L" (" + r_it->getClub() + L")";
@ -627,7 +627,7 @@ void oEvent::generatePreReport(gdioutput &gdi) {
for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) { for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) {
if (r_it->isRemoved()) if (r_it->isRemoved())
continue; continue;
if (r_it->_objectmarker==0){ //Only consider runners not in a team. if (objectMarkers.count(r_it->getId()) == 0){ //Only consider runners not in a team.
gdi.addStringUT(y, x+tab[0], 0, r_it->getClass(true), tab[1]-tab[0]); gdi.addStringUT(y, x+tab[0], 0, r_it->getClass(true), tab[1]-tab[0]);
wstring name = r_it->getName(); wstring name = r_it->getName();
if (!r_it->getClub().empty()) if (!r_it->getClub().empty())

View File

@ -191,21 +191,21 @@ oRunner::~oRunner()
{ {
if (tInTeam){ if (tInTeam){
for(unsigned i=0;i<tInTeam->Runners.size(); i++) for(unsigned i=0;i<tInTeam->Runners.size(); i++)
if (tInTeam->Runners[i] && tInTeam->Runners[i]==this) if (tInTeam->Runners[i] && tInTeam->Runners[i]->getId() == Id)
tInTeam->Runners[i]=0; tInTeam->Runners[i] = nullptr;
tInTeam=0; tInTeam=0;
} }
for (size_t k=0;k<multiRunner.size(); k++) { for (size_t k=0;k<multiRunner.size(); k++) {
if (multiRunner[k]) if (multiRunner[k] && multiRunner[k]->tParentRunner == this)
multiRunner[k]->tParentRunner=0; multiRunner[k]->tParentRunner = nullptr;
} }
if (tParentRunner) { if (tParentRunner) {
for (size_t k=0;k<tParentRunner->multiRunner.size(); k++) for (size_t k=0;k<tParentRunner->multiRunner.size(); k++)
if (tParentRunner->multiRunner[k] == this) if (tParentRunner->multiRunner[k] == this)
tParentRunner->multiRunner[k]=0; tParentRunner->multiRunner[k] = nullptr;
} }
delete tAdaptedCourse; delete tAdaptedCourse;
@ -2200,6 +2200,7 @@ void oRunner::updateStartNo(int no) {
tInTeam->synchronize(true); tInTeam->synchronize(true);
for (pRunner r : tInTeam->Runners) { for (pRunner r : tInTeam->Runners) {
if (r)
r->synchronize(true); r->synchronize(true);
} }
} }
@ -2302,12 +2303,14 @@ void oRunner::setCardNo(int cno, bool matchCard, bool updateFromDatabase)
int oldNo = getCardNo(); int oldNo = getCardNo();
cardNumber = cno; cardNumber = cno;
if (oe->cardToRunnerHash && cno != 0 && !isTemporaryObject) { if (oe->cardToRunnerHash && cno != 0 && isAddedToEvent() && !isTemporaryObject) {
oe->cardToRunnerHash->emplace(cno, this); oe->cardToRunnerHash->emplace(cno, this);
} }
if (isAddedToEvent()) {
oFreePunch::rehashPunches(*oe, oldNo, 0); oFreePunch::rehashPunches(*oe, oldNo, 0);
oFreePunch::rehashPunches(*oe, cardNumber, 0); oFreePunch::rehashPunches(*oe, cardNumber, 0);
}
if (matchCard && !Card) { if (matchCard && !Card) {
pCard c = oe->getCardByNumber(cno); pCard c = oe->getCardByNumber(cno);
@ -2862,21 +2865,23 @@ pRunner oEvent::getRunnerByBibOrStartNo(const wstring &bib, bool findWithoutCard
if (t.getStartNo()==sno || stringMatch(t.getBib(), bib)) { if (t.getStartNo()==sno || stringMatch(t.getBib(), bib)) {
if (!findWithoutCardNo) { if (!findWithoutCardNo) {
for (int leg=0; leg<t.getNumRunners(); leg++) { for (int leg=0; leg<t.getNumRunners(); leg++) {
if (t.Runners[leg] && t.Runners[leg]->getCardNo() > 0 && t.Runners[leg]->getStatus()==StatusUnknown) pRunner r = t.Runners[leg];
return t.Runners[leg]; if (r && r->getCardNo() > 0 && r->getStatus()==StatusUnknown)
return r;
} }
} }
else { else {
for (int leg=0; leg<t.getNumRunners(); leg++) { for (int leg=0; leg<t.getNumRunners(); leg++) {
if (t.Runners[leg] && t.Runners[leg]->getCardNo() == 0 && t.Runners[leg]->needNoCard() == false) pRunner r = t.Runners[leg];
return t.Runners[leg]; if (r && r->getCardNo() == 0 && r->needNoCard() == false)
return r;
} }
} }
} }
} }
} }
} }
return 0; return nullptr;
} }
pRunner oEvent::getRunnerByName(const wstring &pname, const wstring &pclub) const pRunner oEvent::getRunnerByName(const wstring &pname, const wstring &pclub) const
@ -3027,7 +3032,7 @@ void oRunner::createMultiRunner(bool createMaster, bool sync)
{ {
if (tDuplicateLeg) if (tDuplicateLeg)
return; //Never allow chains. return; //Never allow chains.
bool allowCreate = true;
if (multiRunnerId.size()>0) { if (multiRunnerId.size()>0) {
multiRunner.resize(multiRunnerId.size() - 1); multiRunner.resize(multiRunnerId.size() - 1);
for (size_t k=0;k<multiRunner.size();k++) { for (size_t k=0;k<multiRunner.size();k++) {
@ -3044,8 +3049,10 @@ void oRunner::createMultiRunner(bool createMaster, bool sync)
if (multiRunner[k]->Id != multiRunnerId[k]) if (multiRunner[k]->Id != multiRunnerId[k])
markForCorrection(); markForCorrection();
} }
else if (multiRunnerId[k]>0) else if (multiRunnerId[k] > 0) {
markForCorrection(); markForCorrection();
allowCreate = false;
}
assert(multiRunner[k]); assert(multiRunner[k]);
} }
@ -3071,23 +3078,24 @@ void oRunner::createMultiRunner(bool createMaster, bool sync)
toRemove.push_back(multiRunner[k]->getId()); toRemove.push_back(multiRunner[k]->getId());
multiRunner[k]->tParentRunner = 0; multiRunner[k]->tParentRunner = 0;
if (multiRunner[k]->tInTeam && size_t(multiRunner[k]->tLeg)<multiRunner[k]->tInTeam->Runners.size()) { if (multiRunner[k]->tInTeam && size_t(multiRunner[k]->tLeg)<multiRunner[k]->tInTeam->Runners.size()) {
if (multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg]==multiRunner[k]) if (multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] == multiRunner[k])
multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] = 0; multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] = nullptr;
} }
} }
} }
multiRunner.resize(ndup-1); multiRunner.resize(ndup-1);
for(int k=1;k<ndup; k++) { for (int k = 1; k < ndup; k++) {
if (!multiRunner[k-1]) { if (!multiRunner[k - 1] && allowCreate) {
update = true; update = true;
multiRunner[k-1]=oe->addRunner(sName, getClubId(), multiRunner[k - 1] = oe->addRunner(sName, getClubId(),
getClassId(false), 0, 0, false); getClassId(false), 0, 0, false);
multiRunner[k-1]->tDuplicateLeg=k; multiRunner[k - 1]->tDuplicateLeg = k;
multiRunner[k-1]->tParentRunner=this; multiRunner[k - 1]->tParentRunner = this;
multiRunner[k - 1]->cardNumber = 0;
if (sync) if (sync)
multiRunner[k-1]->synchronize(); multiRunner[k - 1]->synchronize();
} }
} }
if (update) if (update)
@ -3111,6 +3119,13 @@ pRunner oRunner::getPredecessor() const
} }
bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) { bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) {
for (size_t k = 0; k < multiRunner.size(); k++) {
if (multiRunner[k] && multiRunner[k]->isRemoved()) {
multiRunner[k]->tParentRunner = nullptr;
multiRunner[k] = nullptr;
}
}
createMultiRunner(false, sync); createMultiRunner(false, sync);
if (sync) { if (sync) {
for (size_t k = 0; k < multiRunner.size(); k++) { for (size_t k = 0; k < multiRunner.size(); k++) {

View File

@ -159,7 +159,7 @@ string oTeam::getRunners() const
for(m=0;m<Runners.size();m++){ for(m=0;m<Runners.size();m++){
if (Runners[m]){ if (Runners[m]){
sprintf_s(bf, 16, "%d;", Runners[m]->Id); sprintf_s(bf, 16, "%d;", Runners[m]->getId());
str+=bf; str+=bf;
} }
else str+="0;"; else str+="0;";
@ -185,40 +185,43 @@ void oTeam::decodeRunners(const string &rns, vector<int> &rid)
} }
} }
void oTeam::importRunners(const vector<int> &rns) void oTeam::importRunners(const vector<int> &rns) {
{
Runners.resize(rns.size()); Runners.resize(rns.size());
for (size_t n=0;n<rns.size(); n++) { for (size_t n=0;n<rns.size(); n++) {
if (rns[n]>0) if (rns[n] > 0)
Runners[n] = oe->getRunner(rns[n], 0); Runners[n] = oe->getRunner(rns[n], 0);
else else
Runners[n] = 0; Runners[n] = nullptr;
pRunner r = Runners[n];
if (r) {
r->tInTeam = this;
r->tLeg = n;
}
} }
} }
void oTeam::importRunners(const vector<pRunner> &rns) void oTeam::importRunners(const vector<pRunner> &rns)
{ {
// Unlink old runners // Unlink old runners
for (size_t k = rns.size(); k<Runners.size(); k++) { for (size_t k = 0; k<Runners.size(); k++) {
if (Runners[k] && Runners[k]->tInTeam == this) { pRunner r = Runners[k];
Runners[k]->tInTeam = 0; if (r && r->tInTeam == this) {
Runners[k]->tLeg = 0; r->tInTeam = 0;
r->tLeg = 0;
} }
} }
Runners.resize(rns.size()); Runners.resize(rns.size());
for (size_t n=0;n<rns.size(); n++) { for (size_t n = 0; n < rns.size(); n++) {
if (Runners[n] && rns[n] != Runners[n]) {
if (Runners[n]->tInTeam == this) {
Runners[n]->tInTeam = 0;
Runners[n]->tLeg = 0;
}
}
Runners[n] = rns[n]; Runners[n] = rns[n];
if (rns[n] && isAddedToEvent()) {
rns[n]->tInTeam = this;
rns[n]->tLeg = n;
}
} }
} }
void oEvent::removeTeam(int Id) void oEvent::removeTeam(int Id)
{ {
oTeamList::iterator it; oTeamList::iterator it;
@ -245,13 +248,14 @@ void oTeam::setRunner(unsigned i, pRunner r, bool sync)
throw std::exception("Bad runner index"); throw std::exception("Bad runner index");
} }
if (Runners[i]==r) if (Runners[i] == r)
return; return;
int oldRaceId = 0; int oldRaceId = 0;
if (Runners[i]) { pRunner tr = Runners[i];
oldRaceId = Runners[i]->getDCI().getInt("RaceId"); if (tr) {
Runners[i]->getDI().setInt("RaceId", 0); oldRaceId = tr->getDCI().getInt("RaceId");
tr->getDI().setInt("RaceId", 0);
} }
setRunnerInternal(i, r); setRunnerInternal(i, r);
@ -285,7 +289,7 @@ void oTeam::setRunner(unsigned i, pRunner r, bool sync)
void oTeam::setRunnerInternal(int k, pRunner r) void oTeam::setRunnerInternal(int k, pRunner r)
{ {
if (r==Runners[k]) { if (r == Runners[k]) {
if (r) { if (r) {
r->tInTeam = this; r->tInTeam = this;
r->tLeg = k; r->tLeg = k;
@ -293,29 +297,30 @@ void oTeam::setRunnerInternal(int k, pRunner r)
return; return;
} }
if (Runners[k]) { pRunner rOld = Runners[k];
assert(Runners[k]->tInTeam == 0 || Runners[k]->tInTeam == this); if (rOld) {
Runners[k]->tInTeam = 0; assert(rOld->tInTeam == 0 || rOld->tInTeam == this);
Runners[k]->tLeg = 0; rOld->tInTeam = 0;
rOld->tLeg = 0;
} }
// Reset old team // Reset old team
if (r && r->tInTeam) { if (r && r->tInTeam) {
if (r->tInTeam->Runners[r->tLeg] != 0) { if (r->tInTeam->Runners[r->tLeg]) {
r->tInTeam->Runners[r->tLeg] = 0; r->tInTeam->Runners[r->tLeg] = nullptr;
r->tInTeam->updateChanged(); r->tInTeam->updateChanged();
if (r->tInTeam != this) if (r->tInTeam != this)
r->tInTeam->synchronize(true); r->tInTeam->synchronize(true);
} }
} }
Runners[k]=r; Runners[k] = r;
if (Runners[k]) { if (r) {
Runners[k]->tInTeam = this; r->tInTeam = this;
Runners[k]->tLeg = k; r->tLeg = k;
if (Class && (Runners[k]->Class==nullptr || Class->getLegType(k) != LTGroup)) if (Class && (r->Class==nullptr || Class->getLegType(k) != LTGroup))
Runners[k]->setClassId(getClassId(false), false); r->setClassId(getClassId(false), false);
} }
updateChanged(); updateChanged();
} }
@ -764,11 +769,9 @@ bool oTeam::compareSNO(const oTeam &a, const oTeam &b) {
b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN; b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN;
} }
bool oTeam::isRunnerUsed(int rId) const {
bool oTeam::isRunnerUsed(int Id) const
{
for(unsigned i=0;i<Runners.size(); i++) { for(unsigned i=0;i<Runners.size(); i++) {
if (Runners[i] && Runners[i]->Id==Id) if (Runners[i] && Runners[i]->getId() == rId)
return true; return true;
} }
return false; return false;
@ -830,13 +833,14 @@ void oTeam::quickApply() {
if (Class && Runners.size()!=size_t(Class->getNumStages())) { if (Class && Runners.size()!=size_t(Class->getNumStages())) {
for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { for (size_t k = Class->getNumStages(); k < Runners.size(); k++) {
if (Runners[k] && Runners[k]->tInTeam) { pRunner tr = Runners[k];
Runners[k]->tInTeam = 0; if (tr && tr->tInTeam) {
Runners[k]->tLeg = 0; tr->tInTeam = 0;
Runners[k]->tLegEquClass = 0; tr->tLeg = 0;
if (Runners[k]->Class == Class) tr->tLegEquClass = 0;
Runners[k]->Class = 0; if (tr->Class == Class)
Runners[k]->updateChanged(); tr->Class = 0;
tr->updateChanged();
} }
} }
Runners.resize(Class->getNumStages()); Runners.resize(Class->getNumStages());
@ -844,8 +848,16 @@ void oTeam::quickApply() {
for (size_t i = 0; i < Runners.size(); i++) { for (size_t i = 0; i < Runners.size(); i++) {
if (Runners[i]) { if (Runners[i]) {
if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { if (Runners[i]->isRemoved()) {
Runners[i]->tInTeam->correctRemove(Runners[i]); // Could happen for database not in sync / invalid manual modification
Runners[i]->tInTeam = nullptr;
Runners[i]->tLeg = 0;
Runners[i] = nullptr;
}
auto tit = Runners[i]->tInTeam;
if (tit && tit!=this) {
tit->correctRemove(Runners[i]);
} }
Runners[i]->tInTeam=this; Runners[i]->tInTeam=this;
Runners[i]->tLeg=i; Runners[i]->tLeg=i;
@ -853,8 +865,6 @@ void oTeam::quickApply() {
} }
} }
bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
if (unsigned(status) >= 100) if (unsigned(status) >= 100)
status = StatusUnknown; // Enforce correct status status = StatusUnknown; // Enforce correct status
@ -866,13 +876,14 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
if (Class && Runners.size()!=size_t(Class->getNumStages())) { if (Class && Runners.size()!=size_t(Class->getNumStages())) {
for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { for (size_t k = Class->getNumStages(); k < Runners.size(); k++) {
if (Runners[k] && Runners[k]->tInTeam) { auto tr = Runners[k];
Runners[k]->tInTeam = 0; if (tr && tr->tInTeam) {
Runners[k]->tLeg = 0; tr->tInTeam = nullptr;
Runners[k]->tLegEquClass = 0; tr->tLeg = 0;
if (Runners[k]->Class == Class) tr->tLegEquClass = 0;
Runners[k]->Class = 0; if (tr->Class == Class)
Runners[k]->updateChanged(); tr->Class = 0;
tr->updateChanged();
} }
} }
Runners.resize(Class->getNumStages()); Runners.resize(Class->getNumStages());
@ -881,7 +892,15 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
BibMode bibMode = (BibMode)-1; BibMode bibMode = (BibMode)-1;
tNumRestarts = 0; tNumRestarts = 0;
vector<int> availableStartTimes; vector<int> availableStartTimes;
for (size_t i=0;i<Runners.size(); i++) { for (size_t i_c=0;i_c<Runners.size(); i_c++) {
const size_t i = i_c;
if (Runners[i] && Runners[i]->isRemoved()) {
// Could happen for database not in sync / invalid manual modification
Runners[i]->tInTeam = nullptr;
Runners[i]->tLeg = 0;
Runners[i] = nullptr;
}
if (!sync && i>0 && source!=0 && Runners[i-1] == source) if (!sync && i>0 && source!=0 && Runners[i-1] == source)
return true; return true;
if (!Runners[i] && Class) { if (!Runners[i] && Class) {
@ -890,7 +909,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
if (lr<i && Runners[lr]) { if (lr<i && Runners[lr]) {
Runners[lr]->createMultiRunner(false, sync); Runners[lr]->createMultiRunner(false, sync);
int dup=Class->getLegRunnerIndex(i); int dup=Class->getLegRunnerIndex(i);
Runners[i]=Runners[lr]->getMultiRunner(dup); Runners[i] = Runners[lr]->getMultiRunner(dup);
} }
} }
@ -899,14 +918,15 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
if (lr == i && Runners[i]->tParentRunner) { if (lr == i && Runners[i]->tParentRunner) {
pRunner parent = Runners[i]->tParentRunner; pRunner parent = Runners[i]->tParentRunner;
for (size_t kk = 0; kk<parent->multiRunner.size(); ++kk) { for (size_t kk = 0; kk<parent->multiRunner.size(); ++kk) {
if (parent->multiRunner[kk] == Runners[i]) { if (Runners[i] == parent->multiRunner[kk]) {
pRunner tr = Runners[i];
parent->multiRunner.erase(parent->multiRunner.begin() + kk); parent->multiRunner.erase(parent->multiRunner.begin() + kk);
Runners[i]->tParentRunner = 0; tr->tParentRunner = 0;
Runners[i]->tDuplicateLeg = 0; tr->tDuplicateLeg = 0;
parent->markForCorrection(); parent->markForCorrection();
parent->updateChanged(); parent->updateChanged();
Runners[i]->markForCorrection(); tr->markForCorrection();
Runners[i]->updateChanged(); tr->updateChanged();
break; break;
} }
} }
@ -918,65 +938,66 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
if (Runners[i]) { if (Runners[i]) {
for (size_t k=0;k<i; k++) for (size_t k=0;k<i; k++)
if (Runners[i] == Runners[k]) if (Runners[i] == Runners[k])
Runners[i] = 0; Runners[i] = nullptr;
} }
if (Runners[i]) { if (Runners[i]) {
pClass actualClass = Runners[i]->getClassRef(true); pRunner tr = Runners[i];
pClass actualClass = tr->getClassRef(true);
if (actualClass == nullptr) if (actualClass == nullptr)
actualClass = Class; actualClass = Class;
if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { if (tr->tInTeam && tr->tInTeam!=this) {
Runners[i]->tInTeam->correctRemove(Runners[i]); tr->tInTeam->correctRemove(tr);
} }
//assert(Runners[i]->tInTeam==0 || Runners[i]->tInTeam==this); //assert(Runners[i]->tInTeam==0 || Runners[i]->tInTeam==this);
Runners[i]->tInTeam = this; tr->tInTeam = this;
Runners[i]->tLeg = i; tr->tLeg = i;
if (Class) { if (Class) {
int unused; int unused;
Class->splitLegNumberParallel(i, Runners[i]->tLegEquClass, unused); Class->splitLegNumberParallel(i, tr->tLegEquClass, unused);
} }
else { else {
Runners[i]->tLegEquClass = i; tr->tLegEquClass = i;
} }
if (actualClass == Class) if (actualClass == Class)
Runners[i]->setStartNo(StartNo, setTmpOnly); tr->setStartNo(StartNo, setTmpOnly);
if (!bib.empty() && Runners[i]->isChanged()) { if (!bib.empty() && tr->isChanged()) {
if (bibMode == -1 && Class) if (bibMode == -1 && Class)
bibMode = Class->getBibMode(); bibMode = Class->getBibMode();
if (bibMode == BibSame) if (bibMode == BibSame)
Runners[i]->setBib(bib, 0, false, setTmpOnly); tr->setBib(bib, 0, false, setTmpOnly);
else if (bibMode == BibAdd) { else if (bibMode == BibAdd) {
wchar_t pattern[32], bf[32]; wchar_t pattern[32], bf[32];
int ibib = oClass::extractBibPattern(bib, pattern) + i; int ibib = oClass::extractBibPattern(bib, pattern) + i;
swprintf_s(bf, pattern, ibib); swprintf_s(bf, pattern, ibib);
Runners[i]->setBib(bf, 0, false, setTmpOnly); tr->setBib(bf, 0, false, setTmpOnly);
} }
else if (bibMode == BibLeg) { else if (bibMode == BibLeg) {
wstring rbib = bib + L"-" + Class->getLegNumber(i); wstring rbib = bib + L"-" + Class->getLegNumber(i);
Runners[i]->setBib(rbib, 0, false, setTmpOnly); tr->setBib(rbib, 0, false, setTmpOnly);
} }
} }
LegTypes legType = Class ? Class->getLegType(i) : LTIgnore; LegTypes legType = Class ? Class->getLegType(i) : LTIgnore;
if (Runners[i]->Class!=Class && legType != LTGroup) { if (tr->Class!=Class && legType != LTGroup) {
Runners[i]->Class=Class; tr->Class=Class;
Runners[i]->updateChanged(); tr->updateChanged();
} }
Runners[i]->tNeedNoCard=false; tr->tNeedNoCard=false;
if (Class) { if (Class) {
pClass pc=Class; pClass pc=Class;
//Ignored runners need no SI-card (used by SI assign function) //Ignored runners need no SI-card (used by SI assign function)
if (legType == LTIgnore) { if (legType == LTIgnore) {
Runners[i]->tNeedNoCard=true; tr->tNeedNoCard=true;
if (lastStatus != StatusUnknown) { if (lastStatus != StatusUnknown) {
Runners[i]->setStatus(max(Runners[i]->tStatus, lastStatus), false, setTmpOnly); tr->setStatus(max(tr->tStatus, lastStatus), false, setTmpOnly);
} }
} }
else else
lastStatus = Runners[i]->getStatus(); lastStatus = tr->getStatus();
StartTypes st = actualClass == pc ? pc->getStartType(i) : actualClass->getStartType(0); StartTypes st = actualClass == pc ? pc->getStartType(i) : actualClass->getStartType(0);
LegTypes lt = legType; LegTypes lt = legType;
@ -987,27 +1008,27 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
} }
if (lt==LTIgnore || lt==LTExtra) { if (lt==LTIgnore || lt==LTExtra) {
if (st != STDrawn) if (st != STDrawn)
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); tr->setStartTime(lastStartTime, false, setTmpOnly);
Runners[i]->tUseStartPunch = (st == STDrawn); tr->tUseStartPunch = (st == STDrawn);
} }
else { //Calculate start time. else { //Calculate start time.
switch (st) { switch (st) {
case STDrawn: //Do nothing case STDrawn: //Do nothing
if (lt==LTParallel || lt==LTParallelOptional) { if (lt==LTParallel || lt==LTParallelOptional) {
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); tr->setStartTime(lastStartTime, false, setTmpOnly);
Runners[i]->tUseStartPunch=false; tr->tUseStartPunch=false;
} }
else else
lastStartTime = Runners[i]->getStartTime(); lastStartTime = tr->getStartTime();
break; break;
case STTime: { case STTime: {
bool prs = false; bool prs = false;
if (Runners[i] && Runners[i]->Card && freeStart) { if (tr && tr->Card && freeStart) {
pCourse crs = Runners[i]->getCourse(false); pCourse crs = tr->getCourse(false);
int startType = crs ? crs->getStartPunchType() : oPunch::PunchStart; int startType = crs ? crs->getStartPunchType() : oPunch::PunchStart;
oPunch *pnc = Runners[i]->Card->getPunchByType(startType); oPunch *pnc = tr->Card->getPunchByType(startType);
if (pnc && pnc->getAdjustedTime() > 0) { if (pnc && pnc->getAdjustedTime() > 0) {
prs = true; prs = true;
lastStartTime = pnc->getAdjustedTime(); lastStartTime = pnc->getAdjustedTime();
@ -1020,8 +1041,8 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
else else
lastStartTime = actualClass->getStartData(0); // Qualification/final classes lastStartTime = actualClass->getStartData(0); // Qualification/final classes
} }
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); tr->setStartTime(lastStartTime, false, setTmpOnly);
Runners[i]->tUseStartPunch=false; tr->tUseStartPunch=false;
} }
} }
break; break;
@ -1080,19 +1101,19 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
int rope=pc->getRopeTime(i); int rope=pc->getRopeTime(i);
if (((restart > 0 && rope > 0 && (ft == 0 || ft > rope)) || (ft == 0 && restart > 0)) && if (((restart > 0 && rope > 0 && (ft == 0 || ft > rope)) || (ft == 0 && restart > 0)) &&
!preventRestart() && !Runners[i]->preventRestart()) { !preventRestart() && !tr->preventRestart()) {
ft = restart; //Runner in restart ft = restart; //Runner in restart
tNumRestarts++; tNumRestarts++;
} }
if (ft > 0) if (ft > 0)
Runners[i]->setStartTime(ft, false, setTmpOnly); tr->setStartTime(ft, false, setTmpOnly);
Runners[i]->tUseStartPunch=false; tr->tUseStartPunch=false;
lastStartTime=ft; lastStartTime=ft;
} }
else {//The else below should only be run by mistake (for an incomplete team) else {//The else below should only be run by mistake (for an incomplete team)
Runners[i]->setStartTime(Class->getRestartTime(i), false, setTmpOnly); tr->setStartTime(Class->getRestartTime(i), false, setTmpOnly);
Runners[i]->tUseStartPunch=false; tr->tUseStartPunch=false;
} }
} }
break; break;
@ -1121,7 +1142,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
} }
if (restart > 0 && rope > 0 && (lastStartTime > rope) && if (restart > 0 && rope > 0 && (lastStartTime > rope) &&
!preventRestart() && !Runners[i]->preventRestart()) { !preventRestart() && !tr->preventRestart()) {
lastStartTime = restart; //Runner in restart lastStartTime = restart; //Runner in restart
tNumRestarts++; tNumRestarts++;
} }
@ -1140,7 +1161,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
setStart = true; setStart = true;
} }
if (Runners[i]->getFinishTime()>0) { if (tr->getFinishTime()>0) {
setStart = true; setStart = true;
if (lastStartTime == 0) if (lastStartTime == 0)
lastStartTime = pc->getRestartTime(i); lastStartTime = pc->getRestartTime(i);
@ -1151,15 +1172,15 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
else else
lastStartTime=0; lastStartTime=0;
Runners[i]->tUseStartPunch=false; tr->tUseStartPunch=false;
Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); tr->setStartTime(lastStartTime, false, setTmpOnly);
} }
break; break;
} }
} }
size_t nextNonPar = i+1; size_t nextNonPar = i+1;
while (nextNonPar < Runners.size() && pc->isOptional(nextNonPar) && Runners[nextNonPar] == 0) while (nextNonPar < Runners.size() && pc->isOptional(nextNonPar) && !Runners[nextNonPar])
nextNonPar++; nextNonPar++;
int nextBaseLeg = nextNonPar; int nextBaseLeg = nextNonPar;
@ -1168,11 +1189,11 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
// Extra finish time is used to split extra legs to parallel legs // Extra finish time is used to split extra legs to parallel legs
if (lt == LTExtra || pc->getLegType(i+1) == LTExtra) { if (lt == LTExtra || pc->getLegType(i+1) == LTExtra) {
if (Runners[i]->getFinishTime()>0) { if (tr->getFinishTime()>0) {
if (extraFinishTime <= 0) if (extraFinishTime <= 0)
extraFinishTime = Runners[i]->getFinishTime(); extraFinishTime = tr->getFinishTime();
else else
extraFinishTime = min(extraFinishTime, Runners[i]->getFinishTime()); extraFinishTime = min(extraFinishTime, tr->getFinishTime());
} }
} }
else else
@ -1181,7 +1202,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
//Add available start times for parallel //Add available start times for parallel
if (nextNonPar < Runners.size()) { if (nextNonPar < Runners.size()) {
st=pc->getStartType(nextNonPar); st=pc->getStartType(nextNonPar);
int finishTime = Runners[i]->getFinishTime(); int finishTime = tr->getFinishTime();
if (lt == LTExtra) if (lt == LTExtra)
finishTime = extraFinishTime; finishTime = extraFinishTime;
@ -1207,7 +1228,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
} }
} }
if (sync) if (sync)
Runners[i]->synchronize(true); tr->synchronize(true);
} }
} }
@ -1258,9 +1279,9 @@ void oTeam::evaluate(bool sync)
void oTeam::correctRemove(pRunner r) { void oTeam::correctRemove(pRunner r) {
for(unsigned i=0;i<Runners.size(); i++) for(unsigned i=0;i<Runners.size(); i++)
if (r!=0 && Runners[i]==r) { if (r != 0 && Runners[i] == r) {
Runners[i] = 0; Runners[i] = nullptr;
r->tInTeam = 0; r->tInTeam = nullptr;
r->tLeg = 0; r->tLeg = 0;
r->tLegEquClass = 0; r->tLegEquClass = 0;
correctionNeeded = true; correctionNeeded = true;
@ -1454,11 +1475,11 @@ void oTeam::fillSpeakerObject(int leg, int courseControlId, int previousControlC
} }
} }
map<int, int>::iterator mapit=Runners[leg]->priority.find(courseControlId); auto mapit = Runners[leg]->priority.find(courseControlId);
if (mapit!=Runners[leg]->priority.end()) if (mapit != Runners[leg]->priority.end())
spk.priority=mapit->second; spk.priority = mapit->second;
else else
spk.priority=0; spk.priority = 0;
spk.runningTimeLeg.preliminary = 0; spk.runningTimeLeg.preliminary = 0;
for (int i = leg; i <= requestedLeg; i++) { for (int i = leg; i <= requestedLeg; i++) {
@ -1502,10 +1523,9 @@ void oTeam::fillSpeakerObject(int leg, int courseControlId, int previousControlC
spk.status = spk.finishStatus; spk.status = spk.finishStatus;
} }
int oTeam::getTimeAfter(int leg) const int oTeam::getTimeAfter(int leg) const {
{ if (leg == -1)
if (leg==-1) leg = Runners.size() - 1;
leg=Runners.size()-1;
if (!Class || Class->tLeaderTime.size()<=unsigned(leg)) if (!Class || Class->tLeaderTime.size()<=unsigned(leg))
return -1; return -1;
@ -1576,12 +1596,11 @@ oDataContainer &oTeam::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &s
return *oe->oTeamData; return *oe->oTeamData;
} }
pRunner oTeam::getRunner(unsigned leg) const pRunner oTeam::getRunner(unsigned leg) const {
{
if (leg==-1) if (leg==-1)
leg=Runners.size()-1; leg=Runners.size()-1;
return leg<Runners.size() ? Runners[leg]: 0; return leg<Runners.size() ? Runners[leg] : 0;
} }
int oTeam::getRogainingPoints(bool multidayTotal) const { int oTeam::getRogainingPoints(bool multidayTotal) const {
@ -1927,7 +1946,6 @@ bool oTeam::inputData(int id, const wstring &input,
setRunner(ix, r, true); setRunner(ix, r, true);
output = r->getName(); output = r->getName();
} }
} }
} }
} }
@ -2138,7 +2156,7 @@ bool oTeam::checkValdParSetup() {
// Move to where a runner is needed // Move to where a runner is needed
Runners[k] = Runners[k+m]; Runners[k] = Runners[k+m];
Runners[k]->tLeg = k; Runners[k]->tLeg = k;
Runners[k+m] = 0; Runners[k+m] = nullptr;
updateChanged(); updateChanged();
cor = true; cor = true;
k+=m; k+=m;

View File

@ -54,7 +54,7 @@ private:
void propagateClub(); void propagateClub();
protected: protected:
//pRunner Runners[maxRunnersTeam];
vector<pRunner> Runners; vector<pRunner> Runners;
void setRunnerInternal(int k, pRunner r); void setRunnerInternal(int k, pRunner r);

View File

@ -160,15 +160,17 @@ pTeam oEvent::addTeam(const wstring &pname, int ClubId, int ClassId)
bibStartNoToRunnerTeam.clear(); bibStartNoToRunnerTeam.clear();
Teams.push_back(t); Teams.push_back(t);
teamById[t.Id] = &Teams.back(); pTeam pt = &Teams.back();
pt->addToEvent();
teamById[t.Id] = pt;
oe->updateTabs(); oe->updateTabs();
Teams.back().StartNo = ++nextFreeStartNo; // Need not be unique pt->StartNo = ++nextFreeStartNo; // Need not be unique
Teams.back().getEntryDate(false);// Store entry time pt->getEntryDate(false);// Store entry time
Teams.back().apply(false, 0, false); pt->apply(false, 0, false);
Teams.back().updateChanged(); pt->updateChanged();
return &Teams.back(); return pt;
} }
pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) { pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) {
@ -181,6 +183,15 @@ pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) {
Teams.push_back(t); Teams.push_back(t);
pTeam pt = &Teams.back(); pTeam pt = &Teams.back();
pt->addToEvent();
for (size_t i = 0; i < pt->Runners.size(); i++) {
if (pt->Runners[i]) {
assert(pt->Runners[i]->tInTeam == nullptr || pt->Runners[i]->tInTeam == &t);
pt->Runners[i]->tInTeam = pt;
}
}
teamById[pt->Id] = pt; teamById[pt->Id] = pt;
if (pt->StartNo == 0 && autoAssignStartNo) { if (pt->StartNo == 0 && autoAssignStartNo) {
@ -306,10 +317,10 @@ bool oTeam::matchTeam(int number, const wchar_t *s_lc) const
void oEvent::fillPredefinedCmp(gdioutput &gdi, const string &name) const void oEvent::fillPredefinedCmp(gdioutput &gdi, const string &name) const
{ {
bool hasPatrol = getMeOSFeatures().hasFeature(MeOSFeatures::Patrol); bool hasPatrol = true;// getMeOSFeatures().hasFeature(MeOSFeatures::Patrol);
bool hasMulti = getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces); bool hasMulti = true;//getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces);
bool hasRelay = getMeOSFeatures().hasFeature(MeOSFeatures::Relay); bool hasRelay = true;//getMeOSFeatures().hasFeature(MeOSFeatures::Relay);
bool hasForked = getMeOSFeatures().hasFeature(MeOSFeatures::ForkedIndividual); bool hasForked = true;//getMeOSFeatures().hasFeature(MeOSFeatures::ForkedIndividual);
gdi.clearList(name); gdi.clearList(name);
gdi.addItem(name, lang.tl("Endast en bana"), PNoMulti); gdi.addItem(name, lang.tl("Endast en bana"), PNoMulti);
@ -328,8 +339,10 @@ void oEvent::fillPredefinedCmp(gdioutput &gdi, const string &name) const
} }
if (hasRelay) if (hasRelay)
gdi.addItem(name, lang.tl("Stafett"), PRelay); gdi.addItem(name, lang.tl("Stafett"), PRelay);
if (hasMulti) if (hasMulti) {
gdi.addItem(name, lang.tl("Tvåmannastafett"), PTwinRelay); gdi.addItem(name, lang.tl("Tvåmannastafett"), PTwinRelay);
gdi.addItem(name, lang.tl("Flera lopp i valfri ordning"), PTwoRacesNoOrder);
}
if (hasRelay) if (hasRelay)
gdi.addItem(name, lang.tl("Extralöparstafett"), PYouthRelay); gdi.addItem(name, lang.tl("Extralöparstafett"), PYouthRelay);
} }
@ -386,6 +399,11 @@ void oEvent::setupRelayInfo(PredefinedTypes type, bool &useNLeg, bool &useStart)
useStart = true; useStart = true;
break; break;
case PTwoRacesNoOrder:
useStart = false;
useNLeg = true;
break;
default: default:
throw std::exception("Bad setup number"); throw std::exception("Bad setup number");
} }
@ -424,7 +442,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
if (crs) { if (crs) {
cls.addStageCourse(0, crsId, -1); cls.addStageCourse(0, crsId, -1);
} }
getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *this);
oe->synchronize(true);
break; break;
case PPoolDrawn: case PPoolDrawn:
@ -439,6 +458,9 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
if (crs) { if (crs) {
cls.addStageCourse(0, crsId, -1); cls.addStageCourse(0, crsId, -1);
} }
getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *this);
oe->synchronize(true);
break; break;
case PPatrol: case PPatrol:
@ -460,6 +482,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
cls.addStageCourse(1, crsId, -1); cls.addStageCourse(1, crsId, -1);
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this);
oe->synchronize(true);
break; break;
case PPatrolOptional: case PPatrolOptional:
@ -481,6 +505,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
cls.addStageCourse(1, crsId, -1); cls.addStageCourse(1, crsId, -1);
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this);
oe->synchronize(true);
break; break;
case PPatrolOneSI: case PPatrolOneSI:
@ -503,6 +529,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this);
oe->synchronize(true);
break; break;
case PRelay: case PRelay:
@ -521,6 +549,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
cls.setRopeTime(k, L"-"); cls.setRopeTime(k, L"-");
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this);
oe->synchronize(true);
break; break;
case PTwinRelay: case PTwinRelay:
@ -543,6 +573,27 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this);
getMeOSFeatures().useFeature(MeOSFeatures::MultipleRaces, true, *this);
oe->synchronize(true);
oe->synchronize(true);
break;
case PTwoRacesNoOrder:
cls.setNumStages(nleg);
for (int k = 0; k<nleg; k++) {
cls.setLegType(k, LTSum);
cls.setStartType(k, STDrawn, false);
cls.setStartData(k, L"-");
cls.setRestartTime(k, L"-");
cls.setRopeTime(k, L"-");
if (k > 0)
cls.setLegRunner(k, 0);
}
cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::MultipleRaces, true, *this);
oe->synchronize(true);
break; break;
case PYouthRelay: case PYouthRelay:
@ -577,6 +628,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
} }
} }
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this);
oe->synchronize(true);
break; break;
case PHunting: { case PHunting: {
@ -595,6 +648,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
cls.setRopeTime(1, formatTimeHMS(t+1800)); cls.setRopeTime(1, formatTimeHMS(t+1800));
cls.setLegRunner(1, 0); cls.setLegRunner(1, 0);
cls.setCoursePool(false); cls.setCoursePool(false);
getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this);
oe->synchronize(true);
break; break;
} }
default: default:
@ -653,7 +708,7 @@ bool oTeam::adjustMultiRunners(bool sync)
if (!Class) if (!Class)
return false; return false;
for (size_t k = Class->getNumStages(); k<Runners.size(); k++) { for (size_t k = Class->getNumStages(); k < Runners.size(); k++) {
setRunnerInternal(k, 0); setRunnerInternal(k, 0);
} }
@ -663,14 +718,14 @@ bool oTeam::adjustMultiRunners(bool sync)
} }
// Create multi runners. // Create multi runners.
for (size_t i=0;i<Runners.size(); i++) { for (size_t i = 0; i < Runners.size(); i++) {
if (!Runners[i] && Class) { if (!Runners[i] && Class) {
unsigned lr = Class->getLegRunner(i); unsigned lr = Class->getLegRunner(i);
if (lr<i && Runners[lr]) { if (lr < i && Runners[lr]) {
Runners[lr]->createMultiRunner(true, sync); Runners[lr]->createMultiRunner(true, sync);
int dup=Class->getLegRunnerIndex(i); int dup = Class->getLegRunnerIndex(i);
Runners[i]=Runners[lr]->getMultiRunner(dup); Runners[i] = Runners[lr]->getMultiRunner(dup);
} }
} }
} }

View File

@ -1248,6 +1248,7 @@ X (Y deltagare, grupp Z, W) = X (Y deltagare, grupp Z, W)
X har startat = X har startat X har startat = X har startat
X kontroller = X kontroller X kontroller = X kontroller
X meter = X meter X meter = X meter
X m = X m
X poäng fattas = X poäng fattas X poäng fattas = X poäng fattas
X rader kunde inte raderas = X rad(er) kunde inte raderas X rader kunde inte raderas = X rad(er) kunde inte raderas
X senaste = X senaste X senaste = X senaste
@ -2440,3 +2441,6 @@ Kunde inte öppna databasen (X) = Kunde inte öppna databasen (X)
Kunde inte ladda upp löpardatabasen (X) = Kunde inte ladda upp löpardatabasen (X) Kunde inte ladda upp löpardatabasen (X) = Kunde inte ladda upp löpardatabasen (X)
Runner check time = Checktid Runner check time = Checktid
ClassNumEntries = Antal anmälda i klassen ClassNumEntries = Antal anmälda i klassen
Flera lopp i valfri ordning = Flera lopp i valfri ordning
Knockout sammanställning = Knockout sammanställning
X anmälda = X anmälda