From 035fec52ecddb9f1f885ac2bf39333362a93d35e Mon Sep 17 00:00:00 2001 From: Erik Melin <31467290+erikmelin@users.noreply.github.com> Date: Wed, 16 Sep 2020 19:50:23 +0200 Subject: [PATCH] MeOS version 3.7SD.1221 --- code/RunnerDB.h | 2 +- code/TabClass.cpp | 2 +- code/TabCompetition.cpp | 105 ++++++++++--- code/TabCompetition.h | 4 +- code/english.lng | 4 + code/iof30interface.cpp | 15 +- code/meosversion.cpp | 36 ++--- code/oBase.h | 2 +- code/oCard.h | 2 +- code/oClass.h | 2 +- code/oClub.h | 2 +- code/oControl.h | 2 +- code/oCourse.h | 2 +- code/oDataContainer.cpp | 68 +++++++++ code/oDataContainer.h | 8 +- code/oEvent.cpp | 8 +- code/oEvent.h | 6 +- code/oEventDraw.cpp | 11 +- code/oFreePunch.h | 2 +- code/oListInfo.cpp | 6 +- code/oPunch.h | 2 +- code/oRunner.h | 7 +- code/oTeam.h | 2 +- code/oevent_transfer.cpp | 318 ++++++++++++++++++++++++++------------- code/restserver.cpp | 5 +- code/swedish.lng | 4 + 26 files changed, 446 insertions(+), 181 deletions(-) diff --git a/code/RunnerDB.h b/code/RunnerDB.h index a9123ed..e6caa34 100644 --- a/code/RunnerDB.h +++ b/code/RunnerDB.h @@ -368,7 +368,7 @@ protected: int getDISize() const {return 0;} void changedObject() {} public: - void merge(const oBase &input) final {} + void merge(const oBase &input, const oBase * base) final {} int getIndex() const {return index;} void init(RunnerDB *db_, int index_) {db=db_, index=index_; Id = index;} diff --git a/code/TabClass.cpp b/code/TabClass.cpp index d615afc..cea9ec7 100644 --- a/code/TabClass.cpp +++ b/code/TabClass.cpp @@ -3477,7 +3477,7 @@ bool TabClass::loadPage(gdioutput &gdi) if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::MultipleRaces)) func.push_back(ButtonData("QualificationFinal", "Kval/final-schema", false)); - if (showAdvanced) + if (showAdvanced || oe->getStartGroups(true).size() > 0) func.push_back(ButtonData("StartGroups", "Startgrupper", true)); RECT funRect; diff --git a/code/TabCompetition.cpp b/code/TabCompetition.cpp index 6a2231c..1d19bf7 100644 --- a/code/TabCompetition.cpp +++ b/code/TabCompetition.cpp @@ -166,6 +166,12 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi) if (oe->open(fileName, true, false)) { gdi.setWindowTitle(oe->getTitleName()); resetSaveTimer(); + + // Save base copy + wstring base = constructBase(L"base", L""); + wchar_t newBase[_MAX_PATH]; + getUserFile(newBase, base.c_str()); + oe->save(newBase); return true; } @@ -763,6 +769,13 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data) oe->getDirectSocket().startUDPSocketThread(gdi.getHWNDMain()); } + // Save base copy + wstring base = constructBase(L"base", L""); + wchar_t newBase[_MAX_PATH]; + getUserFile(newBase, base.c_str()); + if (!fileExist(newBase)) + oe->save(newBase); + loadConnectionPage(gdi); } else if (bi.id == "MultiEvent") { @@ -4167,10 +4180,23 @@ void TabCompetition::checkReadyForResultExport(gdioutput &gdi, const set &c } } +wstring TabCompetition::constructBase(const wstring &r, const wstring &mt) const { + wstring ret = oe->getNameId(0) + L"-"; + if (!mt.empty()) + ret += mt + L"-"; + ret += r + L".meosdiff"; + return ret; +}; + void TabCompetition::mergeCompetition(gdioutput &gdi) { class MergeHandler : public GuiHandler { TabCompetition *tc; + shared_ptr mergeEvent; + shared_ptr baseEvent; + wstring thisFile; + wstring baseFile; + public: MergeHandler(TabCompetition *tc) : tc(tc) {} @@ -4180,19 +4206,29 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { ButtonInfo bi = dynamic_cast(info); if (bi.id == "Cancel") { - if (tc->mergeEvent) - tc->mergeEvent->clear(); + if (mergeEvent) + mergeEvent->clear(); tc->loadPage(gdi); } else if (bi.id == "Merge") { - if (!tc->mergeEvent) + if (!mergeEvent) return; int numAdd, numRemove, numUpdate; + bool allowRemove = true; - wstring anno = lang.tl(L"Kopia (X)#MRG " + wstring(getLocalTime())); - tc->oe->duplicate(anno); + if (gdi.hasWidget("AllowRemove")) + allowRemove = gdi.isChecked("AllowRemove"); - tc->oe->merge(*tc->mergeEvent, numAdd, numRemove, numUpdate); + wstring anno = lang.tl(L"Kopia (X)#MRG " + getLocalTime()); + tc->oe->duplicate(anno, true); + + if (!thisFile.empty()) { + wchar_t newBase[_MAX_PATH]; + getUserFile(newBase, thisFile.c_str()); + mergeEvent->save(newBase); + } + + tc->oe->merge(*mergeEvent, baseEvent.get(), allowRemove, numAdd, numRemove, numUpdate); gdi.clearPage(true); @@ -4207,7 +4243,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { gdi.dropLine(); gdi.addString("", 0, L"Skapade lokal säkerhetskopia (X) innan sammanslagning#" + anno); - tc->mergeEvent->clear(); + mergeEvent->clear(); gdi.dropLine(3); gdi.addButton("Cancel", "Återgå").setHandler(this); @@ -4223,29 +4259,33 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { gdi.enableInput("Read"); } else if (bi.id == "Read") { - tc->mergeEvent = make_shared(gdi); + mergeEvent = make_shared(gdi); - if (!tc->mergeEvent->open(tc->mergeFile, true, true)) + if (!mergeEvent->open(tc->mergeFile, true, true)) return; gdi.restore("merge", false); gdi.fillDown(); - gdi.addStringUT(1, tc->mergeEvent->getName()); - + gdi.addStringUT(1, mergeEvent->getName()); + gdi.dropLine(); bool error = false; - if (tc->mergeEvent->getNameId(0) == tc->oe->getNameId(0)) { - if (tc->mergeEvent->getMergeTag() == tc->oe->getMergeTag()) { + bool sameBase = false; + if (mergeEvent->getNameId(0) == tc->oe->getNameId(0)) { + if (mergeEvent->getMergeTag() == tc->oe->getMergeTag()) { gdi.addString("", 1, "Fel: En tävling kan inte slås ihop med sig själv.").setColor(colorRed); error = true; } else { + sameBase = true; gdi.addString("", 1, "Samma bastävling").setColor(colorDarkGreen); - wstring info = tc->oe->getMergeInfo(tc->mergeEvent->getMergeTag()); - string mod = tc->mergeEvent->getLastModified(); + wstring info = tc->oe->getMergeInfo(mergeEvent->getMergeTag()); + string mod = mergeEvent->getLastModified(); + if (info.empty()) { gdi.addString("", 0, "Denna datakälla är aldrig tidigare infogad"); + baseFile = tc->constructBase(L"base", L""); } else { string merged = gdi.narrow(info); @@ -4258,6 +4298,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { TimeStamp ts; ts.setStamp(merged); gdi.addString("", 0, "Tidigare infogad version: X#" + ts.getStampStringN()); + baseFile = tc->constructBase(info, mergeEvent->getMergeTag()); } } @@ -4265,6 +4306,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { TimeStamp ts; ts.setStamp(mod); gdi.addString("", 0, "Infoga version: X#" + ts.getStampStringN()); + thisFile = tc->constructBase(gdi.widen(mod), mergeEvent->getMergeTag()); } } } @@ -4281,7 +4323,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { gdi.addString("", 1, "Klasser: "); vector cls; - tc->mergeEvent->getClasses(cls, false); + mergeEvent->getClasses(cls, false); int xw, yw; gdi.getTargetDimension(xw, yw); int limit = (xw * 2) / 3; @@ -4298,14 +4340,39 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) { gdi.popX(); gdi.dropLine(); - gdi.addString("", 1, "Antal deltagare: X#" + itos(tc->mergeEvent->getNumRunners())); + gdi.addString("", 1, "Antal deltagare: X#" + itos(mergeEvent->getNumRunners())); + } + + if (!baseFile.empty()) { + wchar_t base[_MAX_PATH]; + getUserFile(base, baseFile.c_str()); + baseEvent = make_shared(gdi); + bool ok = false; + try { + ok = baseEvent->open(base, true, true); + ok = true; + } + catch (...) { + } + + if (!ok) { + baseEvent.reset(); + gdi.dropLine(); + gdi.addString("", 0, L"Varning: Kunde inte hitta föregående version av tävlingen (X).#" + baseFile).setColor(GDICOLOR::colorRed); + gdi.addString("", 0, L"Använd om möjligt samma dator som användes vid senaste importen."); + } + } + + if (sameBase) { + gdi.dropLine(); + gdi.addCheckbox("AllowRemove", "Tillåt borttagning av löpare (med mera) som raderats i den importerade tävlingen"); } gdi.dropLine(); gdi.fillRight(); if (!error) - gdi.addButton("Merge", "Slå ihop").setHandler(tc->mergeHandler.get()); - gdi.addButton("Cancel", "Avbryt").setHandler(tc->mergeHandler.get()); + gdi.addButton("Merge", "Slå ihop").setHandler(this); + gdi.addButton("Cancel", "Avbryt").setHandler(this); gdi.refresh(); } diff --git a/code/TabCompetition.h b/code/TabCompetition.h index 2143e7b..71df33f 100644 --- a/code/TabCompetition.h +++ b/code/TabCompetition.h @@ -135,9 +135,11 @@ class TabCompetition : void listBackups(gdioutput &gdi); shared_ptr mergeHandler; - shared_ptr mergeEvent; void mergeCompetition(gdioutput &gdi); wstring mergeFile; + + wstring constructBase(const wstring &r, const wstring &mt) const; + protected: void clearCompetitionData(); diff --git a/code/english.lng b/code/english.lng index e96d16d..7da2793 100644 --- a/code/english.lng +++ b/code/english.lng @@ -2520,3 +2520,7 @@ Tjänstebeställningar (IOF XML) = Service Requests (IOF XML) Tjänster (IOF XML) = Services (IOF XML) Flytta deltagare från överfulla grupper = Move competitors from full groups Lotta med startgrupper = Draw with Starting Groups +Startgrupp med id X tilldelad Y finns inte = Starting group with ID X defined for Y does not exist +Använd om möjligt samma dator som användes vid senaste importen = If possible, use the same computer that was used to import the last time +Tillåt borttagning av löpare (med mera) som raderats i den importerade tävlingen = Allow removal of competitors (etc) that has was deleted in the imported version. +Varning: Kunde inte hitta föregående version av tävlingen (X) = Warning: Could not find the previous version of the competition (X) diff --git a/code/iof30interface.cpp b/code/iof30interface.cpp index c714c07..84855d1 100644 --- a/code/iof30interface.cpp +++ b/code/iof30interface.cpp @@ -1413,7 +1413,7 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo, } } } - + bool anySG = false; // This is a "hack" to interpret services of the from "XXXX 14:00 - 15:00 XXXX" as a start group. for (auto &srv : services) { vector parts; @@ -1428,10 +1428,15 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo, if (t > 0) times.push_back(t); } - if (times.size() == 2 && times[0] < times[1]) - oe.setStartGroup(srv.id, times[0], times[1]); + int ts = times.size(); + if (ts >= 2 && times[ts - 2] < times[ts - 1]) { + oe.setStartGroup(srv.id, times[ts - 2], times[ts - 1]); + anySG = true; + } } - oe.updateStartGroups(); + + if (anySG) + oe.updateStartGroups(); } void IOF30Interface::setupClassConfig(int classId, const xmlobject &xTeam, map > &teamClassConfig) { @@ -2950,7 +2955,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT)); bool hasTiming = (!r.getClassRef(false) || r.getClassRef(true)->getNoTiming() == false) && - r.getStatusComputed() != RunnerStatus::StatusNoTiming; + r.getStatusComputed() != RunnerStatus::StatusNoTiming && !r.noTiming(); int finishTime, runningTime, place, after; RunnerStatus status; diff --git a/code/meosversion.cpp b/code/meosversion.cpp index a32b2f9..36f79b5 100644 --- a/code/meosversion.cpp +++ b/code/meosversion.cpp @@ -30,18 +30,18 @@ //V35: abcdef //V36: abcdef int getMeosBuild() { - string revision("$Rev: 1031 $"); + string revision("$Rev: 1047 $"); return 174 + atoi(revision.substr(5, string::npos).c_str()); } //V37: ab wstring getMeosDate() { - wstring date(L"$Date: 2020-08-01 10:38:11 +0200 (lö, 01 aug 2020) $"); + wstring date(L"$Date: 2020-09-06 08:57:56 +0200 (sö, 06 sep 2020) $"); return date.substr(7,10); } wstring getBuildType() { - return L"RC1"; // No parantheses (...) + return L""; // No parantheses (...) } wstring getMajorVersion() { @@ -67,29 +67,13 @@ wstring getMeosCompectVersion() { void getSupporters(vector &supp, vector &developSupp) { - supp.emplace_back(L"Sergio Yañez, ABC TRAIL"); - supp.emplace_back(L"Western Race Services"); - supp.emplace_back(L"IK Gandvik, Skara"); - supp.emplace_back(L"IK Stern"); - supp.emplace_back(L"OK Roslagen"); - supp.emplace_back(L"TSV Malente"); - supp.emplace_back(L"Emmaboda Verda OK"); - supp.emplace_back(L"KOB ATU Košice"); - supp.emplace_back(L"Gävle OK"); - supp.emplace_back(L"Kenneth Gattmalm, Jönköpings OK"); - supp.emplace_back(L"Søllerød OK"); - supp.emplace_back(L"Bengt Bengtsson"); - supp.emplace_back(L"OK Landehof"); - supp.emplace_back(L"OK Orinto"); - supp.emplace_back(L"Bredaryds SOK"); - supp.emplace_back(L"Thore Nilsson, Uddevalla OK"); - supp.emplace_back(L"Timrå SOK"); - supp.emplace_back(L"Åke Larsson, OK Hedströmmen"); - supp.emplace_back(L"Avesta OK"); + supp.emplace_back(L"Tjalve IF"); + supp.emplace_back(L"Nyköpings Orienteringsklubb"); supp.emplace_back(L"Motionsorientering Göteborg"); supp.emplace_back(L"OK Måsen"); supp.emplace_back(L"IF Thor"); supp.emplace_back(L"SOS Jindřichův Hradec"); + supp.emplace_back(L"KOB ATU Košice"); supp.emplace_back(L"Mats Holmberg, OK Gränsen"); supp.emplace_back(L"Christoffer Ohlsson, Uddevalla OK"); supp.emplace_back(L"KOB ATU Košice"); @@ -114,6 +98,7 @@ void getSupporters(vector &supp, vector &developSupp) supp.emplace_back(L"Tolereds AIK"); supp.emplace_back(L"OK Snab"); supp.emplace_back(L"OK 73"); + supp.emplace_back(L"Herlufsholm OK"); supp.emplace_back(L"Helsingborgs SOK"); supp.emplace_back(L"Sala OK"); supp.emplace_back(L"OK Roskilde"); @@ -139,14 +124,19 @@ void getSupporters(vector &supp, vector &developSupp) supp.emplace_back(L"Nässjö OK"); supp.emplace_back(L"Ringsjö OK"); supp.emplace_back(L"Big Foot Orienteers"); + supp.emplace_back(L"Erik Hulthen, Mölndal Outdoor IF"); supp.emplace_back(L"Bay Area Orienteering Club"); supp.emplace_back(L"Finspångs SOK"); supp.emplace_back(L"OK Gorm, Denmark"); supp.emplace_back(L"Nyköpings OK"); supp.emplace_back(L"Thomas Engberg, VK Uvarna"); supp.emplace_back(L"LG Axmalm, Sävedalens AIK"); + supp.emplace_back(L"Martin Ivarsson"); supp.emplace_back(L"Falköpings AIK OK"); developSupp.push_back(L"Karlskrona SOK"); - + supp.emplace_back(L"Kristian Toustrup, OK Syd"); + supp.emplace_back(L"Patrick NG, HKAYP"); + supp.emplace_back(L"Lars Ove Karlsson, Västerås SOK"); + supp.emplace_back(L"OK Milan"); reverse(supp.begin(), supp.end()); } diff --git a/code/oBase.h b/code/oBase.h index 9c2263b..95c7ec9 100644 --- a/code/oBase.h +++ b/code/oBase.h @@ -115,7 +115,7 @@ protected: void setLocalObject() { localObject = true; } // Merge into this entity - virtual void merge(const oBase &input) = 0; + virtual void merge(const oBase &input, const oBase *base) = 0; public: diff --git a/code/oCard.h b/code/oCard.h index 17853cb..a2c354f 100644 --- a/code/oCard.h +++ b/code/oCard.h @@ -130,7 +130,7 @@ public: void importPunches(const string &s); const string &getPunchString() const; - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; pair getCardHash() const; void Set(const xmlobject &xo); diff --git a/code/oClass.h b/code/oClass.h index 5fd1bc8..7b92fa3 100644 --- a/code/oClass.h +++ b/code/oClass.h @@ -707,7 +707,7 @@ public: void setResultModule(const string &tag); const string &getResultModuleTag() const; - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; oClass(oEvent *poe); oClass(oEvent *poe, int id); diff --git a/code/oClub.h b/code/oClub.h index 6651bfe..95c479d 100644 --- a/code/oClub.h +++ b/code/oClub.h @@ -177,7 +177,7 @@ public: void setName(const wstring &n); - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; void set(const xmlobject &xo); bool write(xmlparser &xml); diff --git a/code/oControl.h b/code/oControl.h index a250b6a..188d330 100644 --- a/code/oControl.h +++ b/code/oControl.h @@ -219,7 +219,7 @@ public: int getFirstNumber() const; void getNumbers(vector &numbers) const; - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; void set(const xmlobject *xo); void set(int pId, int pNumber, wstring pName); diff --git a/code/oCourse.h b/code/oCourse.h index 5c35d44..cd6dc35 100644 --- a/code/oCourse.h +++ b/code/oCourse.h @@ -239,7 +239,7 @@ public: wstring getStart() const; void setStart(const wstring &start, bool sync); - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; bool Write(xmlparser &xml); diff --git a/code/oDataContainer.cpp b/code/oDataContainer.cpp index 6a92652..da59b66 100644 --- a/code/oDataContainer.cpp +++ b/code/oDataContainer.cpp @@ -845,6 +845,7 @@ namespace { return &bfData[0]; } } + string oDataContainer::generateSQLSet(const oBase *ob, bool forceSetAll) const { void *data, *oldData; vector< vector > *strptr; @@ -914,6 +915,73 @@ string oDataContainer::generateSQLSet(const oBase *ob, bool forceSetAll) const { return sql; } +bool oDataContainer::merge(oBase &destination, const oBase &source, const oBase *base) const { + bool modified = false; + void *destdata, *oldDataDmy; + vector< vector > *deststrptr; + destination.getDataBuffers(destdata, oldDataDmy, deststrptr); + + void *srcdata; + vector< vector > *srcstrptr; + source.getDataBuffers(srcdata, oldDataDmy, srcstrptr); + + void *basedata = nullptr; + vector< vector > *basestrptr = nullptr; + if (base) + base->getDataBuffers(basedata, oldDataDmy, basestrptr); + + auto setData = [](void *d, void *s, void *b, int off, int size) { + LPBYTE vd = LPBYTE(d) + off; + LPBYTE vs = LPBYTE(s) + off; + if (memcmp(vd, vs, size) != 0) { + if (b == nullptr || memcmp(LPBYTE(b) + off, vs, size) != 0) { + memcpy(vd, vs, size); + return true; + } + } + return false; + }; + + for (size_t kk = 0; kk < ordered.size(); kk++) { + const oDataInfo &di = ordered[kk]; + if (di.Type == oDTInt) { + if (di.SubType != oIS64) { + if (setData(destdata, srcdata, basedata, di.Index, sizeof(int))) + modified = true; + } + else { + if (setData(destdata, srcdata, basedata, di.Index, sizeof(int64_t))) + modified = true; + } + } + else if (di.Type == oDTString) { + if (setData(destdata, srcdata, basedata, di.Index, di.Size)) + modified = true; + } + else if (di.Type == oDTStringDynamic) { + const wstring &s = (*srcstrptr)[0][di.Index]; + wstring &d = (*deststrptr)[0][di.Index]; + if (s != d) { + if (basestrptr == nullptr || (*basestrptr)[0][di.Index] != s) { + d = s; + modified = true; + } + } + } + else if (di.Type == oDTStringArray) { + const auto &s = (*srcstrptr)[di.Index]; + auto &d = (*deststrptr)[di.Index]; + if (s != d) { + if (basestrptr == nullptr || (*basestrptr)[di.Index] != s) { + d = s; + modified = true; + } + } + } + } + + return modified; +} void oDataContainer::getVariableInt(const void *data, list &var) const { diff --git a/code/oDataContainer.h b/code/oDataContainer.h index 18701cc..ea1a82d 100644 --- a/code/oDataContainer.h +++ b/code/oDataContainer.h @@ -104,8 +104,6 @@ protected: size_t stringIndexPointer; size_t stringArrayIndexPointer; - //map index; - //vector ordered; inthashmap index; vector ordered; @@ -140,6 +138,8 @@ public: return generateSQLDefinition(std::set()); } + bool merge(oBase &destination, const oBase &source, const oBase *base) const; + string generateSQLSet(const oBase *ob, bool forceSetAll) const; void allDataStored(const oBase *ob); @@ -210,6 +210,10 @@ private: oDataContainer *oDC; oBase *oB; public: + + bool merge(const oBase &source, const oBase *base) { + return oDC->merge(*oB, source, base); + } inline bool setInt(const char *Name, int Value) { diff --git a/code/oEvent.cpp b/code/oEvent.cpp index 97d67b8..3c2e048 100644 --- a/code/oEvent.cpp +++ b/code/oEvent.cpp @@ -824,7 +824,7 @@ bool oEvent::writeCards(xmlparser &xml) return true; } -void oEvent::duplicate(const wstring &annotationIn) { +void oEvent::duplicate(const wstring &annotationIn, bool keepTags) { wchar_t file[260]; wchar_t filename[64]; wchar_t nameid[64]; @@ -854,7 +854,8 @@ void oEvent::duplicate(const wstring &annotationIn) { wstring oldAnno = getAnnotation(); wcscpy_s(CurrentFile, file); - currentNameId = nameid; + if (!keepTags) + currentNameId = nameid; swprintf_s(filename, L"%d/%d %d:%02d", st.wDay, st.wMonth, st.wHour, st.wMinute); @@ -869,7 +870,8 @@ void oEvent::duplicate(const wstring &annotationIn) { } wstring oldTag = getMergeTag(); try { - getMergeTag(true); + if (!keepTags) + getMergeTag(true); save(); } catch(...) { diff --git a/code/oEvent.h b/code/oEvent.h index 5a063c1..9d1ec71 100644 --- a/code/oEvent.h +++ b/code/oEvent.h @@ -963,7 +963,7 @@ public: bool exportOECSV(const wchar_t *file, int LanguageTypeIndex, bool includeSplits); bool save(); - void duplicate(const wstring &annotation); + void duplicate(const wstring &annotation, bool keepTags = false); void newCompetition(const wstring &Name); void clearListedCmp(); bool enumerateCompetitions(const wchar_t *path, const wchar_t *extension); @@ -1301,7 +1301,7 @@ protected: /** type: 0 control, 1 start, 2 finish*/ bool addXMLControl(const xmlobject &xcontrol, int type); - void merge(const oBase &src) final; + void merge(const oBase &src, const oBase *base) final; public: @@ -1313,7 +1313,7 @@ public: void getPredefinedClassTypes(map &types) const; - void merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate); + void merge(oEvent &src, oEvent *base, bool allowRemove, int &numAdd, int &numRemove, int &numUpdate); string getLastModified() const; wstring cloneCompetition(bool cloneRunners, bool cloneTimes, diff --git a/code/oEventDraw.cpp b/code/oEventDraw.cpp index 0b6add4..ccceaee 100644 --- a/code/oEventDraw.cpp +++ b/code/oEventDraw.cpp @@ -1169,9 +1169,7 @@ void oEvent::drawListStartGroups(const vector &spec, int nParallel = -1; if (diIn) nParallel = diIn->nFields; - - pRunner alice = getRunner(155227, 0); - + constexpr bool logOutput = false; auto &sgMap = getStartGroups(true); if (sgMap.empty()) @@ -1218,6 +1216,8 @@ void oEvent::drawListStartGroups(const vector &spec, ++rPerGroupTotal[idRes->second].first; } else { + if (id > 0) + throw meosException(L"Startgrupp med id X tilldelad Y finns inte.#" + itow(id) + L"#" + r.getCompleteIdentification()); ++res->second.unassigned; unassigned.push_back(&r); } @@ -1591,8 +1591,9 @@ void oEvent::drawListStartGroups(const vector &spec, ClassInfo &ci = di.classes[spec[k].classID]; ci.startGroupId = groupId; if (gi.firstStart > firstStart) { - ci.firstStart = (gi.firstStart - firstStart) / di.baseInterval; - ci.hasFixedTime = true; + // Handled by distributor + // ci.firstStart = (gi.firstStart - firstStart) / di.baseInterval; + // ci.hasFixedTime = true; } ci.nVacant = gi.vacantPerGroup[j]; ci.nVacantSpecified = true; diff --git a/code/oFreePunch.h b/code/oFreePunch.h index 431d894..a60fc59 100644 --- a/code/oFreePunch.h +++ b/code/oFreePunch.h @@ -86,7 +86,7 @@ public: static void rehashPunches(oEvent &oe, int cardNo, pFreePunch newPunch); static bool disableHashing; - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; oFreePunch(oEvent *poe, int card, int time, int type); oFreePunch(oEvent *poe, int id); diff --git a/code/oListInfo.cpp b/code/oListInfo.cpp index 1561786..fb69ddb 100644 --- a/code/oListInfo.cpp +++ b/code/oListInfo.cpp @@ -1009,10 +1009,10 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara wbf[0]=0; auto noTimingRunner = [&]() { - return (pc ? pc->getNoTiming() : false) || (r ? r->getStatusComputed() == StatusNoTiming : false); + return (pc ? pc->getNoTiming() : false) || (r ? (r->getStatusComputed() == StatusNoTiming || r->noTiming()) : false); }; auto noTimingTeam = [&]() { - return (pc ? pc->getNoTiming() : false) || (t ? t->getStatusComputed() == StatusNoTiming : false); + return (pc ? pc->getNoTiming() : false) || (t ? (t->getStatusComputed() == StatusNoTiming || t->noTiming()): false); }; bool invalidClass = pc && pc->getClassStatus() != oClass::ClassStatus::Normal; int legIndex = pp.legIndex; @@ -2459,7 +2459,7 @@ void oEvent::listGeneratePunches(const oListInfo &listInfo, gdioutput &gdi, if (cls && cls->getNoTiming()) return; - if (r && r->getStatusComputed() == StatusNoTiming) + if (r && (r->getStatusComputed() == StatusNoTiming || r->noTiming())) return; int h = gdi.getLineHeight(); diff --git a/code/oPunch.h b/code/oPunch.h index 6600a08..a7bbcaa 100644 --- a/code/oPunch.h +++ b/code/oPunch.h @@ -99,7 +99,7 @@ public: void appendCodeString(string &dst) const; - void merge(const oBase &input) override; + void merge(const oBase &input, const oBase *base) override; oPunch(oEvent *poe); virtual ~oPunch(); diff --git a/code/oRunner.h b/code/oRunner.h index 27ff0fa..4a45702 100644 --- a/code/oRunner.h +++ b/code/oRunner.h @@ -201,7 +201,7 @@ public: bool preventRestart() const; void preventRestart(bool state); - void merge(const oBase &input) override; + void merge(const oBase &input, const oBase *base) override; /** Call this method after doing something to just this runner/team that changed the time/status etc, that effects @@ -244,6 +244,9 @@ public: bool hasFlag(TransferFlags flag) const; void setFlag(TransferFlags flag, bool state); + /** Return true if no timing is requested. */ + bool noTiming() const { return hasFlag(FlagNoTiming); } + // Get the runners team or the team itself virtual cTeam getTeam() const = 0; virtual pTeam getTeam() = 0; @@ -958,7 +961,7 @@ public: /** Formats extra line for runner []-syntax, or if r is null, checks validity and throws on error.*/ static wstring formatExtraLine(pRunner r, const wstring &input); - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; virtual ~oRunner(); diff --git a/code/oTeam.h b/code/oTeam.h index 6193083..4a032f7 100644 --- a/code/oTeam.h +++ b/code/oTeam.h @@ -279,7 +279,7 @@ public: void set(const xmlobject &xo); bool write(xmlparser &xml); - void merge(const oBase &input) final; + void merge(const oBase &input, const oBase *base) final; oTeam(oEvent *poe, int id); oTeam(oEvent *poe); diff --git a/code/oevent_transfer.cpp b/code/oevent_transfer.cpp index a7eb2af..23b40a5 100644 --- a/code/oevent_transfer.cpp +++ b/code/oevent_transfer.cpp @@ -43,7 +43,7 @@ Eksoppsv -void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { +void oEvent::merge(oEvent &src, oEvent *base, bool allowRemove, int &numAdd, int &numRemove, int &numUpdate) { numAdd = 0; numRemove = 0; numUpdate = 0; @@ -76,27 +76,62 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto updateNewItem = [&addMinTime, &numAdd](oBase *pNew, const oBase &src) { if (pNew) { numAdd++; - pNew->merge(src); + pNew->merge(src, nullptr); pNew->synchronize(); if (pNew->Modified.getStamp() < addMinTime) pNew->Modified.setStamp(addMinTime); } }; - auto mergeItem = [&numUpdate](oBase *pExisting, const oBase &src) { + auto mergeItem = [&numUpdate](oBase *pExisting, const oBase &src, const oBase *baseItem) { numUpdate++; string oldStamp = pExisting->Modified.getStamp(); - pExisting->merge(src); + pExisting->merge(src, baseItem); if (pExisting->Modified.getStamp() < oldStamp) pExisting->Modified.setStamp(oldStamp); }; - auto computeRemove = [&bt](const auto &list, const set &existing, set &remove) { + auto getBaseMap = [](auto &list) { + map ret; + for (auto &c : list) + ret.emplace(c.getId(), &c); + return ret; + }; + map baseMap; + + auto computeRemove = [&bt, &baseMap](const auto &list, const set &existing, set &remove) { for (auto &c : list) { + if (!baseMap.empty() && !baseMap.count(c.Id)) + continue; // Did non exist in base -> not removed if (!c.isRemoved() && !existing.count(c.Id) && c.getStamp() < bt) remove.insert(c.Id); } }; + + // Swap id + auto changeBaseId = [&baseMap](int oldId, int newId) { + oBase *rOld = nullptr, *rNew = nullptr; + auto ob = baseMap.find(newId); + if (ob != baseMap.end() && ob->second) { + rOld = ob->second; + rOld->changeId(oldId); + } + ob = baseMap.find(oldId); + if (ob != baseMap.end() && ob->second) { + rNew = ob->second; + rNew->changeId(newId); + } + baseMap[newId] = rNew; + baseMap[oldId] = rOld; + }; + + auto getBaseObject = [&baseMap](const oBase &src) { + auto res = baseMap.find(src.getId()); + if (res != baseMap.end()) + return res->second; + else + return (oBase*)nullptr; + }; { map ctrl; @@ -105,8 +140,12 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { ctrl[c.Id] = &c; } + if (base) + baseMap = getBaseMap(base->Controls); + set srcControl; for (const oControl &c : src.Controls) { + const oBase *baseObj = getBaseObject(c); const string &stmp = c.getStamp(); if (!c.isRemoved()) { if (stmp > previousMergeTime) { @@ -114,7 +153,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { thisMergeTime = stmp; auto mc = ctrl.find(c.Id); if (mc != ctrl.end()) { - mergeItem(mc->second, c); + mergeItem(mc->second, c, baseObj); } else { pControl pNew = addControl(c); @@ -135,8 +174,12 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { crs[c.Id] = &c; } + if (base) + baseMap = getBaseMap(base->Courses); + set srcCourse; for (const oCourse &c : src.Courses) { + const oBase *baseObj = getBaseObject(c); const string &stmp = c.getStamp(); if (!c.isRemoved()) { bool okMerge = stmp > previousMergeTime; @@ -145,7 +188,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto mc = crs.find(c.Id); if (mc != crs.end()) { if (okMerge) - mergeItem(mc->second, c); + mergeItem(mc->second, c, baseObj); } else if (okMerge) { pCourse pNew = addCourse(c); @@ -168,9 +211,13 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { clsN[c.Name] = &c; } } + + if (base) + baseMap = getBaseMap(base->Classes); set srcClass; for (oClass &c : src.Classes) { + oBase *baseObj = getBaseObject(c); const string &stmp = c.getStamp(); bool merged = false; if (!c.isRemoved()) { @@ -183,23 +230,24 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { if (mc != cls.end()) { if (compareClassName(mc->second->Name, c.Name)) { if (okMerge) - mergeItem(mc->second, c); + mergeItem(mc->second, c, baseObj); merged = true; } } auto updateIdCls = [&](int id) { - pClass other = src.getClass(id); - if (other) + changeBaseId(c.Id, id); + pClass other = src.getClass(id); + if (other) other->changeId(c.Id); - c.changeId(id); + c.changeId(id); }; if (!merged) { auto mcN = clsN.find(c.Name); if (mcN != clsN.end()) { if (okMerge) - mergeItem(mcN->second, c); + mergeItem(mcN->second, c, baseObj); merged = true; updateIdCls(mcN->second->Id); } @@ -230,8 +278,12 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { crdByHash[c.getCardHash()] = &c; } } + + if (base) + baseMap = getBaseMap(base->Cards); for (oCard &c : src.Cards) { + const oBase *baseObj = getBaseObject(c); const string &stmp = c.getStamp(); if (!c.isRemoved() && stmp > previousMergeTime) { if (stmp > thisMergeTime) @@ -244,12 +296,13 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto c2 = mc->second; auto p2 = c2->getNumPunches() > 0 ? c2->getPunchByIndex(c2->getNumPunches() - 1)->getTimeInt() : 0; if (p1 == p2) - mergeItem(mc->second, c), merged = true; + mergeItem(mc->second, c, baseObj), merged = true; } auto updateIdCrd = [&](int id) { + changeBaseId(c.Id, id); pCard other = src.getCard(id); - if (other) + if (other) other->changeId(c.Id); c.changeId(id); }; @@ -257,7 +310,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { if (!merged) { auto mcN = crdByHash.find(c.getCardHash()); if (mcN != crdByHash.end()) { - mergeItem(mcN->second, c); + mergeItem(mcN->second, c, baseObj); merged = true; updateIdCrd(mcN->second->Id); } @@ -288,9 +341,13 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { clbByName[c.getName()] = &c; } } + + if (base) + baseMap = getBaseMap(base->Clubs); set srcClub; for (oClub &c : src.Clubs) { + const oBase *baseObj = getBaseObject(c); const string &stmp = c.getStamp(); if (!c.isRemoved()) { bool okMerge = stmp > previousMergeTime; @@ -304,12 +361,13 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { if ((c.getExtIdentifier() != 0 && c.getExtIdentifier() == mc->second->getExtIdentifier()) || c.getName() == mc->second->getName()) { if (okMerge) - mergeItem(mc->second, c); + mergeItem(mc->second, c, baseObj); merged = true; } } auto updateIdClb = [&](int id) { + changeBaseId(c.Id, id); pClub other = src.getClub(id); if (other) other->changeId(c.Id); @@ -320,7 +378,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto mcN = clbByExt.find(c.getExtIdentifier()); if (mcN != clbByExt.end()) { if (okMerge) - mergeItem(mcN->second, c); + mergeItem(mcN->second, c, baseObj); merged = true; updateIdClb(mcN->second->Id); } @@ -330,7 +388,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto mcN = clbByName.find(c.getName()); if (mcN != clbByName.end()) { if (okMerge) - mergeItem(mcN->second, c); + mergeItem(mcN->second, c, baseObj); merged = true; updateIdClb(mcN->second->Id); } @@ -356,6 +414,9 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { map rn; map rnByExt; map, pRunner> rnByCardName; + + if (base) + baseMap = getBaseMap(base->Runners); for (oRunner &r : Runners) { if (!r.isRemoved()) { @@ -367,6 +428,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { } set srcRunner; for (oRunner &r : src.Runners) { + const oBase *baseObj = getBaseObject(r); const string &stmp = r.getStamp(); if (!r.isRemoved()) { bool okMerge = stmp > previousMergeTime; @@ -382,15 +444,16 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { || mc->second->isVacant()) { if (okMerge) - mergeItem(mc->second, r); + mergeItem(mc->second, r, baseObj); merged = true; } } auto updateIdR = [&](int id) { - pRunner other = src.getRunner(id, 0); - if (other) - other->changeId(src.Id); + changeBaseId(r.Id, id); + pRunner other = src.getRunner(id, 0); + if (other) + other->changeId(r.Id); r.changeId(id); }; @@ -398,7 +461,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto mcN = rnByExt.find(r.getExtIdentifier()); if (mcN != rnByExt.end()) { if (okMerge) - mergeItem(mcN->second, r); + mergeItem(mcN->second, r, baseObj); merged = true; updateIdR(mcN->second->Id); } @@ -408,7 +471,7 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { auto mcN = rnByCardName.find(make_pair(r.getCardNo(), r.sName)); if (mcN != rnByCardName.end()) { if (okMerge) - mergeItem(mcN->second, r); + mergeItem(mcN->second, r, baseObj); merged = true; updateIdR(mcN->second->Id); } @@ -441,8 +504,12 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { } } + if (base) + baseMap = getBaseMap(base->Teams); + set srcTeam; for (oTeam &t : src.Teams) { + const oBase *baseObj = getBaseObject(t); const string &stmp = t.getStamp(); if (!t.isRemoved()) { bool okMerge = stmp > previousMergeTime; @@ -454,24 +521,24 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { if (mc != tm.end()) { if (t.getClubId() == mc->second->getClubId()) { if (okMerge) - mergeItem(mc->second, t); + mergeItem(mc->second, t, baseObj); merged = true; } } auto updateIdT = [&](int id) { + changeBaseId(t.Id, id); pTeam other = src.getTeam(id); if (other) - other->changeId(src.Id); + other->changeId(t.Id); t.changeId(id); }; - - + if (!merged) { auto mcN = tmByClassName.find(make_pair(t.getClassId(false), t.getName())); if (mcN != tmByClassName.end()) { if (okMerge) - mergeItem(mcN->second, t); + mergeItem(mcN->second, t, baseObj); merged = true; updateIdT(mcN->second->Id); } @@ -503,12 +570,14 @@ void oEvent::merge(oEvent &src, int &numAdd, int &numRemove, int &numUpdate) { } }; - removeEnts(rTeam, [this](int id) -> pBase {return getTeam(id); }); - removeEnts(rRunner, [this](int id) -> pBase {return getRunner(id, 0); }); - removeEnts(rClub, [this](int id) -> pBase {return getClub(id); }); - removeEnts(rClass, [this](int id) -> pBase {return getClass(id); }); - removeEnts(rCourse, [this](int id) -> pBase {return getCourse(id); }); - removeEnts(rControl, [this](int id) -> pBase {return getControl(id); }); + if (allowRemove) { + removeEnts(rTeam, [this](int id) -> pBase {return getTeam(id); }); + removeEnts(rRunner, [this](int id) -> pBase {return getRunner(id, 0); }); + removeEnts(rClub, [this](int id) -> pBase {return getClub(id); }); + removeEnts(rClass, [this](int id) -> pBase {return getClass(id); }); + removeEnts(rCourse, [this](int id) -> pBase {return getCourse(id); }); + removeEnts(rControl, [this](int id) -> pBase {return getControl(id); }); + } wstring mtOut(thisMergeTime.begin(), thisMergeTime.end()); addMergeInfo(mergeTag, mtOut); @@ -1228,102 +1297,149 @@ void oEvent::transferResult(oEvent &ce, }*/ } -void oAbstractRunner::merge(const oBase &input) { +void oAbstractRunner::merge(const oBase &input, const oBase *baseIn) { const oAbstractRunner &src = dynamic_cast(input); - setName(src.sName, false); + const oAbstractRunner *base = dynamic_cast(baseIn); - setStartTime(src.startTime, true, ChangeType::Update, false); - setFinishTime(src.FinishTime); - setStatus(src.status, true, ChangeType::Update); - setStartNo(src.StartNo, ChangeType::Update); - setClubId(src.getClubId()); - setClassId(src.getClassId(false), false); + if (base == nullptr || base->sName != src.sName) + setName(src.sName, false); + + if (base == nullptr || base->startTime != src.startTime) + setStartTime(src.startTime, true, ChangeType::Update, false); + + if (base == nullptr || base->FinishTime != src.FinishTime) + setFinishTime(src.FinishTime); + + if (base == nullptr || base->status != src.status) + setStatus(src.status, true, ChangeType::Update); + + if (base == nullptr || base->StartNo != src.StartNo) + setStartNo(src.StartNo, ChangeType::Update); + + if (base == nullptr || base->getClub() != src.getClub()) + setClubId(src.getClubId()); + + if (base == nullptr || base->getClass(false) != src.getClass(false)) + setClassId(src.getClassId(false), false); - setInputPlace(src.inputPlace); - if (inputTime != src.inputTime) { - inputTime = src.inputTime; - updateChanged(); + if (base == nullptr || base->inputPlace != src.inputPlace) + setInputPlace(src.inputPlace); + + if (base == nullptr || base->inputTime != src.inputTime) { + if (inputTime != src.inputTime) { + inputTime = src.inputTime; + updateChanged(); + } } - setInputStatus(src.inputStatus); - setInputPoints(src.inputPoints); + if (base == nullptr || base->inputStatus != src.inputStatus) + setInputStatus(src.inputStatus); + + if (base == nullptr || base->inputPoints != src.inputPoints) + setInputPoints(src.inputPoints); } -void oRunner::merge(const oBase &input) { - oAbstractRunner::merge(input); +void oRunner::merge(const oBase &input, const oBase *baseIn) { + oAbstractRunner::merge(input, baseIn); const oRunner &src = dynamic_cast(input); - setCourseId(src.getCourseId()); - if (src.getCardId() != 0) - setCard(src.getCardId()); - setCardNo(src.getCardNo(), false); + const oRunner *base = dynamic_cast(baseIn); - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); + if (base == nullptr || base->getCourseId() != src.getCourseId()) + setCourseId(src.getCourseId()); + + if ((base == nullptr && src.getCardId() != 0) || (base != nullptr && base->getCardId() != src.getCardId())) + setCard(src.getCardId()); + + if (base == nullptr || base->getCardNo() != src.getCardNo()) + setCardNo(src.getCardNo(), false); + + if (getDI().merge(input, base)) updateChanged(); - } + synchronize(true); } -void oTeam::merge(const oBase &input) { - oAbstractRunner::merge(input); +void oTeam::merge(const oBase &input, const oBase *baseIn) { + oAbstractRunner::merge(input, baseIn); const oTeam &src = dynamic_cast(input); + const oTeam *base = dynamic_cast(baseIn); - bool same = src.Runners.size() == Runners.size(); - vector r(src.Runners.size()); - for (size_t i = 0; i < src.Runners.size(); i++) { - if (src.Runners[i]) { - r[i] = src.Runners[i]->Id; - src.Runners[i]->tInTeam = nullptr; - } - if (same) { - int rc = Runners[i] ? Runners[i]->Id : 0; - if (rc != r[i]) - same = false; - } - } - - importRunners(r); - if (!same) - updateChanged(); + auto getRId = [](const oTeam &t, int ix) { + pRunner r = t.getRunner(ix); + return r ? r->getId() : 0; + }; - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); - updateChanged(); + bool chR; + if (base) { + chR = base->Runners.size() != src.Runners.size(); + if (!chR) { + for (size_t i = 0; i < src.Runners.size(); i++) { + if (getRId(src, i) != getRId(*base, i)) + chR = true; + } + } } + else chR = true; + + if (chR) { + bool same = src.Runners.size() == Runners.size(); + vector r(src.Runners.size()); + for (size_t i = 0; i < src.Runners.size(); i++) { + if (src.Runners[i]) { + r[i] = src.Runners[i]->Id; + src.Runners[i]->tInTeam = nullptr; + } + if (same) { + int rc = Runners[i] ? Runners[i]->Id : 0; + if (rc != r[i]) + same = false; + } + } + + if (!same) { + importRunners(r); + updateChanged(); + } + } + + if (getDI().merge(input, base)) + updateChanged(); + synchronize(true); } -void oControl::merge(const oBase &input) { +void oControl::merge(const oBase &input, const oBase *base) { const oControl &src = dynamic_cast(input); if (src.Name.length() > 0) setName(src.Name); setNumbers(src.codeNumbers()); setStatus(src.getStatus()); - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); + if (getDI().merge(input, base)) updateChanged(); - } + synchronize(true); } -void oCourse::merge(const oBase &input) { +void oCourse::merge(const oBase &input, const oBase *baseIn) { const oCourse &src = dynamic_cast(input); + const oCourse *base = dynamic_cast(baseIn); - if (src.Name.length() > 0) + if ((base == nullptr || base->Name != src.Name) && (src.Name.length() > 0)) setName(src.Name); - setLength(src.Length); + if (!base || base->Length != src.Length) + setLength(src.Length); + importControls(src.getControls(), true, false); importLegLengths(src.getLegLengths(), true); - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); + if (getDI().merge(input, base)) updateChanged(); - } + synchronize(true); } -void oClass::merge(const oBase &input) { +void oClass::merge(const oBase &input, const oBase *base) { const oClass &src = dynamic_cast(input); if (src.Name.length() > 0) @@ -1351,25 +1467,23 @@ void oClass::merge(const oBase &input) { } } - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); + if (getDI().merge(input, base)) updateChanged(); - } + synchronize(true); } -void oClub::merge(const oBase &input) { +void oClub::merge(const oBase &input, const oBase *base) { const oClub &src = dynamic_cast(input); setName(src.getName()); - if (memcmp(oData, src.oData, sizeof(oData)) != 0) { - memcpy(oData, src.oData, sizeof(oData)); + if (getDI().merge(input, base)) updateChanged(); - } + synchronize(true); } -void oCard::merge(const oBase &input) { +void oCard::merge(const oBase &input, const oBase *base) { const oCard &src = dynamic_cast(input); setCardNo(src.getCardNo()); @@ -1384,19 +1498,19 @@ void oCard::merge(const oBase &input) { synchronize(true); } -void oPunch::merge(const oBase &input) { +void oPunch::merge(const oBase &input, const oBase *base) { const oPunch &src = dynamic_cast(input); // Not implemented } -void oFreePunch::merge(const oBase &input) { +void oFreePunch::merge(const oBase &input, const oBase *base) { const oFreePunch &src = dynamic_cast(input); // Not implemented } -void oEvent::merge(const oBase &srcIn) { +void oEvent::merge(const oBase &srcIn, const oBase *base) { } diff --git a/code/restserver.cpp b/code/restserver.cpp index ac445f4..2b1ac30 100644 --- a/code/restserver.cpp +++ b/code/restserver.cpp @@ -1113,7 +1113,7 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimapgetCardNo()); xml.write("Status", {make_pair("code", itow(r->getStatusComputed()))}, r->getStatusS(true, true)); xml.write("Start", r->getStartTimeS()); - if (r->getFinishTime() > 0 && r->getStatusComputed() != StatusNoTiming) { + if (r->getFinishTime() > 0 && r->getStatusComputed() != StatusNoTiming && !r->noTiming()) { xml.write("Finish", r->getFinishTimeS()); xml.write("RunningTime", r->getRunningTimeS(true)); xml.write("Place", r->getPlaceS()); @@ -1127,7 +1127,8 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimapgetFinishTime() > 0 || r->getCard() != nullptr) && r->getCourse(false) && - r->getStatusComputed() != StatusNoTiming) { + r->getStatusComputed() != StatusNoTiming && + !r->noTiming()) { auto &sd = r->getSplitTimes(false); vector after; r->getLegTimeAfter(after); diff --git a/code/swedish.lng b/code/swedish.lng index 8e0ad77..d71de6f 100644 --- a/code/swedish.lng +++ b/code/swedish.lng @@ -2527,3 +2527,7 @@ Tjänstebeställningar (IOF XML) = Tjänstebeställningar (IOF XML) Tjänster (IOF XML) = Tjänster (IOF XML) Flytta deltagare från överfulla grupper = Flytta deltagare från överfulla grupper Lotta med startgrupper = Lotta med startgrupper +Startgrupp med id X tilldelad Y finns inte = Startgrupp med id X definierad för Y finns inte +Använd om möjligt samma dator som användes vid senaste importen = Använd om möjligt samma dator som användes vid senaste importen +Tillåt borttagning av löpare (med mera) som raderats i den importerade tävlingen = Tillåt borttagning av löpare (med mera) som raderats i den importerade tävlingen +Varning: Kunde inte hitta föregående version av tävlingen (X) = Varning: Kunde inte hitta föregående version av tävlingen (X)