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; bool disablePermisson = true;
gdi.popX(); 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.addInput("RootMap", gdi.recodeToWide(rootMap));
gdi.setInputStatus("RootMap", !rootMap.empty()); gdi.setInputStatus("RootMap", !rootMap.empty());

View File

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

View File

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

View File

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

View File

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

View File

@ -79,8 +79,9 @@ class TabClass :
set<oEvent::DrawMethod> getSupportedDrawMethods(bool multiDay) const; set<oEvent::DrawMethod> getSupportedDrawMethods(bool multiDay) const;
void drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClass &cls); void drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClass &cls);
void pursuitDialog(gdioutput &gdi); 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, int time, bool absTime);
bool warnDrawStartTime(gdioutput &gdi, const wstring &firstStart); bool warnDrawStartTime(gdioutput &gdi, const wstring &firstStart);
@ -117,7 +118,7 @@ class TabClass :
void showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK classesCB) const; void showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK classesCB) const;
// Set simultaneous start in a class // 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 updateFairForking(gdioutput &gdi, pClass pc) const;
void selectCourses(gdioutput &gdi, int legNo); 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); oClub::definedPayModes(*oe, dpm);
pc->generateInvoice(gdi, pay, paid, dpm, ppm); 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); "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, "Print", "Skriv ut...", ClubsCB,
"Skriv ut fakturan", true, false); "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, "PDF", "PDF...", ClubsCB,
"Spara som PDF.", true, false); "Spara som PDF.", true, false);
gdi.refresh(); gdi.refresh();
@ -299,16 +299,20 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
} }
else if (bi.id == "InvoiceSettings") { else if (bi.id == "InvoiceSettings") {
gdi.clearPage(true); gdi.clearPage(true);
gdi.pushX();
gdi.addString("", boldLarge, "Fakturainställningar"); gdi.addString("", boldLarge, "Fakturainställningar");
gdi.dropLine(); gdi.dropLine();
firstInvoice = oClub::getFirstInvoiceNumber(*oe); firstInvoice = oClub::getFirstInvoiceNumber(*oe);
if (firstInvoice == 0) if (firstInvoice == 0)
firstInvoice = oe->getPropertyInt("FirstInvoice", 1000); firstInvoice = oe->getPropertyInt("FirstInvoice", 1000);
gdi.addInput("FirstInvoice", itow(firstInvoice), 5, 0, L"Första fakturanummer:"); gdi.fillRight();
gdi.addInput("InvoiceDate", oClub::getInvoiceDate(*oe), 16, nullptr, L"Fakturadatum:");
gdi.dropLine(); gdi.addInput("FirstInvoice", itow(firstInvoice), 16, 0, L"Första fakturanummer:");
gdi.addString("", boldText, "Organisatör"); gdi.fillDown();
gdi.popX();
gdi.dropLine(4);
gdi.addString("", fontMediumPlus, "Organisatör");
vector<string> fields; vector<string> fields;
gdi.pushY(); gdi.pushY();
@ -320,7 +324,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
oe->getDI().buildDataFields(gdi, fields, 32); oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine(); gdi.dropLine();
gdi.addString("", boldText, "Betalningsinformation"); gdi.addString("", fontMediumPlus, "Betalningsinformation");
fields.clear(); fields.clear();
fields.push_back("Account"); fields.push_back("Account");
fields.push_back("PaymentDue"); fields.push_back("PaymentDue");
@ -334,7 +338,7 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
gdi.dropLine(2); gdi.dropLine(2);
gdi.popX(); gdi.popX();
gdi.addString("", boldText, "Formatering"); gdi.addString("", fontMediumPlus, "Formatering");
gdi.fillRight(); gdi.fillRight();
gdi.addString("", 0, "Koordinater (mm) för adressfält:"); 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.dropLine(1);
gdi.fillRight(); gdi.fillRight();
gdi.addButton("SaveSettings", "Spara", ClubsCB); gdi.addButton("SaveSettings", "Spara", ClubsCB).setDefault();
gdi.addButton("Cancel", "Avbryt", ClubsCB); gdi.addButton("Cancel", "Avbryt", ClubsCB).setCancel();
gdi.dropLine(2); gdi.dropLine(2);
gdi.setOnClearCb(ClubsCB); gdi.setOnClearCb(ClubsCB);
oe->getDI().fillDataFields(gdi); oe->getDI().fillDataFields(gdi);
} }
else if (bi.id == "SaveSettings") { else if (bi.id == "SaveSettings") {
oe->getDI().saveDataFields(gdi); oe->getDI().saveDataFields(gdi);
@ -376,6 +379,13 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
else else
oe->setProperty("FirstInvoice", fn); 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 xc = gdi.getTextNo("XC");
int yc = gdi.getTextNo("YC"); 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") { else if (bi.id=="Browse") {
vector< pair<wstring, wstring> > ext; 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"); wstring f = gdi.browseForOpen(ext, L"xml");
string id; string id;
@ -1545,7 +1545,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
switch (startType) { switch (startType) {
case SMCommon: 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; drawn = true;
break; break;
@ -1570,7 +1572,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
} }
} }
if (!skip) 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; drawn = true;
break; break;
} }
@ -1766,7 +1770,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
par.setLegNumberCoded(-1); par.setLegNumberCoded(-1);
oListInfo li; oListInfo li;
par.selection = allTransfer; par.selection = allTransfer;
oe->generateListInfo(par, gdi.getLineHeight(), li); oe->generateListInfo(par, li);
gdioutput tGdi("temp", gdi.getScale()); gdioutput tGdi("temp", gdi.getScale());
oe->generateList(tGdi, true, li, false); oe->generateList(tGdi, true, li, false);
HTMLWriter::writeTableHTML(tGdi, save, oe->getName(), 0, 1.0); 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.showSplitTimes = true;
par.setLegNumberCoded(-1); par.setLegNumberCoded(-1);
oListInfo li; oListInfo li;
oe->generateListInfo(par, gdi.getLineHeight(), li); oe->generateListInfo(par, li);
gdioutput tGdi("temp", gdi.getScale()); gdioutput tGdi("temp", gdi.getScale());
oe->generateList(tGdi, true, li, false); oe->generateList(tGdi, true, li, false);
HTMLWriter::writeTableHTML(tGdi, save, oe->getName(), 0, 1.0); HTMLWriter::writeTableHTML(tGdi, save, oe->getName(), 0, 1.0);
@ -3459,7 +3463,7 @@ void TabCompetition::entryForm(gdioutput &gdi, bool isGuide) {
gdi.dropLine(3); 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]; wstring filename[5];
filename[0] = gdi.getText("FileNameCmp"); filename[0] = gdi.getText("FileNameCmp");
filename[1] = gdi.getText("FileNameCls"); filename[1] = gdi.getText("FileNameCls");
@ -3574,8 +3578,14 @@ int stageInfoCB(gdioutput *gdi, int type, void *data)
} }
void mainMessageLoop(HACCEL hAccelTable, DWORD time); 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, const wstring & fname,
set<int>& filter, set<int>& filter,
string &preferredIdProvider) { string &preferredIdProvider) {
@ -3591,6 +3601,16 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
reader.getIdTypes(idProviders); 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 stageFilter = scanFilter.size() > 1;
bool idtype = idProviders.size() > 1; bool idtype = idProviders.size() > 1;
@ -3631,7 +3651,7 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.fillRight(); gdi.fillRight();
gdi.addSelection("IdType", 150, 200, stageInfoCB, L"Välj vilken typ du vill importera:"); gdi.addSelection("IdType", 150, 200, stageInfoCB, L"Välj vilken typ du vill importera:");
int i = 0; int i = 0;
for (string &sn : idProviders) { for (const string &sn : idProviders) {
gdi.addItem("IdType", gdi.widen(sn), i++); gdi.addItem("IdType", gdi.widen(sn), i++);
} }
} }

View File

@ -22,7 +22,7 @@
************************************************************************/ ************************************************************************/
#include "tabbase.h" #include "tabbase.h"
#include "gdiconstants.h"
#include "oFreeImport.h" #include "oFreeImport.h"
class PrefsEditor; class PrefsEditor;
@ -31,12 +31,6 @@ class ImportFormats;
class TabCompetition : class TabCompetition :
public TabBase public TabBase
{ {
enum FlowOperation {
FlowContinue,
FlowCancel,
FlowAborted
};
wstring eventorBase; wstring eventorBase;
wstring iofExportVersion; wstring iofExportVersion;
void textSizeControl(gdioutput &gdi) const; 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")) if (!gdi.ask(L"warning:drawresult"))
return 0; 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()) if (!clsNames.empty())
clsNames += L", "; clsNames += L", ";
clsNames += cls[k]->getName(); 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++) for (size_t k=0; k<courseDrawClasses.size(); k++)
par.selection.insert(courseDrawClasses[k].classID); par.selection.insert(courseDrawClasses[k].classID);
oe->generateListInfo(par, gdi.getLineHeight(), info); oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true); oe->generateList(gdi, false, info, true);
gdi.refresh(); gdi.refresh();
} }

View File

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

View File

@ -1944,7 +1944,7 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
par.selection.insert(classId); par.selection.insert(classId);
oListInfo info; oListInfo info;
par.listCode = EStdStartList; par.listCode = EStdStartList;
oe->generateListInfo(par, gdi.getLineHeight(), info); oe->generateListInfo(par, info);
oe->generateList(gdi, false, info, true); 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")); 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::FlagTransferSpecified, gdi.hasWidget("AllStages"));
r->setFlag(oRunner::FlagTransferNew, gdi.isChecked("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.setCX(gdi.getCX()+gdi.scaleLength(20));
gdi.addCheckbox("RentCard", "Hyrbricka", SportIdentCB, storedInfo.rentState); gdi.addCheckbox("RentCard", "Hyrbricka", SportIdentCB, storedInfo.rentState);
gdi.addCheckbox("NoTiming", "Utan tidtagning", nullptr, false);
if (oe->hasNextStage()) if (oe->hasNextStage())
gdi.addCheckbox("AllStages", "Anmäl till efterföljande etapper", SportIdentCB, storedInfo.allStages); 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")) if (gdi.hasWidget("Fee"))
gdi.setText("Fee", oe->formatCurrency(dci.getInt("Fee"))); gdi.setText("Fee", oe->formatCurrency(dci.getInt("Fee")));
gdi.setText("StartTime", r->getStartTimeS());
gdi.setText("Phone", dci.getString("Phone")); gdi.setText("Phone", dci.getString("Phone"));
gdi.setText("Bib", r->getBib()); gdi.setText("Bib", r->getBib());
gdi.check("NoTiming", r->hasFlag(oAbstractRunner::TransferFlags::FlagNoTiming));
gdi.check("RentCard", dci.getInt("CardFee") != 0); gdi.check("RentCard", dci.getInt("CardFee") != 0);
if (gdi.hasWidget("Paid")) if (gdi.hasWidget("Paid"))
gdi.check("Paid", dci.getInt("Paid")>0); 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; int numberPos = xp;
xp += gdi.scaleLength(25); xp += gdi.scaleLength(25);
int dx[6] = {0, 184, 220, 290, 316, 364}; int dx[6] = {0, 184, 220, 290, 316, 364};
for (int i = 0; i<6; i++) dx[1] = gdi.getInputDimension(18).first + gdi.scaleLength(4);
dx[i] = gdi.scaleLength(dx[i]); 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[0], 0, "Namn:");
gdi.addString("", yp, xp + dx[2], 0, "Bricka:"); gdi.addString("", yp, xp + dx[2], 0, "Bricka:");
@ -1225,7 +1226,7 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
gdi.dropLine(0.5); gdi.dropLine(0.5);
for (unsigned i = 0; i < pc->getNumStages(); i++) { for (unsigned i = 0; i < pc->getNumStages(); i++) {
yp = gdi.getCY(); yp = gdi.getCY() - gdi.scaleLength(3);
sprintf_s(bf, "R%d", i); sprintf_s(bf, "R%d", i);
gdi.pushX(); gdi.pushX();
@ -1242,7 +1243,6 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
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 { else {
//gdi.addInput(bf, "", 24);
gdi.addInput(xp + dx[0], yp, bf, L"", 18, 0);//Name gdi.addInput(xp + dx[0], yp, bf, L"", 18, 0);//Name
gdi.disableInput(bf); gdi.disableInput(bf);
} }
@ -1253,7 +1253,6 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
gdi.dropLine(0.5); gdi.dropLine(0.5);
gdi.popX(); gdi.popX();
if (t) { if (t) {
pRunner r = t->getRunner(i); pRunner r = t->getRunner(i);
if (r) { if (r) {

View File

@ -2045,7 +2045,7 @@ void Table::importClipboard(gdioutput &gdi)
tw = max(tw, table[k].size()); tw = max(tw, table[k].size());
if (tw > columns.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 (upperRow == -1) {
if (!gdi.ask(L"Vill du klistra in X nya rader i tabellen?#"+itow(table.size()))) 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); getRowRange(row1, row2);
if ( (row1 + table.size()) > sortIndex.size() ) 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() ) 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; 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. 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. info:pageswithcolumns = Vis listen en side af gangen med det angivne antal kolonner. Genindlæs listen automatisk efter hvert gennemløb.
Övrigt = Øvrigt Ö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 prefsshowheader = Show page headers
help:registerhiredcards = Preregister punching cards as rental cards to get automatic hired card status when the card is assigned. help:registerhiredcards = Preregister punching cards as rental cards to get automatic hired card status when the card is assigned.
Lagändringblankett = Team Change Form 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 ClassAvailableMaps = Available maps for class
ClassTotalMaps = Total number of maps for class ClassTotalMaps = Total number of maps for class
Kunde inte öppna databasen (X) = Could not connect to database (X) 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 (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 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 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 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. 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 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 ClassAvailableMaps = Cartes disponibles pour la catégorie
ClassTotalMaps = Nombre total de cartes pour la catégorie ClassTotalMaps = Nombre total de cartes pour la catégorie
Export split times = Exporter les temps intermédiaires 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, KC_AUTOCOMPLETE,
}; };
/** Enum used to stack GUI command control, "command line wizard" */
enum FlowOperation {
FlowContinue,
FlowCancel,
FlowAborted
};
const int GDI_BUTTON_SPACING = 8; const int GDI_BUTTON_SPACING = 8;
#endif #endif

View File

@ -1358,6 +1358,15 @@ HFONT gdioutput::getGUIFont() const
return getCurrentFont().getGUIFont(); 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, InputInfo &gdioutput::addInput(int x, int y, const string &id, const wstring &text,
int length, GUICALLBACK cb, int length, GUICALLBACK cb,
const wstring &explanation, const wstring &help) { 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; 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 ox=OffsetX;
int oy=OffsetY; int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(),
WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | ES_AUTOHSCROLL | WS_BORDER, 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); hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
int mrg = scaleLength(4);
updatePos(x, y, length*size.cx+scaleLength(12), size.cy+scaleLength(10)); updatePos(x, y, dim.first+mrg, dim.second+mrg);
SendMessage(ii.hWnd, WM_SETFONT, SendMessage(ii.hWnd, WM_SETFONT,
(WPARAM) getGUIFont(), 0); (WPARAM) getGUIFont(), 0);
ii.xp=x; ii.xp=x;
ii.yp=y; ii.yp=y;
ii.width = length*size.cx+scaleLength(8); ii.width = dim.first;
ii.height = size.cy+scaleLength(6); ii.height = dim.second;
ii.text = text; ii.text = text;
ii.original = text; ii.original = text;
ii.focusText = text; ii.focusText = text;

View File

@ -684,6 +684,9 @@ public:
bool isInputChanged(const string &exclude); 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, InputInfo &addInput(const string &id, const wstring &text = L"", int length=16, GUICALLBACK cb=0,
const wstring &Explanation = L"", const wstring &tooltip=L""); const wstring &Explanation = L"", const wstring &tooltip=L"");
InputInfo &addInput(int x, int y, const string &id, const wstring &text, int length, 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("StatusDQ", "Status code for disqualification", false);
parser.declareSymbol("StatusOutOfCompetition", "Status code for running out-of-competition", false); parser.declareSymbol("StatusOutOfCompetition", "Status code for running out-of-competition", false);
parser.declareSymbol("StatusNotCompetiting", "Status code for not competing", 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); parser.declareSymbol("ShortestClassTime", "Shortest time in class", false);

View File

@ -1,4 +1,5 @@
<image source="/meos?image=meos"><br> <image source="/meos?image=meos">
<br>
<h1>Documentation of MeOS REST API</h1> <h1>Documentation of MeOS REST API</h1>
<h2>Competition</h2> <h2>Competition</h2>
@ -58,8 +59,11 @@ controls are only for convenience.
<pre>/meos?get=competitor#class=*c1>,*c2>,...</pre> <pre>/meos?get=competitor#class=*c1>,*c2>,...</pre>
<b>Arguments:</b> <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. <ul>
</li></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> <b>Returns:</b>
<p>MOP Competitors XML</p> <p>MOP Competitors XML</p>
@ -67,12 +71,12 @@ controls are only for convenience.
<b>Example:</b> <b>Example:</b>
<pre> <pre>
*MOPComplete> *MOPComplete>
*cmp id="3565"> *cmp id="3565" card="101050">
*base org="570" cls="5" stat="1" st="360000" rt="20580">Elsa Winter*/base> *base org="570" cls="5" stat="1" st="360000" rt="20580" nat="NOR">Elsa Winter*/base>
*input it="20340" tstat="1"/> *input it="20340" tstat="1"/>
*/cmp> */cmp>
*cmp id="55851"> *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> */cmp>
*/MOPComplete> */MOPComplete>
</pre> </pre>
@ -80,7 +84,7 @@ controls are only for convenience.
<b>Remarks:</b> <b>Remarks:</b>
Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference. Please refer to the MOP documentation for a complete description of all attributes. Below is a quick reference.
<ul> <ul>
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li> <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>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>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/it</i> Input running time accumulated from earlier races. In 1/10 seconds.</li>
@ -93,8 +97,11 @@ Please refer to the MOP documentation for a complete description of all attribut
<pre>/meos?get=team#class=*c1>,*c2>,...</pre> <pre>/meos?get=team#class=*c1>,*c2>,...</pre>
<b>Arguments:</b> <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. <ul>
</li></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> <b>Returns:</b>
<p>MOP Teams XML</p> <p>MOP Teams XML</p>
@ -119,9 +126,11 @@ Please refer to the MOP documentation for a complete description of all attribut
<li><i>stat</i> Status code. 1 is OK, 0 is unknown. Higher codes are used for disqualifications.</li> <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>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>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 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> not be valid for the team, depending on the rules.
</li>
</ul> </ul>
<h2>Organizations and Clubs</h2> <h2>Organizations and Clubs</h2>
@ -141,6 +150,40 @@ Please refer to the MOP documentation for a complete description of all attribut
*/MOPComplete> */MOPComplete>
</pre> </pre>
<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> <h2>Results</h2>
<b>Syntax:</b> <b>Syntax:</b>
<pre><a href="/meos?get=result">/meos?get=result</a></pre> <pre><a href="/meos?get=result">/meos?get=result</a></pre>
@ -157,35 +200,48 @@ Please refer to the MOP documentation for a complete description of all attribut
<b>Arguments:</b> <b>Arguments:</b>
<ul> <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>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. does not visit the control, an empty result set is returned; no error is given.
The default is the start.</li> The default is the start.
<li><i>to</i> Returns the result at a specific control. If a specified class does not visit the control, </li>
an empty result set is returned; no error is given. The default is the finish.</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 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, 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> "1, 2, 3, 4, 5". The default is the last leg.
<li><i>module</i> The result module tag to use for the result calculation. </li>
The support of the leg and control options depends on result module. The default is no module.</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>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 <li>
may be higher than the requested. The default is no limit.</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>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 <b>LegIndividual</b> to calculate individual results. <b>CourseIndividual</b> calculates result
per course, ignoring class. <b>GlobalIndividual</b> calculates results without per course, ignoring class. <b>GlobalIndividual</b> calculates results without
considering classes, <b>LegIndividual</b> calculates results considering classes and legs. 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 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> results. <b>GlobalTeam</b> calculates team results without considering classes.
</li>
</ul> </ul>
<b>Returns:</b> <b>Returns:</b>
<p>MOP Individual or Team Result XML. The result list is sorted according to the result. Note than disqualified <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 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. all radio controls. You may want to filter out such entries, depending on your application.
</p> </p>
@ -366,8 +422,10 @@ When and only when the type is <b>CourseIndividual</b>, the attribute <i>course<
<pre><a href="/meos?lookup=dbcompetitor&name=%dbname%&club=%dbclub%">/meos?lookup=dbcompetitor&name=*name>&club=*club></a></pre> <pre><a href="/meos?lookup=dbcompetitor&name=%dbname%&club=%dbclub%">/meos?lookup=dbcompetitor&name=*name>&club=*club></a></pre>
<b>Returns:</b> <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. <p>
This query is suitable for auto complete functionality.</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> <b>Arguments:</b>
<ul> <ul>
@ -398,8 +456,10 @@ This query is suitable for auto complete functionality.</p>
<pre><a href="/meos?lookup=dbclub&name=%club%">/meos?lookup=dbclub&name=*name></a></pre> <pre><a href="/meos?lookup=dbclub&name=%club%">/meos?lookup=dbclub&name=*name></a></pre>
<b>Returns:</b> <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. <p>
This query is suitable for auto complete functionality.</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> <b>Arguments:</b>
<ul> <ul>
@ -418,7 +478,7 @@ This query is suitable for auto complete functionality.</p>
<h2>API New Entry</h2> <h2>API New Entry</h2>
<b>Syntax:</b> <b>Syntax:</b>
<pre>/meos?entry&id=*id>&class=*classid>&card=*card></pre> <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> <b>Arguments:</b>
<ul> <ul>
@ -427,12 +487,13 @@ This query is suitable for auto complete functionality.</p>
<li><i>club</i> Name of runner's club.</li> <li><i>club</i> Name of runner's club.</li>
<li><i>class</i> Id of class.</li> <li><i>class</i> Id of class.</li>
<li><i>card</i> Card number.</li> <li><i>card</i> Card number.</li>
<li><i>notiming</i> Set status no timing.</li>
</ul> </ul>
<p></p><b>Returns:</b> <p><b>Returns:</b>
Status.</p> 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> <i>hiredCard</i> will be set in the Fee attribute. The returned fee includes any rental card fee.</p>
<pre> <pre>

View File

@ -427,9 +427,12 @@ void InfoMeosStatus::serialize(xmlbuffer &xml, bool diffOnly) const {
bool InfoOrganization::synchronize(oClub &c) { bool InfoOrganization::synchronize(oClub &c) {
const wstring &n = c.getDisplayName(); const wstring &n = c.getDisplayName();
if (n == name) const wstring &nat = c.getDCI().getString("Nationality");
if (n == name && nat == nationality)
return false; return false;
else { else {
nationality = nat;
name = n; name = n;
modified(); modified();
} }
@ -439,6 +442,8 @@ bool InfoOrganization::synchronize(oClub &c) {
void InfoOrganization::serialize(xmlbuffer &xml, bool diffOnly) const { void InfoOrganization::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > prop; vector< pair<string, wstring> > prop;
prop.push_back(make_pair("id", itow(getId()))); prop.push_back(make_pair("id", itow(getId())));
if (!nationality.empty())
prop.emplace_back("nat", nationality);
xml.write("org", prop, name); xml.write("org", prop, name);
} }
@ -461,9 +466,11 @@ void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) co
if (course != 0) if (course != 0)
prop.emplace_back("crs", itow(course)); prop.emplace_back("crs", itow(course));
if (!bib.empty()) { if (!bib.empty())
prop.emplace_back("bib", bib); prop.emplace_back("bib", bib);
}
if (!nationality.empty())
prop.emplace_back("nat", nationality);
xml.write("base", prop, name); xml.write("base", prop, name);
} }
@ -488,11 +495,21 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
ch = true; 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; int rt = bc.getRunningTime(true) * 10;
if (rt > 0) { if (rt > 0) {
if (s == RunnerStatus::StatusUnknown) if (s == RunnerStatus::StatusUnknown)
s = RunnerStatus::StatusOK; s = RunnerStatus::StatusOK;
if (s == RunnerStatus::StatusNoTiming)
rt = 0;
} }
else if (isPossibleResultStatus(s)) else if (isPossibleResultStatus(s))
s = StatusUnknown; s = StatusUnknown;
@ -583,7 +600,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
} }
bool nr; 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; vector<pFreePunch> pv;
r.getEvent()->getPunchesForRunner(r.getId(), false, pv); r.getEvent()->getPunchesForRunner(r.getId(), false, pv);
nr = pv.size() > 0; nr = pv.size() > 0;
@ -597,7 +614,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
} }
vector<RadioTime> newRT; 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()); const vector<int> &radios = cmp.getControls(r.getClassId(true), r.getLegNumber());
for (size_t k = 0; k < radios.size(); k++) { for (size_t k = 0; k < radios.size(); k++) {
RadioTime radioTime; 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) { if (newRT != radioTimes) {
ch = true; ch = true;
changeRadio = true; changeRadio = true;
@ -879,3 +896,33 @@ bool xmlbuffer::commit(xmlparser &xml, int count) {
return !blocks.empty(); 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();} size_t size() const {return blocks.size();}
bool commit(xmlparser &xml, int count); bool commit(xmlparser &xml, int count);
void commitCopy(xmlparser &xml);
bool isComplete() const { return complete; }
void startXML(xmlparser &xml, const wstring &dest); void startXML(xmlparser &xml, const wstring &dest);
}; };
@ -140,6 +142,7 @@ class InfoMeosStatus : public InfoBase {
class InfoOrganization : public InfoBase { class InfoOrganization : public InfoBase {
protected: protected:
wstring name; wstring name;
wstring nationality;
public: public:
InfoOrganization(int id); InfoOrganization(int id);
virtual ~InfoOrganization() {} virtual ~InfoOrganization() {}
@ -169,6 +172,7 @@ class InfoBaseCompetitor : public InfoBase {
int startTime; int startTime;
int runningTime; int runningTime;
wstring bib; wstring bib;
wstring nationality;
void serialize(xmlbuffer &xml, bool diffOnly, int course) const; void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
bool synchronizeBase(oAbstractRunner &bc); bool synchronizeBase(oAbstractRunner &bc);
public: public:

View File

@ -47,13 +47,13 @@ private:
T &rehash(int size, KEY key, const T &value); T &rehash(int size, KEY key, const T &value);
T &get(const KEY key); T &get(const KEY key);
const intkeymap &operator=(const intkeymap &co);
void *lookup(KEY key) const; void *lookup(KEY key) const;
public: public:
virtual ~intkeymap(); virtual ~intkeymap();
intkeymap(int size); intkeymap(int size);
intkeymap(); intkeymap();
intkeymap(const intkeymap &co); intkeymap(const intkeymap &co);
const intkeymap &operator=(const intkeymap &co);
bool empty() const; bool empty() const;
int size() 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() template <class T, class KEY> intkeymap<T, KEY>::~intkeymap()
{ {
delete[] keys; delete[] keys;

View File

@ -492,7 +492,6 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam &team, xmlList &xAss
} }
} }
void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignment, void IOF30Interface::classAssignmentObsolete(gdioutput &gdi, xmlList &xAssignment,
const map<wstring, pCourse> &courses, const map<wstring, pCourse> &courses,
const map<wstring, vector<pCourse> > &coursesFamilies) { 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) { void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount) {
if (!xo) if (!xo)
return; return;
@ -736,15 +752,15 @@ void IOF30Interface::readClubList(gdioutput &gdi, const xmlobject &xo, int &club
void IOF30Interface::prescanEntryList(xmlobject &xo, set<int> &definedStages) { void IOF30Interface::prescanEntryList(xmlobject &xo, set<int> &definedStages) {
definedStages.clear(); definedStages.clear();
xmlList pEntries; xmlList pEntries, work;
xo.getObjects("PersonEntry", pEntries); xo.getObjects("PersonEntry", pEntries);
for (size_t k = 0; k < pEntries.size(); k++) { for (size_t k = 0; k < pEntries.size(); k++) {
prescanEntry(pEntries[k], definedStages); prescanEntry(pEntries[k], definedStages, work);
} }
xo.getObjects("TeamEntry", pEntries); xo.getObjects("TeamEntry", pEntries);
for (size_t k = 0; k < pEntries.size(); k++) { 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; return ix;
} }
void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) { void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages, xmlList &work) {
xmlList races; xmlList &races = work;
xo.getObjects("RaceNumber", races); xo.getObjects("RaceNumber", races);
if (races.empty()) if (races.empty())
xo.getObjects("Race", races); // For unclear reason the attribute is called Race for teams and RaceNumber for persons. 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"); person = teamPerson.getObject("Person");
} }
xmlList ids;
if (person) { if (person) {
person.getObjects("Id", ids); xmlList &ids = work;
string type; string type;
readIdProviders(person, ids, type);
}
}
void IOF30Interface::readIdProviders(xmlobject &person, xmlList &ids, std::string &type)
{
person.getObjects("Id", ids);
if (ids.size() > 1) { if (ids.size() > 1) {
for (auto &id : ids) { for (auto &id : ids) {
id.getObjectString("type", type); id.getObjectString("type", type);
@ -1634,7 +1656,6 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
} }
} }
} }
}
bool IOF30Interface::matchStageFilter(const set<int> &stageFilter, const xmlList &races) { bool IOF30Interface::matchStageFilter(const set<int> &stageFilter, const xmlList &races) {
if (stageFilter.empty() || races.empty()) if (stageFilter.empty() || races.empty())
@ -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(); r->synchronize();
return r; return r;
} }
@ -2766,7 +2803,6 @@ void IOF30Interface::writeCourseInfo(xmlparser &xml, const oCourse &c) {
xml.write("Climb", climb); xml.write("Climb", climb);
} }
wstring formatStatus(RunnerStatus st, bool hasTime) { wstring formatStatus(RunnerStatus st, bool hasTime) {
switch (st) { switch (st) {
case StatusNoTiming: case StatusNoTiming:
@ -2870,6 +2906,9 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
if (r.getStartTime() > 0) if (r.getStartTime() > 0)
xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT)); 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; int finishTime, runningTime, place, after;
RunnerStatus status; RunnerStatus status;
if (!patrolResult) { if (!patrolResult) {
@ -2892,13 +2931,13 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
status = r.getTeam()->getLegStatus(pl, true, false); status = r.getTeam()->getLegStatus(pl, true, false);
} }
if ((r.getClassRef(false) && r.getClassRef(true)->getNoTiming()) || if (!hasTiming) {
r.getStatusComputed() == StatusNoTiming) {
after = -1; after = -1;
runningTime = 0; runningTime = 0;
finishTime = 0;
} }
if (r.getFinishTime() > 0) if (finishTime > 0)
xml.write("FinishTime", oe.getAbsDateTimeISO(finishTime, true, useGMT)); xml.write("FinishTime", oe.getAbsDateTimeISO(finishTime, true, useGMT));
if (runningTime > 0) if (runningTime > 0)
@ -2918,7 +2957,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
if (r.getClassRef(false)) { if (r.getClassRef(false)) {
if (r.statusOK(true) && r.getClassRef(false)->getNoTiming() == false) { if (r.statusOK(true) && hasTiming) {
if (!teamMember && place > 0 && place < 50000) { if (!teamMember && place > 0 && place < 50000) {
xml.write("Position", place); 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) { if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult"); xml.startTag("OverallResult");
int rt = r.getTotalRunningTime(); int rt = r.getTotalRunningTime();
if (rt > 0) if (rt > 0 && hasTiming)
xml.write("Time", rt); xml.write("Time", rt);
bool hasTiming = r.getClassRef(false)->getNoTiming() == false;
RunnerStatus stat = r.getTotalStatus(); RunnerStatus stat = r.getTotalStatus();
int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0; int tleg = r.getLegNumber() >= 0 ? r.getLegNumber() : 0;
@ -3002,7 +3041,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
else else
xml.startTag("SplitTime"); xml.startTag("SplitTime");
xml.write("ControlCode", crs->getControl(k)->getFirstNumber()); 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.write("Time", sp[k].time - r.getStartTime());
xml.endTag(); xml.endTag();
} }
@ -3014,6 +3053,21 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Time", it->first); xml.write("Time", it->first);
xml.endTag(); 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); writeFees(xml, rPerson);
if (!hasTiming) {
xml.startTag("Extensions");
xml.write("TimePresentation", L"false");
xml.endTag();
}
xml.endTag(); xml.endTag();
} }
@ -3464,9 +3524,13 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
if (!person) return false; if (!person) return false;
int pidI;
long long pid;
readId(person, pidI, pid);
/*
wstring pidS; wstring pidS;
person.getObjectString("Id", pidS); person.getObjectString("Id", pidS);xxx
long long pid = oBase::converExtIdentifierString(pidS); long long pid = oBase::converExtIdentifierString(pidS);*/
xmlobject pname = person.getObject("Name"); xmlobject pname = person.getObject("Name");
if (!pname) return false; if (!pname) return false;

View File

@ -167,7 +167,8 @@ class IOF30Interface {
static int getIndexFromLegPos(int leg, int legorder, const vector<LegInfo> &setup); 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 setupClassConfig(int classId, const xmlobject &xTeam, map<int, vector<LegInfo> > &teamClassConfig);
void setupRelayClasses(const 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 readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
void prescanCompetitorList(xmlobject &xo);
void readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount); void readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount);
void readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount); void readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount);

View File

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

View File

@ -30,24 +30,18 @@
//V35: abcdef //V35: abcdef
//V36: abcdef //V36: abcdef
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 972 $"); string revision("$Rev: 1004 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
//ABCDEFGHIJKILMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz //V37: a
//V2: abcdefgh
//V3: abcdefghijklmnopqrstuvxyz
//V31: abcde
//V32: abcdefgh
//V33: abcdefghij
//V34: abcdfge
wstring getMeosDate() { 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); return date.substr(7,10);
} }
wstring getBuildType() { wstring getBuildType() {
return L"Beta 1"; // No parantheses (...) return L"RC1"; // No parantheses (...)
} }
wstring getMajorVersion() { 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"Finspångs SOK");
supp.emplace_back(L"OK Gorm, Denmark"); supp.emplace_back(L"OK Gorm, Denmark");
supp.emplace_back(L"Nyköpings OK"); 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()); reverse(supp.begin(), supp.end());
} }

View File

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

View File

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

View File

@ -54,6 +54,59 @@ oBase::oBase(oEvent *poe) {
localObject = false; 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(){ oBase::~oBase(){
if (myReference) if (myReference)
myReference->ref = nullptr; myReference->ref = nullptr;
@ -64,6 +117,7 @@ void oBase::remove() {
myReference->ref = nullptr; myReference->ref = nullptr;
} }
bool oBase::synchronize(bool writeOnly) bool oBase::synchronize(bool writeOnly)
{ {
if (oe && (changed || transientChanged)) { if (oe && (changed || transientChanged)) {

View File

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

View File

@ -656,11 +656,14 @@ void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid,
data.resPos = gdi.scaleLength(550); data.resPos = gdi.scaleLength(550);
gdi.addString("", ys, xs+data.adrPos, boldHuge, "FAKTURA"); gdi.addString("", ys, xs+data.adrPos, boldHuge, "FAKTURA");
if (number>0) if (number > 0) {
gdi.addStringUT(ys + lh * 3, xs + data.adrPos, fontMedium, lang.tl("Faktura nr") + L": " + itow(number)); 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; int &yp = data.yp;
yp = ys+lh; yp = ys+lh * 2;
wstring ostreet = oe->getDI().getString("Street"); wstring ostreet = oe->getDI().getString("Street");
wstring oaddress = oe->getDI().getString("Address"); wstring oaddress = oe->getDI().getString("Address");
wstring oco = oe->getDI().getString("CareOf"); 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 city = getDCI().getString("ZIP") + L" " + getDCI().getString("City");
wstring country = getDCI().getString("Country"); wstring country = getDCI().getString("Country");
int ayp = ys + 122; int ayp = ys + gdi.scaleLength(122);
const int absX = oe->getPropertyInt("addressxpos", 125); const int absX = oe->getPropertyInt("addressxpos", 125);
int absY = oe->getPropertyInt("addressypos", 50); int absY = oe->getPropertyInt("addressypos", 50);
@ -706,7 +709,7 @@ void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid,
if (!country.empty()) if (!country.empty())
gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, country).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; 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, boldSmall, "Deltagare");
gdi.addString("", yp, xs+data.clsPos, boldSmall, "Klass"); gdi.addString("", yp, xs+data.clsPos, boldSmall, "Klass");
@ -1148,3 +1151,17 @@ bool oClub::operator<(const oClub &c) const {
name.c_str(), name.length(), name.c_str(), name.length(),
c.name.c_str(), c.name.length()) == CSTR_LESS_THAN; 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 void assignInvoiceNumber(oEvent &oe, bool reset);
static int getFirstInvoiceNumber(oEvent &oe); 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); static void definedPayModes(oEvent &oe, map<int, wstring> &definedPayModes);
/** Remove all clubs from a competion (and all belong to club relations)*/ /** Remove all clubs from a competion (and all belong to club relations)*/
static void clearClubs(oEvent &oe); static void clearClubs(oEvent &oe);

View File

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

View File

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

View File

@ -212,6 +212,7 @@ namespace {
void drawMeOSMethod(vector<pRunner> &runners) { void drawMeOSMethod(vector<pRunner> &runners) {
if (runners.empty()) if (runners.empty())
return; return;
map<int, vector<pRunner>> runnersPerClub; map<int, vector<pRunner>> runnersPerClub;
for (pRunner r : runners) for (pRunner r : runners)
runnersPerClub[r->getClubId()].push_back(r); 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) { for (oClassList::iterator it = Classes.begin(); it != Classes.end(); ++it) {
vector<ClassDrawSpecification> spec; 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); drawList(spec, method, 1, drawType);
} }
@ -1120,6 +1121,21 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
if (gdibase.isTest()) if (gdibase.isTest())
InitRanom(0,0); 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) { switch (method) {
case DrawMethod::SOFT: case DrawMethod::SOFT:
drawSOFTMethod(runners, true); drawSOFTMethod(runners, true);
@ -1128,12 +1144,28 @@ void oEvent::drawList(const vector<ClassDrawSpecification> &spec,
drawMeOSMethod(runners); drawMeOSMethod(runners);
break; break;
case DrawMethod::Random: 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; break;
default: default:
throw 0; 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(); int minStartNo = Runners.size();
vector<pair<int, int>> newStartNo; vector<pair<int, int>> newStartNo;
for(unsigned k=0;k<stimes.size(); k++) { 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; delete[] stimes;
} }
void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart, void oEvent::automaticDrawAll(gdioutput &gdi,
const wstring &minIntervall, const wstring &vacances, const wstring &firstStart,
bool lateBefore, bool allowNeighbourSameCourse, DrawMethod method, int pairSize) const wstring &minIntervall,
{ const wstring &vacances,
VacantPosition vp,
bool lateBefore,
bool allowNeighbourSameCourse,
DrawMethod method,
int pairSize) {
gdi.refresh(); gdi.refresh();
const int leg = 0; const int leg = 0;
const double extraFactor = 0.0; const double extraFactor = 0.0;
@ -1350,7 +1387,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
if (it->isRemoved()) if (it->isRemoved())
continue; continue;
vector<ClassDrawSpecification> spec; 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); oe->drawList(spec, DrawMethod::Random, 1, DrawType::DrawAll);
} }
return; return;
@ -1505,9 +1542,9 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
gdi.addString("", 0, L"Lottar: X#" + getClass(ci.classId)->getName()); gdi.addString("", 0, L"Lottar: X#" + getClass(ci.classId)->getName());
vector<ClassDrawSpecification> spec; vector<ClassDrawSpecification> spec;
spec.push_back(ClassDrawSpecification(ci.classId, leg, spec.emplace_back(ci.classId, leg,
di.firstStart + di.baseInterval * ci.firstStart, 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); drawList(spec, method, pairSize, DrawType::DrawAll);
gdi.scrollToBottom(); 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()); gdi.addStringUT(0, lang.tl(L"Lottar efteranmälda: ") + it->getName());
vector<ClassDrawSpecification> spec; 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); drawList(spec, method, 1, lateBefore ? DrawType::RemainingBefore : DrawType::RemainingAfter);
gdi.scrollToBottom(); gdi.scrollToBottom();

View File

@ -22,6 +22,8 @@
************************************************************************/ ************************************************************************/
#include "oEvent.h"
struct ClassDrawSpecification { struct ClassDrawSpecification {
int classID; int classID;
int leg; int leg;
@ -29,11 +31,11 @@ struct ClassDrawSpecification {
mutable int interval; mutable int interval;
int vacances; int vacances;
mutable int ntimes; mutable int ntimes;
oEvent::VacantPosition vacantPosition;
ClassDrawSpecification() : ntimes(0) {} ClassDrawSpecification() : ntimes(0), vacantPosition(oEvent::VacantPosition::Mixed) {}
ClassDrawSpecification(int classID, int leg, int firstStart, int interval, int vacances) : ClassDrawSpecification(int classID, int leg, int firstStart, int interval, int vacances, oEvent::VacantPosition vp) :
classID(classID), leg(leg), firstStart(firstStart), 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; vPlace = 0;
cScore = 0; cScore = 0;
pClass cls = it.dst->getClassRef(true); 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; invalidClass = cls ? cls->getClassStatus() != oClass::Normal : false;
} }

View File

@ -51,9 +51,17 @@
#include <fcntl.h> #include <fcntl.h>
#include "localizer.h" #include "localizer.h"
#include "iof30interface.h" #include "iof30interface.h"
#include "gdiconstants.h"
#include "meosdb/sqltypes.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) string conv_is(int i)
{ {
char bf[256]; char bf[256];
@ -1276,6 +1284,22 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
if (xo && xo.getAttrib("iofVersion")) { if (xo && xo.getAttrib("iofVersion")) {
IOF30Interface reader(this, false); 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); reader.readCompetitorList(gdibase, xo, personCount);
} }
else { else {
@ -1306,8 +1330,6 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
gdibase.addString("", 0, "Uppdaterar serverns databas..."); gdibase.addString("", 0, "Uppdaterar serverns databas...");
gdibase.refresh(); gdibase.refresh();
//msUploadRunnerDB(this);
OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this); OpFailStatus stat = (OpFailStatus)msUploadRunnerDB(this);
if (stat == opStatusFail) { 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<int> row(pps.size(), 0);
vector<wstring> samples(pps.size()); vector<wstring> samples(pps.size());
wstring totWord = L""; wstring totWord = L"";
@ -527,11 +526,8 @@ int oListInfo::getMaxCharWidth(const oEvent *oe,
wstring dummy; wstring dummy;
int w = totMeasure.measure(gdi, font, fontFace, dummy); int w = totMeasure.measure(gdi, font, fontFace, dummy);
w = max(w, minSize); w = max(w, gdi.scaleLength(minSize));
if (large) return int(0.5 + (w + (large ? 5 : 15))/gdi.getScale());
return w + 5;
else
return w + 15;
} }
const wstring & oEvent::formatListString(EPostType type, const pRunner r) const 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) if (pp.color != colorDefault)
ti->setColor(pp.color); ti->setColor(pp.color);
} }
@ -3719,7 +3714,7 @@ void oEvent::generateListInfo(EStdListType lt, const gdioutput &gdi, int classId
par.listCode=lt; par.listCode=lt;
generateListInfo(par, gdi.getLineHeight(), li); generateListInfo(par, li);
} }
int openRunnerTeamCB(gdioutput *gdi, int type, void *data); 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); 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 li.getParam().sourceParam = -1;// Reset source
loadGeneralResults(false, false); loadGeneralResults(false, false);
lineHeight = 14;
for (size_t k = 0; k < par.size(); k++) { for (size_t k = 0; k < par.size(); k++) {
par[k].cb = 0; par[k].cb = 0;
} }
@ -3839,7 +3833,7 @@ void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo
getListTypes(listMap, false); getListTypes(listMap, false);
if (par.size() == 1) { 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; set<int> used;
// Add linked lists // Add linked lists
oListParam *cPar = &par[0]; 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); oListParam &nextPar = oe->getListContainer().getParam(cPar->nextList-1);
li.next.push_back(oListInfo()); li.next.push_back(oListInfo());
nextPar.cb = 0; nextPar.cb = 0;
generateListInfoAux(nextPar, lineHeight, li.next.back(), L""); generateListInfoAux(nextPar, li.next.back(), L"");
cPar = &nextPar; cPar = &nextPar;
} }
} }
@ -3860,14 +3854,14 @@ void oEvent::generateListInfo(vector<oListParam> &par, int lineHeight, oListInfo
if (k > 0) { if (k > 0) {
li.next.push_back(oListInfo()); 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); li.Name = listMap[par[0].listCode].Name);
} }
} }
} }
void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li, const wstring &name) { void oEvent::generateListInfoAux(oListParam &par, oListInfo &li, const wstring &name) {
const int lh=lineHeight; const int lh=14;
const int vspace=lh/2; const int vspace=lh/2;
int bib; int bib;
pair<int, bool> ln; pair<int, bool> ln;
@ -3896,7 +3890,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
switch (lt) { switch (lt) {
case EStdStartList: { 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)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
int bib = 0; int bib = 0;
@ -3926,7 +3920,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
} }
case EStdClubStartList: { 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)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
if (hasBib(true, true)) { if (hasBib(true, true)) {
@ -3964,7 +3958,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
} }
case EStdClubResultList: { 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)); li.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
pos.add("class", li.getMaxCharWidth(this, par.selection, lClassName, L"", normalText)); 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: 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.addHead(oPrintPost(lCmpDate, L"", normalText, 0, 25));
li.addListPost(oPrintPost(lTotalCounter, L"%s", normalText, 0, 0)); 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(lRunnerName);
mList.addToSubList(lRunnerCard).align(lClassStartName); mList.addToSubList(lRunnerCard).align(lClassStartName);
mList.interpret(this, gdibase, par, lh, li); mList.interpret(this, gdibase, par, li);
} }
li.listType=li.EBaseTypeTeam; li.listType=li.EBaseTypeTeam;
li.listSubType=li.EBaseTypeRunner; li.listSubType=li.EBaseTypeRunner;
@ -4583,7 +4577,7 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
mList.setListType(li.EBaseTypeTeam); mList.setListType(li.EBaseTypeTeam);
mList.setSortOrder(ClassStartTime); mList.setSortOrder(ClassStartTime);
mList.addFilter(EFilterExcludeDNS); mList.addFilter(EFilterExcludeDNS);
mList.interpret(this, gdibase, par, lh, li); mList.interpret(this, gdibase, par, li);
break; break;
} }
case EStdPatrolResultList: case EStdPatrolResultList:
@ -4793,10 +4787,10 @@ void oEvent::generateListInfoAux(oListParam &par, int lineHeight, oListInfo &li,
continue; continue;
par.setLegNumberCoded(out[k].second); par.setLegNumberCoded(out[k].second);
if (k == 0) if (k == 0)
generateListInfo(par, lineHeight, li); generateListInfo(par, li);
else { else {
li.next.push_back(oListInfo()); 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; break;
default: default:
if (!getListContainer().interpret(this, gdibase, par, lineHeight, li)) if (!getListContainer().interpret(this, gdibase, par, li))
throw std::exception("Not implemented"); throw std::exception("Not implemented");
} }
} }

View File

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

View File

@ -408,6 +408,7 @@ public:
else else
return true; return true;
} }
/** Sets the status. If updatePermanent is true, the stored start /** Sets the status. If updatePermanent is true, the stored start
time is updated, otherwise the value is considered deduced. time is updated, otherwise the value is considered deduced.
*/ */
@ -646,7 +647,6 @@ protected:
bool isHiredCard(int card) const; bool isHiredCard(int card) const;
public: public:
static const shared_ptr<Table> &getTable(oEvent *oe); static const shared_ptr<Table> &getTable(oEvent *oe);
// Get the leg defineing parallel results for this runner (in a team) // 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. // 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(); } 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). */ /** Returns a check time (or zero for no time). */
int getCheckTime() const; 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); return a.Class->tSortIndex < b.Class->tSortIndex || (a.Class->tSortIndex == b.Class->tSortIndex && a.Class->Id < b.Class->Id);
else return true; else return true;
} }
else return false;
} }
return CompareString(LOCALE_USER_DEFAULT, 0, return CompareString(LOCALE_USER_DEFAULT, 0,
@ -2382,8 +2383,9 @@ oTeam::TeamPlace &oTeam::getTeamPlace(int leg) const {
if (size_t(leg) < tPlace.size()) if (size_t(leg) < tPlace.size())
return tPlace[leg]; return tPlace[leg];
if (tComputedResults.empty()) if (tComputedResults.empty() || tPlace.empty())
tPlace.resize(1); tPlace.resize(1);
return tPlace[0]; return tPlace[0];
} }

View File

@ -290,16 +290,18 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
string nt = gdi.toUTF8(info[k].ti.text); string nt = gdi.toUTF8(info[k].ti.text);
if (info[k].ti.format & textRight) { 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 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, HPDF_Page_TextOut (page, info[k].xp + w - sw - space, h - info[k].yp,
nt.c_str()); nt.c_str());
} }
else if (info[k].ti.format & textCenter) { 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()); 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()); nt.c_str());
} }
else { else {

View File

@ -21,15 +21,18 @@ Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/ ************************************************************************/
#include "stdafx.h" #include "stdafx.h"
#include <thread>
#include <random>
#include <chrono>
#include "oEvent.h" #include "oEvent.h"
#include "xmlparser.h" #include "xmlparser.h"
#include <thread>
#include "restbed/restbed" #include "restbed/restbed"
#include "meosexception.h" #include "meosexception.h"
#include "restserver.h" #include "restserver.h"
#include "infoserver.h" #include "infoserver.h"
#include <chrono>
#include "oListInfo.h" #include "oListInfo.h"
#include "TabList.h" #include "TabList.h"
@ -376,6 +379,16 @@ void RestServer::computeInternal(oEvent &ref, shared_ptr<RestServer::EventReques
string what = rq->parameters.find("lookup")->second; string what = rq->parameters.find("lookup")->second;
lookup(ref, what, rq->parameters, rq->answer); 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) { else if (rq->parameters.count("page") > 0) {
string what = rq->parameters.find("page")->second; string what = rq->parameters.find("page")->second;
auto &writer = HTMLWriter::getWriter(HTMLWriter::TemplateType::Page, what); 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) { if (!res->second.second) {
res->second.second = make_shared<oListInfo>(); 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); ref.generateList(gdiPrint, true, *res->second.second, false);
wstring exportFile = getTempFile(); 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("Card", r->getCardNo());
xml.write("Status", {make_pair("code", itow(r->getStatusComputed()))}, r->getStatusS(true, true)); xml.write("Status", {make_pair("code", itow(r->getStatusComputed()))}, r->getStatusS(true, true));
xml.write("Start", r->getStartTimeS()); xml.write("Start", r->getStartTimeS());
if (r->getFinishTime() > 0) { if (r->getFinishTime() > 0 && r->getStatusComputed() != StatusNoTiming) {
xml.write("Finish", r->getFinishTimeS()); xml.write("Finish", r->getFinishTimeS());
xml.write("RunningTime", r->getRunningTimeS(true)); xml.write("RunningTime", r->getRunningTimeS(true));
xml.write("Place", r->getPlaceS()); xml.write("Place", r->getPlaceS());
@ -1112,7 +1125,9 @@ void RestServer::lookup(oEvent &oe, const string &what, const multimap<string, s
if (cls) if (cls)
xml.write("Leg", cls->getLegNumber(r->getLegNumber())); 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); auto &sd = r->getSplitTimes(false);
vector<int> after; vector<int> after;
r->getLegTimeAfter(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"; error = L"Anmälan måste hanteras manuellt";
} }
bool noTiming = false;
if (param.count("notiming"))
noTiming = true;
int cardNo = 0; int cardNo = 0;
if (param.count("card")) if (param.count("card"))
cardNo = atoi(param.find("card")->second.c_str()); 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->setFlag(oRunner::FlagAddedViaAPI, true);
r->addClassDefaultFee(true); r->addClassDefaultFee(true);
if (noTiming)
r->setStatus(StatusNoTiming, true, oBase::ChangeType::Update, false);
r->synchronize(); r->synchronize();
r->markClassChanged(-1); r->markClassChanged(-1);
xml.write("Status", "OK"); 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("Fee", rentCard, itow(r->getDCI().getInt("Fee") + max(cf, 0)));
xml.write("Info", r->getClass(true) + L", " + r->getCompleteIdentification(false)); 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)); res.emplace_back(lang.tl("Med direktanmälan"), size_t(EntryPermissionClass::DirectEntry));
return res; 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 <deque>
#include <condition_variable> #include <condition_variable>
#include <tuple> #include <tuple>
#include <random>
class InfoCompetition;
class xmlbuffer;
namespace restbed { namespace restbed {
class Service; class Service;
@ -111,6 +115,29 @@ private:
string root; string root;
multimap<string, string> rootMap; 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: public:
~RestServer(); ~RestServer();

View File

@ -53,7 +53,7 @@ void SpeakerMonitor::setClassFilter(const set<int> &filter, const set<int> &cfil
classFilter = filter; classFilter = filter;
controlIdFilter = cfilter; controlIdFilter = cfilter;
oListInfo li; 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) { void SpeakerMonitor::setLimits(int place, int num) {

View File

@ -2428,7 +2428,7 @@ prefsLastExportTarget = Senaste exportmål
prefsServiceRootMap = Standardfunktion för webbserverns root prefsServiceRootMap = Standardfunktion för webbserverns root
prefsshowheader = Visa sidrubriker i listor prefsshowheader = Visa sidrubriker i listor
Lagändringblankett = Lagändringblankett 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 ClassAvailableMaps = Klassens lediga kartor
ClassTotalMaps = Klassens antal kartor ClassTotalMaps = Klassens antal kartor
Patrol overtime = Patrulls tid övertid 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 (on last day of current year) = Ålder vid årets slut
Age above or equal implies senior/pensioner = Åldersgräns äldre/pensionär Age above or equal implies senior/pensioner = Åldersgräns äldre/pensionär
Age below or equal implies youth = Åldersgräns ungdom 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->setProperty("TestPath", tp);
oe_main->getPropertyInt("UseEventor", 1); oe_main->getPropertyInt("UseEventor", 1);
oe_main->setProperty("Interactive", 0); oe_main->setProperty("Interactive", 0);
oe_main->backupRunnerDatabase();
TabSI *tsi = dynamic_cast<TabSI*>(gdi_main->getTabs().get(TabType::TSITab)); TabSI *tsi = dynamic_cast<TabSI*>(gdi_main->getTabs().get(TabType::TSITab));
tsi->setMode(TabSI::ModeReadOut); tsi->setMode(TabSI::ModeReadOut);
tsi->clearQueue(); tsi->clearQueue();
//string pmOrig = oe_main->getPropertyString("PayModes", "");
//oe_main->setProperty("PayModes", "");
OutputDebugString((L"Running test" + gdi_main->widen(test) + L"\n").c_str()); OutputDebugString((L"Running test" + gdi_main->widen(test) + L"\n").c_str());
try { try {
@ -161,20 +160,20 @@ void TestMeOS::runProtected(bool protect) const {
catch (const meosAssertionFailure & ex) { catch (const meosAssertionFailure & ex) {
OutputDebugString(L"Test FAILED (assert)\n"); OutputDebugString(L"Test FAILED (assert)\n");
status = FAILED; status = FAILED;
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false); oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false); gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, ""); gdi_main->dbRegisterSubCommand(0, "");
gdi_main->isTestMode = false; gdi_main->isTestMode = false;
subWindows.clear(); subWindows.clear();
message = ex.message; message = ex.message;
//oe_main->setProperty("PayModes", pmOrig);
if (!protect) if (!protect)
throw meosException(message); throw meosException(message);
} }
catch (const std::exception &ex) { catch (const std::exception &ex) {
status = FAILED; status = FAILED;
OutputDebugString(L"Test FAILED (std)\n"); OutputDebugString(L"Test FAILED (std)\n");
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false); oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false); gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, ""); gdi_main->dbRegisterSubCommand(0, "");
@ -189,18 +188,18 @@ void TestMeOS::runProtected(bool protect) const {
OutputDebugString(L"Test FAILED (...)\n"); OutputDebugString(L"Test FAILED (...)\n");
status = FAILED; status = FAILED;
oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false); oe_main->useDefaultProperties(false);
gdi_main->clearDialogAnswers(false); gdi_main->clearDialogAnswers(false);
gdi_main->dbRegisterSubCommand(0, ""); gdi_main->dbRegisterSubCommand(0, "");
gdi_main->isTestMode = false; gdi_main->isTestMode = false;
subWindows.clear(); subWindows.clear();
//oe_main->setProperty("PayModes", pmOrig);
message = L"Unknown Exception"; message = L"Unknown Exception";
cleanup(); cleanup();
if (!protect) if (!protect)
throw; throw;
} }
//oe_main->setProperty("PayModes", pmOrig); oe_main->restoreRunnerDatabase();
oe_main->useDefaultProperties(false); oe_main->useDefaultProperties(false);
gdi_main->dbRegisterSubCommand(0, ""); gdi_main->dbRegisterSubCommand(0, "");
for (size_t k = 0; k < tmpFiles.size(); k++) for (size_t k = 0; k < tmpFiles.size(); k++)