From 06a6c4ff6772e9fd5f3a24cf8478e1f968678f54 Mon Sep 17 00:00:00 2001 From: Erik Melin <31467290+erikmelin@users.noreply.github.com> Date: Wed, 31 Jul 2019 13:14:41 +0200 Subject: [PATCH] MeOS version 3.6.1089 --- code/StdAfx.cpp | 1 - code/czech.lng | 1 + code/danish.lng | 1 + code/english.lng | 6 +- code/french.lng | 1 + code/meosdb/MeosSQL.cpp | 301 ++++++++++++++++++++++++++++++++-------- code/meosdb/MeosSQL.h | 21 ++- code/meosdb/meosdb.cpp | 76 ++++------ code/meosversion.cpp | 11 +- code/oBase.h | 18 ++- code/oCard.cpp | 5 +- code/oClass.cpp | 4 +- code/oClub.cpp | 9 +- code/oEvent.cpp | 44 +++--- code/oEvent.h | 2 +- code/oEventSQL.cpp | 2 +- code/oFreePunch.cpp | 42 +----- code/oReport.cpp | 16 +-- code/oRunner.cpp | 71 ++++++---- code/oTeam.cpp | 268 ++++++++++++++++++----------------- code/oTeam.h | 2 +- code/oTeamEvent.cpp | 95 ++++++++++--- code/swedish.lng | 4 + 23 files changed, 632 insertions(+), 369 deletions(-) diff --git a/code/StdAfx.cpp b/code/StdAfx.cpp index ed1181b..160a32f 100644 --- a/code/StdAfx.cpp +++ b/code/StdAfx.cpp @@ -7,7 +7,6 @@ const wstring _EmptyWString=L""; const string _EmptyString=""; const string _VacantName="Vakant"; -const string _UnkownName="N.N."; // TODO: reference any additional headers you need in STDAFX.H // and not in this file diff --git a/code/czech.lng b/code/czech.lng index a45b6ab..30fc86a 100644 --- a/code/czech.lng +++ b/code/czech.lng @@ -1252,6 +1252,7 @@ X (Y deltagare, grupp Z, W) = X (Y závodníků, skupina Z, W) X har startat = X odstartovalo X kontroller = X kontrol X meter = X metrů +X m = X m X poäng fattas = X bodů chybí X rader kunde inte raderas = X řádků nemůže být smazáno X senaste = X nejnovějších diff --git a/code/danish.lng b/code/danish.lng index 4ead5b9..3121f11 100644 --- a/code/danish.lng +++ b/code/danish.lng @@ -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 kontroller = X poster X meter = X meter +X m = X m X och Y[N by N] = X og Y X p = X p X platser. Startar Y = X pladser. Starter Y diff --git a/code/english.lng b/code/english.lng index 32797a3..300c4eb 100644 --- a/code/english.lng +++ b/code/english.lng @@ -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 har startat = X started X kontroller = X controls -X meter = X meter +X meter = X meters +X m = X m X poäng fattas = X points missing X rader kunde inte raderas = X row(s) could not be deleted 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) Runner check time = Runner check time 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 diff --git a/code/french.lng b/code/french.lng index 88e00cd..1252241 100644 --- a/code/french.lng +++ b/code/french.lng @@ -1254,6 +1254,7 @@ X (Y deltagare, grupp Z, W) = X (Y coureurs, groupe Z, W) X har startat = X est parti X kontroller = X postes X meter = X mètres +X m = X m X poäng fattas = X points manquant X rader kunde inte raderas = X lignes ne peuvent être effacées X senaste = X derniers diff --git a/code/meosdb/MeosSQL.cpp b/code/meosdb/MeosSQL.cpp index e6ee3ef..53a3d6a 100644 --- a/code/meosdb/MeosSQL.cpp +++ b/code/meosdb/MeosSQL.cpp @@ -390,9 +390,9 @@ void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) { query.execute(sql); } } - else if (db == "oRunner") { + else if (db == "oRunner" || db == "oTeam") { 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("InputStatus"); sql += "ADD COLUMN " + C_INT("InputPoints"); @@ -522,7 +522,7 @@ bool MeosSQL::openDB(oEvent *oe) query << C_START("oCard") << C_INT("CardNo") << C_UINT("ReadId") - << C_STRING("Punches", 1024) << C_END(); + << C_STRING("Punches", 16*190) << C_END(); query.execute(); @@ -558,7 +558,6 @@ bool MeosSQL::openDB(oEvent *oe) // Ugrade oRunner upgradeDB("oControl", oe->oControlData); - query.reset(); query << C_START("oCourse") << C_STRING("Name") @@ -577,6 +576,7 @@ bool MeosSQL::openDB(oEvent *oe) << C_INT("Club") << C_INT("Class") << C_INT("StartTime") << C_INT("FinishTime") << C_INT("Status") << C_INT("StartNo") + << C_INT("InputTime") << C_INT("InputStatus") << C_INT("InputPoints") << C_INT("InputPlace") << oe->oTeamData->generateSQLDefinition() << C_END(); query.execute(); @@ -1165,8 +1165,8 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { while (row = res.fetch_row()) { oControl c(oe, row["Id"]); storeControl(row, c); - oe->Controls.push_back(c); - + oe->addControl(c); + oe->sqlUpdateControls = max(c.sqlUpdated, oe->sqlUpdateControls); oe->sqlCounterControls = max(c.counter, oe->sqlCounterControls); } @@ -1191,7 +1191,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { set tmp; while (row = res.fetch_row()) { oCourse c(oe, row["Id"]); - storeCourse(row, c, tmp); + storeCourse(row, c, tmp, false); oe->addCourse(c); oe->sqlUpdateCourses = max(c.sqlUpdated, oe->sqlUpdateCourses); @@ -1216,7 +1216,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { Row row; while (row = res.fetch_row()) { oClass c(oe, row["Id"]); - storeClass(row, c, false); + storeClass(row, c, false, false); c.changed = false; c.reChanged = false; @@ -1277,7 +1277,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { Row row; while (row = res.fetch_row()) { oRunner r(oe, row["Id"]); - storeRunner(row, r, false, false, false); + storeRunner(row, r, false, false, false, false); assert(!r.changed); oe->addRunner(r, false); @@ -1309,7 +1309,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { while (row = res.fetch_row()) { oTeam t(oe, row["Id"]); - storeTeam(row, t, false); + storeTeam(row, t, false, false); pTeam at = oe->addTeam(t, false); @@ -1427,6 +1427,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) { } oe->runnerDB->setDataDate(dateTime); + processMissingObjects(); return retValue; } @@ -1512,7 +1513,7 @@ void MeosSQL::storePunch(const Row &row, oFreePunch &p, bool rehash) } OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, - bool readCourses) + bool readCourses, bool allowSubRead) { OpFailStatus success = opStatusOK; @@ -1523,11 +1524,13 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, c.importLegMethod(lm); set cid; - vector< vector > multip; + vector> multip; oClass::parseCourses(multi, multip, cid); + int classCourse = row["Course"]; if (classCourse != 0) cid.insert(classCourse); + if (!readCourses) { for (set::iterator clsIt = cid.begin(); clsIt != cid.end(); ++clsIt) { if (!c.oe->getCourse(*clsIt)) @@ -1535,12 +1538,26 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, } } - if (readCourses) - success = min(success, syncReadClassCourses(&c, cid, readCourses)); + if (readCourses) { + if (allowSubRead) { + 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) c.Course = c.oe->getCourse(classCourse); else - c.Course = 0; + c.Course = nullptr; c.importCourses(multip); @@ -1559,8 +1576,8 @@ OpFailStatus MeosSQL::storeClass(const Row &row, oClass &c, } OpFailStatus MeosSQL::storeCourse(const Row &row, oCourse &c, - set &readControls) -{ + set &readControls, + bool allowSubRead) { OpFailStatus success = opStatusOK; 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. // Then just read to update if (!c.Controls[i]->existInDB()) { - c.Controls[i]->changed = false; - success = min(success, syncRead(true, c.Controls[i])); + c.Controls[i]->setImplicitlyCreated(); + if (allowSubRead) { + c.Controls[i]->changed = false; + success = min(success, syncRead(true, c.Controls[i])); + } + addedFromDatabase(c.Controls[i]); } - else + else { 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, bool readCourseCard, bool readClassClub, - bool readRunners) + bool readRunners, + bool allowSubRead) { OpFailStatus success = opStatusOK; oEvent *oe=r.oe; @@ -1637,10 +1659,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, set controlIds; if (!r.Course) { oCourse oc(oe, row["Course"]); - success = min(success, syncReadCourse(true, &oc, controlIds)); - r.Course = oe->addCourse(oc); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncReadCourse(true, &oc, controlIds)); + if (!oc.isRemoved()) { + r.Course = oe->addCourse(oc); + addedFromDatabase(r.Course); + } } - else if (readCourseCard) + else if (readCourseCard && allowSubRead) success = min(success, syncReadCourse(false, r.Course, controlIds)); if (readCourseCard) @@ -1653,10 +1680,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, if (!r.Class) { oClass oc(oe, row["Class"]); - success = min(success, syncRead(true, &oc, readClassClub)); - r.Class = oe->addClass(oc); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &oc, readClassClub)); + if (!oc.isRemoved()) { + r.Class = oe->addClass(oc); + addedFromDatabase(r.Class); + } } - else if (readClassClub) + else if (readClassClub && allowSubRead) success = min(success, syncRead(false, r.Class, true)); if (r.tInTeam && r.tInTeam->Class!=r.Class) @@ -1669,10 +1701,15 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, if (!r.Club) { oClub oc(oe, row["Club"]); - success = min(success, syncRead(true, &oc)); - r.Club = oe->addClub(oc); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &oc)); + if (!oc.isRemoved()) { + r.Club = oe->addClub(oc); + addedFromDatabase(r.Club); + } } - else if (readClassClub) + else if (readClassClub && allowSubRead) success = min(success, syncRead(false, r.Club)); } else r.Club=0; @@ -1684,12 +1721,18 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, if (!r.Card){ oCard oc(oe, row["Card"]); - oe->Cards.push_back(oc); - r.Card = &oe->Cards.back(); - r.Card->changed = false; - success = min(success, syncRead(true, r.Card)); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &oc)); + if (!oc.isRemoved()) { + r.Card = oe->addCard(oc); + r.Card->changed = false; + } + else { + addedFromDatabase(r.Card); + } } - else if (readCourseCard) + else if (readCourseCard && allowSubRead) success = min(success, syncRead(false, r.Card)); } else r.Card=0; @@ -1713,10 +1756,18 @@ OpFailStatus MeosSQL::storeRunner(const Row &row, oRunner &r, pRunner pr = oe->getRunner(rid, 0); if (pr==0) { oRunner or(oe, rid); - success = min(success, syncRead(true, &or, false, readCourseCard)); - pr = oe->addRunner(or, false); + or.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &or, false, readCourseCard)); + if (!or.isRemoved()) { + pr = oe->addRunner(or , false); + addedFromDatabase(pr); + } + else { + r.multiRunnerId[i] = 0; + } } - else + else if (allowSubRead) 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, - bool readRecursive) + bool readRecursive, bool allowSubRead) { oEvent *oe=t.oe; OpFailStatus success = opStatusOK; @@ -1747,8 +1798,14 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, t.sName=fromUTF((string)row["Name"]); t.StartNo=row["StartNo"]; t.tStartTime = t.startTime = row["StartTime"]; - t.FinishTime=row["FinishTime"]; + t.FinishTime = row["FinishTime"]; 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); if (oldSno != t.StartNo || oldBib != t.getBib()) @@ -1768,10 +1825,15 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, if (!t.Class) { oClass oc(oe, classId); - success = min(success, syncRead(true, &oc, readRecursive)); - t.Class = oe->addClass(oc); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &oc, readRecursive)); + if (!oc.isRemoved()) { + t.Class = oe->addClass(oc); + addedFromDatabase(t.Class); + } } - else if (readRecursive) + else if (readRecursive && allowSubRead) success = min(success, syncRead(false, t.Class, readRecursive)); } else t.Class=0; @@ -1782,10 +1844,15 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, if (!t.Club) { oClub oc(oe, clubId); - success = min(success, syncRead(true, &oc)); - t.Club = oe->addClub(oc); + oc.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &oc)); + if (!oc.isRemoved()) { + t.Club = oe->addClub(oc); + addedFromDatabase(t.Club); + } } - else if (readRecursive) + else if (readRecursive && allowSubRead) success = min(success, syncRead(false, t.Club)); } else t.Club = 0; @@ -1798,19 +1865,24 @@ OpFailStatus MeosSQL::storeTeam(const Row &row, oTeam &t, for (size_t k=0;k0) { pRns[k] = oe->getRunner(rns[k], 0); - if (!pRns[k]) { oRunner or(oe, rns[k]); - success = min(success, syncRead(true, &or, readRecursive, readRecursive)); + or.setImplicitlyCreated(); + if (allowSubRead) + success = min(success, syncRead(true, &or, readRecursive, readRecursive)); if (or.sName.empty()) { or.sName = L"@AutoCorrection"; oRunner::getRealName(or.sName, or.tRealName); } - pRns[k] = oe->addRunner(or, false); - assert(pRns[k] && !pRns[k]->changed); + + if (!or.isRemoved()) { + pRns[k] = oe->addRunner(or , false); + addedFromDatabase(pRns[k]); + assert(pRns[k] && !pRns[k]->changed); + } } - else if (readRecursive) + else if (readRecursive && allowSubRead) success = min(success, syncRead(false, pRns[k])); } } @@ -1936,7 +2008,10 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r) } string MeosSQL::andWhereOld(oBase *ob) { - return " AND (Counter!=" + itos(ob->counter) + " OR Modified!='" + ob->sqlUpdated + "')"; + if (ob->sqlUpdated.empty()) + return " AND Counter!=" + itos(ob->counter); + else + return " AND (Counter!=" + itos(ob->counter) + " OR Modified!='" + ob->sqlUpdated + "')"; } OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r, bool readClassClub, bool readCourseCard) @@ -1967,7 +2042,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r, bool readClassClub, b if (r->changed) 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->Modified.update(); @@ -1994,7 +2069,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oRunner *r, bool readClassClub, b } if (r->Club && readClassClub) syncRead(false, r->Club); - + if (r->changed) return syncUpdate(r, false); @@ -2105,7 +2180,11 @@ OpFailStatus MeosSQL::syncUpdate(oTeam *t, bool forceWriteAll) { << " Class=" << t->getClassId(false) << ", " << " Club=" << t->getClubId() << ", " << " 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); //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) success=opStatusWarning; - storeTeam(row, *t, readRecursive); + storeTeam(row, *t, readRecursive, true); t->oe->dataRevision++; t->Modified.update(); t->changed = false; @@ -2236,7 +2315,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oClass *c, bool readCourses) if (c->changed) success=opStatusWarning; - storeClass(row, *c, readCourses); + storeClass(row, *c, readCourses, true); c->oe->dataRevision++; c->Modified.update(); c->changed = false; @@ -2296,8 +2375,10 @@ OpFailStatus MeosSQL::syncReadClassCourses(oClass *c, const set &courses, pCourse pc = oe->getCourse(id); if (!pc) { oCourse oc(oe, id); + oc.setImplicitlyCreated(); 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)) { success = min(success, syncReadCourse(false, pc, controlIds)); @@ -2576,7 +2657,7 @@ OpFailStatus MeosSQL::syncReadCourse(bool forceRead, oCourse *c, set &readC if (c->changed) success = opStatusWarning; - storeCourse(row, *c, readControls); + storeCourse(row, *c, readControls, true); c->oe->dataRevision++; c->Modified.update(); c->changed=false; @@ -2771,6 +2852,12 @@ OpFailStatus MeosSQL::syncUpdate(mysqlpp::Query &updateqry, Result res=query.store(); if (res && res.num_rows()==0) setId = true; + else if (ob->isImplicitlyCreated()) { + return opStatusWarning;//XXX Should we read this object? + } + } + else { + assert(!ob->isImplicitlyCreated()); } query.reset(); @@ -3729,3 +3816,97 @@ int MeosSQL::getModifiedMask(oEvent &oe) { } 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(obj); + if (r && r->getName().empty()) { + r->setName(L"@AutoCorrection", false); + syncUpdate(r, false); + } + } + { + oTeam *t = dynamic_cast(obj); + if (t && t->getName().empty()) { + t->setName(L"@AutoCorrection", false); + syncUpdate(t, false); + } + } + { + oClass *cls = dynamic_cast(obj); + if (cls && cls->getName().empty()) { + cls->setName(L"@AutoCorrection"); + syncUpdate(cls, false); + } + } + { + oCourse *crs = dynamic_cast(obj); + if (crs && crs->getName().empty()) { + crs->setName(L"@AutoCorrection"); + syncUpdate(crs, false); + } + } + { + oClub *clb = dynamic_cast(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; +} diff --git a/code/meosdb/MeosSQL.h b/code/meosdb/MeosSQL.h index ef90b9d..98ec413 100644 --- a/code/meosdb/MeosSQL.h +++ b/code/meosdb/MeosSQL.h @@ -58,6 +58,8 @@ protected: string CmpDataBase; void alert(const string &s); + vector missingObjects; + string errorMessage; string serverName; @@ -94,16 +96,19 @@ protected: void storePunch(const mysqlpp::Row &row, oFreePunch &p, bool rehash); OpFailStatus storeTeam(const mysqlpp::Row &row, oTeam &t, - bool readRecursive); + bool readRecursive, bool allowSubRead); OpFailStatus storeRunner(const mysqlpp::Row &row, oRunner &r, bool readCourseCard, bool readClassClub, - bool readRunners); + bool readRunners, + bool allowSubRead); OpFailStatus storeCourse(const mysqlpp::Row &row, oCourse &c, - set &readControls); + set &readControls, + bool allowSubRead); OpFailStatus storeClass(const mysqlpp::Row &row, oClass &c, - bool readCourses); + bool readCourses, + bool allowSubRead); void getColumns(const string &table, set &output); @@ -120,9 +125,13 @@ protected: mysqlpp::ResNSel updateCounter(const char *oTable, int id, mysqlpp::Query *updateqry); string selectUpdated(const char *oTable, const string &updated, int counter); + void addedFromDatabase(oBase *object); + + public: bool dropDatabase(oEvent *oe); bool checkConnection(oEvent *oe); + void processMissingObjects(); bool repairTables(const string &db, vector &output); @@ -179,6 +188,10 @@ public: OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll); OpFailStatus syncRead(bool forceRead, oTeam *t); + /** General interface. TypeId lookup */ + OpFailStatus syncRead(bool forceRead, oBase *c); + + int getModifiedMask(oEvent &oe); MeosSQL(void); diff --git a/code/meosdb/meosdb.cpp b/code/meosdb/meosdb.cpp index 1e0dc2f..d5d83b2 100644 --- a/code/meosdb/meosdb.cpp +++ b/code/meosdb/meosdb.cpp @@ -74,25 +74,36 @@ bool MEOSDB_API msSynchronizeList(oEvent *oe, oListId lid) nSynchList++; if (nSynchList % 100 == 99) 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) - return msql.syncListRunner(oe); - 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; + msql.processMissingObjects(); + return ret; } int MEOSDB_API msSynchronizeUpdate(oBase *obj) @@ -134,34 +145,7 @@ int MEOSDB_API msSynchronizeRead(oBase *obj) if (nSynchEnt % 100 == 99) OutputDebugString(L"Synchronized 100 entities\n"); - if (typeid(*obj)==typeid(oRunner)){ - 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; + return msql.syncRead(false, obj); } // Removes (marks it as removed) an entry from the database. diff --git a/code/meosversion.cpp b/code/meosversion.cpp index fe62d77..13f15cc 100644 --- a/code/meosversion.cpp +++ b/code/meosversion.cpp @@ -30,7 +30,7 @@ //V35: abcdef //V36: abcdef int getMeosBuild() { - string revision("$Rev: 912 $"); + string revision("$Rev: 915 $"); return 174 + atoi(revision.substr(5, string::npos).c_str()); } @@ -42,12 +42,12 @@ int getMeosBuild() { //V33: abcdefghij //V34: abcdfge wstring getMeosDate() { - wstring date(L"$Date: 2019-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); } wstring getBuildType() { - return L"Update 1"; // No parantheses (...) + return L"Update 2"; // No parantheses (...) } wstring getMajorVersion() { @@ -60,7 +60,7 @@ wstring getMeosFullVersion() { if (getBuildType().empty()) swprintf_s(bf, L"Version X#%s.%d, %s", maj.c_str(), getMeosBuild(), getMeosDate().c_str()); 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; } @@ -133,5 +133,8 @@ void getSupporters(vector &supp, vector &developSupp) supp.emplace_back(L"Kexholm SK"); supp.emplace_back(L"Utby IK"); supp.emplace_back(L"JWOC 2019"); + developSupp.emplace_back(L"OK Nackhe"); + supp.emplace_back(L"OK Rodhen"); + reverse(supp.begin(), supp.end()); } diff --git a/code/oBase.h b/code/oBase.h index dda3853..2817016 100644 --- a/code/oBase.h +++ b/code/oBase.h @@ -101,17 +101,20 @@ protected: TimeStamp Modified; string sqlUpdated; //SQL TIMESTAMP int counter; + oEvent *oe; + bool Removed; // True if the object is incorrect and needs correction // An example is if id changed as we wrote. Then owner // needs to be updated. - bool correctionNeeded; + bool correctionNeeded = false; - oEvent *oe; - bool Removed; +private: + + bool implicitlyAdded = false; + bool addedToEvent = false; - //Used for selections, etc. - int _objectmarker; +protected: /// Mark the object as changed (on client) and that it needs synchronize to server virtual void updateChanged(); @@ -165,6 +168,11 @@ public: 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(); oDataConstInterface getDCI() const; diff --git a/code/oCard.cpp b/code/oCard.cpp index dc0742e..0b9ac90 100644 --- a/code/oCard.cpp +++ b/code/oCard.cpp @@ -487,7 +487,7 @@ bool oCard::setPunchTime(const pPunch punch, const wstring &time) pCard oEvent::getCard(int Id) const -{ +{ // Do allow removed cards if (Id < int(Cards.size() / 2)) { for (oCardList::const_iterator it = Cards.begin(); it != Cards.end(); ++it){ if (it->Id==Id) @@ -514,18 +514,17 @@ void oEvent::getCards(vector &c) { } } - pCard oEvent::addCard(const oCard &oc) { if (oc.Id<=0) return 0; Cards.push_back(oc); + Cards.back().addToEvent(); return &Cards.back(); } - pCard oEvent::getCardByNumber(int cno) const { oCardList::const_reverse_iterator it; diff --git a/code/oClass.cpp b/code/oClass.cpp index 6b27774..d11ef9d 100644 --- a/code/oClass.cpp +++ b/code/oClass.cpp @@ -716,6 +716,7 @@ pClass oEvent::addClass(const wstring &pname, int CourseId, int classId) c.Course=getCourse(CourseId); Classes.push_back(c); + Classes.back().addToEvent(); Classes.back().synchronize(); updateTabs(); return &Classes.back(); @@ -732,8 +733,9 @@ pClass oEvent::addClass(oClass &c) } Classes.push_back(c); + Classes.back().addToEvent(); - if (!Classes.back().existInDB()) { + if (!Classes.back().existInDB() && !c.isImplicitlyCreated()) { Classes.back().changed = true; Classes.back().synchronize(); } diff --git a/code/oClub.cpp b/code/oClub.cpp index e404e27..69f7191 100644 --- a/code/oClub.cpp +++ b/code/oClub.cpp @@ -233,7 +233,7 @@ pClub oEvent::addClub(const wstring &pname, int createId) { oClub c(this, createId); c = *dbClub; c.Id = createId; - Clubs.push_back(c); + return addClub(c); } else { if (createId==0) @@ -241,11 +241,8 @@ pClub oEvent::addClub(const wstring &pname, int createId) { oClub c(this, createId); 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) @@ -254,6 +251,8 @@ pClub oEvent::addClub(const oClub &oc) return clubIdIndex[oc.Id]; Clubs.push_back(oc); + Clubs.back().addToEvent(); + if (!oc.existInDB()) Clubs.back().synchronize(); diff --git a/code/oEvent.cpp b/code/oEvent.cpp index 052b7b1..aa21140 100644 --- a/code/oEvent.cpp +++ b/code/oEvent.cpp @@ -64,7 +64,7 @@ #include "Table.h" //Version of database -int oEvent::dbVersion = 82; +int oEvent::dbVersion = 83; class RelativeTimeFormatter : public oDataDefiner { string name; @@ -610,7 +610,7 @@ pControl oEvent::addControl(int Id, int Number, const wstring &Name) oControl c(this); c.set(Id, Number, Name); - Controls.push_back(c); + addControl(c); oe->updateTabs(); return &Controls.back(); @@ -636,6 +636,8 @@ pControl oEvent::addControl(const oControl &oc) qFreeControlId = max (qFreeControlId, Id); Controls.push_back(oc); + oe->Controls.back().addToEvent(); + return &Controls.back(); } @@ -1181,9 +1183,8 @@ bool oEvent::open(const xmlparser &xml) { oControl c(this); c.set(&*it); - if (c.Id>0 && knownControls.count(c.Id) == 0) { - Controls.push_back(c); - knownControls.insert(c.Id); + if (c.Id>0 && knownControls.insert(c.Id).second) { + addControl(c); } } } @@ -1227,6 +1228,7 @@ bool oEvent::open(const xmlparser &xml) { c.Set(&*it); if (c.Id>0 && knownClass.count(c.Id) == 0) { Classes.push_back(c); + Classes.back().addToEvent(); knownClass.insert(c.Id); } } @@ -1249,7 +1251,7 @@ bool oEvent::open(const xmlparser &xml) { oClub c(this); c.set(*it); 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); c.Set(*it); 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()); pCourse pc = &Courses.back(); + pc->addToEvent(); - if (!pc->existInDB()) { + if (!pc->existInDB() && !pc->isImplicitlyCreated()) { pc->updateChanged(); pc->synchronize(); } @@ -1609,7 +1612,7 @@ void oEvent::autoRemoveTeam(pRunner pr) if (pr->tInTeam) { // A team may have more than this runner -> do not remove bool canRemove = true; - const vector &runners = pr->tInTeam->Runners; + const auto &runners = pr->tInTeam->Runners; for (size_t k = 0; ksName != pr->sName) canRemove = false; @@ -1726,7 +1729,15 @@ pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) { Runners.push_back(r); 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(); if (cardToRunnerHash && r.getCardNo() != 0) { cardToRunnerHash->emplace(r.getCardNo(), pr); @@ -1743,7 +1754,7 @@ pRunner oEvent::addRunner(const oRunner &r, bool updateStartNo) { pr->Card->tOwner = pr; if (HasDBConnection) { - if (!pr->existInDB()) + if (!pr->existInDB() && !pr->isImplicitlyCreated()) pr->synchronize(); } if (needUpdate) @@ -2041,6 +2052,7 @@ pCard oEvent::allocateCard(pRunner owner) c.tOwner = owner; Cards.push_back(c); pCard newCard = &Cards.back(); + newCard->addToEvent(); return newCard; } @@ -2152,7 +2164,7 @@ bool oEvent::sortTeams(SortOrder so, int leg, bool linearLeg) { // Count number of races with results int numResult = 0; int lastClassHeat = 0; - for (pRunner r : it->Runners) { + for (auto &r : it->Runners) { if (r && (r->prelStatusOK() || (r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) { @@ -2266,7 +2278,7 @@ bool oEvent::sortTeams(SortOrder so, int leg, bool linearLeg, vectorRunners) { + for (auto &r : it->Runners) { if (r && (r->prelStatusOK() || (r->tStatus != StatusUnknown && r->tStatus != StatusDNS && r->tStatus != StatusCANCEL))) { @@ -2675,7 +2687,7 @@ void oEvent::removeRunner(const vector &ids) // Reset team runner (this should not happen) if (it->tInTeam) { if (it->tInTeam->Runners[it->tLeg]==&*it) - it->tInTeam->Runners[it->tLeg] = 0; + it->tInTeam->Runners[it->tLeg] = nullptr; } oRunnerList::iterator next = it; @@ -4451,10 +4463,10 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) { if (!firstNumber.empty()) { // 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()) continue; - if (ClassId==0 || it->getClassId(false)==ClassId) { + 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]) { diff --git a/code/oEvent.h b/code/oEvent.h index 35b6d3d..7834adf 100644 --- a/code/oEvent.h +++ b/code/oEvent.h @@ -629,7 +629,7 @@ public: enum PredefinedTypes {PNoSettings, PPool, PForking, PPoolDrawn, PHunting, PPatrol, PPatrolOptional, PPatrolOneSI, PRelay, PTwinRelay, - PYouthRelay, PNoMulti}; + PYouthRelay, PTwoRacesNoOrder, PNoMulti}; void fillPredefinedCmp(gdioutput &gdi, const string &name) const; diff --git a/code/oEventSQL.cpp b/code/oEventSQL.cpp index 971b3e3..2f01bd2 100644 --- a/code/oEventSQL.cpp +++ b/code/oEventSQL.cpp @@ -651,7 +651,7 @@ bool oEvent::readSynchronize(const CompetitionInfo &ci) pRunner r = it->Runners[i]; if (r != 0) { if (usedInTeam[r->Id]) { - it->Runners[i] = 0; // Reset duplicate runners + it->Runners[i] = nullptr; // Reset duplicate runners it->updateChanged(); teamCorrected = true; if (r->tInTeam == &*it) diff --git a/code/oFreePunch.cpp b/code/oFreePunch.cpp index 5f336ed..5a0123d 100644 --- a/code/oFreePunch.cpp +++ b/code/oFreePunch.cpp @@ -442,7 +442,6 @@ bool oEvent::isInPunchHash(int card, int code, int time) { return readPunchHash.count(make_pair(p1, p2)) > 0; } - pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFinish) { if (time > 0 && isInPunchHash(card, type, time)) return 0; @@ -450,6 +449,7 @@ pFreePunch oEvent::addFreePunch(int time, int type, int card, bool updateStartFi punches.push_back(ofp); pFreePunch fp=&punches.back(); + fp->addToEvent(); oFreePunch::rehashPunches(*this, card, fp); insertIntoPunchHash(card, type, time); @@ -519,6 +519,7 @@ pFreePunch oEvent::addFreePunch(oFreePunch &fp) { insertIntoPunchHash(fp.CardNo, fp.Type, fp.Time); punches.push_back(fp); pFreePunch fpz=&punches.back(); + fpz->addToEvent(); oFreePunch::rehashPunches(*this, fp.CardNo, fpz); if (!fpz->existInDB() && HasDBConnection) { @@ -618,44 +619,7 @@ void oEvent::getPunchesForRunner(int runnerId, bool doSort, vector & pRunner r = getRunner(runnerId, 0); if (r == 0) return; - /* - // Get times for when other runners used this card - vector< pair > 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 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[k].first && t <= times[k].second) - other = true; - } - - if (!other) - runnerPunches.push_back(pFreePunch(&*it)); - } - } - */ - + //Lazy setup oFreePunch::rehashPunches(*oe, 0, 0); diff --git a/code/oReport.cpp b/code/oReport.cpp index b63566e..f2e9e41 100644 --- a/code/oReport.cpp +++ b/code/oReport.cpp @@ -582,10 +582,8 @@ void oEvent::generatePreReport(gdioutput &gdi) { } } - // Clear markers - for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) - r_it->_objectmarker=0; - + map objectMarkers; + //List all competitors not in a team. if (oe->hasTeam()) { for (t_it=Teams.begin(); t_it != Teams.end(); ++t_it) { @@ -596,7 +594,9 @@ void oEvent::generatePreReport(gdioutput &gdi) { if (pc){ for(unsigned i=0;igetNumStages();i++){ pRunner r=t_it->getRunner(i); - if (r) r->_objectmarker++; + if (r) { + ++objectMarkers[r->getId()]; + } } } } @@ -605,11 +605,11 @@ void oEvent::generatePreReport(gdioutput &gdi) { gdi.addString("", 1, "Löpare som förekommer i mer än ett lag:"); bool any = false; 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(); if (!r_it->getClub().empty()) name += L" (" + r_it->getClub() + L")"; - + gdi.addStringUT(0, name); any = true; } @@ -627,7 +627,7 @@ void oEvent::generatePreReport(gdioutput &gdi) { for (r_it=Runners.begin(); r_it != Runners.end(); ++r_it) { if (r_it->isRemoved()) 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]); wstring name = r_it->getName(); if (!r_it->getClub().empty()) diff --git a/code/oRunner.cpp b/code/oRunner.cpp index 765838c..43a5484 100644 --- a/code/oRunner.cpp +++ b/code/oRunner.cpp @@ -191,21 +191,21 @@ oRunner::~oRunner() { if (tInTeam){ for(unsigned i=0;iRunners.size(); i++) - if (tInTeam->Runners[i] && tInTeam->Runners[i]==this) - tInTeam->Runners[i]=0; + if (tInTeam->Runners[i] && tInTeam->Runners[i]->getId() == Id) + tInTeam->Runners[i] = nullptr; tInTeam=0; } for (size_t k=0;ktParentRunner=0; + if (multiRunner[k] && multiRunner[k]->tParentRunner == this) + multiRunner[k]->tParentRunner = nullptr; } if (tParentRunner) { for (size_t k=0;kmultiRunner.size(); k++) if (tParentRunner->multiRunner[k] == this) - tParentRunner->multiRunner[k]=0; + tParentRunner->multiRunner[k] = nullptr; } delete tAdaptedCourse; @@ -2200,7 +2200,8 @@ void oRunner::updateStartNo(int no) { tInTeam->synchronize(true); for (pRunner r : tInTeam->Runners) { - r->synchronize(true); + if (r) + r->synchronize(true); } } else { @@ -2302,12 +2303,14 @@ void oRunner::setCardNo(int cno, bool matchCard, bool updateFromDatabase) int oldNo = getCardNo(); cardNumber = cno; - if (oe->cardToRunnerHash && cno != 0 && !isTemporaryObject) { + if (oe->cardToRunnerHash && cno != 0 && isAddedToEvent() && !isTemporaryObject) { oe->cardToRunnerHash->emplace(cno, this); } - oFreePunch::rehashPunches(*oe, oldNo, 0); - oFreePunch::rehashPunches(*oe, cardNumber, 0); + if (isAddedToEvent()) { + oFreePunch::rehashPunches(*oe, oldNo, 0); + oFreePunch::rehashPunches(*oe, cardNumber, 0); + } if (matchCard && !Card) { 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 (!findWithoutCardNo) { for (int leg=0; leggetCardNo() > 0 && t.Runners[leg]->getStatus()==StatusUnknown) - return t.Runners[leg]; + pRunner r = t.Runners[leg]; + if (r && r->getCardNo() > 0 && r->getStatus()==StatusUnknown) + return r; } } else { for (int leg=0; leggetCardNo() == 0 && t.Runners[leg]->needNoCard() == false) - return t.Runners[leg]; + pRunner r = 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 @@ -3027,7 +3032,7 @@ void oRunner::createMultiRunner(bool createMaster, bool sync) { if (tDuplicateLeg) return; //Never allow chains. - + bool allowCreate = true; if (multiRunnerId.size()>0) { multiRunner.resize(multiRunnerId.size() - 1); for (size_t k=0;kId != multiRunnerId[k]) markForCorrection(); } - else if (multiRunnerId[k]>0) + else if (multiRunnerId[k] > 0) { markForCorrection(); + allowCreate = false; + } assert(multiRunner[k]); } @@ -3071,24 +3078,25 @@ void oRunner::createMultiRunner(bool createMaster, bool sync) toRemove.push_back(multiRunner[k]->getId()); multiRunner[k]->tParentRunner = 0; if (multiRunner[k]->tInTeam && size_t(multiRunner[k]->tLeg)tInTeam->Runners.size()) { - if (multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg]==multiRunner[k]) - multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] = 0; + if (multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] == multiRunner[k]) + multiRunner[k]->tInTeam->Runners[multiRunner[k]->tLeg] = nullptr; } } } multiRunner.resize(ndup-1); - for(int k=1;kaddRunner(sName, getClubId(), - getClassId(false), 0, 0, false); - multiRunner[k-1]->tDuplicateLeg=k; - multiRunner[k-1]->tParentRunner=this; + for (int k = 1; k < ndup; k++) { + if (!multiRunner[k - 1] && allowCreate) { + update = true; + multiRunner[k - 1] = oe->addRunner(sName, getClubId(), + getClassId(false), 0, 0, false); + multiRunner[k - 1]->tDuplicateLeg = k; + multiRunner[k - 1]->tParentRunner = this; + multiRunner[k - 1]->cardNumber = 0; - if (sync) - multiRunner[k-1]->synchronize(); - } + if (sync) + multiRunner[k - 1]->synchronize(); + } } if (update) updateChanged(); @@ -3111,6 +3119,13 @@ pRunner oRunner::getPredecessor() const } 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); if (sync) { for (size_t k = 0; k < multiRunner.size(); k++) { diff --git a/code/oTeam.cpp b/code/oTeam.cpp index 008c367..bca0e41 100644 --- a/code/oTeam.cpp +++ b/code/oTeam.cpp @@ -159,7 +159,7 @@ string oTeam::getRunners() const for(m=0;mId); + sprintf_s(bf, 16, "%d;", Runners[m]->getId()); str+=bf; } else str+="0;"; @@ -185,40 +185,43 @@ void oTeam::decodeRunners(const string &rns, vector &rid) } } -void oTeam::importRunners(const vector &rns) -{ +void oTeam::importRunners(const vector &rns) { Runners.resize(rns.size()); for (size_t n=0;n0) + if (rns[n] > 0) Runners[n] = oe->getRunner(rns[n], 0); else - Runners[n] = 0; + Runners[n] = nullptr; + + pRunner r = Runners[n]; + if (r) { + r->tInTeam = this; + r->tLeg = n; + } } } void oTeam::importRunners(const vector &rns) { // Unlink old runners - for (size_t k = rns.size(); ktInTeam == this) { - Runners[k]->tInTeam = 0; - Runners[k]->tLeg = 0; + for (size_t k = 0; ktInTeam == this) { + r->tInTeam = 0; + r->tLeg = 0; } } Runners.resize(rns.size()); - for (size_t n=0;ntInTeam == this) { - Runners[n]->tInTeam = 0; - Runners[n]->tLeg = 0; - } - } + for (size_t n = 0; n < rns.size(); n++) { Runners[n] = rns[n]; + if (rns[n] && isAddedToEvent()) { + rns[n]->tInTeam = this; + rns[n]->tLeg = n; + } } } - void oEvent::removeTeam(int Id) { oTeamList::iterator it; @@ -245,13 +248,14 @@ void oTeam::setRunner(unsigned i, pRunner r, bool sync) throw std::exception("Bad runner index"); } - if (Runners[i]==r) + if (Runners[i] == r) return; int oldRaceId = 0; - if (Runners[i]) { - oldRaceId = Runners[i]->getDCI().getInt("RaceId"); - Runners[i]->getDI().setInt("RaceId", 0); + pRunner tr = Runners[i]; + if (tr) { + oldRaceId = tr->getDCI().getInt("RaceId"); + tr->getDI().setInt("RaceId", 0); } setRunnerInternal(i, r); @@ -285,7 +289,7 @@ void oTeam::setRunner(unsigned i, pRunner r, bool sync) void oTeam::setRunnerInternal(int k, pRunner r) { - if (r==Runners[k]) { + if (r == Runners[k]) { if (r) { r->tInTeam = this; r->tLeg = k; @@ -293,29 +297,30 @@ void oTeam::setRunnerInternal(int k, pRunner r) return; } - if (Runners[k]) { - assert(Runners[k]->tInTeam == 0 || Runners[k]->tInTeam == this); - Runners[k]->tInTeam = 0; - Runners[k]->tLeg = 0; + pRunner rOld = Runners[k]; + if (rOld) { + assert(rOld->tInTeam == 0 || rOld->tInTeam == this); + rOld->tInTeam = 0; + rOld->tLeg = 0; } // Reset old team if (r && r->tInTeam) { - if (r->tInTeam->Runners[r->tLeg] != 0) { - r->tInTeam->Runners[r->tLeg] = 0; + if (r->tInTeam->Runners[r->tLeg]) { + r->tInTeam->Runners[r->tLeg] = nullptr; r->tInTeam->updateChanged(); if (r->tInTeam != this) r->tInTeam->synchronize(true); } } - Runners[k]=r; + Runners[k] = r; - if (Runners[k]) { - Runners[k]->tInTeam = this; - Runners[k]->tLeg = k; - if (Class && (Runners[k]->Class==nullptr || Class->getLegType(k) != LTGroup)) - Runners[k]->setClassId(getClassId(false), false); + if (r) { + r->tInTeam = this; + r->tLeg = k; + if (Class && (r->Class==nullptr || Class->getLegType(k) != LTGroup)) + r->setClassId(getClassId(false), false); } updateChanged(); } @@ -764,11 +769,9 @@ bool oTeam::compareSNO(const oTeam &a, const oTeam &b) { b.sName.c_str(), b.sName.length()) == CSTR_LESS_THAN; } - -bool oTeam::isRunnerUsed(int Id) const -{ +bool oTeam::isRunnerUsed(int rId) const { for(unsigned i=0;iId==Id) + if (Runners[i] && Runners[i]->getId() == rId) return true; } return false; @@ -830,13 +833,14 @@ void oTeam::quickApply() { if (Class && Runners.size()!=size_t(Class->getNumStages())) { for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { - if (Runners[k] && Runners[k]->tInTeam) { - Runners[k]->tInTeam = 0; - Runners[k]->tLeg = 0; - Runners[k]->tLegEquClass = 0; - if (Runners[k]->Class == Class) - Runners[k]->Class = 0; - Runners[k]->updateChanged(); + pRunner tr = Runners[k]; + if (tr && tr->tInTeam) { + tr->tInTeam = 0; + tr->tLeg = 0; + tr->tLegEquClass = 0; + if (tr->Class == Class) + tr->Class = 0; + tr->updateChanged(); } } Runners.resize(Class->getNumStages()); @@ -844,8 +848,16 @@ void oTeam::quickApply() { for (size_t i = 0; i < Runners.size(); i++) { if (Runners[i]) { - if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { - Runners[i]->tInTeam->correctRemove(Runners[i]); + if (Runners[i]->isRemoved()) { + // 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]->tLeg=i; @@ -853,8 +865,6 @@ void oTeam::quickApply() { } } - - bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { if (unsigned(status) >= 100) 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())) { for (size_t k = Class->getNumStages(); k < Runners.size(); k++) { - if (Runners[k] && Runners[k]->tInTeam) { - Runners[k]->tInTeam = 0; - Runners[k]->tLeg = 0; - Runners[k]->tLegEquClass = 0; - if (Runners[k]->Class == Class) - Runners[k]->Class = 0; - Runners[k]->updateChanged(); + auto tr = Runners[k]; + if (tr && tr->tInTeam) { + tr->tInTeam = nullptr; + tr->tLeg = 0; + tr->tLegEquClass = 0; + if (tr->Class == Class) + tr->Class = 0; + tr->updateChanged(); } } Runners.resize(Class->getNumStages()); @@ -881,7 +892,15 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { BibMode bibMode = (BibMode)-1; tNumRestarts = 0; vector availableStartTimes; - for (size_t i=0;iisRemoved()) { + // 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) return true; if (!Runners[i] && Class) { @@ -890,7 +909,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { if (lrcreateMultiRunner(false, sync); 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) { pRunner parent = Runners[i]->tParentRunner; for (size_t kk = 0; kkmultiRunner.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); - Runners[i]->tParentRunner = 0; - Runners[i]->tDuplicateLeg = 0; + tr->tParentRunner = 0; + tr->tDuplicateLeg = 0; parent->markForCorrection(); parent->updateChanged(); - Runners[i]->markForCorrection(); - Runners[i]->updateChanged(); + tr->markForCorrection(); + tr->updateChanged(); break; } } @@ -918,65 +938,66 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { if (Runners[i]) { for (size_t k=0;kgetClassRef(true); + pRunner tr = Runners[i]; + pClass actualClass = tr->getClassRef(true); if (actualClass == nullptr) actualClass = Class; - if (Runners[i]->tInTeam && Runners[i]->tInTeam!=this) { - Runners[i]->tInTeam->correctRemove(Runners[i]); + if (tr->tInTeam && tr->tInTeam!=this) { + tr->tInTeam->correctRemove(tr); } //assert(Runners[i]->tInTeam==0 || Runners[i]->tInTeam==this); - Runners[i]->tInTeam = this; - Runners[i]->tLeg = i; + tr->tInTeam = this; + tr->tLeg = i; if (Class) { int unused; - Class->splitLegNumberParallel(i, Runners[i]->tLegEquClass, unused); + Class->splitLegNumberParallel(i, tr->tLegEquClass, unused); } else { - Runners[i]->tLegEquClass = i; + tr->tLegEquClass = i; } if (actualClass == Class) - Runners[i]->setStartNo(StartNo, setTmpOnly); - if (!bib.empty() && Runners[i]->isChanged()) { + tr->setStartNo(StartNo, setTmpOnly); + if (!bib.empty() && tr->isChanged()) { if (bibMode == -1 && Class) bibMode = Class->getBibMode(); if (bibMode == BibSame) - Runners[i]->setBib(bib, 0, false, setTmpOnly); + tr->setBib(bib, 0, false, setTmpOnly); else if (bibMode == BibAdd) { wchar_t pattern[32], bf[32]; int ibib = oClass::extractBibPattern(bib, pattern) + i; swprintf_s(bf, pattern, ibib); - Runners[i]->setBib(bf, 0, false, setTmpOnly); + tr->setBib(bf, 0, false, setTmpOnly); } else if (bibMode == BibLeg) { 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; - if (Runners[i]->Class!=Class && legType != LTGroup) { - Runners[i]->Class=Class; - Runners[i]->updateChanged(); + if (tr->Class!=Class && legType != LTGroup) { + tr->Class=Class; + tr->updateChanged(); } - Runners[i]->tNeedNoCard=false; + tr->tNeedNoCard=false; if (Class) { pClass pc=Class; //Ignored runners need no SI-card (used by SI assign function) if (legType == LTIgnore) { - Runners[i]->tNeedNoCard=true; + tr->tNeedNoCard=true; if (lastStatus != StatusUnknown) { - Runners[i]->setStatus(max(Runners[i]->tStatus, lastStatus), false, setTmpOnly); + tr->setStatus(max(tr->tStatus, lastStatus), false, setTmpOnly); } } else - lastStatus = Runners[i]->getStatus(); + lastStatus = tr->getStatus(); StartTypes st = actualClass == pc ? pc->getStartType(i) : actualClass->getStartType(0); LegTypes lt = legType; @@ -987,27 +1008,27 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { } if (lt==LTIgnore || lt==LTExtra) { if (st != STDrawn) - Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); - Runners[i]->tUseStartPunch = (st == STDrawn); + tr->setStartTime(lastStartTime, false, setTmpOnly); + tr->tUseStartPunch = (st == STDrawn); } else { //Calculate start time. switch (st) { case STDrawn: //Do nothing if (lt==LTParallel || lt==LTParallelOptional) { - Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); - Runners[i]->tUseStartPunch=false; + tr->setStartTime(lastStartTime, false, setTmpOnly); + tr->tUseStartPunch=false; } else - lastStartTime = Runners[i]->getStartTime(); + lastStartTime = tr->getStartTime(); break; case STTime: { bool prs = false; - if (Runners[i] && Runners[i]->Card && freeStart) { - pCourse crs = Runners[i]->getCourse(false); + if (tr && tr->Card && freeStart) { + pCourse crs = tr->getCourse(false); 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) { prs = true; lastStartTime = pnc->getAdjustedTime(); @@ -1020,8 +1041,8 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { else lastStartTime = actualClass->getStartData(0); // Qualification/final classes } - Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); - Runners[i]->tUseStartPunch=false; + tr->setStartTime(lastStartTime, false, setTmpOnly); + tr->tUseStartPunch=false; } } break; @@ -1080,19 +1101,19 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { int rope=pc->getRopeTime(i); 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 tNumRestarts++; } if (ft > 0) - Runners[i]->setStartTime(ft, false, setTmpOnly); - Runners[i]->tUseStartPunch=false; + tr->setStartTime(ft, false, setTmpOnly); + tr->tUseStartPunch=false; lastStartTime=ft; } else {//The else below should only be run by mistake (for an incomplete team) - Runners[i]->setStartTime(Class->getRestartTime(i), false, setTmpOnly); - Runners[i]->tUseStartPunch=false; + tr->setStartTime(Class->getRestartTime(i), false, setTmpOnly); + tr->tUseStartPunch=false; } } break; @@ -1121,7 +1142,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { } if (restart > 0 && rope > 0 && (lastStartTime > rope) && - !preventRestart() && !Runners[i]->preventRestart()) { + !preventRestart() && !tr->preventRestart()) { lastStartTime = restart; //Runner in restart tNumRestarts++; } @@ -1140,7 +1161,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { setStart = true; } - if (Runners[i]->getFinishTime()>0) { + if (tr->getFinishTime()>0) { setStart = true; if (lastStartTime == 0) lastStartTime = pc->getRestartTime(i); @@ -1151,15 +1172,15 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { else lastStartTime=0; - Runners[i]->tUseStartPunch=false; - Runners[i]->setStartTime(lastStartTime, false, setTmpOnly); + tr->tUseStartPunch=false; + tr->setStartTime(lastStartTime, false, setTmpOnly); } break; } } 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++; 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 if (lt == LTExtra || pc->getLegType(i+1) == LTExtra) { - if (Runners[i]->getFinishTime()>0) { + if (tr->getFinishTime()>0) { if (extraFinishTime <= 0) - extraFinishTime = Runners[i]->getFinishTime(); + extraFinishTime = tr->getFinishTime(); else - extraFinishTime = min(extraFinishTime, Runners[i]->getFinishTime()); + extraFinishTime = min(extraFinishTime, tr->getFinishTime()); } } else @@ -1181,7 +1202,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { //Add available start times for parallel if (nextNonPar < Runners.size()) { st=pc->getStartType(nextNonPar); - int finishTime = Runners[i]->getFinishTime(); + int finishTime = tr->getFinishTime(); if (lt == LTExtra) finishTime = extraFinishTime; @@ -1207,7 +1228,7 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) { } } if (sync) - Runners[i]->synchronize(true); + tr->synchronize(true); } } @@ -1258,9 +1279,9 @@ void oTeam::evaluate(bool sync) void oTeam::correctRemove(pRunner r) { for(unsigned i=0;itInTeam = 0; + if (r != 0 && Runners[i] == r) { + Runners[i] = nullptr; + r->tInTeam = nullptr; r->tLeg = 0; r->tLegEquClass = 0; correctionNeeded = true; @@ -1454,11 +1475,11 @@ void oTeam::fillSpeakerObject(int leg, int courseControlId, int previousControlC } } - map::iterator mapit=Runners[leg]->priority.find(courseControlId); - if (mapit!=Runners[leg]->priority.end()) - spk.priority=mapit->second; + auto mapit = Runners[leg]->priority.find(courseControlId); + if (mapit != Runners[leg]->priority.end()) + spk.priority = mapit->second; else - spk.priority=0; + spk.priority = 0; spk.runningTimeLeg.preliminary = 0; for (int i = leg; i <= requestedLeg; i++) { @@ -1502,10 +1523,9 @@ void oTeam::fillSpeakerObject(int leg, int courseControlId, int previousControlC spk.status = spk.finishStatus; } -int oTeam::getTimeAfter(int leg) const -{ - if (leg==-1) - leg=Runners.size()-1; +int oTeam::getTimeAfter(int leg) const { + if (leg == -1) + leg = Runners.size() - 1; if (!Class || Class->tLeaderTime.size()<=unsigned(leg)) return -1; @@ -1576,12 +1596,11 @@ oDataContainer &oTeam::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &s return *oe->oTeamData; } -pRunner oTeam::getRunner(unsigned leg) const -{ +pRunner oTeam::getRunner(unsigned leg) const { if (leg==-1) leg=Runners.size()-1; - return leggetName(); } - } } } @@ -2137,8 +2155,8 @@ bool oTeam::checkValdParSetup() { if (Runners[m+k]) { // Move to where a runner is needed Runners[k] = Runners[k+m]; - Runners[k]->tLeg = k; - Runners[k+m] = 0; + Runners[k]->tLeg = k; + Runners[k+m] = nullptr; updateChanged(); cor = true; k+=m; diff --git a/code/oTeam.h b/code/oTeam.h index 8713982..21165f8 100644 --- a/code/oTeam.h +++ b/code/oTeam.h @@ -54,7 +54,7 @@ private: void propagateClub(); protected: - //pRunner Runners[maxRunnersTeam]; + vector Runners; void setRunnerInternal(int k, pRunner r); diff --git a/code/oTeamEvent.cpp b/code/oTeamEvent.cpp index 4f0e008..cf1565e 100644 --- a/code/oTeamEvent.cpp +++ b/code/oTeamEvent.cpp @@ -160,15 +160,17 @@ pTeam oEvent::addTeam(const wstring &pname, int ClubId, int ClassId) bibStartNoToRunnerTeam.clear(); Teams.push_back(t); - teamById[t.Id] = &Teams.back(); + pTeam pt = &Teams.back(); + pt->addToEvent(); + teamById[t.Id] = pt; oe->updateTabs(); - Teams.back().StartNo = ++nextFreeStartNo; // Need not be unique - Teams.back().getEntryDate(false);// Store entry time - Teams.back().apply(false, 0, false); - Teams.back().updateChanged(); - return &Teams.back(); + pt->StartNo = ++nextFreeStartNo; // Need not be unique + pt->getEntryDate(false);// Store entry time + pt->apply(false, 0, false); + pt->updateChanged(); + return pt; } pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) { @@ -181,6 +183,15 @@ pTeam oEvent::addTeam(const oTeam &t, bool autoAssignStartNo) { Teams.push_back(t); 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; 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 { - bool hasPatrol = getMeOSFeatures().hasFeature(MeOSFeatures::Patrol); - bool hasMulti = getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces); - bool hasRelay = getMeOSFeatures().hasFeature(MeOSFeatures::Relay); - bool hasForked = getMeOSFeatures().hasFeature(MeOSFeatures::ForkedIndividual); + bool hasPatrol = true;// getMeOSFeatures().hasFeature(MeOSFeatures::Patrol); + bool hasMulti = true;//getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces); + bool hasRelay = true;//getMeOSFeatures().hasFeature(MeOSFeatures::Relay); + bool hasForked = true;//getMeOSFeatures().hasFeature(MeOSFeatures::ForkedIndividual); gdi.clearList(name); gdi.addItem(name, lang.tl("Endast en bana"), PNoMulti); @@ -328,8 +339,10 @@ void oEvent::fillPredefinedCmp(gdioutput &gdi, const string &name) const } if (hasRelay) gdi.addItem(name, lang.tl("Stafett"), PRelay); - if (hasMulti) + if (hasMulti) { gdi.addItem(name, lang.tl("Tvåmannastafett"), PTwinRelay); + gdi.addItem(name, lang.tl("Flera lopp i valfri ordning"), PTwoRacesNoOrder); + } if (hasRelay) gdi.addItem(name, lang.tl("Extralöparstafett"), PYouthRelay); } @@ -386,6 +399,11 @@ void oEvent::setupRelayInfo(PredefinedTypes type, bool &useNLeg, bool &useStart) useStart = true; break; + case PTwoRacesNoOrder: + useStart = false; + useNLeg = true; + break; + default: throw std::exception("Bad setup number"); } @@ -424,7 +442,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri if (crs) { cls.addStageCourse(0, crsId, -1); } - + getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *this); + oe->synchronize(true); break; case PPoolDrawn: @@ -439,6 +458,9 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri if (crs) { cls.addStageCourse(0, crsId, -1); } + + getMeOSFeatures().useFeature(MeOSFeatures::ForkedIndividual, true, *this); + oe->synchronize(true); break; case PPatrol: @@ -460,6 +482,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri cls.addStageCourse(1, crsId, -1); } cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this); + oe->synchronize(true); break; case PPatrolOptional: @@ -481,6 +505,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri cls.addStageCourse(1, crsId, -1); } cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this); + oe->synchronize(true); break; case PPatrolOneSI: @@ -503,6 +529,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri } cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Patrol, true, *this); + oe->synchronize(true); break; case PRelay: @@ -521,6 +549,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri cls.setRopeTime(k, L"-"); } cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this); + oe->synchronize(true); break; case PTwinRelay: @@ -543,6 +573,27 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri } 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 0) + cls.setLegRunner(k, 0); + } + cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::MultipleRaces, true, *this); + oe->synchronize(true); break; case PYouthRelay: @@ -577,6 +628,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri } } cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this); + oe->synchronize(true); break; case PHunting: { @@ -595,6 +648,8 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri cls.setRopeTime(1, formatTimeHMS(t+1800)); cls.setLegRunner(1, 0); cls.setCoursePool(false); + getMeOSFeatures().useFeature(MeOSFeatures::Relay, true, *this); + oe->synchronize(true); break; } default: @@ -653,7 +708,7 @@ bool oTeam::adjustMultiRunners(bool sync) if (!Class) return false; - for (size_t k = Class->getNumStages(); kgetNumStages(); k < Runners.size(); k++) { setRunnerInternal(k, 0); } @@ -663,15 +718,15 @@ bool oTeam::adjustMultiRunners(bool sync) } // Create multi runners. - for (size_t i=0;igetLegRunner(i); + unsigned lr = Class->getLegRunner(i); - if (lrcreateMultiRunner(true, sync); - int dup=Class->getLegRunnerIndex(i); - Runners[i]=Runners[lr]->getMultiRunner(dup); - } + if (lr < i && Runners[lr]) { + Runners[lr]->createMultiRunner(true, sync); + int dup = Class->getLegRunnerIndex(i); + Runners[i] = Runners[lr]->getMultiRunner(dup); + } } } diff --git a/code/swedish.lng b/code/swedish.lng index 27650eb..b6b8590 100644 --- a/code/swedish.lng +++ b/code/swedish.lng @@ -1248,6 +1248,7 @@ X (Y deltagare, grupp Z, W) = X (Y deltagare, grupp Z, W) X har startat = X har startat X kontroller = X kontroller X meter = X meter +X m = X m X poäng fattas = X poäng fattas X rader kunde inte raderas = X rad(er) kunde inte raderas 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) Runner check time = Checktid 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