MeOS version 3.7.1178 RC1

This commit is contained in:
Erik Melin 2020-02-29 21:34:01 +01:00
parent 3dcdfa3b65
commit 338fb3c34e
53 changed files with 1404 additions and 526 deletions

View File

@ -96,7 +96,7 @@ void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
bool disablePermisson = true;
gdi.popX();
gdi.addCheckbox("MapRoot", "Mappa rootadresssen (http:///localhost:port/) till funktion:", nullptr, !rootMap.empty()).setHandler(this);
gdi.addCheckbox("MapRoot", "Mappa rootadressen (http:///localhost:port/) till funktion:", nullptr, !rootMap.empty()).setHandler(this);
gdi.addInput("RootMap", gdi.recodeToWide(rootMap));
gdi.setInputStatus("RootMap", !rootMap.empty());

View File

@ -48,8 +48,24 @@ RunnerDB::RunnerDB(oEvent *oe_): oe(oe_)
loadedFromServer = false;
dataDate = 20100201;
dataTime = 222222;
runnerTable = 0;
clubTable = 0;
}
RunnerDB::RunnerDB(const RunnerDB &in) : oe(in.oe) {
loadedFromServer = false;
dataDate = in.dataDate;
dataTime = in.dataTime;
rdb = in.rdb;
rwdb = in.rwdb;
for (size_t k = 0; k < rwdb.size(); k++)
rwdb[k].init(this, k);
rhash = in.rhash;
cdb = in.cdb;
oRDB = in.oRDB;
chash = in.chash;
freeCIx = in.freeCIx;
}
RunnerDB::~RunnerDB(void)
@ -57,6 +73,15 @@ RunnerDB::~RunnerDB(void)
releaseTables();
}
bool RunnerDB::operator!=(const RunnerDB &in) const {
return dataDate != in.dataDate ||
dataTime != in.dataTime ||
freeCIx != in.freeCIx ||
rdb.size() != in.rdb.size() ||
cdb.size() != in.cdb.size() ||
(!rdb.empty() && !(rdb.back() == in.rdb.back()));
}
RunnerDBEntry::RunnerDBEntry()
{
memset(this, 0, sizeof(RunnerDBEntry));
@ -268,8 +293,8 @@ RunnerWDBEntry *RunnerDB::addRunner(const wchar_t *name,
int club, int card)
{
assert(rdb.size() == rwdb.size());
rdb.push_back(RunnerDBEntry());
rwdb.push_back(RunnerWDBEntry());
rdb.emplace_back();
rwdb.emplace_back();
rwdb.back().init(this, rdb.size()-1);
RunnerWDBEntry &e=rwdb.back();
@ -290,7 +315,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const wchar_t *name,
if (!idhash.empty())
idhash[extId] = rdb.size()-1;
if (!nhash.empty())
nhash.insert(pair<wstring, int>(canonizeName(e.name), rdb.size()-1));
nhash.emplace(canonizeName(e.name), rdb.size()-1);
}
return &e;
}
@ -301,8 +326,8 @@ RunnerWDBEntry *RunnerDB::addRunner(const char *nameUTF,
int club, int card)
{
assert(rdb.size() == rwdb.size());
rdb.push_back(RunnerDBEntry());
rwdb.push_back(RunnerWDBEntry());
rdb.emplace_back();
rwdb.emplace_back();
rwdb.back().init(this, rdb.size()-1);
RunnerWDBEntry &e=rwdb.back();
@ -325,7 +350,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const char *nameUTF,
if (!nhash.empty()) {
wstring wn;
e.getName(wn);
nhash.insert(pair<wstring, int>(canonizeName(wn.c_str()), rdb.size()-1));
nhash.emplace(canonizeName(wn.c_str()), rdb.size()-1);
}
}
return &e;
@ -406,7 +431,7 @@ void RunnerDB::importClub(oClub &club, bool matchName)
else {
// Completely new club
chash [club.getId()] = cdb.size();
cdb.push_back(oDBClubEntry(club, cdb.size(), this));
cdb.emplace_back(club, cdb.size(), this);
}
}
@ -1139,17 +1164,41 @@ void RunnerDB::fillClubs(vector< pair<wstring, size_t> > &out) const {
out.reserve(cdb.size());
for (size_t k = 0; k<cdb.size(); k++) {
if (!cdb[k].isRemoved()) {
out.push_back(make_pair(cdb[k].getName(), cdb[k].getId()));
out.emplace_back(cdb[k].getName(), cdb[k].getId());
}
}
sort(out.begin(), out.end());
}
oDBRunnerEntry::oDBRunnerEntry(oEvent *oe) : oBase(oe) {
db = 0;
db = nullptr;
index = -1;
}
oDBRunnerEntry::oDBRunnerEntry(oDBRunnerEntry &&in) : oBase(std::move(in)) {
db = in.db;
index = in.index;
}
oDBRunnerEntry::oDBRunnerEntry(const oDBRunnerEntry &in) : oBase(in) {
db = in.db;
index = in.index;
}
const oDBRunnerEntry &oDBRunnerEntry::operator=(const oDBRunnerEntry &in) {
oBase::operator=(in);
db = in.db;
index = in.index;
return *this;
}
const oDBRunnerEntry &oDBRunnerEntry::operator=(oDBRunnerEntry &&in) {
oBase::operator=(std::move(in));
db = in.db;
index = in.index;
return *this;
}
oDBRunnerEntry::~oDBRunnerEntry() {}
void RunnerDB::generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry)
@ -1210,7 +1259,7 @@ const shared_ptr<Table> &RunnerDB::getRunnerTB() {
table->addColumn("Nationalitet", 70, false, true);
table->addColumn("Kön", 50, false, true);
table->addColumn("Födelseår", 70, true, true);
table->addColumn("Anmäl", 70, false, true);
table->addColumn("Anmäl", 120, false, true);
table->setTableProp(Table::CAN_INSERT|Table::CAN_DELETE|Table::CAN_PASTE);
table->setClearOnHide(false);
@ -1224,6 +1273,25 @@ const shared_ptr<Table> &RunnerDB::getRunnerTB() {
if (runnerTable->getNumDataRows() != nr)
runnerTable->update();
else {
/*vector<pRunner> runners;
setupIdHash();
oe->getRunners(0, 0, runners, false);
for (pRunner r : runners) {
int64_t extId = r->getExtIdentifier();
if (extId != 0) {
int value;
if (idhash.lookup(extId, value)) {
try {
runnerTable->reloadRow(value + 1);
}
catch (const std::exception &) {
// Ignore any problems with the table.
}
}
}
}*/
}
return runnerTable;
}
@ -1259,15 +1327,15 @@ void RunnerDB::refreshRunnerTableData(Table &table) {
if (row) {
row->setObject(oRDB[k]);
oClass *val = 0;
int runnerId;
bool found = false;
if (rdb[k].extId != 0)
found = runnerInEvent.lookup(rdb[k].extId, val);
found = runnerInEvent.lookup(rdb[k].extId, runnerId);
if (found && row->getCellType(cellEntryIndex) == cellAction) {
row->updateCell(cellEntryIndex, cellEdit, val->getName());
if (found) {
pRunner r = oe->getRunner(runnerId, 0);
row->updateCell(cellEntryIndex, cellEdit, r ? r->getClass(true) : L"");
}
else if (!found && row->getCellType(cellEntryIndex) == cellEdit) {
row->updateCell(cellEntryIndex, cellAction, L"@+");
@ -1343,11 +1411,11 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
table.set(row++, it, TID_SEX, sex, canEdit, cellEdit);
table.set(row++, it, TID_YEAR, itow(rn.birthYear), canEdit, cellEdit);
oClass *val = 0;
int runnerId;
bool found = false;
if (rn.extId != 0)
found = db->runnerInEvent.lookup(rn.extId, val);
found = db->runnerInEvent.lookup(rn.extId, runnerId);
if (canEdit)
table.setTableProp(Table::CAN_DELETE|Table::CAN_INSERT|Table::CAN_PASTE);
@ -1357,8 +1425,10 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
RunnerDB::cellEntryIndex = row;
if (!found)
table.set(row++, it, TID_ENTER, L"@+", false, cellAction);
else
table.set(row++, it, TID_ENTER, val ? val->getName() : L"", false, cellEdit);
else {
pRunner r = oe->getRunner(runnerId, 0);
table.set(row++, it, TID_ENTER, r ? r->getClass(true) : L"", false, cellEdit);
}
}
const RunnerDBEntry &oDBRunnerEntry::getRunner() const {
@ -1427,7 +1497,7 @@ void oDBRunnerEntry::fillInput(int id, vector< pair<wstring, size_t> > &out, siz
RunnerDBEntry &r = db->rdb[index];
if (id==TID_CLUB) {
db->fillClubs(out);
out.push_back(make_pair(L"-", 0));
out.emplace_back(L"-", 0);
selected = r.clubNo;
}
}
@ -1460,11 +1530,11 @@ bool oDBRunnerEntry::canRemove() const {
}
oDBRunnerEntry *RunnerDB::addRunner() {
rdb.push_back(RunnerDBEntry());
rwdb.push_back(RunnerWDBEntry());
rdb.emplace_back();
rwdb.emplace_back();
rwdb.back().init(this, rdb.size() -1);
oRDB.push_back(oDBRunnerEntry(oe));
oRDB.emplace_back(oe);
oRDB.back().init(this, rdb.size() - 1);
return &oRDB.back();
@ -1475,7 +1545,7 @@ oClub *RunnerDB::addClub() {
while (chash.count(freeCIx))
freeCIx++;
cdb.push_back(oDBClubEntry(oe, freeCIx, cdb.size(), this));
cdb.emplace_back(oe, freeCIx, cdb.size(), this);
chash.insert(freeCIx, cdb.size()-1);
cnhash.clear();

View File

@ -107,6 +107,10 @@ struct RunnerDBEntry {
bool isUTF() const { return (reserved & 2) == 2; }
void setUTF() { reserved |= 2; }
bool operator==(const RunnerDBEntry &d) const {
return memcmp(this, &d, sizeof(RunnerDBEntry)) == 0;
}
};
class RunnerDB;
@ -168,7 +172,7 @@ private:
bool check(const RunnerDBEntry &rde) const;
intkeymap<oClass *, __int64> runnerInEvent;
intkeymap<int, __int64> runnerInEvent;
/** Init name hash lazy */
void setupNameHash() const;
@ -345,6 +349,9 @@ public:
void getAllNames(vector<wstring> &givenName, vector<wstring> &familyName);
RunnerDB(oEvent *);
RunnerDB(const RunnerDB &in);
bool operator!=(const RunnerDB &other) const;
~RunnerDB(void);
friend class oDBRunnerEntry;
friend class oDBClubEntry;
@ -373,6 +380,12 @@ public:
void fillInput(int id, vector< pair<wstring, size_t> > &out, size_t &selected) override;
oDBRunnerEntry(oEvent *oe);
oDBRunnerEntry(oDBRunnerEntry &&in);
oDBRunnerEntry(const oDBRunnerEntry &in);
const oDBRunnerEntry &operator=(oDBRunnerEntry &&in);
const oDBRunnerEntry &operator=(const oDBRunnerEntry &in);
virtual ~oDBRunnerEntry();
void remove();

View File

@ -366,7 +366,7 @@ int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu)
else
par.setLegNumberCoded(0);
oe->generateListInfo(par, gdi.getLineHeight(), prm->listInfo);
oe->generateListInfo(par, prm->listInfo);
}
}
prm->po.onlyChanged = gdi.isChecked("OnlyChanged");

View File

@ -913,7 +913,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
readClassSettings(gdi);
oEvent::DrawMethod method = (oEvent::DrawMethod)gdi.getSelectedItem("Method").first;
int pairSize = gdi.getSelectedItem("PairSize").first;
auto vp = readVacantPosition(gdi);
bool drawCoursebased = drawInfo.coursesTogether;
int maxST = 0;
@ -923,7 +923,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
const ClassInfo &ci=cInfo[k];
ClassDrawSpecification cds(ci.classId, 0, drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart,
drawInfo.baseInterval * ci.interval, ci.nVacant);
drawInfo.baseInterval * ci.interval, ci.nVacant, vp);
if (drawCoursebased) {
pCourse pCrs = oe->getClass(ci.classId)->getCourse();
int id = pCrs ? pCrs->getId() : 101010101 + ci.classId;
@ -954,7 +954,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
for (size_t k=0; k<cInfo.size(); k++)
par.selection.insert(cInfo[k].classId);
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.refresh();
}
@ -1013,8 +1013,10 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.fillRight();
gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, L"Första (ordinarie) start:");
gdi.addInput("MinInterval", L"2:00", 10, 0, L"Minsta startintervall:");
gdi.fillDown();
gdi.addInput("Vacances", getDefaultVacant(), 10, 0, L"Andel vakanser:");
gdi.fillDown();
addVacantPosition(gdi);
gdi.popX();
createDrawMethod(gdi);
@ -1134,7 +1136,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
oListInfo info;
par.listCode = EStdStartList;
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.dropLine();
gdi.addButton("Cancel", "Återgå", ClassesCB);
@ -1151,6 +1153,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
return 0;
wstring minInterval = gdi.getText("MinInterval");
wstring vacances = gdi.getText("Vacances");
auto vp = readVacantPosition(gdi);
setDefaultVacant(vacances);
bool lateBefore = gdi.isChecked("LateBefore");
bool allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
@ -1160,7 +1163,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (gdi.hasWidget("PairSize")) {
pairSize = gdi.getSelectedItem("PairSize").first;
}
oEvent::DrawMethod method = (oEvent::DrawMethod)gdi.getSelectedItem("Method").first;
int baseInterval = convertAbsoluteTimeMS(minInterval) / 2;
@ -1174,7 +1176,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
throw meosException("Ogiltig första starttid. Måste vara efter nolltid.");
clearPage(gdi, true);
oe->automaticDrawAll(gdi, firstStart, minInterval, vacances,
oe->automaticDrawAll(gdi, firstStart, minInterval, vacances, vp,
lateBefore, allowNeighbourSameCourse, method, pairSize);
oe->addAutoBib();
gdi.scrollToBottom();
@ -1203,13 +1205,16 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
showClassSelection(gdi, bx, by, 0);
gdi.pushX();
gdi.fillRight();
gdi.addInput("FirstStart", firstStart, 10, 0, L"Starttid:");
gdi.addInput("Vacanses", lastNumVac, 10, 0, L"Antal vakanser:").setSynchData(&lastNumVac);
gdi.dropLine(4);
gdi.popX();
gdi.fillRight();
gdi.addButton("AssignStart", "Tilldela", ClassesCB).isEdit(true);
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
gdi.addButton("Cancel", "Återgå", ClassesCB).setCancel();
gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(1);
gdi.refresh();
@ -1226,8 +1231,10 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (warnDrawStartTime(gdi, time))
return 0;
int nVacant = gdi.getTextNo("Vacanses");
for (set<int>::iterator it = classes.begin(); it!=classes.end();++it) {
simultaneous(*it, time);
simultaneous(*it, time, nVacant);
}
bi.id = "Simultaneous";
@ -1412,7 +1419,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
for (set<int>::const_iterator it = classes.begin(); it != classes.end(); ++it) {
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(*it, 0, 0, 0, 0));
spec.emplace_back(ClassDrawSpecification(*it, 0, 0, 0, 0, oEvent::VacantPosition::Mixed));
oe->drawList(spec, oEvent::DrawMethod::Random, 1, oEvent::DrawType::DrawAll);
}
@ -1487,15 +1494,14 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (warnDrawStartTime(gdi, t, false))
return 0;
}
//bool pairwise = false;
// if (gdi.hasWidget("Pairwise"))
// pairwise = gdi.isChecked("Pairwise");
int pairSize = 1;
if (gdi.hasWidget("PairSize")) {
pairSize = gdi.getSelectedItem("PairSize").first;
}
auto vp = readVacantPosition(gdi);
int maxTime = 0, restartTime = 0;
double scaleFactor = 1.0;
@ -1510,7 +1516,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (method == oEvent::DrawMethod::Random || method == oEvent::DrawMethod::SOFT || method == oEvent::DrawMethod::MeOS) {
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(cid, leg, t, interval, vacanses));
spec.emplace_back(cid, leg, t, interval, vacanses, vp);
oe->drawList(spec, method, pairSize, dtype);
}
@ -1523,7 +1529,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
scaleFactor);
}
else if (method == oEvent::DrawMethod::Simultaneous) {
simultaneous(cid, time);
simultaneous(cid, time, vacanses);
}
else if (method == oEvent::DrawMethod::Seeded) {
ListBoxInfo seedMethod;
@ -1572,7 +1578,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
oListInfo info;
par.listCode = EStdStartList;
par.setLegNumberCoded(leg);
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.refresh();
@ -1596,7 +1602,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
leg = gdi.getSelectedItem("Leg").first;
}
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(ClassId, leg, 0, 0, 0));
spec.emplace_back(ClassId, leg, 0, 0, 0, oEvent::VacantPosition::Mixed);
oe->drawList(spec, oEvent::DrawMethod::Random, 1, oEvent::DrawType::DrawAll);
loadPage(gdi);
@ -1822,7 +1828,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
par.listCode = EStdStartList;
}
}
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.refresh();
@ -1953,7 +1959,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
par.selection.insert(outClass.begin(), outClass.end());
oListInfo info;
par.listCode = EStdStartList;
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
}
else if (bi.id == "LockAllForks" || bi.id == "UnLockAllForks") {
@ -2069,7 +2075,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
par.selection.insert(ClassId);
oListInfo info;
par.listCode = EStdStartList;
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.refresh();
}
@ -2452,6 +2458,8 @@ void TabClass::showClassSettings(gdioutput &gdi)
createDrawMethod(gdi);
addVacantPosition(gdi);
gdi.addSelection("PairSize", 150, 200, 0, L"Tillämpa parstart:");
gdi.addItem("PairSize", getPairOptions());
gdi.selectItemByData("PairSize", 1);
@ -3634,9 +3642,18 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
if (method != oEvent::DrawMethod::Simultaneous)
gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
if ((method == oEvent::DrawMethod::Random || method == oEvent::DrawMethod::SOFT || method == oEvent::DrawMethod::Clumped || method == oEvent::DrawMethod::MeOS) && pc.getParentClass() == 0)
if ((method == oEvent::DrawMethod::Random ||
method == oEvent::DrawMethod::SOFT ||
method == oEvent::DrawMethod::Clumped ||
method == oEvent::DrawMethod::MeOS ||
method == oEvent::DrawMethod::Simultaneous) && pc.getParentClass() == 0) {
gdi.addInput("Vacanses", itow(vac), 10, 0, L"Antal vakanser:").setSynchData(&lastNumVac);
if (method == oEvent::DrawMethod::SOFT ||
method == oEvent::DrawMethod::Random ||
method == oEvent::DrawMethod::MeOS)
addVacantPosition(gdi);
}
if ((method == oEvent::DrawMethod::Random || method == oEvent::DrawMethod::SOFT || method == oEvent::DrawMethod::Seeded || method == oEvent::DrawMethod::MeOS) && pc.getNumStages() > 1 && pc.getClassType() != oClassPatrol) {
gdi.addSelection("Leg", 90, 100, 0, L"Sträcka:", L"Sträcka att lotta");
for (unsigned k = 0; k < pc.getNumStages(); k++)
@ -3691,6 +3708,26 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
lastDrawMethod = method;
}
void TabClass::addVacantPosition(gdioutput &gdi) {
gdi.addSelection("VacantPosition", 120, 80, nullptr, L"Vakansplacering:");
vector<pair<wstring, size_t>> vp;
vp.emplace_back(lang.tl("Lottat"), size_t(oEvent::VacantPosition::Mixed));
vp.emplace_back(lang.tl("Först"), size_t(oEvent::VacantPosition::First));
vp.emplace_back(lang.tl("Sist"), size_t(oEvent::VacantPosition::Last));
gdi.addItem("VacantPosition", vp);
int def = oe->getPropertyInt("VacantPosition", size_t(oEvent::VacantPosition::Mixed));
gdi.selectItemByData("VacantPosition", def);
}
oEvent::VacantPosition TabClass::readVacantPosition(gdioutput &gdi) const {
if (gdi.hasWidget("VacantPosition")) {
int val = gdi.getSelectedItem("VacantPosition").first;
oe->setProperty("VacantPosition", val);
return oEvent::VacantPosition(val);
}
return oEvent::VacantPosition::Mixed;
}
set<oEvent::DrawMethod> TabClass::getSupportedDrawMethods(bool hasMulti) const {
set<oEvent::DrawMethod> base = { oEvent::DrawMethod::Random, oEvent::DrawMethod::SOFT, oEvent::DrawMethod::Clumped,
oEvent::DrawMethod::MeOS, oEvent::DrawMethod::Simultaneous, oEvent::DrawMethod::Seeded };
@ -3916,13 +3953,34 @@ void TabClass::enableLoadSettings(gdioutput &gdi) {
}
void TabClass::simultaneous(int classId, const wstring &time) {
void TabClass::simultaneous(int classId, const wstring &time, int nVacant) {
pClass pc = oe->getClass(classId);
if (!pc)
throw exception();
pc->getNumStages();
if (nVacant >= 0 && pc->getNumStages() <= 1) {
vector<int> toRemove;
vector<pRunner> runners;
oe->getRunners(classId, 0, runners, true);
//Remove old vacances
for (pRunner r : runners) {
if (r->getTeam())
continue; // Cannot remove team runners
if (r->isVacant()) {
if (--nVacant < 0)
toRemove.push_back(r->getId());
}
}
oe->removeRunner(toRemove);
toRemove.clear();
for (int i = 0; i < nVacant; i++) {
oe->addRunnerVacant(classId);
}
}
if (pc->getNumStages() == 0) {
pCourse crs = pc->getCourse();
pc->setNumStages(1);

View File

@ -79,8 +79,9 @@ class TabClass :
set<oEvent::DrawMethod> getSupportedDrawMethods(bool multiDay) const;
void drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClass &cls);
void pursuitDialog(gdioutput &gdi);
void addVacantPosition(gdioutput &gdi);
oEvent::VacantPosition TabClass::readVacantPosition(gdioutput &gdi) const;
bool warnDrawStartTime(gdioutput &gdi, int time, bool absTime);
bool warnDrawStartTime(gdioutput &gdi, const wstring &firstStart);
@ -117,7 +118,7 @@ class TabClass :
void showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK classesCB) const;
// Set simultaneous start in a class
void simultaneous(int classId, const wstring &time);
void simultaneous(int classId, const wstring &time, int nVacant);
void updateFairForking(gdioutput &gdi, pClass pc) const;
void selectCourses(gdioutput &gdi, int legNo);

View File

@ -144,12 +144,12 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
oClub::definedPayModes(*oe, dpm);
pc->generateInvoice(gdi, pay, paid, dpm, ppm);
}
gdi.addButton(gdi.getWidth()+20, 15, gdi.scaleLength(120),
gdi.addButton(gdi.getWidth()+20, gdi.scaleLength(15), gdi.scaleLength(120),
"Cancel", "Återgå", ClubsCB, "", true, false);
gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(120),
gdi.addButton(gdi.getWidth()+20, gdi.scaleLength(45), gdi.scaleLength(120),
"Print", "Skriv ut...", ClubsCB,
"Skriv ut fakturan", true, false);
gdi.addButton(gdi.getWidth()+20, 75, gdi.scaleLength(120),
gdi.addButton(gdi.getWidth()+20, gdi.scaleLength(75), gdi.scaleLength(120),
"PDF", "PDF...", ClubsCB,
"Spara som PDF.", true, false);
gdi.refresh();
@ -299,16 +299,20 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "InvoiceSettings") {
gdi.clearPage(true);
gdi.pushX();
gdi.addString("", boldLarge, "Fakturainställningar");
gdi.dropLine();
firstInvoice = oClub::getFirstInvoiceNumber(*oe);
if (firstInvoice == 0)
firstInvoice = oe->getPropertyInt("FirstInvoice", 1000);
gdi.addInput("FirstInvoice", itow(firstInvoice), 5, 0, L"Första fakturanummer:");
gdi.dropLine();
gdi.addString("", boldText, "Organisatör");
gdi.fillRight();
gdi.addInput("InvoiceDate", oClub::getInvoiceDate(*oe), 16, nullptr, L"Fakturadatum:");
gdi.addInput("FirstInvoice", itow(firstInvoice), 16, 0, L"Första fakturanummer:");
gdi.fillDown();
gdi.popX();
gdi.dropLine(4);
gdi.addString("", fontMediumPlus, "Organisatör");
vector<string> fields;
gdi.pushY();
@ -320,7 +324,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine();
gdi.addString("", boldText, "Betalningsinformation");
gdi.addString("", fontMediumPlus, "Betalningsinformation");
fields.clear();
fields.push_back("Account");
fields.push_back("PaymentDue");
@ -334,7 +338,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(2);
gdi.popX();
gdi.addString("", boldText, "Formatering");
gdi.addString("", fontMediumPlus, "Formatering");
gdi.fillRight();
gdi.addString("", 0, "Koordinater (mm) för adressfält:");
@ -353,12 +357,11 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(1);
gdi.fillRight();
gdi.addButton("SaveSettings", "Spara", ClubsCB);
gdi.addButton("Cancel", "Avbryt", ClubsCB);
gdi.addButton("SaveSettings", "Spara", ClubsCB).setDefault();
gdi.addButton("Cancel", "Avbryt", ClubsCB).setCancel();
gdi.dropLine(2);
gdi.setOnClearCb(ClubsCB);
oe->getDI().fillDataFields(gdi);
}
else if (bi.id == "SaveSettings") {
oe->getDI().saveDataFields(gdi);
@ -376,6 +379,13 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
else
oe->setProperty("FirstInvoice", fn);
if (gdi.getText("InvoiceDate").empty()) {
gdi.setText("InvoiceDate", oClub::getInvoiceDate(*oe));
dynamic_cast<InputInfo &>(gdi.getBaseInfo("InvoiceDate")).setBgColor(colorLightRed);
return 0;
}
oClub::setInvoiceDate(*oe, gdi.getText("InvoiceDate"));
int xc = gdi.getTextNo("XC");
int yc = gdi.getTextNo("YC");

View File

@ -621,7 +621,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id=="Browse") {
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(lang.tl(L"Databaskälla"), L"*.xml;*.csv"));
ext.push_back(make_pair(L"Databaskälla", L"*.xml;*.csv"));
wstring f = gdi.browseForOpen(ext, L"xml");
string id;
@ -1545,7 +1545,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
switch (startType) {
case SMCommon:
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0", L"0", false, false, oEvent::DrawMethod::Random, 1);
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0",
L"0", oEvent::VacantPosition::Mixed,
false, false, oEvent::DrawMethod::Random, 1);
drawn = true;
break;
@ -1570,7 +1572,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
}
if (!skip)
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00", L"2", true, false, oEvent::DrawMethod::MeOS, 1);
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00",
L"2", oEvent::VacantPosition::Mixed,
true, false, oEvent::DrawMethod::MeOS, 1);
drawn = true;
break;
}
@ -1766,7 +1770,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
par.setLegNumberCoded(-1);
oListInfo li;
par.selection = allTransfer;
oe->generateListInfo(par, gdi.getLineHeight(), li);
oe->generateListInfo(par, li);
gdioutput tGdi("temp", gdi.getScale());
oe->generateList(tGdi, true, li, false);
HTMLWriter::writeTableHTML(tGdi, save, oe->getName(), 0, 1.0);
@ -1851,7 +1855,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
par.showSplitTimes = true;
par.setLegNumberCoded(-1);
oListInfo li;
oe->generateListInfo(par, gdi.getLineHeight(), li);
oe->generateListInfo(par, li);
gdioutput tGdi("temp", gdi.getScale());
oe->generateList(tGdi, true, li, false);
HTMLWriter::writeTableHTML(tGdi, save, oe->getName(), 0, 1.0);
@ -3459,7 +3463,7 @@ void TabCompetition::entryForm(gdioutput &gdi, bool isGuide) {
gdi.dropLine(3);
}
TabCompetition::FlowOperation TabCompetition::saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide) {
FlowOperation TabCompetition::saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide) {
wstring filename[5];
filename[0] = gdi.getText("FileNameCmp");
filename[1] = gdi.getText("FileNameCls");
@ -3574,8 +3578,14 @@ int stageInfoCB(gdioutput *gdi, int type, void *data)
}
void mainMessageLoop(HACCEL hAccelTable, DWORD time);
FlowOperation importFilterGUI(oEvent *oe,
gdioutput & gdi,
const set<int>& stages,
const vector<string> &idProviders,
set<int> & filter,
string &preferredIdProvider);
TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
const wstring & fname,
set<int>& filter,
string &preferredIdProvider) {
@ -3591,6 +3601,16 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
reader.getIdTypes(idProviders);
}
}
return importFilterGUI(oe, gdi, scanFilter, idProviders, filter, preferredIdProvider);
}
FlowOperation importFilterGUI(oEvent *oe,
gdioutput & gdi,
const set<int>& stages,
const vector<string> &idProviders,
set<int> & filter,
string &preferredIdProvider) {
auto &scanFilter = stages;
bool stageFilter = scanFilter.size() > 1;
bool idtype = idProviders.size() > 1;
@ -3631,7 +3651,7 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.fillRight();
gdi.addSelection("IdType", 150, 200, stageInfoCB, L"Välj vilken typ du vill importera:");
int i = 0;
for (string &sn : idProviders) {
for (const string &sn : idProviders) {
gdi.addItem("IdType", gdi.widen(sn), i++);
}
}

View File

@ -22,7 +22,7 @@
************************************************************************/
#include "tabbase.h"
#include "gdiconstants.h"
#include "oFreeImport.h"
class PrefsEditor;
@ -31,12 +31,6 @@ class ImportFormats;
class TabCompetition :
public TabBase
{
enum FlowOperation {
FlowContinue,
FlowCancel,
FlowAborted
};
wstring eventorBase;
wstring iofExportVersion;
void textSizeControl(gdioutput &gdi) const;

View File

@ -510,7 +510,7 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
if (!gdi.ask(L"warning:drawresult"))
return 0;
}
courseDrawClasses.push_back(ClassDrawSpecification(cls[k]->getId(), 0, -1, -1, 0));
courseDrawClasses.emplace_back(cls[k]->getId(), 0, -1, -1, 0, oEvent::VacantPosition::Mixed);
if (!clsNames.empty())
clsNames += L", ";
clsNames += cls[k]->getName();
@ -586,7 +586,7 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
for (size_t k=0; k<courseDrawClasses.size(); k++)
par.selection.insert(courseDrawClasses[k].classID);
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
gdi.refresh();
}

View File

@ -449,7 +449,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
if (gdi.getSelectedItem("SavedInstance", lbi)) {
oListParam &par = oe->getListContainer().getParam(lbi.data);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.getParam().sourceParam = lbi.data;
generateList(gdi);
}
@ -646,7 +646,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
lastSplitState = par.showSplitTimes;
lastLargeSize = par.useLargeSize;
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
@ -676,7 +676,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
cnf.getIndividual(par.selection, false);
readSettings(gdi, par, true);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -692,7 +692,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
par.showSplitTimes = true;
par.setLegNumberCoded(-1);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -704,7 +704,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
getStartIndividual(par, cnf);
readSettings(gdi, par, false);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -715,7 +715,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
getStartClub(par);
readSettings(gdi, par, false);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -730,7 +730,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
readSettings(gdi, par, false);
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -762,7 +762,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
getStartTeam(par, cnf);
readSettings(gdi, par, false);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -778,7 +778,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getRaceNStart(race, par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -794,7 +794,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getLegNStart(race, par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -806,7 +806,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
oe->getClassConfigurationInfo(cnf);
getResultTeam(par, cnf);
readSettings(gdi, par, true);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -818,7 +818,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getRaceNRes(0, par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -833,7 +833,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getRaceNRes(race, par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -848,7 +848,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
cnf.getLegNRes(race, par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -861,7 +861,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
getResultRogaining(par, cnf);
readSettings(gdi, par, true);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -891,7 +891,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
cnf.getIndividual(par.back().selection, true);
}
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -902,7 +902,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
par.listCode = EStdRentedCard;
par.showHeader = gdi.isChecked("ShowHeader");
par.setLegNumberCoded(-1);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -914,7 +914,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
par.listCode = EIndPriceList;
par.showHeader = gdi.isChecked("ShowHeader");
par.filterMaxPer = gdi.getSelectedItem("ClassLimit").first;
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
generateList(gdi);
gdi.refresh();
}
@ -984,7 +984,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
cnf.getPatrol(par.selection);
}
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -999,7 +999,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
ClassConfigInfo cnf;
oe->getClassConfigurationInfo(cnf);
par.selection = set<int>(cnf.knockout.begin(), cnf.knockout.end());
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -1019,7 +1019,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else
par.selection = set<int>(cnf.lapcountsingle.begin(), cnf.lapcountsingle.end());
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -1043,7 +1043,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
if (oListInfo::addTeams(type))
cnf.getTeamClass(par.selection);
oe->generateListInfo(par, gdi.getLineHeight(), currentList);
oe->generateListInfo(par, currentList);
currentList.setCallback(openRunnerTeamCB);
generateList(gdi);
gdi.refresh();
@ -1965,6 +1965,7 @@ void TabList::htmlSettings(gdioutput &gdi, string targetTag) {
html2IdToInfo[id] = t.desc;
}
gdi.addSelection("Format", 200, 100, 0, L"Format:").setHandler(&htmlClass);
gdi.autoGrow("Format");
if (!htmlTemplateTag2Id.count(tmpSettingsParam.htmlTypeTag))
tmpSettingsParam.htmlTypeTag = "free";

View File

@ -1944,7 +1944,7 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
par.selection.insert(classId);
oListInfo info;
par.listCode = EStdStartList;
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true);
}
}

View File

@ -944,6 +944,11 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
di.setString("Phone", gdi.getText("Phone"));
if (gdi.isChecked("NoTiming"))
r->setStatus(RunnerStatus::StatusNoTiming, true, oBase::ChangeType::Update, false);
else if (r->getStatus() == RunnerStatus::StatusNoTiming)
r->setStatus(RunnerStatus::StatusUnknown, true, oBase::ChangeType::Update, false);
r->setFlag(oRunner::FlagTransferSpecified, gdi.hasWidget("AllStages"));
r->setFlag(oRunner::FlagTransferNew, gdi.isChecked("AllStages"));
@ -2938,6 +2943,8 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
gdi.setCX(gdi.getCX()+gdi.scaleLength(20));
gdi.addCheckbox("RentCard", "Hyrbricka", SportIdentCB, storedInfo.rentState);
gdi.addCheckbox("NoTiming", "Utan tidtagning", nullptr, false);
if (oe->hasNextStage())
gdi.addCheckbox("AllStages", "Anmäl till efterföljande etapper", SportIdentCB, storedInfo.allStages);
@ -2955,9 +2962,10 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r) {
if (gdi.hasWidget("Fee"))
gdi.setText("Fee", oe->formatCurrency(dci.getInt("Fee")));
gdi.setText("StartTime", r->getStartTimeS());
gdi.setText("Phone", dci.getString("Phone"));
gdi.setText("Bib", r->getBib());
gdi.check("NoTiming", r->hasFlag(oAbstractRunner::TransferFlags::FlagNoTiming));
gdi.check("RentCard", dci.getInt("CardFee") != 0);
if (gdi.hasWidget("Paid"))
gdi.check("Paid", dci.getInt("Paid")>0);

View File

@ -1215,8 +1215,9 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
int numberPos = xp;
xp += gdi.scaleLength(25);
int dx[6] = {0, 184, 220, 290, 316, 364};
for (int i = 0; i<6; i++)
dx[i] = gdi.scaleLength(dx[i]);
dx[1] = gdi.getInputDimension(18).first + gdi.scaleLength(4);
for (int i = 2; i<6; i++)
dx[i] = dx[1] + gdi.scaleLength(dx[i]-188);
gdi.addString("", yp, xp + dx[0], 0, "Namn:");
gdi.addString("", yp, xp + dx[2], 0, "Bricka:");
@ -1224,38 +1225,36 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
gdi.addString("", yp, xp + dx[5], 0, "Status:");
gdi.dropLine(0.5);
for (unsigned i=0;i<pc->getNumStages();i++) {
yp = gdi.getCY();
for (unsigned i = 0; i < pc->getNumStages(); i++) {
yp = gdi.getCY() - gdi.scaleLength(3);
sprintf_s(bf, "R%d", i);
gdi.pushX();
bool hasSI = false;
gdi.addStringUT(yp, numberPos, 0, pc->getLegNumber(i) + L".");
if (pc->getLegRunner(i)==i) {
if (pc->getLegRunner(i) == i) {
gdi.addInput(xp + dx[0], yp, bf, L"", 18, TeamCB);//Name
gdi.addButton(xp + dx[1], yp-2, gdi.scaleLength(28), "DR" + itos(i), "<>", TeamCB, "Knyt löpare till sträckan.", false, false); // Change
gdi.addButton(xp + dx[1], yp - 2, gdi.scaleLength(28), "DR" + itos(i), "<>", TeamCB, "Knyt löpare till sträckan.", false, false); // Change
sprintf_s(bf_si, "SI%d", i);
hasSI = true;
gdi.addInput(xp + dx[2], yp, bf_si, L"", 5, TeamCB).setExtra(i); //Si
gdi.addCheckbox(xp + dx[3], yp + gdi.scaleLength(10), "RENT"+itos(i), "", 0, false); //Rentcard
gdi.addCheckbox(xp + dx[3], yp + gdi.scaleLength(10), "RENT" + itos(i), "", 0, false); //Rentcard
}
else {
//gdi.addInput(bf, "", 24);
gdi.addInput(xp + dx[0], yp, bf, L"", 18, 0);//Name
gdi.disableInput(bf);
}
gdi.addButton(xp + dx[4], yp-2, gdi.scaleLength(38), "MR" + itos(i), "...", TeamCB, "Redigera deltagaren.", false, false); // Change
gdi.addButton(xp + dx[4], yp - 2, gdi.scaleLength(38), "MR" + itos(i), "...", TeamCB, "Redigera deltagaren.", false, false); // Change
gdi.addString(("STATUS"+itos(i)).c_str(), yp+gdi.scaleLength(5), xp + dx[5], 0, "#MMMMMMMMMMMMMMMM");
gdi.setText("STATUS"+itos(i), L"", false);
gdi.addString(("STATUS" + itos(i)).c_str(), yp + gdi.scaleLength(5), xp + dx[5], 0, "#MMMMMMMMMMMMMMMM");
gdi.setText("STATUS" + itos(i), L"", false);
gdi.dropLine(0.5);
gdi.popX();
if (t) {
pRunner r=t->getRunner(i);
pRunner r = t->getRunner(i);
if (r) {
gdi.setText(bf, r->getNameRaw())->setExtra(r->getId());
@ -1265,7 +1264,7 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
warnDuplicateCard(gdi, bf_si, cno, r);
gdi.check("RENT" + itos(i), r->getDCI().getInt("CardFee") != 0);
}
string sid = "STATUS"+itos(i);
string sid = "STATUS" + itos(i);
if (r->statusOK(true)) {
TextInfo * ti = (TextInfo *)gdi.setText(sid, L"OK, " + r->getRunningTimeS(true), false);
if (ti)

View File

@ -2045,7 +2045,7 @@ void Table::importClipboard(gdioutput &gdi)
tw = max(tw, table[k].size());
if (tw > columns.size())
throw std::exception("Antalet columner i urklippet är större än antalet kolumner i tabellen.");
throw meosException("Antalet kolumner i urklippet är större än antalet kolumner i tabellen.");
if (upperRow == -1) {
if (!gdi.ask(L"Vill du klistra in X nya rader i tabellen?#"+itow(table.size())))
@ -2059,10 +2059,10 @@ void Table::importClipboard(gdioutput &gdi)
getRowRange(row1, row2);
if ( (row1 + table.size()) > sortIndex.size() )
throw std::exception("Antalet rader i urklipp får inte plats i selektionen.");
throw meosException("Antalet rader i urklipp får inte plats i selektionen.");
if ( (col1 + tw) > columns.size() )
throw std::exception("Antalet kolumner i urklipp får inte plats i selektionen.");
throw meosException("Antalet kolumner i urklipp får inte plats i selektionen.");
bool wrongSize = false;

View File

@ -2410,3 +2410,70 @@ help:custom_text_lines = Du kan indsætte egne data ved at skrive [Symbol Name].
htmlhelp = HTML kan eksporteres som en struktureret tabel eller som et frit formateret dokument (mere i stil med MeOS lister). Du kan også bruge eksporter skabeloner med egen formatering: kolonner, JavaScript base page flips, automatisk rulning, o.s.v. Det er muligt at tilføje egne skabeloner ved at tilføje '.template' filer i MeOS mappen. Hvis du bruger skabeloner er der et antal parametre der skal angives, se nedenfor. Den præcise fortolkning af parametrene afhænger af skabelonen.\n\nHvis du vælger <Store Settings> bliver listen og dens opsætning gemt permanent i løbet. Du kan så tilgå listen ved at bruge MeOS som Web server (Tjenesten 'Information Server') eller ved at eksportere listen ved jævne mellemrum.
info:pageswithcolumns = Vis listen en side af gangen med det angivne antal kolonner. Genindlæs listen automatisk efter hvert gennemløb.
Övrigt = Øvrigt
Age (on last day of current year) = Alder ved årets udgang
Age above or equal implies senior/pensioner = Aldersgrænse for seniorer
Age below or equal implies youth = Aldersgrænse for ungdom
Anmälningsdatum = Tilmeldingsdato
ClassAvailableMaps = Tilgængelige kort for klasse
ClassNumEntries = Antal tilmeldte i klassen
ClassTotalMaps = Antal kort total
EFilterWrongFee = Forkert gebyr
Flera lopp i valfri ordning = Flere løb i vilkårlig rækkefølge
Flytta ner = Flyt ned
Flytta upp = Flyt op
Från första = Fra første
Förväntad = Forventet
Heat = Heat
Inkludera bana = Inkluder bane
Kartor = Kort
Klassen är full = Klassen er fuld
Knockout sammanställning = Knock-out opsummering
Kunde inte ladda upp löpardatabasen (X) = Kunne ikke overføre løberdatabase (X)
Kunde inte öppna databasen (X) = Kunne ikke åbne database (X)
Kvalschema = Kvalifikationsskema
Lagändringblankett = Holdændringsskema
Lås funktion = Lås funktion
Lås upp = Lås op
Låst gaffling = Låst gaffling
Mappa rootadressen (http:///localhost:port/) till funktion = Map root addresse (http:///localhost:port/) til funktion
Målstämpling tillåts inte (X) = Målstempling ikke tilladt (X)
Plac. E[stageno] = Plac. E
Poäng E[stageno] = Point E
Poängreduktion = Reduktion
Radio = Radio
Radio tillåts inte (X) = Radioposter ikke tilladt (X)
Referens = Reference
Registrera hyrbrickor = Registrer lejebrikker
Result module = Resultat modul
Rogaining points before automatic reduction = Rogaining point før automatisk reduktion
Runner check time = Løbers check tid
Runner/team earlier stage places = Deltagere/hold: placering på tidligere etapper
Runner/team earlier stage points = Deltagere/hold: point på tidligere etapper
Runner/team earlier stage running times = Deltagere/hold: tid på tidligere etapper
Runner/team earlier stage statuses = Deltagere/hold: status for tidligere etapper
RunnerExpectedFee = Forventet deltagerafgift
Senast sedd: X vid Y = Sidst set: X ved Y
Startstämpling tillåts inte (X) = Startstempling ikke tilladt (X)
Status E[stageno] = Status E
Status code for cancelled entry = Statuskode for afbud
Status code for no timing = Statuskode for uden tidsstempling
Status code for running out-of-competition = Statuskode for udenfor konkurrance (OOC)
Stigning = Stigning
There is no result module with X as identifier = Der er intet resultatmodul med identifikator X
Tid E[stageno] = Tid E
Till sista = Til sidste
Tillåt = Tillad
Unexpected Fee = Uventet tilmeldingsgebyr
Utom tävlan = Udenfor konkurrance OOC
Vill du sätta hyrbricka på befintliga löpare med dessa brickor? = Vil du tildele lejebrikker til eksisterende løbere med disse brikker?
Vill du ta bort brickan från hyrbrickslistan? = Vil du fjerne brikken fra listen af lejebrikker?
Vill du tömma listan med hyrbrickor? = Vil du slette listen med lejebrikker?
X anmälda = X tilmeldte
ask:usecourseinclass = Banen bruges ikke af andre deltagere i klassen.\n\nV il du alligevel bruge den?
help:registerhiredcards = Forregistrer Si-brikker som lejebrikker så de automatisk får status lejebrik når de tildeles.
info:advanceinfo = Det var ikke muligt at starte tjesten for forhåndsinformation om resultat. Resultatet vil komme med nogle skunders forsinkelse. Dette kan forventes hvis der kører flere udgaver at MeOS på maskinen samtidigt.
prefsLastExportTarget = Seneste mål for eksport
prefsServiceRootMap = Standardfunktion for webserverens root
prefsshowheader = Vis overskrifter på siderne
warn:printmodeonly = Bemærk: Du laver kun en udskrift af Si-brikkens indhold. Hvis du vil gemme resultatet skal du bruge funktionen aflæs/radiotider.
Åldersfiltrering = Aldersfiltrering

View File

@ -2426,7 +2426,7 @@ prefsServiceRootMap = Standard function for web server root
prefsshowheader = Show page headers
help:registerhiredcards = Preregister punching cards as rental cards to get automatic hired card status when the card is assigned.
Lagändringblankett = Team Change Form
Mappa rootadresssen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function
Mappa rootadressen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function
ClassAvailableMaps = Available maps for class
ClassTotalMaps = Total number of maps for class
Kunde inte öppna databasen (X) = Could not connect to database (X)
@ -2474,4 +2474,22 @@ Status code for cancelled entry = Status code for cancelled entry
Age (on last day of current year) = Age (on last day of current year)
Age above or equal implies senior/pensioner = Age above or equal implies senior/pensioner
Age below or equal implies youth = Age below or equal implies youth
Status code for not no timing = Status code for not no timing
Det finns multiplia Id-nummer för personer = There are multiple ID:s for persons
Välj vilken typ du vill importera = Select type of ID to import
Status code for no timing = Status code for no timing
prefsVacantPercent = Percent vacant default
ClassNumEntries = Number of entries
Före X = Before X
Efter X = After X
Slå ihop X = Merge with X
Slå ihop med = Merge with
Mellan X och Y = Between X and Y
Ett okänt fel inträffade = An unknown error occurred
Antalet kolumner i urklippet är större än antalet kolumner i tabellen = The number of columns in the clipboard is greater than the number of columns in the table
Antalet kolumner i urklipp får inte plats i selektionen = The number of columns in the clipboard does not fit the selection
prefsVacantPosition = Placement of vacancies
Vakansplacering = Vacancy placement
Först = First
Lottat = Drawn
Sist = Last
Fakturadatum = Fakturadatum

View File

@ -2429,7 +2429,61 @@ prefsServiceRootMap = Fonctions standard pour la source du serveur Web
prefsshowheader = Afficher les titres
help:registerhiredcards = Pré-inscrivez des puces comme puces louées pour assigner automatiquement le statut et le tarif correspondant quand cette puce est assignée.
Lagändringblankett = Modifications d'équipes
Mappa rootadresssen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function ($2428)
Mappa rootadressen (http:///localhost:port/) till funktion = Map root address (http:///localhost:port/) to function ($2428)
ClassAvailableMaps = Cartes disponibles pour la catégorie
ClassTotalMaps = Nombre total de cartes pour la catégorie
Export split times = Exporter les temps intermédiaires
Age (on last day of current year) = Age (au dernier jour de l'année en cours)
Age above or equal implies senior/pensioner = Limite d'âge haute des jeunes (défini dans Compétition/Configuration de la competition)
Age below or equal implies youth = Limite d'âge haute des jeunes (défini dans Compétition/Configuration de la competition)
ClassNumEntries = Nombres d'inscrits dans la catégorie
Endast tidtagning = chronométrage seul
Flera lopp i valfri ordning = Plusieurs circuits dans un ordre quelconque
Från första = Dép. au premier poste
Heat = Manche
Inkludera bana = Inclure le circuit
Kartor = Cartes
Knockout sammanställning = Résumé des éliminations
Kunde inte ladda upp löpardatabasen (X) = Impossible d'importer la base de données coureurs (X)
Kunde inte öppna databasen (X) = Impossible de se connecter à la base de données (X)
Kvalschema = Procédé de qualification
Lås funktion = Verr. fonction
Lås upp = Déverouiller
Låst gaffling = Variations verrouillées
Målstämpling tillåts inte (X) = Arrivée radio désactivée (x) [Finish punch disallowed]
Plac. E[stageno] = Place E
Poäng E[stageno] = Points E
Poängreduktion = Réduction
Radio = Radio
Radio tillåts inte (X) = Postes de contrôle radios désactivés (X) [Radio controls disallowed]
Referens = Référence
Result module = Module de résultats
Rogaining points before automatic reduction = Points du circuit avant réduction automatique
Runner check time = Heure de contrôle du coureur
Runner/team earlier stage places = Places du coureur/de l'équipe aux étapes précédentes
Runner/team earlier stage points = Points du coureur/de l'équipe aux étapes précédentes
Runner/team earlier stage running times = Temps du coureur/de l'équipe aux étapes précédentes
Runner/team earlier stage statuses = Statuts du coureur/de l'équipe aux étapes précédentes
Senast sedd: X vid Y = Dernières infos: à X au poste Y
Startstämpling tillåts inte (X) = Départ radio désactivé (X) [Start punch disallowed]
Status E[stageno] = Statut E
Status code for cancelled entry = Code de statut pour une inscription annulée
Status code for no timing = Code de statut pour une course non chronométrée
Status code for running out-of-competition = Code de statut pour non classé (NC)
Stigning = Dénivellé
Tid E[stageno] = Temps E
Till sista = Arr. au dernier poste
Tillåt = Autoriser
Utom tävlan = NC
X anmälda = X inscrits
ask:usecourseinclass = Le circuit n'est utilisé par aucun autre coureur dans cette catégorie\n\nVoulez-vous tout de même l'utiliser ?
warn:printmodeonly = Attention, notez bien que vous ne faites qu'imprimer les données de la puce sans l'enregistrer.\n\nPour l'intégrer à la course, utilisez la fonction Lecture des puces/Radios.
Åldersfiltrering = Filtrer par âge
There is no result module with X as identifier = Aucun module de résultat n'a X comme identifiant
prefsVacantPercent = Pourcentage de vacants
ClassNumEntries = Nombre d'inscrits dans la catégorie
Före X = Avant X
Efter X = Après X
Slå ihop X = Fusionner X
Slå ihop med = Fusionner avec
Ett okänt fel inträffade = Une erreur inconnue s'est produite

View File

@ -40,5 +40,14 @@ enum KeyCommandCode {
KC_AUTOCOMPLETE,
};
/** Enum used to stack GUI command control, "command line wizard" */
enum FlowOperation {
FlowContinue,
FlowCancel,
FlowAborted
};
const int GDI_BUTTON_SPACING = 8;
#endif

View File

@ -1358,6 +1358,15 @@ HFONT gdioutput::getGUIFont() const
return getCurrentFont().getGUIFont();
}
pair<int, int> gdioutput::getInputDimension(int length) const {
HDC hDC = GetDC(hWndTarget);
SelectObject(hDC, getGUIFont());
SIZE size;
GetTextExtentPoint32(hDC, L"M", 1, &size);
ReleaseDC(hWndTarget, hDC);
return make_pair(length*size.cx + scaleLength(8), size.cy + scaleLength(6));
}
InputInfo &gdioutput::addInput(int x, int y, const string &id, const wstring &text,
int length, GUICALLBACK cb,
const wstring &explanation, const wstring &help) {
@ -1367,30 +1376,25 @@ InputInfo &gdioutput::addInput(int x, int y, const string &id, const wstring &te
}
InputInfo ii;
SIZE size;
HDC hDC=GetDC(hWndTarget);
SelectObject(hDC, getGUIFont());
GetTextExtentPoint32(hDC, L"M", 1, &size);
ReleaseDC(hWndTarget, hDC);
auto dim = getInputDimension(length);
int ox=OffsetX;
int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(),
WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | ES_AUTOHSCROLL | WS_BORDER,
x-ox, y-oy, length*size.cx+scaleLength(8), size.cy+scaleLength(6),
x-ox, y-oy, dim.first, dim.second,
hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
updatePos(x, y, length*size.cx+scaleLength(12), size.cy+scaleLength(10));
int mrg = scaleLength(4);
updatePos(x, y, dim.first+mrg, dim.second+mrg);
SendMessage(ii.hWnd, WM_SETFONT,
(WPARAM) getGUIFont(), 0);
ii.xp=x;
ii.yp=y;
ii.width = length*size.cx+scaleLength(8);
ii.height = size.cy+scaleLength(6);
ii.width = dim.first;
ii.height = dim.second;
ii.text = text;
ii.original = text;
ii.focusText = text;

View File

@ -684,6 +684,9 @@ public:
bool isInputChanged(const string &exclude);
/** Get width of input widget with specified length (chars)*/
pair<int,int> getInputDimension(int length) const;
InputInfo &addInput(const string &id, const wstring &text = L"", int length=16, GUICALLBACK cb=0,
const wstring &Explanation = L"", const wstring &tooltip=L"");
InputInfo &addInput(int x, int y, const string &id, const wstring &text, int length,

View File

@ -1063,7 +1063,7 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
parser.declareSymbol("StatusDQ", "Status code for disqualification", false);
parser.declareSymbol("StatusOutOfCompetition", "Status code for running out-of-competition", false);
parser.declareSymbol("StatusNotCompetiting", "Status code for not competing", false);
parser.declareSymbol("StatusNoTiming", "Status code for not no timing", false);
parser.declareSymbol("StatusNoTiming", "Status code for no timing", false);
parser.declareSymbol("ShortestClassTime", "Shortest time in class", false);

View File

@ -1,28 +1,29 @@
<image source="/meos?image=meos"><br>
<h1>Documentation of MeOS REST API</h1>
<image source="/meos?image=meos">
<br>
<h1>Documentation of MeOS REST API</h1>
<h2>Competition</h2>
<b>Syntax:</b>
<h2>Competition</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=competition">/meos?get=competition</a></pre>
<b>Returns:</b>
<p>MOP Competition XML</p>
<b>Returns:</b>
<p>MOP Competition XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*competition date="2015-09-06" organizer="Orienteringsklubben Linn&eacute;" homepage="http://www.oklinne.nu">Stafett-DM, Uppland*/competition>
*/MOPComplete>
</pre>
<h2>Classes</h2>
<b>Syntax:</b>
<h2>Classes</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=class">/meos?get=class</a></pre>
<b>Returns:</b>
<p>MOP Classes XML</p>
<b>Returns:</b>
<p>MOP Classes XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*cls id="1" ord="10" radio="90,130;90,130;90,130">D21*/cls>
@ -30,20 +31,20 @@
*/MOPComplete>
</pre>
<b>Remarks:</b> The attribute <i>ord</i> should be used to sort classes. The attribute <i>radio</i>
lists the MeOS default radio control for each class and leg.
Each leg of the class is separated by ';' and each radio control within a leg with ','.
Note that you may query for results at any control; the listed
controls are only for convenience.
<b>Remarks:</b> The attribute <i>ord</i> should be used to sort classes. The attribute <i>radio</i>
lists the MeOS default radio control for each class and leg.
Each leg of the class is separated by ';' and each radio control within a leg with ','.
Note that you may query for results at any control; the listed
controls are only for convenience.
<h2>Controls</h2>
<b>Syntax:</b>
<h2>Controls</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=control">/meos?get=control</a></pre>
<b>Returns:</b>
<p>MOP Controls XML</p>
<b>Returns:</b>
<p>MOP Controls XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*control id="31">[31]*/control>
@ -52,54 +53,60 @@ controls are only for convenience.
*/MOPComplete>
</pre>
<h2>Competitors</h2>
<b>Syntax:</b>
<h2>Competitors</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=competitor">/meos?get=competitor</a></pre>
<pre>/meos?get=competitor#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul><li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li></ul>
<b>Arguments:</b>
<ul>
<li>
<i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li>
</ul>
<b>Returns:</b>
<p>MOP Competitors XML</p>
<b>Returns:</b>
<p>MOP Competitors XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*cmp id="3565">
*base org="570" cls="5" stat="1" st="360000" rt="20580">Elsa Winter*/base>
*cmp id="3565" card="101050">
*base org="570" cls="5" stat="1" st="360000" rt="20580" nat="NOR">Elsa Winter*/base>
*input it="20340" tstat="1"/>
*/cmp>
*cmp id="55851">
*base org="134" cls="7" stat="1" st="380710" rt="46910">Anna Spring*/base>
*base org="134" cls="7" stat="1" st="380710" rt="46910" nat="SWE">Anna Spring*/base>
*/cmp>
*/MOPComplete>
</pre>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown, 2 is no timing. Higher codes are used for disqualifications etc.</li>
<li><i>st</i> Start time. In 1/10 seconds after 00:00:00.</li>
<li><i>rt</i> Running time. In 1/10 seconds.</li>
<li><i>input/it</i> Input running time accumulated from earlier races. In 1/10 seconds.</li>
<li><i>input/st</i> Input status from earlier races.</li>
</ul>
</ul>
<h2>Teams</h2>
<b>Syntax:</b>
<h2>Teams</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=team">/meos?get=team</a></pre>
<pre>/meos?get=team#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul><li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li></ul>
<b>Arguments:</b>
<ul>
<li>
<i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.
</li>
</ul>
<b>Returns:</b>
<p>MOP Teams XML</p>
<b>Returns:</b>
<p>MOP Teams XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*tm id="2928771">
@ -113,25 +120,27 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete>
</pre>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li>
<li><i>st</i> Start time. In 1/10 seconds after 00:00:00.</li>
<li><i>rt</i> Running time (At finish, last leg). In 1/10 seconds.</li>
<li><i>r</i> List of runners in the team. A ';' is used to separate the legs, a ',' within a legs
<li>
<i>r</i> List of runners in the team. A ';' is used to separate the legs, a ',' within a legs
are used to list paralell runners. A '0' indicates a vacant leg, which may or may
not be valid for the team, depending on the rules.</li>
</ul>
not be valid for the team, depending on the rules.
</li>
</ul>
<h2>Organizations and Clubs</h2>
<b>Syntax:</b>
<h2>Organizations and Clubs</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=organization">/meos?get=organization</a></pre>
<b>Returns:</b>
<p>MOP Organization XML</p>
<b>Returns:</b>
<p>MOP Organization XML</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*org id="1012">BAOC*/org>
@ -141,8 +150,42 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete>
</pre>
<h2>Results</h2>
<b>Syntax:</b>
<h2>Recent Competition Changes</h2>
<b>Purpose:</b>
Keep a separate database with results synchronized with MeOS.
<br />
<b>Syntax:</b>
<pre><a href="/meos?difference=zero">/meos?difference=zero</a></pre>
<pre>/meos?difference=*nextdifference></pre>
<b>Returns:</b>
<p>
Complete or difference MOP of changes since last time API was called. Use litteral 'zero' to obtain
a new set of differences (the difference from zero).
The returned data includes an attribute <i>nextdifference</i> that you use as argument in
the nex call to difference, to get changes since this call.
</p>
<b>Example:</b>
<p>
Start by invoking /meos?difference=zero. The returned data will look like:
<pre>
*MOPComplete nextdifference="332617">
...
*/MOPComplete>
</pre>
Next time, you invoke /meos?difference=332617, which may return
<pre>
*MOPDiff nextdifference="324254">
...
*/MOPDiff>
</pre>
Next time you use difference=324254 and so on. Note that under some circumstances,
you may also get a complete event instead of a difference. See the general MOP documentation.
</p>
<h2>Results</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=result">/meos?get=result</a></pre>
<pre>/meos?get=result#class=*c1>,*c2>,...</pre>
<pre>/meos?get=result#to=*c1></pre>
@ -154,46 +197,59 @@ Please refer to the MOP documentation for a complete description of all attribut
<pre><a href="/meos?get=result&total=true">/meos?get=result#total=*true/false></a></pre>
<pre><a href="/meos?get=result&type=GlobalIndividual">/meos?get=result#type=*type></a></pre>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
<li><i>from</i> Returns the result measuring time from a specific control. If a specified class
<li>
<i>from</i> Returns the result measuring time from a specific control. If a specified class
does not visit the control, an empty result set is returned; no error is given.
The default is the start.</li>
<li><i>to</i> Returns the result at a specific control. If a specified class does not visit the control,
an empty result set is returned; no error is given. The default is the finish.</li>
The default is the start.
</li>
<li>
<i>to</i> Returns the result at a specific control. If a specified class does not visit the control,
an empty result set is returned; no error is given. The default is the finish.
</li>
<li><i>leg</i> In a team competition, returns result for a specified leg. If the leg is parallel,
<li>
<i>leg</i> In a team competition, returns result for a specified leg. If the leg is parallel,
the result is for the completed parallel leg. The leg number refer to the flat view in
MeOS class settings, i.e., for a setup "1, 2a, 2b, 2c, 3", correspons to flat leg numbers,
"1, 2, 3, 4, 5". The default is the last leg.</li>
<li><i>module</i> The result module tag to use for the result calculation.
The support of the leg and control options depends on result module. The default is no module.</li>
"1, 2, 3, 4, 5". The default is the last leg.
</li>
<li>
<i>module</i> The result module tag to use for the result calculation.
The support of the leg and control options depends on result module. The default is no module.
</li>
<li><i>argument</i> A numeric argument, defined and used by the result module.</li>
<li><i>limit</i> Limit the number of results per class. If there is a tie, the number of returned results
may be higher than the requested. The default is no limit.</li>
<li>
<i>limit</i> Limit the number of results per class. If there is a tie, the number of returned results
may be higher than the requested. The default is no limit.
</li>
<li><i>total</i> Set to <b>true</b> if you want to calculate total results, i.e., results including earliers stages.</li>
<li><i>type</i> Use one of <b>ClassIndividual</b> (default for individual classes), <b>CourseIndividual</b>, <b>GlobalIndividual</b>, or
<li>
<i>type</i> Use one of <b>ClassIndividual</b> (default for individual classes), <b>CourseIndividual</b>, <b>GlobalIndividual</b>, or
<b>LegIndividual</b> to calculate individual results. <b>CourseIndividual</b> calculates result
per course, ignoring class. <b>GlobalIndividual</b> calculates results without
considering classes, <b>LegIndividual</b> calculates results considering classes and legs.
Use one of <b>ClassTeam</b> (default for team classes) or <b>GlobalTeam</b> to calculate team
results. <b>GlobalTeam</b> calculates team results without considering classes.</li>
</ul>
results. <b>GlobalTeam</b> calculates team results without considering classes.
</li>
</ul>
<b>Returns:</b>
<p>MOP Individual or Team Result XML. The result list is sorted according to the result. Note than disqualified
<b>Returns:</b>
<p>
MOP Individual or Team Result XML. The result list is sorted according to the result. Note than disqualified
competitors are also included; for example a competitor with status *DNS> will be returned with this status for
all radio controls. You may want to filter out such entries, depending on your application.
</p>
</p>
<b>Examples:</b>
<b>Examples:</b>
<p>Individual results at the finish.</p>
<p>Individual results at the finish.</p>
<pre>
*MOPComplete>
*results location="Finish">
@ -215,7 +271,7 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete>
</pre>
<p>Team results, leg 2 at Radio 1, leg has three parallel runners.</p>
<p>Team results, leg 2 at Radio 1, leg has three parallel runners.</p>
<pre>
*MOPComplete>
*results leg="2" location="Radio 1">
@ -241,7 +297,7 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete>
</pre>
<p>Roganing results, Invoke with argument module=rogaining, which is a built in module.</p>
<p>Roganing results, Invoke with argument module=rogaining, which is a built in module.</p>
<pre>
*MOPComplete>
*results module="rogaining" location="Finish">
@ -264,8 +320,8 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete>
</pre>
<b>Remarks:</b>
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course</i> is included.
<b>Remarks:</b>
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course</i> is included.
<pre>
*person cls="1" stat="1" st="324000" rt="72550" place="1" course=28>
*name id="4">Jordan Griesmer*/name>
@ -273,26 +329,26 @@ When and only when the type is <b>CourseIndividual</b>, the attribute <i>course<
</pre>
<h2>Status</h2>
<b>Syntax:</b>
<h2>Status</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=status">/meos?get=status</a></pre>
<b>Returns:</b>
<p>MeOS Status Data. Includes MeOS version and competition name id, which also is the name of the database used, if any.</p>
<b>Returns:</b>
<p>MeOS Status Data. Includes MeOS version and competition name id, which also is the name of the database used, if any.</p>
<b>Example:</b>
<b>Example:</b>
<pre>
*MOPComplete>
*status version="3.6.1029" eventNameId="meos_20190223_212818_2FD" onDatabase="1"/>
*/MOPComplete>
</pre>
<h2>Entry Classes</h2>
<b>Syntax:</b>
<h2>Entry Classes</h2>
<b>Syntax:</b>
<pre><a href="/meos?get=entryclass">/meos?get=entryclass</a></pre>
<b>Returns:</b>
<p>Classes where entry is allowed via the API.</p>
<b>Returns:</b>
<p>Classes where entry is allowed via the API.</p>
<pre>
*EntryClasses>
@ -306,24 +362,24 @@ When and only when the type is <b>CourseIndividual</b>, the attribute <i>course<
*/EntryClasses>
</pre>
<h2>Lookup competitor</h2>
<b>Syntax:</b>
<h2>Lookup competitor</h2>
<b>Syntax:</b>
<pre><a href="/meos?lookup=competitor&id=%runnerid%">/meos?lookup=competitor&id=*id></a></pre>
<pre><a href="/meos?lookup=competitor&card=%card%">/meos?lookup=competitor&card=*card></a></pre>
<pre><a href="/meos?lookup=competitor&bib=%bib%">/meos?lookup=competitor&bib=*bib></a></pre>
<pre><a href="/meos?lookup=competitor&name=%name%&club=%club%">/meos?lookup=competitor&name=*name>&club=*club></a></pre>
<b>Returns:</b>
<p>Competitor including individual result.</p>
<b>Returns:</b>
<p>Competitor including individual result.</p>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>id</i> Competitor id. MeOS internal id.</li>
<li><i>card</i> Card number.</li>
<li><i>bib</i> Bib or start number.</li>
<li><i>name</i> Name of competitor.</li>
<li><i>club</i> Name of club.</li>
</ul>
</ul>
<pre>
*Competitors>
@ -359,23 +415,25 @@ When and only when the type is <b>CourseIndividual</b>, the attribute <i>course<
</pre>
<h2>Lookup Database Competitor</h2>
<b>Syntax:</b>
<h2>Lookup Database Competitor</h2>
<b>Syntax:</b>
<pre><a href="/meos?lookup=dbcompetitor&id=%runnerextid%">/meos?lookup=dbcompetitor&id=*id></a></pre>
<pre><a href="/meos?lookup=dbcompetitor&card=%card%">/meos?lookup=dbcompetitor&card=*card></a></pre>
<pre><a href="/meos?lookup=dbcompetitor&name=%dbname%&club=%dbclub%">/meos?lookup=dbcompetitor&name=*name>&club=*club></a></pre>
<b>Returns:</b>
<p>Competitor from runner database. Note that a partial name may be submitted, and that several matching result may be returned, sorted by relevance.
This query is suitable for auto complete functionality.</p>
<b>Returns:</b>
<p>
Competitor from runner database. Note that a partial name may be submitted, and that several matching result may be returned, sorted by relevance.
This query is suitable for auto complete functionality.
</p>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>id</i> External id from runner database.</li>
<li><i>card</i> Card number.</li>
<li><i>name</i> Name of competitor. Possibly a partial name.</li>
<li><i>club</i> Name of club.</li>
</ul>
</ul>
<pre>
@ -392,20 +450,22 @@ This query is suitable for auto complete functionality.</p>
</pre>
<h2>Lookup Database Club</h2>
<b>Syntax:</b>
<h2>Lookup Database Club</h2>
<b>Syntax:</b>
<pre><a href="/meos?lookup=dbclub&id=%clubid%">/meos?lookup=dbclub&id=*id></a></pre>
<pre><a href="/meos?lookup=dbclub&name=%club%">/meos?lookup=dbclub&name=*name></a></pre>
<b>Returns:</b>
<p>Club from club database. Note that a partial name may be submitted, and that several matching result may be returned, sorted by relevance.
This query is suitable for auto complete functionality.</p>
<b>Returns:</b>
<p>
Club from club database. Note that a partial name may be submitted, and that several matching result may be returned, sorted by relevance.
This query is suitable for auto complete functionality.
</p>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>id</i> External id from club database.</li>
<li><i>name</i> Name of club. Possibly a partial name.</li>
</ul>
</ul>
<pre>
*DatabaseClubs>
@ -415,24 +475,25 @@ This query is suitable for auto complete functionality.</p>
*/DatabaseClubs>
</pre>
<h2>API New Entry</h2>
<b>Syntax:</b>
<h2>API New Entry</h2>
<b>Syntax:</b>
<pre>/meos?entry&id=*id>&class=*classid>&card=*card></pre>
<pre>/meos?entry&name=*name>&club=*club>&class=*classid>&card=*card></pre>
<pre>/meos?entry&name=*name>&club=*club>&class=*classid>&card=*card>&notiming</pre>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>id</i> External id of runner from runner database.</li>
<li><i>name</i> Name of runner.</li>
<li><i>club</i> Name of runner's club.</li>
<li><i>class</i> Id of class.</li>
<li><i>card</i> Card number.</li>
</ul>
<li><i>notiming</i> Set status no timing.</li>
</ul>
<p></p><b>Returns:</b>
Status.</p>
<p><b>Returns:</b>
Status.</p>
<b>Note: </b> <p></p>If the card number is registered as a rental card, it will be set as such and
<p><b>Note: </b> <br />If the card number is registered as a rental card, it will be set as such and
<i>hiredCard</i> will be set in the Fee attribute. The returned fee includes any rental card fee.</p>
<pre>
@ -450,44 +511,44 @@ Status.</p>
*/Answer>
</pre>
<h2>Page template</h2>
<b>Syntax:</b>
<h2>Page template</h2>
<b>Syntax:</b>
<pre>/meos?page=*page></pre>
<b>Returns:</b>
Installed template file with the specified tag.
<b>Returns:</b>
Installed template file with the specified tag.
<h2>Image</h2>
<b>Syntax:</b>
<h2>Image</h2>
<b>Syntax:</b>
<pre>/meos?image=*image></pre>
<b>Returns:</b>
Image, *image>.png, if installed in MeOS datafolder. MeOS logo if *image> is meos.
<b>Returns:</b>
Image, *image>.png, if installed in MeOS datafolder. MeOS logo if *image> is meos.
<h2>IOF XML Results</h2>
<h2>IOF XML Results</h2>
<b>Syntax:</b>
<b>Syntax:</b>
<pre><a href="/meos?get=iofresult">/meos?get=iofresult</a></pre>
<pre>/meos?get=iofresult#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
</ul>
</ul>
<b>Returns:</b>
<p>IOF XML version 3.0 result list.</p>
<b>Returns:</b>
<p>IOF XML version 3.0 result list.</p>
<h2>IOF XML Startlist</h2>
<h2>IOF XML Startlist</h2>
<b>Syntax:</b>
<b>Syntax:</b>
<pre><a href="/meos?get=iofstart">/meos?get=iofstart</a></pre>
<pre>/meos?get=iofstart#class=*c1>,*c2>,...</pre>
<b>Arguments:</b>
<ul>
<b>Arguments:</b>
<ul>
<li><i>class</i> A list of one or more class id:s, separated by comma. The default is all classes.</li>
</ul>
</ul>
<b>Returns:</b>
<p>IOF XML version 3.0 start list.</p>
<b>Returns:</b>
<p>IOF XML version 3.0 start list.</p>

View File

@ -427,9 +427,12 @@ void InfoMeosStatus::serialize(xmlbuffer &xml, bool diffOnly) const {
bool InfoOrganization::synchronize(oClub &c) {
const wstring &n = c.getDisplayName();
if (n == name)
const wstring &nat = c.getDCI().getString("Nationality");
if (n == name && nat == nationality)
return false;
else {
nationality = nat;
name = n;
modified();
}
@ -439,6 +442,8 @@ bool InfoOrganization::synchronize(oClub &c) {
void InfoOrganization::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > prop;
prop.push_back(make_pair("id", itow(getId())));
if (!nationality.empty())
prop.emplace_back("nat", nationality);
xml.write("org", prop, name);
}
@ -461,9 +466,11 @@ void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) co
if (course != 0)
prop.emplace_back("crs", itow(course));
if (!bib.empty()) {
if (!bib.empty())
prop.emplace_back("bib", bib);
}
if (!nationality.empty())
prop.emplace_back("nat", nationality);
xml.write("base", prop, name);
}
@ -488,11 +495,21 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
ch = true;
}
RunnerStatus s = bc.getStatus();
const wstring &nat = bc.getDCI().getString("Nationality");
if (nat != nationality) {
nationality = nat;
ch = true;
}
RunnerStatus s = bc.getStatusComputed();
int rt = bc.getRunningTime(true) * 10;
if (rt > 0) {
if (s == RunnerStatus::StatusUnknown)
s = RunnerStatus::StatusOK;
if (s == RunnerStatus::StatusNoTiming)
rt = 0;
}
else if (isPossibleResultStatus(s))
s = StatusUnknown;
@ -583,7 +600,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
}
bool nr;
if ((r.getStatus() == StatusUnknown || r.getStatus() == StatusOutOfCompetition || r.getStatus() == StatusNoTiming) && r.getFinishTime() <= 0) {
if ((r.getStatus() == StatusUnknown || isPossibleResultStatus(r.getStatus())) && r.getFinishTime() <= 0) {
vector<pFreePunch> pv;
r.getEvent()->getPunchesForRunner(r.getId(), false, pv);
nr = pv.size() > 0;
@ -597,7 +614,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
}
vector<RadioTime> newRT;
if (r.getClassId(false) > 0) {
if (r.getClassId(false) > 0 && r.getStatusComputed() != RunnerStatus::StatusNoTiming) {
const vector<int> &radios = cmp.getControls(r.getClassId(true), r.getLegNumber());
for (size_t k = 0; k < radios.size(); k++) {
RadioTime radioTime;
@ -611,7 +628,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
}
}
}
changeRadio = radioTimes.size() > 0;//false; // Always write full attributes
changeRadio = radioTimes.size() > 0; // Always write full attributes
if (newRT != radioTimes) {
ch = true;
changeRadio = true;
@ -879,3 +896,33 @@ bool xmlbuffer::commit(xmlparser &xml, int count) {
return !blocks.empty();
}
void xmlbuffer::commitCopy(xmlparser &xml) {
vector<wstring> p2;
for (block &block : blocks) {
if (block.subValues.empty()) {
xml.write(block.tag.c_str(), block.prop, block.value);
}
else {
if (block.prop.size() > 1) {
p2.resize(block.prop.size() * 2);
for (size_t k = 0; k < block.prop.size(); k++) {
p2[k * 2] = gdi_main->widen(block.prop[k].first);
p2[k * 2 + 1] = block.prop[k].second;
}
xml.startTag(block.tag.c_str(), p2);
}
else if (block.prop.size() == 1) {
xml.startTag(block.tag.c_str(), block.prop[0].first.c_str(), block.prop[0].second);
}
else if (block.prop.empty()) {
xml.startTag(block.tag.c_str());
}
for (size_t k = 0; k < block.subValues.size(); k++)
block.subValues[k].commitCopy(xml);
xml.endTag();
}
}
}

View File

@ -64,7 +64,9 @@ public:
size_t size() const {return blocks.size();}
bool commit(xmlparser &xml, int count);
void commitCopy(xmlparser &xml);
bool isComplete() const { return complete; }
void startXML(xmlparser &xml, const wstring &dest);
};
@ -140,6 +142,7 @@ class InfoMeosStatus : public InfoBase {
class InfoOrganization : public InfoBase {
protected:
wstring name;
wstring nationality;
public:
InfoOrganization(int id);
virtual ~InfoOrganization() {}
@ -169,6 +172,7 @@ class InfoBaseCompetitor : public InfoBase {
int startTime;
int runningTime;
wstring bib;
wstring nationality;
void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
bool synchronizeBase(oAbstractRunner &bc);
public:

View File

@ -47,13 +47,13 @@ private:
T &rehash(int size, KEY key, const T &value);
T &get(const KEY key);
const intkeymap &operator=(const intkeymap &co);
void *lookup(KEY key) const;
public:
virtual ~intkeymap();
intkeymap(int size);
intkeymap();
intkeymap(const intkeymap &co);
const intkeymap &operator=(const intkeymap &co);
bool empty() const;
int size() const;

View File

@ -83,6 +83,34 @@ template <class T, class KEY> intkeymap<T, KEY>::intkeymap(const intkeymap &co)
}
}
template <class T, class KEY>
const intkeymap<T, KEY> &intkeymap<T, KEY>::operator=(const intkeymap<T, KEY> &co) {
clear();
delete[] keys;
allocFactor = co.allocFactor;
siz = co.siz;
keys = new keypair[siz];
hash1 = co.hash1;
hash2 = co.hash2;
used = co.used;
level = co.level;
dummy = co.dummy;
noValue = co.noValue;
for (unsigned k = 0; k<siz; k++)
keys[k] = co.keys[k];
parent = 0;
next = 0;
if (co.next) {
next = new intkeymap<T, KEY>(*co.next);
next->parent = this;
}
return *this;
}
template <class T, class KEY> intkeymap<T, KEY>::~intkeymap()
{
delete[] keys;

View File

@ -492,7 +492,6 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
}
}
void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignment,
const map<wstring, pCourse> &courses,
const map<wstring, vector<pCourse> > &coursesFamilies) {
@ -690,6 +689,23 @@ void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignmen
}
}
void IOF30Interface::prescanCompetitorList(xmlobject &xo) {
xmlList xl;
xo.getObjects(xl);
xmlList::const_iterator it;
xmlList work;
string wstring;
for (it = xl.begin(); it != xl.end(); ++it) {
if (it->is("Competitor")) {
xmlobject person = it->getObject("Person");
if (person) {
readIdProviders(person, work, wstring);
}
}
}
}
void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount) {
if (!xo)
return;
@ -704,7 +720,7 @@ void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int
xmlList::const_iterator it;
for (it=xl.begin(); it != xl.end(); ++it) {
for (it = xl.begin(); it != xl.end(); ++it) {
if (it->is("Competitor")) {
if (readXMLCompetitorDB(*it))
personCount++;
@ -736,15 +752,15 @@ void IOF30Interface::readClubList(gdioutput &gdi, const xmlobject &xo, int &club
void IOF30Interface::prescanEntryList(xmlobject &xo, set<int> &definedStages) {
definedStages.clear();
xmlList pEntries;
xmlList pEntries, work;
xo.getObjects("PersonEntry", pEntries);
for (size_t k = 0; k < pEntries.size(); k++) {
prescanEntry(pEntries[k], definedStages);
prescanEntry(pEntries[k], definedStages, work);
}
xo.getObjects("TeamEntry", pEntries);
for (size_t k = 0; k < pEntries.size(); k++) {
prescanEntry(pEntries[k], definedStages);
prescanEntry(pEntries[k], definedStages, work);
}
}
@ -1598,8 +1614,8 @@ int IOF30Interface::getIndexFromLegPos(int leg, int legorder, const vector<LegIn
return ix;
}
void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
xmlList races;
void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages, xmlList &work) {
xmlList &races = work;
xo.getObjects("RaceNumber", races);
if (races.empty())
xo.getObjects("Race", races); // For unclear reason the attribute is called Race for teams and RaceNumber for persons.
@ -1621,10 +1637,16 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
person = teamPerson.getObject("Person");
}
xmlList ids;
if (person) {
person.getObjects("Id", ids);
xmlList &ids = work;
string type;
readIdProviders(person, ids, type);
}
}
void IOF30Interface::readIdProviders(xmlobject &person, xmlList &ids, std::string &type)
{
person.getObjects("Id", ids);
if (ids.size() > 1) {
for (auto &id : ids) {
id.getObjectString("type", type);
@ -1633,7 +1655,6 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
}
}
}
}
}
bool IOF30Interface::matchStageFilter(const set<int> &stageFilter, const xmlList &races) {
@ -1767,6 +1788,22 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
}
}
bool hasTime = true;
xmlobject ext = xo.getObject("Extensions");
if (ext) {
xmlList exts;
ext.getObjects(exts);
for (xmlobject &xx : exts) {
if (xx.is("TimePresentation")) {
hasTime = xx.getObjectBool(nullptr);
}
}
}
if (!hasTime)
r->setStatus(StatusNoTiming, true, oBase::ChangeType::Update);
else if (r->getStatus() == StatusNoTiming)
r->setStatus(StatusUnknown, true, oBase::ChangeType::Update);
r->synchronize();
return r;
}
@ -2766,7 +2803,6 @@ void IOF30Interface::writeCourseInfo(xmlparser &xml, const oCourse &c) {
xml.write("Climb", climb);
}
wstring formatStatus(RunnerStatus st, bool hasTime) {
switch (st) {
case StatusNoTiming:
@ -2870,6 +2906,9 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
if (r.getStartTime() > 0)
xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT));
bool hasTiming = (!r.getClassRef(false) || r.getClassRef(true)->getNoTiming() == false) &&
r.getStatusComputed() != RunnerStatus::StatusNoTiming;
int finishTime, runningTime, place, after;
RunnerStatus status;
if (!patrolResult) {
@ -2892,13 +2931,13 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
status = r.getTeam()->getLegStatus(pl, true, false);
}
if ((r.getClassRef(false) && r.getClassRef(true)->getNoTiming()) ||
r.getStatusComputed() == StatusNoTiming) {
if (!hasTiming) {
after = -1;
runningTime = 0;
finishTime = 0;
}
if (r.getFinishTime() > 0)
if (finishTime > 0)
xml.write("FinishTime", oe.getAbsDateTimeISO(finishTime, true, useGMT));
if (runningTime > 0)
@ -2918,7 +2957,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
if (r.getClassRef(false)) {
if (r.statusOK(true) && r.getClassRef(false)->getNoTiming() == false) {
if (r.statusOK(true) && hasTiming) {
if (!teamMember && place > 0 && place < 50000) {
xml.write("Position", place);
}
@ -2941,11 +2980,11 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
}
if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult");
int rt = r.getTotalRunningTime();
if (rt > 0)
if (rt > 0 && hasTiming)
xml.write("Time", rt);
bool hasTiming = r.getClassRef(false)->getNoTiming() == false;
RunnerStatus stat = r.getTotalStatus();
int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0;
@ -3002,7 +3041,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
else
xml.startTag("SplitTime");
xml.write("ControlCode", crs->getControl(k)->getFirstNumber());
if (sp[k].hasTime())
if (sp[k].hasTime() && hasTiming)
xml.write("Time", sp[k].time - r.getStartTime());
xml.endTag();
}
@ -3014,6 +3053,21 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Time", it->first);
xml.endTag();
}
oCard *card = r.getCard();
if (card) { // Write additional punches
vector<pPunch> plist;
card->getPunches(plist);
for (pPunch p : plist) {
if (p->getTypeCode() >= 30 && !p->isUsedInCourse()) {
xml.startTag("SplitTime", "status", "Additional");
xml.write("ControlCode", p->getTypeCode());
if (p->getTimeInt() > r.getStartTime())
xml.write("Time", p->getTimeInt() - r.getStartTime());
xml.endTag();
}
}
}
}
}
}
@ -3023,6 +3077,12 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
writeFees(xml, rPerson);
if (!hasTiming) {
xml.startTag("Extensions");
xml.write("TimePresentation", L"false");
xml.endTag();
}
xml.endTag();
}
@ -3464,9 +3524,13 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
if (!person) return false;
int pidI;
long long pid;
readId(person, pidI, pid);
/*
wstring pidS;
person.getObjectString("Id", pidS);
long long pid = oBase::converExtIdentifierString(pidS);
person.getObjectString("Id", pidS);xxx
long long pid = oBase::converExtIdentifierString(pidS);*/
xmlobject pname = person.getObject("Name");
if (!pname) return false;

View File

@ -167,7 +167,8 @@ class IOF30Interface {
static int getIndexFromLegPos(int leg, int legorder, const vector<LegInfo> &setup);
void prescanEntry(xmlobject & xo, set<int>& stages);
void prescanEntry(xmlobject & xo, set<int>& stages, xmlList &work);
void readIdProviders(xmlobject &person, xmlList &ids, std::string &type);
void setupClassConfig(int classId, const xmlobject &xTeam, map<int, vector<LegInfo> > &teamClassConfig);
void setupRelayClasses(const map<int, vector<LegInfo> > &teamClassConfig);
@ -298,6 +299,7 @@ public:
void readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
void prescanCompetitorList(xmlobject &xo);
void readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount);
void readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount);

View File

@ -225,7 +225,7 @@ void ListEditor::show(gdioutput &gdi) {
gdi.fillDown();
try {
currentList->interpret(oe, gdi, par, gdi.getLineHeight(), li);
currentList->interpret(oe, gdi, par, li);
rc.left = gdi.getCX();
rc.right = gdi.getCX() + gdi.getWidth() - 20;
rc.top = gdi.getCY();

View File

@ -30,24 +30,18 @@
//V35: abcdef
//V36: abcdef
int getMeosBuild() {
string revision("$Rev: 972 $");
string revision("$Rev: 1004 $");
return 174 + atoi(revision.substr(5, string::npos).c_str());
}
//ABCDEFGHIJKILMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz
//V2: abcdefgh
//V3: abcdefghijklmnopqrstuvxyz
//V31: abcde
//V32: abcdefgh
//V33: abcdefghij
//V34: abcdfge
//V37: a
wstring getMeosDate() {
wstring date(L"$Date: 2020-01-18 15:14:04 +0100 (lö, 18 jan 2020) $");
wstring date(L"$Date: 2020-02-25 21:05:03 +0100 (ti, 25 feb 2020) $");
return date.substr(7,10);
}
wstring getBuildType() {
return L"Beta 1"; // No parantheses (...)
return L"RC1"; // No parantheses (...)
}
wstring getMajorVersion() {
@ -149,5 +143,8 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
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");
reverse(supp.begin(), supp.end());
}

View File

@ -358,8 +358,7 @@ static void setFixedWidth(oPrintPost &added,
added.fixedWidth = 0;
}
void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par,
int lineHeight, oListInfo &li) const {
void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const {
const MetaList &mList = *this;
Position pos;
const bool large = par.useLargeSize;
@ -376,19 +375,20 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
if (fontFaces[k].scale > 0 && fontFaces[k].scale != 100) {
face += L";" + itow(fontFaces[k].scale/100) + L"." + itow(fontFaces[k].scale%100);
}
fontHeight[make_pair(it->first, int(k))] = gdi.getLineHeight(it->first, face.c_str());
fontHeight[make_pair(it->first, int(k))] = int(gdi.getLineHeight(it->first, face.c_str()) / gdi.getScale());
}
}
int lineHeight;
if (large) {
s_factor = 0.9;
normal = fontLarge;
header = boldLarge;
small = normalText;
lineHeight = int(lineHeight *1.6);
lineHeight = 22;
italic = italicMediumPlus;
}
else {
lineHeight = 14;
s_factor = 1.0;
normal = normalText;
header = boldText;
@ -511,6 +511,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
oPrintPost::encodeFont(fontFaces[i].font,
fontFaces[i].scale).c_str(),
large, max(mp.blockWidth, extraMinWidth));
++linePostCount[make_pair(i, j)]; // Count how many positions on this line
indexPosToWidth[tuple<int,int,int>(i, j, k)] = width;
}
@ -584,7 +585,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
resultToIndex.clear();
/*if (large == false && par.pageBreak == false) {*/
{
int head_dy = gdi.scaleLength(mList.getExtraSpace(MLHead));
int head_dy = mList.getExtraSpace(MLHead);
for (size_t j = 0; j<mList.getHead().size(); j++) {
const vector<MetaListPost> &cline = mList.getHead()[j];
next_dy = 0;
@ -639,7 +640,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
}
dy = lineHeight;
int subhead_dy = gdi.scaleLength(mList.getExtraSpace(MLSubHead));
int subhead_dy = mList.getExtraSpace(MLSubHead);
last = 0;
base = 0;
@ -689,7 +690,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
last = 0;
base = 0;
int list_dy = gdi.scaleLength(mList.getExtraSpace(MLList));//mList.getSubList().size() > 0 ? lineHeight/2 : 0;
int list_dy = mList.getExtraSpace(MLList);
dy = 0;
for (size_t j = 0; j<mList.getList().size(); j++) {
const vector<MetaListPost> &cline = mList.getList()[j];
@ -731,7 +732,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
dy += next_dy;
}
int sublist_dy = gdi.scaleLength(mList.getExtraSpace(MLSubList));
int sublist_dy = mList.getExtraSpace(MLSubList);
last = 0;
base = 0;
dy = 0;
@ -2309,12 +2310,11 @@ wstring MetaListContainer::makeUniqueParamName(const wstring &nameIn) const {
}
bool MetaListContainer::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par,
int lineHeight, oListInfo &li) const {
bool MetaListContainer::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const {
map<EStdListType, int>::const_iterator it = globalIndex.find(par.listCode);
if (it != globalIndex.end()) {
data[it->second].second.interpret(oe, gdi, par, lineHeight, li);
data[it->second].second.interpret(oe, gdi, par, li);
return true;
}
return false;

View File

@ -307,8 +307,7 @@ public:
void save(xmlparser &xml, const oEvent *oe) const;
void load(const xmlobject &xDef);
void interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par,
int lineHeight, oListInfo &li) const;
void interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const;
MetaList &setListName(const wstring &title) {listName = title; return *this;}
@ -424,8 +423,7 @@ public:
void synchronizeTo(MetaListContainer &dst) const;
bool interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par,
int lineHeight, oListInfo &li) const;
bool interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const;
void enumerateLists(vector< pair<wstring, pair<string, wstring> > > &out) const;
};

View File

@ -54,6 +54,59 @@ oBase::oBase(oEvent *poe) {
localObject = false;
}
oBase::oBase(const oBase &in) {
Removed = in.Removed;
oe = in.oe;
Id = in.Id;
changed = false;
counter = in.counter;
Modified.update();
correctionNeeded = in.correctionNeeded;
localObject = in.localObject;
implicitlyAdded = in.implicitlyAdded;
addedToEvent = in.addedToEvent;
sqlUpdated = in.sqlUpdated;
localObject = in.localObject;
transientChanged = in.transientChanged;
}
oBase::oBase(oBase &&in) {
Removed = in.Removed;
oe = in.oe;
Id = in.Id;
changed = false;
counter = in.counter;
Modified.update();
correctionNeeded = in.correctionNeeded;
localObject = in.localObject;
implicitlyAdded = in.implicitlyAdded;
addedToEvent = in.addedToEvent;
sqlUpdated = in.sqlUpdated;
localObject = in.localObject;
transientChanged = in.transientChanged;
if (in.myReference) {
myReference.swap(in.myReference);
myReference->ref = this;
}
}
const oBase &oBase::operator=(const oBase &in) {
Removed = in.Removed;
oe = in.oe;
Id = in.Id;
changed = false;
counter = in.counter;
Modified.update();
correctionNeeded = in.correctionNeeded;
localObject = in.localObject;
implicitlyAdded = in.implicitlyAdded;
addedToEvent = in.addedToEvent;
sqlUpdated = in.sqlUpdated;
localObject = in.localObject;
transientChanged = in.transientChanged;
return *this;
}
oBase::~oBase(){
if (myReference)
myReference->ref = nullptr;
@ -64,6 +117,7 @@ void oBase::remove() {
myReference->ref = nullptr;
}
bool oBase::synchronize(bool writeOnly)
{
if (oe && (changed || transientChanged)) {

View File

@ -65,21 +65,19 @@ public:
};
private:
// Changed in client, not yet sent to server
bool changed;
// Changed in client, silent mode, should not be sent to server
bool transientChanged;
bool localObject;
const static unsigned long long BaseGenStringFlag = 1ull << 63;
const static unsigned long long Base36StringFlag = 1ull << 62;
const static unsigned long long ExtStringMask = ~(BaseGenStringFlag|Base36StringFlag);
shared_ptr<oBaseReference> myReference;
protected:
int Id;
TimeStamp Modified;
string sqlUpdated; //SQL TIMESTAMP
private:
const static unsigned long long BaseGenStringFlag = 1ull << 63;
const static unsigned long long Base36StringFlag = 1ull << 62;
const static unsigned long long ExtStringMask = ~(BaseGenStringFlag | Base36StringFlag);
shared_ptr<oBaseReference> myReference;
protected:
int counter;
oEvent *oe;
bool Removed;
@ -93,6 +91,11 @@ private:
bool implicitlyAdded = false;
bool addedToEvent = false;
// Changed in client, not yet sent to server
bool changed;
// Changed in client, silent mode, should not be sent to server
bool transientChanged;
bool localObject;
protected:
@ -186,6 +189,9 @@ public:
static __int64 converExtIdentifierString(const wstring &str);
oBase(oEvent *poe);
oBase(const oBase &in);
oBase(oBase &&in);
const oBase &operator=(const oBase &in);
virtual ~oBase();
friend class RunnerDB;

View File

@ -656,11 +656,14 @@ void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid,
data.resPos = gdi.scaleLength(550);
gdi.addString("", ys, xs+data.adrPos, boldHuge, "FAKTURA");
if (number>0)
gdi.addStringUT(ys+lh*3, xs+data.adrPos, fontMedium, lang.tl("Faktura nr")+ L": " + itow(number));
if (number > 0) {
gdi.addStringUT(ys + lh * 3, xs + data.adrPos, fontMedium, lang.tl("Faktura nr") + L": " + itow(number));
gdi.addStringUT(ys + lh * 4, xs + data.adrPos, fontMedium, getInvoiceDate(*oe));
}
int &yp = data.yp;
yp = ys+lh;
yp = ys+lh * 2;
wstring ostreet = oe->getDI().getString("Street");
wstring oaddress = oe->getDI().getString("Address");
wstring oco = oe->getDI().getString("CareOf");
@ -684,7 +687,7 @@ void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid,
wstring city = getDCI().getString("ZIP") + L" " + getDCI().getString("City");
wstring country = getDCI().getString("Country");
int ayp = ys + 122;
int ayp = ys + gdi.scaleLength(122);
const int absX = oe->getPropertyInt("addressxpos", 125);
int absY = oe->getPropertyInt("addressypos", 50);
@ -706,7 +709,7 @@ void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid,
if (!country.empty())
gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, country).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL;
yp = ayp+30;
yp = ayp+gdi.scaleLength(36);
gdi.addString("", yp, xs, boldSmall, "Deltagare");
gdi.addString("", yp, xs+data.clsPos, boldSmall, "Klass");
@ -1148,3 +1151,17 @@ bool oClub::operator<(const oClub &c) const {
name.c_str(), name.length(),
c.name.c_str(), c.name.length()) == CSTR_LESS_THAN;
}
wstring oClub::getInvoiceDate(oEvent &oe) {
wstring invoiceDate = oe.getDCI().getDate("InvoiceDate");
int invoiceDateI = oe.getDCI().getInt("InvoiceDate");
if (invoiceDateI == 0) {
invoiceDate = getLocalDate();
setInvoiceDate(oe, invoiceDate);
}
return invoiceDate;
}
void oClub::setInvoiceDate(oEvent &oe, const wstring &id) {
oe.getDI().setDate("InvoiceDate", id);
}

View File

@ -147,10 +147,11 @@ public:
static void assignInvoiceNumber(oEvent &oe, bool reset);
static int getFirstInvoiceNumber(oEvent &oe);
static wstring getInvoiceDate(oEvent &oe);
static void setInvoiceDate(oEvent &oe, const wstring &id);
static void definedPayModes(oEvent &oe, map<int, wstring> &definedPayModes);
/** Remove all clubs from a competion (and all belong to club relations)*/
static void clearClubs(oEvent &oe);

View File

@ -249,7 +249,7 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
ZeroTime=st.wHour*3600;
oe=this;
runnerDB = new RunnerDB(this);
runnerDB = make_shared<RunnerDB>(this);
meosFeatures = new MeOSFeatures();
openFileLock = new MeOSFileLock();
@ -342,6 +342,8 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
oEventData->addVariableInt("LongTimes", oDataContainer::oIS8U, "Långa tider");
oEventData->addVariableString("PayModes", "Betalsätt");
oEventData->addVariableInt("TransferFlags", oDataContainer::oIS32, "Överföring");
oEventData->addVariableDate("InvoiceDate", "Fakturadatum");
oEventData->initData(this, dataSize);
oClubData=new oDataContainer(oClub::dataSize);
@ -520,9 +522,8 @@ oEvent::~oEvent()
{
//Clean up things in the right order.
clear();
delete runnerDB;
runnerDB.reset();
delete meosFeatures;
runnerDB = 0;
meosFeatures = 0;
delete oEventData;
@ -1595,6 +1596,17 @@ void oEvent::updateRunnerDatabase(pRunner r, map<int, int> &clubIdMap)
runnerDB->updateAdd(*r, clubIdMap);
}
void oEvent::backupRunnerDatabase() {
if (!runnerDBCopy)
runnerDBCopy = make_shared<RunnerDB>(*runnerDB);
}
void oEvent::restoreRunnerDatabase() {
if (runnerDBCopy && *runnerDB != *runnerDBCopy) {
runnerDB = make_shared<RunnerDB>(*runnerDBCopy);
}
}
pCourse oEvent::addCourse(const wstring &pname, int plengh, int id) {
oCourse c(this, id);
c.Length = plengh;
@ -2181,6 +2193,7 @@ void oEvent::setDate(const wstring &m, bool manualSet)
throw meosException(L"Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD).#" + m);
wstring nDate = formatDate(d, true);
if (Date != nDate) {
Date = nDate;
if (manualSet)
setFlag(TransferFlags::FlagManualDateTime, true);
updateChanged();
@ -2210,7 +2223,7 @@ const wstring &oEvent::getTimeZoneString() const {
wstring oEvent::getAbsDateTimeISO(DWORD time, bool includeDate, bool useGMT) const
{
DWORD t = ZeroTime + time;
int t = ZeroTime + time;
wstring dateS, timeS;
if (int(t)<0) {
dateS = L"2000-01-01";
@ -2888,7 +2901,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
// Get a set with unknown runner id:s
set<int> statUnknown;
for (oRunnerList::const_iterator itr=Runners.begin(); itr != Runners.end(); ++itr) {
if (itr->tStatus == StatusUnknown && !(itr->skip() || itr->needNoCard())) {
if (!itr->hasFinished() && !(itr->skip() || itr->needNoCard())) {
statUnknown.insert(itr->getId());
}
}
@ -2959,7 +2972,7 @@ void oEvent::generateInForestList(gdioutput &gdi, GUICALLBACK cb, GUICALLBACK cb
if (it->skip() || it->needNoCard())
continue;
if (it->tStatus == StatusUnknown) {
if (!it->hasFinished()) {
if (id != it->getClassId(true)) {
if (nr>0) {
@ -5181,7 +5194,7 @@ void oEvent::generateTestCompetition(int nClasses, int nRunners,
nRunners-=nRInClass;
if (k%5!=5) {
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(cls->getId(), 0, getRelativeTime(start), 10, 3));
spec.emplace_back(cls->getId(), 0, getRelativeTime(start), 10, 3, VacantPosition::Mixed);
drawList(spec, DrawMethod::MeOS, 1, oEvent::DrawType::DrawAll);
}
else
@ -5203,7 +5216,7 @@ void oEvent::generateTestCompetition(int nClasses, int nRunners,
if ( cls->getStartType(0)==STDrawn ) {
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(cls->getId(), 0, getRelativeTime(start), 20, 3));
spec.emplace_back(cls->getId(), 0, getRelativeTime(start), 20, 3, VacantPosition::Mixed);
drawList(spec, DrawMethod::MeOS, 1, DrawType::DrawAll);
}
}

View File

@ -263,7 +263,9 @@ protected:
oRunnerList Runners;
intkeymap<pRunner> runnerById;
RunnerDB *runnerDB;
shared_ptr<RunnerDB> runnerDB;
shared_ptr<RunnerDB> runnerDBCopy;
MeOSFeatures *meosFeatures;
oCardList Cards;
@ -296,35 +298,6 @@ protected:
SqlUpdated sqlPunches;
SqlUpdated sqlTeams;
/*
string sqlUpdateRunners;
string sqlUpdateClasses;
string sqlUpdateCourses;
string sqlUpdateControls;
string sqlUpdateClubs;
string sqlUpdateCards;
string sqlUpdatePunches;
string sqlUpdateTeams;
int sqlCounterRunners;
int sqlCounterClasses;
int sqlCounterCourses;
int sqlCounterControls;
int sqlCounterClubs;
int sqlCounterCards;
int sqlCounterPunches;
int sqlCounterTeams;
bool sqlChangedRunners;
bool sqlChangedClasses;
bool sqlChangedCourses;
bool sqlChangedControls;
bool sqlChangedClubs;
bool sqlChangedCards;
bool sqlChangedPunches;
bool sqlChangedTeams;
*/
bool needReEvaluate();
DirectSocket *directSocket;
@ -496,6 +469,13 @@ public:
DrawAll, RemainingBefore, RemainingAfter,
};
/** Where to put vacancies */
enum class VacantPosition {
Mixed = 0,
First = 1,
Last = 2,
};
/** Drawing algorithm. */
enum class DrawMethod {
NOMethod = -1,
@ -553,9 +533,11 @@ public:
void getExtraLines(const char *attrib, vector<pair<wstring, int> > &lines) const;
RunnerDB &getRunnerDatabase() const {return *runnerDB;}
void backupRunnerDatabase();
void restoreRunnerDatabase();
MeOSFeatures &getMeOSFeatures() const {return *meosFeatures;}
void getDBRunnersInEvent(intkeymap<pClass, __int64> &runners) const;
void getDBRunnersInEvent(intkeymap<int, __int64> &runners) const;
MetaListContainer &getListContainer() const;
wstring getNameId(int id) const;
const wstring &getFileNameFromId(int id) const;
@ -607,8 +589,10 @@ public:
// Automatic draw of all classes
void automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
const wstring &minIntervall, const wstring &vacances,
bool lateBefore, bool allowNeighbourSameCourse, DrawMethod method, int pairSize);
const wstring &minIntervall,
const wstring &vacances, VacantPosition vp,
bool lateBefore, bool allowNeighbourSameCourse,
DrawMethod method, int pairSize);
// Restore a backup by renamning the file to .meos
void restoreBackup();
@ -728,10 +712,10 @@ public:
void generateList(gdioutput &gdi, bool reEvaluate, const oListInfo &li, bool updateScrollBars);
void generateListInfo(oListParam &par, int lineHeight, oListInfo &li);
void generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo &li);
void generateListInfo(oListParam &par, oListInfo &li);
void generateListInfo(vector<oListParam> &par, oListInfo &li);
void generateListInfo(EStdListType lt, const gdioutput &gdi, int classId, oListInfo &li);
void generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li, const wstring &name);
void generateListInfoAux(oListParam &par, oListInfo &li, const wstring &name);
/** Format a string for a list. Returns true of output is not empty*/
const wstring &formatListString(const oPrintPost &pp, const oListParam &par,

View File

@ -212,6 +212,7 @@ namespace {
void drawMeOSMethod(vector<pRunner> &runners) {
if (runners.empty())
return;
map<int, vector<pRunner>> runnersPerClub;
for (pRunner r : runners)
runnersPerClub[r->getClubId()].push_back(r);
@ -960,7 +961,7 @@ void oEvent::drawRemaining(DrawMethod method, bool placeAfter)
for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) {
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(it->getId(), 0, 0, 0, 0));
spec.emplace_back(it->getId(), 0, 0, 0, 0, VacantPosition::Mixed);
drawList(spec, method, 1, drawType);
}
@ -1120,6 +1121,21 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
if (gdibase.isTest())
InitRanom(0,0);
vector<pRunner> vacant;
VacantPosition vp = spec[0].vacantPosition;
if (vp != VacantPosition::Mixed) {
// Move vacants to a dedicated container
for (size_t k = 0; k < runners.size(); k++) {
if (runners[k]->isVacant()) {
vacant.push_back(runners[k]);
swap(runners[k], runners.back());
runners.pop_back();
k--;
}
}
}
switch (method) {
case DrawMethod::SOFT:
drawSOFTMethod(runners, true);
@ -1128,12 +1144,28 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
drawMeOSMethod(runners);
break;
case DrawMethod::Random:
permute(stimes);
{
vector<int> pv(runners.size());
for (size_t k = 0; k < pv.size(); k++)
pv[k] = k;
permute(pv);
vector<pRunner> r2(runners.size());
for (size_t k = 0; k < pv.size(); k++)
r2[k] = runners[pv[k]];
r2.swap(runners);
}
break;
default:
throw 0;
}
if (vp == VacantPosition::First) {
runners.insert(runners.begin(), vacant.begin(), vacant.end());
}
else if (vp == VacantPosition::Last) {
runners.insert(runners.end(), vacant.begin(), vacant.end());
}
int minStartNo = Runners.size();
vector<pair<int, int>> newStartNo;
for(unsigned k=0;k<stimes.size(); k++) {
@ -1323,10 +1355,15 @@ void oEvent::drawListClumped(int ClassID, int FirstStart, int Interval, int Vaca
delete[] stimes;
}
void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
const wstring &minIntervall, const wstring &vacances,
bool lateBefore, bool allowNeighbourSameCourse, DrawMethod method, int pairSize)
{
void oEvent::automaticDrawAll(gdioutput &gdi,
const wstring &firstStart,
const wstring &minIntervall,
const wstring &vacances,
VacantPosition vp,
bool lateBefore,
bool allowNeighbourSameCourse,
DrawMethod method,
int pairSize) {
gdi.refresh();
const int leg = 0;
const double extraFactor = 0.0;
@ -1350,7 +1387,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
if (it->isRemoved())
continue;
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(it->getId(), 0, iFirstStart, 0, 0));
spec.emplace_back(it->getId(), 0, iFirstStart, 0, 0, vp);
oe->drawList(spec, DrawMethod::Random, 1, DrawType::DrawAll);
}
return;
@ -1505,9 +1542,9 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
gdi.addString("", 0, L"Lottar: X#" + getClass(ci.classId)->getName());
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(ci.classId, leg,
spec.emplace_back(ci.classId, leg,
di.firstStart + di.baseInterval * ci.firstStart,
di.baseInterval * ci.interval, ci.nVacant));
di.baseInterval * ci.interval, ci.nVacant, vp);
drawList(spec, method, pairSize, DrawType::DrawAll);
gdi.scrollToBottom();
@ -1526,7 +1563,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
gdi.addStringUT(0, lang.tl(L"Lottar efteranmälda: ") + it->getName());
vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(it->getId(), leg, 0, 0, 0));
spec.emplace_back(it->getId(), leg, 0, 0, 0, vp);
drawList(spec, method, 1, lateBefore ? DrawType::RemainingBefore : DrawType::RemainingAfter);
gdi.scrollToBottom();

View File

@ -22,6 +22,8 @@
************************************************************************/
#include "oEvent.h"
struct ClassDrawSpecification {
int classID;
int leg;
@ -29,11 +31,11 @@ struct ClassDrawSpecification {
mutable int interval;
int vacances;
mutable int ntimes;
ClassDrawSpecification() : ntimes(0) {}
ClassDrawSpecification(int classID, int leg, int firstStart, int interval, int vacances) :
oEvent::VacantPosition vacantPosition;
ClassDrawSpecification() : ntimes(0), vacantPosition(oEvent::VacantPosition::Mixed) {}
ClassDrawSpecification(int classID, int leg, int firstStart, int interval, int vacances, oEvent::VacantPosition vp) :
classID(classID), leg(leg), firstStart(firstStart),
interval(interval), vacances(vacances), ntimes(0) {}
interval(interval), vacances(vacances), ntimes(0), vacantPosition(vp) {}
};

View File

@ -69,7 +69,7 @@ template<typename T, typename Apply> void calculatePlace(vector<ResultCalcData<T
vPlace = 0;
cScore = 0;
pClass cls = it.dst->getClassRef(true);
useResults = cls ? cls->getNoTiming() == false : true;
useResults = true;// cls ? cls->getNoTiming() == false : true;
invalidClass = cls ? cls->getClassStatus() != oClass::Normal : false;
}

View File

@ -51,9 +51,17 @@
#include <fcntl.h>
#include "localizer.h"
#include "iof30interface.h"
#include "gdiconstants.h"
#include "meosdb/sqltypes.h"
FlowOperation importFilterGUI(oEvent *oe,
gdioutput & gdi,
const set<int>& stages,
const vector<string> &idProviders,
set<int> & filter,
string &preferredIdProvider);
string conv_is(int i)
{
char bf[256];
@ -1276,6 +1284,22 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
if (xo && xo.getAttrib("iofVersion")) {
IOF30Interface reader(this, false);
vector<string> idProviders;
reader.prescanCompetitorList(xo);
reader.getIdTypes(idProviders);
if (idProviders.size() > 1) {
string preferredIdProvider;
set<int> dmy;
FlowOperation op = importFilterGUI(oe, gdibase,
{}, idProviders,
dmy, preferredIdProvider);
if (op != FlowContinue)
return;
reader.setPreferredIdType(preferredIdProvider);
}
reader.readCompetitorList(gdibase, xo, personCount);
}
else {
@ -1306,8 +1330,6 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
gdibase.addString("", 0, "Uppdaterar serverns databas...");
gdibase.refresh();
//msUploadRunnerDB(this);
OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this);
if (stat == opStatusFail) {

View File

@ -471,7 +471,6 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
}
}
int width = minSize;
vector<int> row(pps.size(), 0);
vector<wstring> samples(pps.size());
wstring totWord = L"";
@ -527,11 +526,8 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
wstring dummy;
int w = totMeasure.measure(gdi, font, fontFace, dummy);
w = max(w, minSize);
if (large)
return w + 5;
else
return w + 15;
w = max(w, gdi.scaleLength(minSize));
return int(0.5 + (w + (large ? 5 : 15))/gdi.getScale());
}
const wstring & oEvent::formatListString(EPostType type, const pRunner r) const
@ -2416,7 +2412,6 @@ bool oEvent::formatPrintPost(const list<oPrintPost> &ppli, PrintPostInfo &ppi,
}
if (pp.color != colorDefault)
ti->setColor(pp.color);
}
@ -3719,7 +3714,7 @@ void oEvent::generateListInfo(EStdListType lt, const gdioutput &gdi, int classId
par.listCode=lt;
generateListInfo(par, gdi.getLineHeight(), li);
generateListInfo(par, li);
}
int openRunnerTeamCB(gdioutput *gdi, int type, void *data);
@ -3822,15 +3817,14 @@ void oListInfo::setCallback(GUICALLBACK cb) {
}
}
void oEvent::generateListInfo(oListParam &par, int lineHeight, oListInfo &li) {
void oEvent::generateListInfo(oListParam &par, oListInfo &li) {
vector<oListParam> parV(1, par);
generateListInfo(parV, lineHeight, li);
generateListInfo(parV, li);
}
void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo &li) {
void oEvent::generateListInfo(vector<oListParam> &par, oListInfo &li) {
li.getParam().sourceParam = -1;// Reset source
loadGeneralResults(false, false);
lineHeight = 14;
for (size_t k = 0; k < par.size(); k++) {
par[k].cb = 0;
}
@ -3839,7 +3833,7 @@ void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo
getListTypes(listMap, false);
if (par.size() == 1) {
generateListInfoAux(par[0], lineHeight, li, listMap[par[0].listCode].Name);
generateListInfoAux(par[0], li, listMap[par[0].listCode].Name);
set<int> used;
// Add linked lists
oListParam *cPar = &par[0];
@ -3851,7 +3845,7 @@ void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo
oListParam &nextPar = oe->getListContainer().getParam(cPar->nextList-1);
li.next.push_back(oListInfo());
nextPar.cb = 0;
generateListInfoAux(nextPar, lineHeight, li.next.back(), L"");
generateListInfoAux(nextPar, li.next.back(), L"");
cPar = &nextPar;
}
}
@ -3860,14 +3854,14 @@ void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo
if (k > 0) {
li.next.push_back(oListInfo());
}
generateListInfoAux(par[k], lineHeight, k == 0 ? li : li.next.back(),
generateListInfoAux(par[k], k == 0 ? li : li.next.back(),
li.Name = listMap[par[0].listCode].Name);
}
}
}
void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li, const wstring &name) {
const int lh=lineHeight;
void oEvent::generateListInfoAux(oListParam &par, oListInfo &li, const wstring &name) {
const int lh=14;
const int vspace=lh/2;
int bib;
pair<int, bool> ln;
@ -3896,7 +3890,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
switch (lt) {
case EStdStartList: {
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Startlista - %s")), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Startlista - %s", true)), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
int bib = 0;
@ -3926,7 +3920,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
}
case EStdClubStartList: {
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbstartlista - %s")), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbstartlista - %s", true)), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
if (hasBib(true, true)) {
@ -3964,7 +3958,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
}
case EStdClubResultList: {
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbresultatlista - %s")), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Klubbresultatlista - %s", true)), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, L"", normalText));
@ -3994,7 +3988,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
case EStdRentedCard:
{
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Hyrbricksrapport - %s")), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpName, makeDash(lang.tl(L"Hyrbricksrapport - %s", true)), boldLarge, 0,0));
li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
li.addListPost(oPrintPost(lTotalCounter, L"%s", normalText, 0, 0));
@ -4334,7 +4328,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
mList.addToSubList(lRunnerName);
mList.addToSubList(lRunnerCard).align(lClassStartName);
mList.interpret(this, gdibase, par, lh, li);
mList.interpret(this, gdibase, par, li);
}
li.listType=li.EBaseTypeTeam;
li.listSubType=li.EBaseTypeRunner;
@ -4583,7 +4577,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
mList.setListType(li.EBaseTypeTeam);
mList.setSortOrder(ClassStartTime);
mList.addFilter(EFilterExcludeDNS);
mList.interpret(this, gdibase, par, lh, li);
mList.interpret(this, gdibase, par, li);
break;
}
case EStdPatrolResultList:
@ -4793,10 +4787,10 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
continue;
par.setLegNumberCoded(out[k].second);
if (k == 0)
generateListInfo(par, lineHeight, li);
generateListInfo(par, li);
else {
li.next.push_back(oListInfo());
generateListInfo(par, lineHeight, li.next.back());
generateListInfo(par, li.next.back());
}
}
}
@ -4814,7 +4808,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
break;
default:
if (!getListContainer().interpret(this, gdibase, par, lineHeight, li))
if (!getListContainer().interpret(this, gdibase, par, li))
throw std::exception("Not implemented");
}
}

View File

@ -1557,6 +1557,8 @@ bool oRunner::evaluateCard(bool doApply, vector<int> & MissingPunches,
*refStatus = StatusOutOfCompetition;
else if (hasFlag(TransferFlags::FlagNoTiming))
*refStatus = StatusNoTiming;
else if (clz && clz->getNoTiming())
*refStatus = StatusNoTiming;
}
// Adjust times on course, including finish time
doAdjustTimes(course);
@ -4128,6 +4130,11 @@ void oRunner::fillSpeakerObject(int leg, int courseControlId, int previousContro
getSplitTime(courseControlId, spk.status, spk.runningTime.time);
if (getStatus() == StatusNoTiming || getStatus() == StatusOutOfCompetition) {
if (spk.status == StatusOK)
spk.status = getStatus();
}
if (courseControlId == oPunch::PunchFinish)
spk.timeSinceChange = oe->getComputerTime() - FinishTime;
else
@ -4380,7 +4387,7 @@ void oEvent::analyseDNS(vector<pRunner> &unknown_dns, vector<pRunner> &known_dns
for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end();++it) {
if (!it->isRemoved() && !it->needNoCard()) {
if (it->getStatus() == StatusUnknown)
if (!it->hasFinished())
stUnknown.push_back(&*it);
else if (it->getStatus() == StatusDNS) {
stDNS.push_back(&*it);
@ -5909,14 +5916,14 @@ void oRunner::setInputData(const oRunner &r) {
}
}
void oEvent::getDBRunnersInEvent(intkeymap<pClass, __int64> &runners) const {
void oEvent::getDBRunnersInEvent(intkeymap<int, __int64> &runners) const {
runners.clear();
for (oRunnerList::const_iterator it = Runners.begin(); it != Runners.end(); ++it) {
if (it->isRemoved())
continue;
__int64 id = it->getExtIdentifier();
if (id != 0)
runners.insert(id, it->Class);
runners.insert(id, it->getId());
}
}
@ -6338,6 +6345,7 @@ void oAbstractRunner::getInputResults(vector<RunnerStatus> &st,
// Add current result to input result. Only use when transferring to next stage
void oAbstractRunner::addToInputResult(int thisStageNo, const oAbstractRunner *src) {
thisStageNo = max(thisStageNo, 0);
int p = src->getPlace();
int rt = src->getRunningTime(true);
RunnerStatus st = src->getStatusComputed();
@ -6594,7 +6602,7 @@ int oRunner::getCheckTime() const {
const pair<wstring, int> oRunner::getRaceInfo() {
pair<wstring, int> res;
RunnerStatus baseStatus = getStatus();
if (baseStatus != StatusUnknown) {
if (hasFinished()) {
int p = getPlace();
int rtComp = getRunningTime(true);
int rtActual = getRunningTime(false);

View File

@ -408,6 +408,7 @@ public:
else
return true;
}
/** Sets the status. If updatePermanent is true, the stored start
time is updated, otherwise the value is considered deduced.
*/
@ -646,7 +647,6 @@ protected:
bool isHiredCard(int card) const;
public:
static const shared_ptr<Table> &getTable(oEvent *oe);
// Get the leg defineing parallel results for this runner (in a team)
@ -655,6 +655,17 @@ public:
// Returns true if there are radio control results, provided result calculation oEvent::ResultType::PreliminarySplitResults was invoked.
bool hasOnCourseResult() const { return !tOnCourseResults.empty() || getFinishTime() > 0 || hasResult(); }
/** Return true if the race is completed (or definitely never will be started), e.g., not in forest*/
bool hasFinished() const {
if (tStatus == StatusUnknown)
return false;
else if (isPossibleResultStatus(tStatus)) {
return Card || FinishTime > 0;
}
else
return true;
}
/** Returns a check time (or zero for no time). */
int getCheckTime() const;

View File

@ -805,6 +805,7 @@ bool oTeam::compareSNO(const oTeam &a, const oTeam &b) {
return a.Class->tSortIndex < b.Class->tSortIndex || (a.Class->tSortIndex == b.Class->tSortIndex && a.Class->Id < b.Class->Id);
else return true;
}
else return false;
}
return CompareString(LOCALE_USER_DEFAULT, 0,
@ -2382,8 +2383,9 @@ oTeam::TeamPlace &oTeam::getTeamPlace(int leg) const {
if (size_t(leg) < tPlace.size())
return tPlace[leg];
if (tComputedResults.empty())
if (tComputedResults.empty() || tPlace.empty())
tPlace.resize(1);
return tPlace[0];
}

View File

@ -290,16 +290,18 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
string nt = gdi.toUTF8(info[k].ti.text);
if (info[k].ti.format & textRight) {
float w = float(info[k].ti.xlimit) * scale*fontScale;
float w = float(info[k].ti.xlimit) * scale;
float sw = HPDF_Page_TextWidth(page, nt.c_str());
float space = info[k].ti.xlimit > 0 ? 2 * HPDF_Page_GetCharSpace(page) : 0;
//float space = info[k].ti.xlimit > 0 ? 2 * HPDF_Page_GetCharSpace(page) : 0;
float space = info[k].ti.xlimit > 0 ? HPDF_Page_TextWidth(page, "-") : 0;
HPDF_Page_TextOut (page, info[k].xp + w - sw - space, h - info[k].yp,
nt.c_str());
}
else if (info[k].ti.format & textCenter) {
float w = float(info[k].ti.xlimit) * scale*fontScale;
float w = float(info[k].ti.xlimit) * scale;
float sw = HPDF_Page_TextWidth(page, nt.c_str());
HPDF_Page_TextOut (page, info[k].xp + w - sw/2, h - info[k].yp,
HPDF_Page_TextOut (page, info[k].xp + (w - sw) *0.5, h - info[k].yp,
nt.c_str());
}
else {

View File

@ -21,15 +21,18 @@ Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "stdafx.h"
#include <thread>
#include <random>
#include <chrono>
#include "oEvent.h"
#include "xmlparser.h"
#include <thread>
#include "restbed/restbed"
#include "meosexception.h"
#include "restserver.h"
#include "infoserver.h"
#include <chrono>
#include "oListInfo.h"
#include "TabList.h"
@ -376,6 +379,16 @@ void RestServer::computeInternal(oEvent &ref, shared_ptr<RestServer::EventReques
string what = rq->parameters.find("lookup")->second;
lookup(ref, what, rq->parameters, rq->answer);
}
else if (rq->parameters.count("difference")) {
string what = rq->parameters.find("difference")->second;
int id = -2;
if (what == "zero")
id = -1;
else
id = atoi(what.c_str());
difference(ref, id, rq->answer);
}
else if (rq->parameters.count("page") > 0) {
string what = rq->parameters.find("page")->second;
auto &writer = HTMLWriter::getWriter(HTMLWriter::TemplateType::Page, what);
@ -424,7 +437,7 @@ void RestServer::computeInternal(oEvent &ref, shared_ptr<RestServer::EventReques
if (!res->second.second) {
res->second.second = make_shared<oListInfo>();
ref.generateListInfo(res->second.first, gdiPrint.getLineHeight(), *res->second.second);
ref.generateListInfo(res->second.first, *res->second.second);
}
ref.generateList(gdiPrint, true, *res->second.second, false);
wstring exportFile = getTempFile();
@ -1100,7 +1113,7 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
xml.write("Card", r->getCardNo());
xml.write("Status", {make_pair("code", itow(r->getStatusComputed()))}, r->getStatusS(true, true));
xml.write("Start", r->getStartTimeS());
if (r->getFinishTime() > 0) {
if (r->getFinishTime() > 0 && r->getStatusComputed() != StatusNoTiming) {
xml.write("Finish", r->getFinishTimeS());
xml.write("RunningTime", r->getRunningTimeS(true));
xml.write("Place", r->getPlaceS());
@ -1112,7 +1125,9 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
if (cls)
xml.write("Leg", cls->getLegNumber(r->getLegNumber()));
}
if ((r->getFinishTime() > 0 || r->getCard() != nullptr) && r->getCourse(false)) {
if ((r->getFinishTime() > 0 || r->getCard() != nullptr) &&
r->getCourse(false) &&
r->getStatusComputed() != StatusNoTiming) {
auto &sd = r->getSplitTimes(false);
vector<int> after;
r->getLegTimeAfter(after);
@ -1343,6 +1358,10 @@ void RestServer::newEntry(oEvent &oe, const multimap<string, string> &param, str
error = L"Anmälan måste hanteras manuellt";
}
bool noTiming = false;
if (param.count("notiming"))
noTiming = true;
int cardNo = 0;
if (param.count("card"))
cardNo = atoi(param.find("card")->second.c_str());
@ -1374,6 +1393,9 @@ void RestServer::newEntry(oEvent &oe, const multimap<string, string> &param, str
}
r->setFlag(oRunner::FlagAddedViaAPI, true);
r->addClassDefaultFee(true);
if (noTiming)
r->setStatus(StatusNoTiming, true, oBase::ChangeType::Update, false);
r->synchronize();
r->markClassChanged(-1);
xml.write("Status", "OK");
@ -1383,6 +1405,8 @@ void RestServer::newEntry(oEvent &oe, const multimap<string, string> &param, str
}
xml.write("Fee", rentCard, itow(r->getDCI().getInt("Fee") + max(cf, 0)));
xml.write("Info", r->getClass(true) + L", " + r->getCompleteIdentification(false));
if (r->getStatus() == StatusNoTiming)
xml.write("NoTiming", "true");
}
}
}
@ -1413,3 +1437,131 @@ vector<pair<wstring, size_t>> RestServer::getPermissionsClass() {
res.emplace_back(lang.tl("Med direktanmälan"), size_t(EntryPermissionClass::DirectEntry));
return res;
}
//constexpr int largePrime = 5000011;
//constexpr int smallPrime = 101;
constexpr int largePrime = 5000011;
constexpr int smallPrime = 101;
constexpr int idOffset = 100;
int RestServer::InfoServerContainer::getNextInstanceId() {
int newInstanceId = (thisInstanceId - idOffset + instanceIncrementor) % (largePrime * smallPrime);
return newInstanceId + idOffset;
}
int RestServer::getNewInstanceId() {
int limit = 10;
if (isContainers.size() > 10) {
isContainers.pop_back();
}
set<int> usedBaseId;
for (auto &c : isContainers) {
int baseId = (c.nextInstanceId - idOffset) % smallPrime;
usedBaseId.insert(baseId);
OutputDebugString((L"used: " + itow(baseId) + L"\n").c_str());
}
if (!randGen) {
random_device r;
randGen = make_shared<default_random_engine>(r());
}
int first = (*randGen)() % smallPrime;
int off = 1 + (*randGen)() % (smallPrime-1);
for (int i = 0; i < smallPrime; i++) {
int s = (first + i * off) % smallPrime;
if (!usedBaseId.count(s)) {
int id = s + smallPrime * ((*randGen)() % 32767) + idOffset;
int f = smallPrime * ((113 + (*randGen)() % 32767) % (largePrime - 1) + 1);
OutputDebugString((L"add: " + itow(s) + L", " + itow(f) + L"\n").c_str());
isContainers.emplace_front(id, f);
return id;
}
}
throw meosException("No server instance found");
}
xmlbuffer * RestServer::getMOPXML(oEvent &oe, int id, int &nextId) {
for (auto it = isContainers.begin(); it != isContainers.end(); ++it) {
auto &c = *it;
if (c.thisInstanceId == id) {
nextId = c.nextInstanceId;
if (it != isContainers.begin())
isContainers.splice(isContainers.begin(), isContainers, it);
return c.lastData.get();
}
else if (c.nextInstanceId == id) {
if (it != isContainers.begin())
isContainers.splice(isContainers.begin(), isContainers, it);
oe.autoSynchronizeLists(true);
if (!c.cmpModel) {
c.cmpModel = make_shared<InfoCompetition>(id);
if (c.classes.empty()) {
vector<pClass> classes;
oe.getClasses(classes, false);
for (pClass pc : classes) {
if (!pc->isQualificationFinalBaseClass())
c.classes.insert(pc->getId());
}
}
if (c.controls.empty()) {
vector<pControl> ctrl;
vector<int> ids;
oe.getControls(ctrl, true);
for (size_t k = 0; k < ctrl.size(); k++) {
if (ctrl[k]->isValidRadio()) {
ctrl[k]->getCourseControls(ids);
c.controls.insert(ids.begin(), ids.end());
}
}
}
}
c.cmpModel->synchronize(oe, false, c.classes, c.controls, true);
c.lastData = make_shared<xmlbuffer>();
c.cmpModel->getDiffXML(*c.lastData);
c.cmpModel->commitComplete();
if (c.lastData->size() == 0) {
nextId = c.nextInstanceId;
return c.lastData.get();
}
c.thisInstanceId = id;
nextId = c.nextInstanceId = c.getNextInstanceId();
return c.lastData.get();
}
}
return nullptr;
}
void RestServer::difference(oEvent &oe, int id, string &answer) {
string type;
if (id == -1) {
id = getNewInstanceId();
}
int nextId;
xmlbuffer *bf = getMOPXML(oe, id, nextId);
if (bf) {
xmlparser mem;
mem.openMemoryOutput(false);
if (bf->isComplete())
type = "MOPComplete";
else
type = "MOPDiff";
mem.startTag(type.c_str(), { L"xmlns", L"http://www.melin.nu/mop",
L"nextdifference", itow(nextId)});
bf->commitCopy(mem);
mem.endTag();
mem.getMemoryOutput(answer);
}
else {
answer = "Error (MeOS): Unknown difference state. Use litteral 'zero' (?difference=zero) to get complete competition";
}
}

View File

@ -31,6 +31,10 @@ Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
#include <deque>
#include <condition_variable>
#include <tuple>
#include <random>
class InfoCompetition;
class xmlbuffer;
namespace restbed {
class Service;
@ -111,6 +115,29 @@ private:
string root;
multimap<string, string> rootMap;
struct InfoServerContainer {
//static int currentInstanceId;
int getNextInstanceId();
const int instanceIncrementor;
int thisInstanceId = -1;
int nextInstanceId;
shared_ptr<InfoCompetition> cmpModel;
shared_ptr<xmlbuffer> lastData;
set<int> classes;
set<int> controls;
InfoServerContainer(int s, int e) : nextInstanceId(s), instanceIncrementor(e) {}
};
shared_ptr<default_random_engine> randGen;
list<InfoServerContainer> isContainers;
int getNewInstanceId();
xmlbuffer *getMOPXML(oEvent &oe, int id, int &nextId);
void difference(oEvent &oe, int id, string &answer);
public:
~RestServer();

View File

@ -53,7 +53,7 @@ void SpeakerMonitor::setClassFilter(const set<int> &filter, const set<int> &cfil
classFilter = filter;
controlIdFilter = cfilter;
oListInfo li;
maxClassNameWidth = li.getMaxCharWidth(&oe, classFilter, lClassName, L"", normalText, false);
maxClassNameWidth = oe.gdiBase().scaleLength(li.getMaxCharWidth(&oe, classFilter, lClassName, L"", normalText, false));
}
void SpeakerMonitor::setLimits(int place, int num) {

View File

@ -2428,7 +2428,7 @@ prefsLastExportTarget = Senaste exportmål
prefsServiceRootMap = Standardfunktion för webbserverns root
prefsshowheader = Visa sidrubriker i listor
Lagändringblankett = Lagändringblankett
Mappa rootadresssen (http:///localhost:port/) till funktion = Mappa rootadresssen (http:///localhost:port/) till funktion
Mappa rootadressen (http:///localhost:port/) till funktion = Mappa rootadressen (http:///localhost:port/) till funktion
ClassAvailableMaps = Klassens lediga kartor
ClassTotalMaps = Klassens antal kartor
Patrol overtime = Patrulls tid övertid
@ -2482,4 +2482,21 @@ Status code for cancelled entry = Statuskod för återbud
Age (on last day of current year) = Ålder vid årets slut
Age above or equal implies senior/pensioner = Åldersgräns äldre/pensionär
Age below or equal implies youth = Åldersgräns ungdom
Status code for not no timing = Statuskod för utan tidtagning
Det finns multiplia Id-nummer för personer = Det finns multiplia Id-nummer för personer
Välj vilken typ du vill importera = Välj vilken typ du vill importera
Status code for no timing = Statuskod för utan tidtagning
prefsVacantPercent = Andel vakanser
Före X = Före X
Efter X = Efter X
Slå ihop X = Slå ihop X
Slå ihop med = Slå ihop med
Mellan X och Y = Mellan X och Y
Ett okänt fel inträffade = Ett okänt fel inträffade
Antalet kolumner i urklippet är större än antalet kolumner i tabellen = Antalet kolumner i urklippet är större än antalet kolumner i tabellen
Antalet kolumner i urklipp får inte plats i selektionen = Fler kolumner i urklippet än i selektionen
prefsVacantPosition = Placering av vakanser
Vakansplacering = Vakansplacering
Först = Först
Lottat = Lottat
Sist = Sist
Fakturadatum = Fakturadatum

View File

@ -137,11 +137,10 @@ void TestMeOS::runProtected(bool protect) const {
oe_main->setProperty("TestPath", tp);
oe_main->getPropertyInt("UseEventor", 1);
oe_main->setProperty("Interactive", 0);
oe_main->backupRunnerDatabase();
TabSI *tsi = dynamic_cast<TabSI*>(gdi_main->getTabs().get(TabType::TSITab));
tsi->setMode(TabSI::ModeReadOut);
tsi->clearQueue();
//string pmOrig = oe_main->getPropertyString("PayModes", "");
//oe_main->setProperty("PayModes", "");
OutputDebugString((L"Running test" + gdi_main->widen(test) + L"\n").c_str());
try {
@ -161,20 +160,20 @@ void TestMeOS::runProtected(bool protect) const {
catch (const meosAssertionFailure & ex) {
OutputDebugString(L"Test FAILED (assert)\n");
status = FAILED;
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, "");
gdi_main->isTestMode = false;
subWindows.clear();
message = ex.message;
//oe_main->setProperty("PayModes", pmOrig);
if (!protect)
throw meosException(message);
}
catch (const std::exception &ex) {
status = FAILED;
OutputDebugString(L"Test FAILED (std)\n");
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, "");
@ -189,18 +188,18 @@ void TestMeOS::runProtected(bool protect) const {
OutputDebugString(L"Test FAILED (...)\n");
status = FAILED;
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, "");
gdi_main->isTestMode = false;
subWindows.clear();
//oe_main->setProperty("PayModes", pmOrig);
message = L"Unknown Exception";
cleanup();
if (!protect)
throw;
}
//oe_main->setProperty("PayModes", pmOrig);
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false);
gdi_main->dbRegisterSubCommand(0, "");
for (size_t k = 0; k < tmpFiles.size(); k++)