MeOS version 3.5.826 RC1
This commit is contained in:
parent
4da3c93866
commit
34c8f1e29c
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -41,6 +41,7 @@
|
||||
|
||||
extern gdioutput *gdi_main;
|
||||
|
||||
int RunnerDB::cellEntryIndex = -1;
|
||||
|
||||
RunnerDB::RunnerDB(oEvent *oe_): oe(oe_)
|
||||
{
|
||||
@ -107,12 +108,22 @@ RunnerDBEntryV2::RunnerDBEntryV2()
|
||||
memset(this, 0, sizeof(RunnerDBEntryV2));
|
||||
}
|
||||
|
||||
RunnerDBEntryV3::RunnerDBEntryV3()
|
||||
{
|
||||
memset(this, 0, sizeof(RunnerDBEntryV3));
|
||||
}
|
||||
|
||||
void RunnerWDBEntry::getName(wstring &n) const
|
||||
{
|
||||
initName();
|
||||
n=name;
|
||||
}
|
||||
|
||||
const wchar_t *RunnerWDBEntry::getNameCstr() const {
|
||||
initName();
|
||||
return name;
|
||||
}
|
||||
|
||||
void RunnerWDBEntry::setName(const wchar_t *n)
|
||||
{
|
||||
const int blen = min<int>(wcslen(n)+1, baseNameLength);
|
||||
@ -230,6 +241,22 @@ void RunnerDBEntry::init(const RunnerDBEntryV2 &dbe)
|
||||
extId = dbe.extId;
|
||||
}
|
||||
|
||||
void RunnerDBEntry::init(const RunnerDBEntryV3 &dbe)
|
||||
{
|
||||
memcpy(name, dbe.name, 56);
|
||||
|
||||
cardNo = dbe.cardNo;
|
||||
clubNo = dbe.clubNo;
|
||||
national[0] = dbe.national[0];
|
||||
national[1] = dbe.national[1];
|
||||
national[2] = dbe.national[2];
|
||||
sex = dbe.sex;
|
||||
birthYear = dbe.birthYear;
|
||||
reserved = dbe.reserved;
|
||||
extId = dbe.extId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RunnerWDBEntry::init(RunnerDB *p, size_t ixin) {
|
||||
owner = p;
|
||||
@ -386,6 +413,7 @@ void RunnerDB::importClub(oClub &club, bool matchName)
|
||||
void RunnerDB::compactifyClubs()
|
||||
{
|
||||
chash.clear();
|
||||
clubHash.clear();
|
||||
freeCIx = 0;
|
||||
|
||||
map<int, int> clubmap;
|
||||
@ -611,11 +639,7 @@ bool RunnerDB::getClub(int clubId, wstring &club) const
|
||||
return false;
|
||||
}
|
||||
|
||||
oClub *RunnerDB::getClub(int clubId) const
|
||||
{
|
||||
//map<int,int>::const_iterator it = chash.find(clubId);
|
||||
|
||||
//if (it!=chash.end())
|
||||
oClub *RunnerDB::getClub(int clubId) const {
|
||||
int value;
|
||||
if (chash.lookup(clubId, value))
|
||||
return pClub(&cdb[value]);
|
||||
@ -760,7 +784,7 @@ void RunnerDB::saveRunners(const wstring &file)
|
||||
_SH_DENYWR, _S_IREAD|_S_IWRITE);
|
||||
|
||||
if (f!=-1) {
|
||||
int version = 5460003;
|
||||
int version = 5460004;
|
||||
_write(f, &version, 4);
|
||||
_write(f, &dataDate, 4);
|
||||
_write(f, &dataTime, 4);
|
||||
@ -839,61 +863,83 @@ void RunnerDB::loadRunners(const wstring &file)
|
||||
loadedFromServer = false;
|
||||
|
||||
int len = _filelength(f);
|
||||
if ( (len%sizeof(RunnerDBEntryV1) != 0) && (len % sizeof(RunnerDBEntry) != 12)) {
|
||||
if ( (len%sizeof(RunnerDBEntryV1) != 0) && (len % sizeof(RunnerDBEntryV3) != 12) && (len % sizeof(RunnerDBEntry) != 12)) {
|
||||
_close(f);
|
||||
return;//Failed
|
||||
}
|
||||
int nentry = 0;
|
||||
|
||||
if (len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntry) == 12) {
|
||||
int version;
|
||||
version = 0;
|
||||
dataDate = 0;
|
||||
dataTime = 0;
|
||||
|
||||
int version;
|
||||
if (len % sizeof(RunnerDBEntry) == 12 || len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntryV3) == 12) {
|
||||
_read(f, &version, 4);
|
||||
_read(f, &dataDate, 4);
|
||||
_read(f, &dataTime, 4);
|
||||
}
|
||||
|
||||
if (version == 5460002 || version == 5460003 || version == 5460004) {
|
||||
|
||||
bool migrateV2 = false;
|
||||
bool migrateV3 = false;
|
||||
|
||||
if (version == 5460002) {
|
||||
migrateV2 = true;
|
||||
nentry = (len-12) / sizeof(RunnerDBEntryV2);
|
||||
nentry = (len - 12) / sizeof(RunnerDBEntryV2);
|
||||
}
|
||||
else if (version == 5460003) {
|
||||
nentry = (len-12) / sizeof(RunnerDBEntry);
|
||||
nentry = (len - 12) / sizeof(RunnerDBEntryV3);
|
||||
migrateV3 = true;
|
||||
}
|
||||
else if (version == 5460004) {
|
||||
nentry = (len - 12) / sizeof(RunnerDBEntry);
|
||||
}
|
||||
// Else unknown version: fail
|
||||
|
||||
|
||||
rdb.resize(nentry);
|
||||
if (rdb.empty()) {
|
||||
_close(f);
|
||||
_close(f);
|
||||
return;
|
||||
}
|
||||
rwdb.resize(rdb.size());
|
||||
|
||||
if (!migrateV2) {
|
||||
_read(f, &rdb[0], len-12);
|
||||
if (!migrateV2 && !migrateV3) {
|
||||
_read(f, &rdb[0], len - 12);
|
||||
_close(f);
|
||||
}
|
||||
else {
|
||||
else if (migrateV2) {
|
||||
vector<RunnerDBEntryV2> rdbV2(nentry);
|
||||
_read(f, &rdbV2[0], len-12);
|
||||
_read(f, &rdbV2[0], len - 12);
|
||||
_close(f);
|
||||
|
||||
for (int k=0;k<nentry;k++) {
|
||||
for (int k = 0; k < nentry; k++) {
|
||||
rdb[k].init(rdbV2[k]);
|
||||
rwdb[k].init(this, k);
|
||||
if (!check(rdb[k]))
|
||||
throw meosException(ex);
|
||||
}
|
||||
}
|
||||
else if (migrateV3) {
|
||||
vector<RunnerDBEntryV3> rdbV3(nentry);
|
||||
_read(f, &rdbV3[0], len - 12);
|
||||
_close(f);
|
||||
|
||||
for (int k=0;k<nentry;k++) {
|
||||
for (int k = 0; k < nentry; k++) {
|
||||
rdb[k].init(rdbV3[k]);
|
||||
rwdb[k].init(this, k);
|
||||
if (!check(rdb[k]))
|
||||
throw meosException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < nentry; k++) {
|
||||
rwdb[k].init(this, k);
|
||||
if (!check(rdb[k]))
|
||||
throw meosException(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else { //V1
|
||||
dataDate = 0;
|
||||
dataTime = 0;
|
||||
|
||||
@ -905,7 +951,7 @@ void RunnerDB::loadRunners(const wstring &file)
|
||||
return;
|
||||
}
|
||||
vector<RunnerDBEntryV1> rdbV1(nentry);
|
||||
|
||||
_lseek(f, 0, SEEK_SET);
|
||||
_read(f, &rdbV1[0], len);
|
||||
_close(f);
|
||||
rwdb.resize(rdb.size());
|
||||
@ -986,7 +1032,23 @@ void RunnerDB::updateAdd(const oRunner &r, map<int, int> &clubIdMap)
|
||||
|
||||
RunnerWDBEntry *dbe = getRunnerByCard(r.getCardNo());
|
||||
|
||||
if (dbe == 0) {
|
||||
if (dbe == nullptr) {
|
||||
// Lookup by name
|
||||
setupNameHash();
|
||||
vector<int> ix;
|
||||
wstring cname(canonizeName(r.getName().c_str()));
|
||||
auto it = nhash.find(cname);
|
||||
|
||||
while (it != nhash.end() && cname == it->first) {
|
||||
auto &dbr = rwdb[it->second];
|
||||
if (dbr.dbe().clubNo == localClubId) {
|
||||
dbe = &dbr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dbe == nullptr) {
|
||||
dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo());
|
||||
if (dbe)
|
||||
dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
|
||||
@ -1020,6 +1082,7 @@ void RunnerDB::clearClubs()
|
||||
clearRunners(); // Runners refer to clubs. Clear runners
|
||||
cnhash.clear();
|
||||
chash.clear();
|
||||
clubHash.clear(); // Autocomplete
|
||||
freeCIx = 0;
|
||||
cdb.clear();
|
||||
if (clubTable)
|
||||
@ -1032,6 +1095,8 @@ void RunnerDB::clearRunners()
|
||||
nhash.clear();
|
||||
idhash.clear();
|
||||
rhash.clear();
|
||||
runnerHash.clear(); // Autocomplete
|
||||
runnerHashByClub.clear(); // Autocomplete
|
||||
rdb.clear();
|
||||
rwdb.clear();
|
||||
if (runnerTable)
|
||||
@ -1193,11 +1258,27 @@ void RunnerDB::refreshClubTableData(Table &table) {
|
||||
}
|
||||
|
||||
void RunnerDB::refreshRunnerTableData(Table &table) {
|
||||
oe->getDBRunnersInEvent(runnerInEvent); //XXX
|
||||
for (size_t k = 0; k<oRDB.size(); k++){
|
||||
if (!oRDB[k].isRemoved()) {
|
||||
TableRow *row = table.getRowById(oRDB[k].getIndex() + 1);
|
||||
if (row)
|
||||
if (row) {
|
||||
row->setObject(oRDB[k]);
|
||||
|
||||
oClass *val = 0;
|
||||
bool found = false;
|
||||
|
||||
if (rdb[k].extId != 0)
|
||||
found = runnerInEvent.lookup(rdb[k].extId, val);
|
||||
|
||||
|
||||
if (found && row->getCellType(cellEntryIndex) == cellAction) {
|
||||
row->updateCell(cellEntryIndex, cellEdit, val->getName());
|
||||
}
|
||||
else if (!found && row->getCellType(cellEntryIndex) == cellEdit) {
|
||||
row->updateCell(cellEntryIndex, cellAction, L"@+");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1282,6 +1363,7 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
|
||||
else
|
||||
table.setTableProp(0);
|
||||
|
||||
RunnerDB::cellEntryIndex = row;
|
||||
if (!found)
|
||||
table.set(row++, it, TID_ENTER, L"@+", false, cellAction);
|
||||
else
|
||||
@ -1307,6 +1389,8 @@ bool oDBRunnerEntry::inputData(int id, const wstring &input,
|
||||
r.setName(input.c_str());
|
||||
r.getName(output);
|
||||
db->nhash.clear();
|
||||
db->runnerHash.clear();
|
||||
db->runnerHashByClub.clear();
|
||||
return true;
|
||||
case TID_CARD:
|
||||
db->rhash.remove(rd.cardNo);
|
||||
@ -1459,3 +1543,271 @@ const RunnerDBEntry &RunnerWDBEntry::dbe() const {
|
||||
RunnerDBEntry &RunnerWDBEntry::dbe() {
|
||||
return owner->rdb[ix];
|
||||
}
|
||||
|
||||
|
||||
void RunnerDB::ClubNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key, const wstring &skey) const {
|
||||
for (size_t k = 0; k < index.size(); k++) {
|
||||
int x = index[k];
|
||||
if (db.cdb[x].isRemoved())
|
||||
continue;
|
||||
const wstring &n = db.cdb[x].getCanonizedName();
|
||||
int nMatch = 0;
|
||||
for (size_t k = 0; k < key.size(); k++) {
|
||||
const wchar_t *str = wcsstr(n.c_str(), key[k].c_str());
|
||||
if (str != nullptr)
|
||||
nMatch++;
|
||||
}
|
||||
if (wcsstr(db.cdb[x].getCanonizedNameExact().c_str(), skey.c_str()) != nullptr)
|
||||
nMatch += 3;
|
||||
|
||||
if (nMatch > 0)
|
||||
ix.insert(make_pair(nMatch, x));
|
||||
}
|
||||
}
|
||||
|
||||
void RunnerDB::ClubNodeHash::setupHash(const wstring &key, int keyOffset, int ix) {
|
||||
index.push_back(ix);
|
||||
}
|
||||
|
||||
void RunnerDB::RunnerClubNodeHash::setupHash(const wchar_t *key, int keyOffset, int ix) {
|
||||
index.push_back(ix);
|
||||
}
|
||||
|
||||
void RunnerDB::RunnerClubNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const {
|
||||
wchar_t bf[256];
|
||||
for (size_t k = 0; k < index.size(); k++) {
|
||||
int x = index[k];
|
||||
if (db.rdb[x].isRemoved())
|
||||
continue;
|
||||
const wchar_t *n = db.rwdb[x].getNameCstr();
|
||||
int i = 0, di = 0;
|
||||
while (n[i]) {
|
||||
if (n[i] == ',') {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
bf[di++] = toLowerStripped(n[i++]);
|
||||
}
|
||||
bf[di] = 0;
|
||||
int nMatch = 0;
|
||||
for (size_t k = 0; k < key.size(); k++) {
|
||||
const wchar_t *ref = key[k].c_str();
|
||||
const wchar_t *str = wcsstr(bf, ref);
|
||||
int add = 0;
|
||||
if (str == bf || (str != nullptr && (iswspace(str[-1]) || str[-1]=='-'))) {
|
||||
//Beginning of string or beginning of word
|
||||
int len = 0;
|
||||
while (str[len] && !iswspace(str[len]))
|
||||
len++;
|
||||
|
||||
if (wcsncmp(ref, str, max<int>(len, key[k].length())) == 0)
|
||||
add = 3; // Points for full name
|
||||
else
|
||||
add = 2; // Points for matching beginning of name
|
||||
|
||||
/*if (k > 0 && k + 1 == key.size()) {
|
||||
add *= 2; // Last is full string
|
||||
}*/
|
||||
}
|
||||
else if (str != nullptr && key[k].length() > 3) { // Inner part of name
|
||||
add = 1;
|
||||
}
|
||||
if (nMatch > 1 && add > 1)
|
||||
nMatch = 10 * nMatch + add;
|
||||
else
|
||||
nMatch += add;
|
||||
}
|
||||
|
||||
if (nMatch > 0)
|
||||
ix.insert(make_pair(nMatch, x));
|
||||
}
|
||||
}
|
||||
|
||||
void RunnerDB::RunnerNodeHash::setupHash(const wchar_t *key, int keyOffset, int ix) {
|
||||
index.push_back(ix);
|
||||
}
|
||||
|
||||
void RunnerDB::RunnerNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const {
|
||||
RunnerDB::RunnerClubNodeHash::match(db, ix, key);
|
||||
}
|
||||
|
||||
|
||||
void RunnerDB::setupAutoCompleteHash(AutoHashMode mode) {
|
||||
vector<wstring> names;
|
||||
|
||||
if (mode == AutoHashMode::Clubs) {
|
||||
if (!clubHash.empty())
|
||||
return;
|
||||
|
||||
for (size_t k = 0; k < cdb.size(); k++) {
|
||||
auto &c = cdb[k];
|
||||
canonizeSplitName(c.getName(), names);
|
||||
wstring ccn, ccne;
|
||||
ccne = canonizeName(c.getName().c_str());
|
||||
for (size_t j = 0; j < names.size(); j++) {
|
||||
const wstring &n = names[j];
|
||||
if (j > 0)
|
||||
ccn.append(L" ");
|
||||
ccn += n;
|
||||
int ikey = keyFromString(n, 0);
|
||||
clubHash[ikey].setupHash(n, 2, k);
|
||||
}
|
||||
c.setCanonizedName(std::move(ccn), std::move(ccne));
|
||||
}
|
||||
}
|
||||
else if (mode == AutoHashMode::RunnerClub) {
|
||||
if (!runnerHashByClub.empty())
|
||||
return;
|
||||
for (size_t k = 0; k < rwdb.size(); k++) {
|
||||
int key = rwdb[k].dbe().clubNo;
|
||||
if (key > 0) {
|
||||
runnerHashByClub[key].setupHash(rwdb[k].getNameCstr(), 2, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mode == AutoHashMode::Runners) {
|
||||
if (!runnerHash.empty())
|
||||
return;
|
||||
wstring tn;
|
||||
wchar_t bf[256];
|
||||
vector<int> ps;
|
||||
for (size_t k = 0; k < rwdb.size(); k++) {
|
||||
auto &r = rwdb[k];
|
||||
const wchar_t *name = r.getNameCstr();
|
||||
int ix = 0, iy = 0;
|
||||
ps.resize(1, 0);
|
||||
while (name[ix]) {
|
||||
if (name[ix] != ',') {
|
||||
if (name[ix] == '-' || name[ix] == ' ') {
|
||||
bf[iy] = 0;
|
||||
ps.push_back(iy+1);
|
||||
}
|
||||
else
|
||||
bf[iy] = toLowerStripped(name[ix]);
|
||||
iy++;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
bf[iy] = 0;
|
||||
for (int j : ps) {
|
||||
if (j < iy) {
|
||||
int ikey = keyFromString(bf + j);
|
||||
runnerHash[ikey].setupHash(bf, 2, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<pClub> RunnerDB::getClubSuggestions(const wstring &key, int limit) {
|
||||
setupAutoCompleteHash(AutoHashMode::Clubs);
|
||||
set<pair<int, int>> ix;
|
||||
vector<wstring> nn;
|
||||
wstring cankey = canonizeName(key.c_str());
|
||||
canonizeSplitName(key, nn);
|
||||
for (wstring &part : nn) {
|
||||
int ikey = keyFromString(part, 0);
|
||||
auto res = clubHash.find(ikey);
|
||||
if (res != clubHash.end()) {
|
||||
res->second.match(*this, ix, nn, cankey);
|
||||
}
|
||||
}
|
||||
vector<pClub> ret;
|
||||
vector< pair<int, int> > outOrder;
|
||||
outOrder.reserve(ix.size());
|
||||
for (const pair<int, int> &x : ix) {
|
||||
const wstring &name = cdb[x.second].getCanonizedNameExact();
|
||||
|
||||
double sd = stringDistanceAssymetric(name, cankey);
|
||||
outOrder.emplace_back(-(int(10000.0*(10 * x.first - sd))), x.second);
|
||||
}
|
||||
|
||||
sort(outOrder.begin(), outOrder.end());
|
||||
|
||||
for (const pair<int, int> &x : outOrder) {
|
||||
ret.push_back(&cdb[x.second]);
|
||||
if (ret.size() > size_t(limit))
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<pair<RunnerWDBEntry *, int>> RunnerDB::getRunnerSuggestions(const wstring &key, int clubId, int limit) {
|
||||
if (clubId > 0)
|
||||
setupAutoCompleteHash(AutoHashMode::RunnerClub);
|
||||
else
|
||||
setupAutoCompleteHash(AutoHashMode::Runners);
|
||||
|
||||
vector< pair<int, int> > outOrder;
|
||||
set<pair<int, int>> ix;
|
||||
wchar_t bf[256];
|
||||
int iy = 0;
|
||||
for (size_t k = 0; k < key.length(); k++) {
|
||||
if (key[k] != ',') {
|
||||
|
||||
if (key[k] == '-')
|
||||
bf[k] = ' ';
|
||||
else
|
||||
bf[k] = toLowerStripped(key[k]);
|
||||
|
||||
iy++;
|
||||
if (iy >= 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bf[iy] = 0;
|
||||
wstring cankey = trim(bf);
|
||||
vector<pair<RunnerWDBEntry *, int>> ret;
|
||||
vector<wstring> nameParts;
|
||||
split(cankey, L" ", nameParts);
|
||||
// if (nameParts.size() > 1)
|
||||
// nameParts.push_back(cankey);
|
||||
|
||||
if (clubId > 0) {
|
||||
auto res = runnerHashByClub.find(clubId);
|
||||
if (res != runnerHashByClub.end()) {
|
||||
res->second.match(*this, ix, nameParts);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int np = nameParts.size();
|
||||
if (np > 1)
|
||||
np--;// Last is full string.
|
||||
for (int k = 0; k < np; k++) {
|
||||
wstring &part = nameParts[k];
|
||||
int ikey = keyFromString(part, 0);
|
||||
auto res = runnerHash.find(ikey);
|
||||
if (res != runnerHash.end())
|
||||
res->second.match(*this, ix, nameParts);
|
||||
}
|
||||
|
||||
}
|
||||
if (ix.empty())
|
||||
return ret;
|
||||
|
||||
outOrder.reserve(ix.size());
|
||||
wstring tname;
|
||||
int maxP = 0;
|
||||
for (auto itr = ix.rbegin(); itr != ix.rend(); ++itr) {
|
||||
auto &x = *itr;
|
||||
maxP = max(maxP, x.first);
|
||||
if (x.first <= (maxP - 10) || (outOrder.size() > size_t(limit) && x.first < maxP))
|
||||
break;
|
||||
const wchar_t *name = rwdb[x.second].getNameCstr();
|
||||
const wchar_t *cname = canonizeName(name);
|
||||
tname = cname;
|
||||
double sd = stringDistanceAssymetric(tname, cankey);
|
||||
outOrder.emplace_back(-(int(10000.0*(10 * x.first - sd))), x.second);
|
||||
}
|
||||
|
||||
// Fine-sort on string distance
|
||||
sort(outOrder.begin(), outOrder.end());
|
||||
|
||||
for (const pair<int, int> &x : outOrder) {
|
||||
ret.emplace_back(&rwdb[x.second], x.second);
|
||||
if (ret.size() > size_t(limit))
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
128
code/RunnerDB.h
128
code/RunnerDB.h
@ -2,18 +2,16 @@
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "inthashmap.h"
|
||||
#include "oclub.h"
|
||||
|
||||
#ifdef OLD
|
||||
#include <hash_set>
|
||||
#else
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -33,8 +31,8 @@
|
||||
|
||||
************************************************************************/
|
||||
|
||||
const int baseNameLength=40;
|
||||
const int baseNameLengthUTF=56;
|
||||
const int baseNameLength = 64;
|
||||
const int baseNameLengthUTF = 96;
|
||||
|
||||
//Has 0-clearing constructor. Must not contain any
|
||||
//dynamic data etc.
|
||||
@ -65,18 +63,29 @@ struct RunnerDBEntryV2 {
|
||||
short int reserved;
|
||||
/** End of V1*/
|
||||
__int64 extId;
|
||||
|
||||
bool isRemoved() const {return (reserved & 1) == 1;}
|
||||
void remove() {reserved |= 1;}
|
||||
|
||||
bool isUTF() const {return (reserved & 2) == 2;}
|
||||
void setUTF() {reserved |= 2;}
|
||||
};
|
||||
|
||||
|
||||
struct RunnerDBEntryV3 {
|
||||
// Init from old struct
|
||||
RunnerDBEntryV3();
|
||||
|
||||
char name[56];
|
||||
int cardNo;
|
||||
int clubNo;
|
||||
char national[3];
|
||||
char sex;
|
||||
short int birthYear;
|
||||
short int reserved;
|
||||
/** End of V1*/
|
||||
__int64 extId;
|
||||
};
|
||||
|
||||
struct RunnerDBEntry {
|
||||
// Init from old struct
|
||||
void init(const RunnerDBEntryV2 &dbe);
|
||||
void init(const RunnerDBEntryV3 &dbe);
|
||||
|
||||
RunnerDBEntry();
|
||||
|
||||
// 8 it versions
|
||||
@ -93,11 +102,11 @@ struct RunnerDBEntry {
|
||||
/** End of V1*/
|
||||
__int64 extId;
|
||||
|
||||
bool isRemoved() const {return (reserved & 1) == 1;}
|
||||
void remove() {reserved |= 1;}
|
||||
bool isRemoved() const { return (reserved & 1) == 1; }
|
||||
void remove() { reserved |= 1; }
|
||||
|
||||
bool isUTF() const {return (reserved & 2) == 2;}
|
||||
void setUTF() {reserved |= 2;}
|
||||
bool isUTF() const { return (reserved & 2) == 2; }
|
||||
void setUTF() { reserved |= 2; }
|
||||
};
|
||||
|
||||
class RunnerDB;
|
||||
@ -125,6 +134,9 @@ public:
|
||||
void setName(const wchar_t *name);
|
||||
void setNameUTF(const char *name);
|
||||
|
||||
|
||||
const wchar_t *RunnerWDBEntry::getNameCstr() const;
|
||||
|
||||
wstring getGivenName() const;
|
||||
wstring getFamilyName() const;
|
||||
|
||||
@ -152,6 +164,8 @@ private:
|
||||
Table *runnerTable;
|
||||
Table *clubTable;
|
||||
|
||||
static int cellEntryIndex;
|
||||
|
||||
bool check(const RunnerDBEntry &rde) const;
|
||||
|
||||
intkeymap<oClass *, __int64> runnerInEvent;
|
||||
@ -197,8 +211,74 @@ private:
|
||||
|
||||
void fillClubs(vector< pair<wstring, size_t> > &out) const;
|
||||
|
||||
class ClubNodeHash {
|
||||
//map<wchar_t, ClubNodeHash> hash;
|
||||
vector<int> index;
|
||||
|
||||
public:
|
||||
void setupHash(const wstring &key, int keyOffset, int ix);
|
||||
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key, const wstring &skey) const;
|
||||
};
|
||||
|
||||
class RunnerClubNodeHash {
|
||||
protected:
|
||||
vector<int> index;
|
||||
public:
|
||||
void setupHash(const wchar_t *key, int keyOffset, int ix);
|
||||
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const;
|
||||
};
|
||||
|
||||
class RunnerNodeHash : public RunnerClubNodeHash {
|
||||
map<wchar_t, RunnerNodeHash> hash;
|
||||
public: // Note: Non virtual. No reference by parent type
|
||||
void setupHash(const wchar_t *key, int keyOffset, int ix);
|
||||
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const;
|
||||
};
|
||||
|
||||
unordered_map<int, ClubNodeHash> clubHash;
|
||||
unordered_map<int, RunnerNodeHash> runnerHash;
|
||||
unordered_map<int, RunnerClubNodeHash> runnerHashByClub;
|
||||
|
||||
enum class AutoHashMode {
|
||||
Clubs, Runners, RunnerClub
|
||||
};
|
||||
|
||||
void setupAutoCompleteHash(AutoHashMode mode);
|
||||
|
||||
static int keyFromString(const wstring &n, size_t offset) {
|
||||
pair<wchar_t, wchar_t> key;
|
||||
//static_assert(sizeof(key) == sizeof int);
|
||||
|
||||
if (n.length() == 1 + offset) {
|
||||
key.first = n[offset];
|
||||
key.second = 0;
|
||||
}
|
||||
else if (n.length() > 1 + offset) {
|
||||
key.first = n[offset];
|
||||
key.second = n[offset+1];
|
||||
}
|
||||
int *ikey = static_cast<int *>((void *)&key);
|
||||
|
||||
return *ikey;
|
||||
}
|
||||
|
||||
static int keyFromString(const wchar_t *n) {
|
||||
pair<wchar_t, wchar_t> key;
|
||||
if (n[0] == 0)
|
||||
return 0;
|
||||
else {
|
||||
key.first = n[0];
|
||||
key.second = n[1];
|
||||
}
|
||||
int *ikey = static_cast<int *>((void *)&key);
|
||||
return *ikey;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
vector<pClub> getClubSuggestions(const wstring &key, int limit);
|
||||
vector<pair<RunnerWDBEntry *, int>> getRunnerSuggestions(const wstring &name, int clubId, int limit);
|
||||
|
||||
void generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry);
|
||||
void generateClubTableData(Table &table, oClub *addEntry);
|
||||
|
||||
@ -306,7 +386,21 @@ class oDBClubEntry : public oClub {
|
||||
private:
|
||||
int index;
|
||||
RunnerDB *db;
|
||||
wstring canonizedName;
|
||||
wstring canonizedNameExact;
|
||||
public:
|
||||
|
||||
void setCanonizedName(wstring &&n, wstring &&nExact) {
|
||||
canonizedName = n;
|
||||
canonizedNameExact = nExact;
|
||||
}
|
||||
|
||||
const wstring &getCanonizedName() {
|
||||
return canonizedName;
|
||||
}
|
||||
const wstring &getCanonizedNameExact() {
|
||||
return canonizedNameExact;
|
||||
}
|
||||
oDBClubEntry(oEvent *oe, int id, int index, RunnerDB *db);
|
||||
oDBClubEntry(const oClub &c, int index, RunnerDB *db);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -46,6 +46,22 @@
|
||||
extern pEvent gEvent;
|
||||
const char *visualDrawWindow = "visualdraw";
|
||||
|
||||
|
||||
struct DrawSettingsCSV {
|
||||
int classId;
|
||||
wstring cls;
|
||||
int nCmp;
|
||||
wstring crs;
|
||||
int ctrl;
|
||||
|
||||
int firstStart;
|
||||
int interval;
|
||||
int vacant;
|
||||
|
||||
static void write(gdioutput &gdi, const oEvent &oe, const wstring &fn, vector<DrawSettingsCSV> &arg);
|
||||
static vector<DrawSettingsCSV> read(gdioutput &gdi, const oEvent &oe, const wstring &fn);
|
||||
};
|
||||
|
||||
TabClass::TabClass(oEvent *poe):TabBase(poe)
|
||||
{
|
||||
handleCloseWindow.tabClass = this;
|
||||
@ -133,12 +149,31 @@ int DrawClassesCB(gdioutput *gdi, int type, void *data)
|
||||
InputInfo &ii = *(InputInfo *)data;
|
||||
if (ii.id.length() > 1) {
|
||||
int id = atoi(ii.id.substr(1).c_str());
|
||||
if (id > 0 && ii.changed()) {
|
||||
if (id > 0 ) {
|
||||
bool changed = false;
|
||||
string key = "C" + itos(id);
|
||||
TextInfo &ti = dynamic_cast<TextInfo&>(gdi->getBaseInfo(key.c_str()));
|
||||
ti.setColor(colorRed);
|
||||
gdi->enableInput("DrawAdjust");
|
||||
gdi->refreshFast();
|
||||
if (ii.changed()) {
|
||||
changed = changed || ti.getColor() != colorRed;
|
||||
ti.setColor(colorRed);
|
||||
if (ii.getBgColor() != colorLightCyan) {
|
||||
ii.setBgColor(colorLightCyan).refresh();
|
||||
}
|
||||
gdi->enableInput("DrawAdjust");
|
||||
}
|
||||
else {
|
||||
GDICOLOR def = GDICOLOR(ti.getExtraInt());
|
||||
if (def != ti.getColor()) {
|
||||
ti.setColor(def); // Restore
|
||||
changed = true;
|
||||
}
|
||||
GDICOLOR nColor = ii.getExtraInt() != 0 ? GDICOLOR(ii.getExtraInt()) : colorDefault;
|
||||
if (nColor != ii.getBgColor()) {
|
||||
ii.setBgColor(nColor).refresh();
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
gdi->refreshFast();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -652,18 +687,171 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id=="SaveDrawSettings") {
|
||||
readClassSettings(gdi);
|
||||
for(size_t k=0; k<cInfo.size(); k++) {
|
||||
const ClassInfo &ci = cInfo[k];
|
||||
if (ci.pc) {
|
||||
saveDrawSettings();
|
||||
}
|
||||
else if (bi.id == "ExportDrawSettings") {
|
||||
int fi;
|
||||
wstring fn = gdi.browseForSave({ make_pair(lang.tl("Kalkylblad/csv"), L"*.csv") }, L"csv", fi);
|
||||
|
||||
if (fn.empty())
|
||||
return false;
|
||||
|
||||
vector<DrawSettingsCSV> res;
|
||||
|
||||
if (bi.getExtraInt() == 1) {
|
||||
vector<pClass> cls;
|
||||
oe->getClasses(cls, true);
|
||||
for (pClass pc : cls) {
|
||||
if (pc->hasFreeStart())
|
||||
continue;
|
||||
DrawSettingsCSV ds;
|
||||
ds.classId = pc->getId();
|
||||
ds.cls = pc->getName();
|
||||
ds.nCmp = pc->getNumRunners(1, false, false);
|
||||
pCourse crs = pc->getCourse();
|
||||
pControl ctrl = nullptr;
|
||||
if (crs) {
|
||||
ds.crs = crs->getName();
|
||||
ctrl = crs->getControl(0);
|
||||
}
|
||||
if (ctrl) {
|
||||
ds.ctrl = ctrl->getId();
|
||||
}
|
||||
else ds.ctrl = 0;
|
||||
|
||||
// Save settings with class
|
||||
ci.pc->synchronize(false);
|
||||
ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart);
|
||||
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
|
||||
ci.pc->setDrawVacant(ci.nVacant);
|
||||
ci.pc->setDrawNumReserved(ci.nExtra);
|
||||
ci.pc->synchronize(true);
|
||||
ds.firstStart = 3600;
|
||||
ds.interval = 120;
|
||||
ds.vacant = 1;
|
||||
|
||||
res.push_back(ds);
|
||||
}
|
||||
}
|
||||
else {
|
||||
readClassSettings(gdi);
|
||||
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||
const ClassInfo &ci = cInfo[k];
|
||||
if (ci.pc) {
|
||||
DrawSettingsCSV ds;
|
||||
ds.classId = ci.pc->getId();
|
||||
ds.cls = ci.pc->getName();
|
||||
ds.nCmp = ci.pc->getNumRunners(1, false, false);
|
||||
pCourse crs = ci.pc->getCourse();
|
||||
pControl ctrl = nullptr;
|
||||
if (crs) {
|
||||
ds.crs = crs->getName();
|
||||
ctrl = crs->getControl(0);
|
||||
}
|
||||
|
||||
if (ctrl) {
|
||||
ds.ctrl = ctrl->getId();
|
||||
}
|
||||
else ds.ctrl = 0;
|
||||
|
||||
// Save settings with class
|
||||
ds.firstStart = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
|
||||
ds.interval = ci.interval * drawInfo.baseInterval;
|
||||
ds.vacant = ci.nVacant;
|
||||
|
||||
res.push_back(ds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawSettingsCSV::write(gdi, *oe, fn, res);
|
||||
|
||||
/*csvparser writer;
|
||||
writer.openOutput(fn.c_str());
|
||||
vector<string> header;
|
||||
|
||||
writer.outputRow(header);
|
||||
header.emplace_back("ClassId");
|
||||
header.emplace_back("Class");
|
||||
header.emplace_back("Competitors");
|
||||
header.emplace_back("Course");
|
||||
header.emplace_back("First Control");
|
||||
|
||||
header.emplace_back("First Start");
|
||||
header.emplace_back("Interval");
|
||||
header.emplace_back("Vacant");
|
||||
|
||||
writer.outputRow(header);
|
||||
vector<string> line;
|
||||
|
||||
for (size_t k = 0; k<cInfo.size(); k++) {
|
||||
const ClassInfo &ci = cInfo[k];
|
||||
if (ci.pc) {
|
||||
line.clear();
|
||||
line.push_back(itos(ci.pc->getId()));
|
||||
line.push_back(gdi.toUTF8(ci.pc->getName()));
|
||||
line.push_back(itos(ci.pc->getNumRunners(1, false, false)));
|
||||
pCourse crs = ci.pc->getCourse();
|
||||
pControl ctrl = nullptr;
|
||||
if (crs) {
|
||||
line.push_back(gdi.toUTF8(crs->getName()));
|
||||
ctrl = crs->getControl(0);
|
||||
}
|
||||
else line.emplace_back("");
|
||||
|
||||
if (ctrl) {
|
||||
line.push_back(itos(ctrl->getId()));
|
||||
}
|
||||
else line.emplace_back("");
|
||||
|
||||
// Save settings with class
|
||||
|
||||
line.push_back(gdi.narrow(oe->getAbsTime(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart)));
|
||||
line.push_back(gdi.narrow(formatTime(ci.interval * drawInfo.baseInterval)));
|
||||
line.push_back(itos(ci.nVacant));
|
||||
writer.outputRow(line);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else if (bi.id == "ImportDrawSettings") {
|
||||
|
||||
wstring fn = gdi.browseForOpen({ make_pair(lang.tl("Kalkylblad/csv"), L"*.csv") }, L"csv");
|
||||
|
||||
if (fn.empty())
|
||||
return false;
|
||||
|
||||
wstring firstStart = gdi.getText("FirstStart");
|
||||
wstring minInterval = gdi.getText("MinInterval");
|
||||
wstring vacances = gdi.getText("Vacances");
|
||||
|
||||
clearPage(gdi, false);
|
||||
gdi.addString("", boldLarge, "Lotta flera klasser");
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
gdi.addString("", 0, "Importerar lottningsinställningar...");
|
||||
set<int> classes;
|
||||
for (auto &ds : DrawSettingsCSV::read(gdi, *oe, fn)) {
|
||||
pClass pc = oe->getClass(ds.classId);
|
||||
if (pc) {
|
||||
classes.insert(ds.classId);
|
||||
pc->setDrawFirstStart(ds.firstStart);
|
||||
pc->setDrawInterval(ds.interval);
|
||||
pc->setDrawVacant(ds.vacant);
|
||||
pc->setDrawNumReserved(0);
|
||||
pc->setDrawSpecification({ oClass::DrawSpecified::FixedTime, oClass::DrawSpecified::Vacant});
|
||||
}
|
||||
}
|
||||
|
||||
if (classes.empty()) {
|
||||
throw meosException("Ingen klass vald.");
|
||||
}
|
||||
|
||||
int by = 0;
|
||||
int bx = gdi.getCX();
|
||||
|
||||
loadBasicDrawSetup(gdi, bx, by, firstStart, 1, minInterval, vacances, classes);
|
||||
loadReadyToDistribute(gdi, bx, by);
|
||||
|
||||
oe->loadDrawSettings(classes, drawInfo, cInfo);
|
||||
|
||||
writeDrawInfo(gdi, drawInfo);
|
||||
gdi.enableEditControls(false);
|
||||
|
||||
showClassSettings(gdi);
|
||||
}
|
||||
else if (bi.id=="DoDrawAll") {
|
||||
readClassSettings(gdi);
|
||||
@ -675,19 +863,10 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
int maxST = 0;
|
||||
map<int, vector<ClassDrawSpecification> > specs;
|
||||
saveDrawSettings();
|
||||
for(size_t k=0; k<cInfo.size(); k++) {
|
||||
const ClassInfo &ci=cInfo[k];
|
||||
if (ci.pc) {
|
||||
// Save settings with class
|
||||
ci.pc->synchronize(false);
|
||||
int stloc = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
|
||||
maxST = max(maxST, stloc);
|
||||
ci.pc->setDrawFirstStart(stloc);
|
||||
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
|
||||
ci.pc->setDrawVacant(ci.nVacant);
|
||||
ci.pc->setDrawNumReserved(ci.nExtra);
|
||||
ci.pc->synchronize(true);
|
||||
}
|
||||
|
||||
ClassDrawSpecification cds(ci.classId, 0, drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart,
|
||||
drawInfo.baseInterval * ci.interval, ci.nVacant);
|
||||
if (drawCoursebased) {
|
||||
@ -791,7 +970,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.popX();
|
||||
gdi.fillRight();
|
||||
gdi.addButton("AutomaticDraw", "Automatisk lottning", ClassesCB).setDefault();
|
||||
gdi.addButton("AutomaticDraw", "Automatisk lottning", ClassesCB);
|
||||
gdi.addButton("DrawAll", "Manuell lottning", ClassesCB).setExtra(1);
|
||||
gdi.addButton("Simultaneous", "Gemensam start", ClassesCB);
|
||||
|
||||
@ -802,7 +981,24 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.addButton("Cancel", "Återgå", ClassesCB).setCancel();
|
||||
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
int xs = gdi.getCX();
|
||||
int ys = gdi.getCY();
|
||||
gdi.dropLine();
|
||||
gdi.setCX(xs + gdi.getLineHeight());
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.addString("", 10, "help:exportdraw");
|
||||
gdi.dropLine(0.5);
|
||||
gdi.fillRight();
|
||||
gdi.addButton("ExportDrawSettings", "Exportera", ClassesCB).setExtra(1);
|
||||
gdi.addButton("ImportDrawSettings", "Importera", ClassesCB);
|
||||
|
||||
gdi.dropLine(2.5);
|
||||
RECT rc = {xs, ys, gdi.getWidth(), gdi.getCY()};
|
||||
gdi.addRectangle(rc, colorLightCyan);
|
||||
|
||||
gdi.newColumn();
|
||||
|
||||
@ -996,11 +1192,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
clearPage(gdi, false);
|
||||
gdi.addString("", boldLarge, "Lotta flera klasser");
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
showClassSelection(gdi, bx, by, DrawClassesCB);
|
||||
vector<pClass> cls;
|
||||
oe->getClasses(cls, false);
|
||||
set<int> clsId;
|
||||
@ -1012,64 +1203,11 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
clsId.insert(cls[k]->getId());
|
||||
}
|
||||
|
||||
gdi.setSelection("Classes", clsId);
|
||||
|
||||
gdi.addString("", 1, "Grundinställningar");
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
|
||||
gdi.addInput("FirstStart", firstStart, 10, 0, L"Första start:");
|
||||
gdi.addInput("nFields", L"10", 10, 0, L"Max parallellt startande:");
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addSelection("MaxCommonControl", 150, 100, 0,
|
||||
L"Max antal gemensamma kontroller:");
|
||||
|
||||
vector< pair<wstring, size_t> > items;
|
||||
items.push_back(make_pair(lang.tl("Inga"), 1));
|
||||
items.push_back(make_pair(lang.tl("Första kontrollen"), 2));
|
||||
for (int k = 2; k<10; k++)
|
||||
items.push_back(make_pair(lang.tl("X kontroller#" + itos(k)), k+1));
|
||||
items.push_back(make_pair(lang.tl("Hela banan"), 1000));
|
||||
gdi.addItem("MaxCommonControl", items);
|
||||
gdi.selectItemByData("MaxCommonControl", maxNumControl);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(4);
|
||||
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, true);
|
||||
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(2);
|
||||
gdi.addString("", 1, "Startintervall");
|
||||
gdi.dropLine(1.4);
|
||||
gdi.popX();
|
||||
gdi.fillRight();
|
||||
gdi.addInput("BaseInterval", L"1:00", 10, 0, L"Basintervall (min):");
|
||||
gdi.addInput("MinInterval", minInterval, 10, 0, L"Minsta intervall i klass:");
|
||||
gdi.addInput("MaxInterval", minInterval, 10, 0, L"Största intervall i klass:");
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(4);
|
||||
gdi.addString("", 1, "Vakanser och efteranmälda");
|
||||
gdi.dropLine(1.4);
|
||||
gdi.popX();
|
||||
gdi.addInput("Vacances", vacances, 10, 0, L"Andel vakanser:");
|
||||
gdi.addInput("VacancesMin", L"1", 10, 0, L"Min. vakanser (per klass):");
|
||||
gdi.addInput("VacancesMax", L"10", 10, 0, L"Max. vakanser (per klass):");
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addInput("Extra", L"0%", 10, 0, L"Förväntad andel efteranmälda:");
|
||||
|
||||
gdi.dropLine(4);
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
gdi.setRestorePoint("Setup");
|
||||
clearPage(gdi, false);
|
||||
gdi.addString("", boldLarge, "Lotta flera klasser");
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
loadBasicDrawSetup(gdi, bx, by, firstStart, maxNumControl, minInterval, vacances, clsId);
|
||||
}
|
||||
else {
|
||||
gdi.restore("Setup");
|
||||
@ -1077,51 +1215,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.enableEditControls(true);
|
||||
}
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
RECT rcPrepare;
|
||||
rcPrepare.left = gdi.getCX();
|
||||
rcPrepare.top = gdi.getCY();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.dropLine();
|
||||
gdi.addString("", fontMediumPlus, "Förbered lottning");
|
||||
gdi.dropLine(2.5);
|
||||
gdi.popX();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.addButton("PrepareDrawAll", "Fördela starttider...", ClassesCB).isEdit(true).setDefault();
|
||||
gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(0);
|
||||
gdi.addButton("LoadSettings", "Hämta inställningar från föregående lottning", ClassesCB).isEdit(true);
|
||||
enableLoadSettings(gdi);
|
||||
|
||||
gdi.dropLine(3);
|
||||
rcPrepare.bottom = gdi.getCY();
|
||||
rcPrepare.right = gdi.getWidth();
|
||||
gdi.addRectangle(rcPrepare, colorLightGreen);
|
||||
gdi.dropLine();
|
||||
gdi.popX();
|
||||
|
||||
gdi.addString("", 1, "Efteranmälningar");
|
||||
gdi.dropLine(1.5);
|
||||
gdi.popX();
|
||||
gdi.addButton("DrawAllBefore", "Efteranmälda (före ordinarie)", ClassesCB).isEdit(true);
|
||||
gdi.addButton("DrawAllAfter", "Efteranmälda (efter ordinarie)", ClassesCB).isEdit(true);
|
||||
|
||||
gdi.dropLine(4);
|
||||
gdi.popX();
|
||||
|
||||
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
|
||||
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
|
||||
gdi.dropLine(3);
|
||||
|
||||
by = max(by, gdi.getCY());
|
||||
|
||||
gdi.setCX(bx);
|
||||
gdi.setCY(by);
|
||||
gdi.fillDown();
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.setRestorePoint("ReadyToDistribute");
|
||||
gdi.refresh();
|
||||
loadReadyToDistribute(gdi, bx, by);
|
||||
}
|
||||
else if (bi.id == "HelpDraw") {
|
||||
|
||||
@ -1145,6 +1239,12 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
throw meosException("Ingen klass vald.");
|
||||
}
|
||||
gdi.restore("ReadyToDistribute");
|
||||
/*
|
||||
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
|
||||
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
|
||||
gdi.dropLine(3);
|
||||
*/
|
||||
|
||||
drawInfo.classes.clear();
|
||||
|
||||
for (set<int>::iterator it = classes.begin(); it!=classes.end();++it) {
|
||||
@ -1194,62 +1294,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.restore("ReadyToDistribute");
|
||||
oe->loadDrawSettings(classes, drawInfo, cInfo);
|
||||
|
||||
/*
|
||||
drawInfo.firstStart = 3600 * 22;
|
||||
drawInfo.minClassInterval = 3600;
|
||||
drawInfo.maxClassInterval = 1;
|
||||
drawInfo.minVacancy = 10;
|
||||
|
||||
set<int> reducedStart;
|
||||
for (set<int>::iterator it = classes.begin(); it != classes.end(); ++it) {
|
||||
pClass pc = oe->getClass(*it);
|
||||
if (pc) {
|
||||
int fs = pc->getDrawFirstStart();
|
||||
int iv = pc->getDrawInterval();
|
||||
if (iv > 0 && fs > 0) {
|
||||
drawInfo.firstStart = min(drawInfo.firstStart, fs);
|
||||
drawInfo.minClassInterval = min(drawInfo.minClassInterval, iv);
|
||||
drawInfo.maxClassInterval = max(drawInfo.maxClassInterval, iv);
|
||||
drawInfo.minVacancy = min(drawInfo.minVacancy, pc->getDrawVacant());
|
||||
drawInfo.maxVacancy = max(drawInfo.maxVacancy, pc->getDrawVacant());
|
||||
reducedStart.insert(fs%iv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawInfo.baseInterval = drawInfo.minClassInterval;
|
||||
int lastStart = -1;
|
||||
for (set<int>::iterator it = reducedStart.begin(); it != reducedStart.end(); ++it) {
|
||||
if (lastStart == -1)
|
||||
lastStart = *it;
|
||||
else {
|
||||
drawInfo.baseInterval = min(drawInfo.baseInterval, *it-lastStart);
|
||||
lastStart = *it;
|
||||
}
|
||||
}
|
||||
|
||||
cInfo.clear();
|
||||
cInfo.resize(classes.size());
|
||||
int i = 0;
|
||||
for (set<int>::iterator it = classes.begin(); it != classes.end(); ++it) {
|
||||
pClass pc = oe->getClass(*it);
|
||||
if (pc) {
|
||||
int fs = pc->getDrawFirstStart();
|
||||
int iv = pc->getDrawInterval();
|
||||
cInfo[i].pc = pc;
|
||||
cInfo[i].classId = *it;
|
||||
cInfo[i].courseId = pc->getCourseId();
|
||||
cInfo[i].firstStart = fs;
|
||||
cInfo[i].unique = pc->getCourseId();
|
||||
if (cInfo[i].unique == 0)
|
||||
cInfo[i].unique = pc->getId() * 10000;
|
||||
cInfo[i].firstStart = (fs - drawInfo.firstStart) / drawInfo.baseInterval;
|
||||
cInfo[i].interval = iv / drawInfo.baseInterval;
|
||||
cInfo[i].nVacant = pc->getDrawVacant();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
writeDrawInfo(gdi, drawInfo);
|
||||
gdi.enableEditControls(false);
|
||||
|
||||
@ -1272,6 +1316,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
gdi_new->addButton("CloseWindow", "Stäng", ClassesCB);
|
||||
gdi_new->registerEvent("CloseWindow", 0).setHandler(&handleCloseWindow);
|
||||
gdi_new->refresh();
|
||||
gdi.refreshFast();
|
||||
}
|
||||
else if (bi.id == "EraseStartAll") {
|
||||
set<int> classes;
|
||||
@ -1872,7 +1917,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
save(gdi, true);
|
||||
pClass pc = oe->addClass(oe->getAutoClassName(), 0);
|
||||
if (pc) {
|
||||
@ -2136,13 +2180,29 @@ void TabClass::showClassSettings(gdioutput &gdi)
|
||||
gdi.fillRight();
|
||||
|
||||
int id = ci.classId;
|
||||
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2);
|
||||
y = gdi.getCY();
|
||||
gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB);
|
||||
gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
|
||||
gdi.addInput(xp+300+width*2, y, "V"+itos(id), itow(ci.nVacant), 7, DrawClassesCB);
|
||||
gdi.addInput(xp+300+width*3, y, "R"+itos(id), itow(ci.nExtra), 7, DrawClassesCB);
|
||||
GDICOLOR clr = ci.hasFixedTime || ci.nExtraSpecified || ci.nVacantSpecified ? colorDarkGreen : colorBlack;
|
||||
|
||||
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2).setColor(clr).setExtra(clr);
|
||||
|
||||
y = gdi.getCY();
|
||||
InputInfo *ii;
|
||||
GDICOLOR fixedColor = colorLightGreen;
|
||||
ii = &gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB);
|
||||
if (ci.hasFixedTime) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
ii = &gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
|
||||
if (ci.hasFixedTime) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
ii = &gdi.addInput(xp+300+width*2, y, "V"+itos(id), itow(ci.nVacant), 7, DrawClassesCB);
|
||||
if (ci.nVacantSpecified) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
ii = &gdi.addInput(xp+300+width*3, y, "R"+itos(id), itow(ci.nExtra), 7, DrawClassesCB);
|
||||
if (ci.nExtraSpecified) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
if (k%5 == 4)
|
||||
gdi.dropLine(1);
|
||||
|
||||
@ -2161,6 +2221,10 @@ void TabClass::showClassSettings(gdioutput &gdi)
|
||||
gdi.addButton("SaveDrawSettings", "Spara starttider", ClassesCB,
|
||||
"Spara inmatade tider i tävlingen utan att tilldela starttider.");
|
||||
|
||||
gdi.addButton("ExportDrawSettings", "Exportera...", ClassesCB,
|
||||
"Exportera ett kalkylblad med lottningsinställningar som du kan redigera och sedan läsa in igen.");
|
||||
|
||||
|
||||
gdi.addButton("DrawAllAdjust", "Ändra inställningar", ClassesCB,
|
||||
"Ändra grundläggande inställningar och gör en ny fördelning").setExtra(13);
|
||||
|
||||
@ -2169,6 +2233,7 @@ void TabClass::showClassSettings(gdioutput &gdi)
|
||||
"Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan");
|
||||
gdi.disableInput("DrawAdjust");
|
||||
}
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
@ -3454,7 +3519,7 @@ void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK
|
||||
gdi.pushY();
|
||||
int cx = gdi.getCX();
|
||||
int width = gdi.scaleLength(230);
|
||||
gdi.addListBox("Classes", 200, 400, classesCB, L"Klasser:", L"", true);
|
||||
gdi.addListBox("Classes", 200, 480, classesCB, L"Klasser:", L"", true);
|
||||
gdi.setTabStops("Classes", 185);
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
@ -4051,13 +4116,28 @@ vector< pair<wstring, size_t> > TabClass::getPairOptions() {
|
||||
void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfoOut) {
|
||||
drawInfoOut.maxCommonControl = gdi.getSelectedItem("MaxCommonControl").first;
|
||||
|
||||
drawInfoOut.maxVacancy=gdi.getTextNo("VacancesMax");
|
||||
drawInfoOut.minVacancy=gdi.getTextNo("VacancesMin");
|
||||
drawInfoOut.vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
|
||||
drawInfoOut.extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
|
||||
int maxVacancy = gdi.getTextNo("VacancesMax");
|
||||
int minVacancy = gdi.getTextNo("VacancesMin");
|
||||
double vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
|
||||
double extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
|
||||
|
||||
|
||||
drawInfoOut.changedVacancyInfo = drawInfoOut.maxVacancy != maxVacancy ||
|
||||
drawInfoOut.minVacancy != minVacancy ||
|
||||
drawInfoOut.vacancyFactor != vacancyFactor;
|
||||
|
||||
drawInfoOut.maxVacancy = maxVacancy;
|
||||
drawInfoOut.minVacancy = minVacancy;
|
||||
drawInfoOut.vacancyFactor = vacancyFactor;
|
||||
|
||||
drawInfoOut.changedExtraInfo = drawInfoOut.extraFactor != extraFactor;
|
||||
drawInfoOut.extraFactor = extraFactor;
|
||||
|
||||
|
||||
drawInfoOut.baseInterval=convertAbsoluteTimeMS(gdi.getText("BaseInterval"));
|
||||
drawInfoOut.allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
|
||||
oe->setProperty("DrawInterlace", drawInfoOut.allowNeighbourSameCourse ? 1 : 0);
|
||||
|
||||
drawInfoOut.coursesTogether = gdi.isChecked("CoursesTogether");
|
||||
drawInfoOut.minClassInterval = convertAbsoluteTimeMS(gdi.getText("MinInterval"));
|
||||
drawInfoOut.maxClassInterval = convertAbsoluteTimeMS(gdi.getText("MaxInterval"));
|
||||
@ -4115,3 +4195,246 @@ void TabClass::clearPage(gdioutput &gdi, bool autoRefresh) {
|
||||
gdi.clearPage(autoRefresh);
|
||||
gdi.setData("ClassPageLoaded", 1);
|
||||
}
|
||||
|
||||
void TabClass::saveDrawSettings() const {
|
||||
for (size_t k = 0; k<cInfo.size(); k++) {
|
||||
const ClassInfo &ci = cInfo[k];
|
||||
if (ci.pc) {
|
||||
// Save settings with class
|
||||
ci.pc->synchronize(false);
|
||||
ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart);
|
||||
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
|
||||
ci.pc->setDrawVacant(ci.nVacant);
|
||||
ci.pc->setDrawNumReserved(ci.nExtra);
|
||||
vector<oClass::DrawSpecified> ds;
|
||||
if (ci.nExtraSpecified)
|
||||
ds.push_back(oClass::DrawSpecified::Extra);
|
||||
if (ci.hasFixedTime)
|
||||
ds.push_back(oClass::DrawSpecified::FixedTime);
|
||||
if (ci.nVacantSpecified)
|
||||
ds.push_back(oClass::DrawSpecified::Vacant);
|
||||
ci.pc->setDrawSpecification(ds);
|
||||
|
||||
ci.pc->synchronize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSettingsCSV::write(gdioutput &gdi, const oEvent &oe, const wstring &fn, vector<DrawSettingsCSV> &cInfo) {
|
||||
csvparser writer;
|
||||
writer.openOutput(fn.c_str(), true);
|
||||
vector<string> header, line;
|
||||
|
||||
header.emplace_back("ClassId");
|
||||
header.emplace_back("Class");
|
||||
header.emplace_back("Competitors");
|
||||
header.emplace_back("Course");
|
||||
header.emplace_back("First Control");
|
||||
header.emplace_back("First Start");
|
||||
header.emplace_back("Interval");
|
||||
header.emplace_back("Vacant");
|
||||
|
||||
// Save settings with class
|
||||
writer.outputRow(header);
|
||||
for (size_t k = 0; k<cInfo.size(); k++) {
|
||||
auto &ci = cInfo[k];
|
||||
line.clear();
|
||||
line.push_back(itos(ci.classId));
|
||||
line.push_back(gdi.toUTF8(ci.cls));
|
||||
line.push_back(itos(ci.nCmp));
|
||||
if (!ci.crs.empty()) {
|
||||
line.push_back(gdi.toUTF8(ci.crs));
|
||||
}
|
||||
else line.emplace_back("");
|
||||
|
||||
if (ci.ctrl) {
|
||||
line.push_back(itos(ci.ctrl));
|
||||
}
|
||||
else line.emplace_back("");
|
||||
|
||||
line.push_back(gdi.narrow(oe.getAbsTime(ci.firstStart)));
|
||||
line.push_back(gdi.narrow(formatTime(ci.interval)));
|
||||
line.push_back(itos(ci.vacant));
|
||||
writer.outputRow(line);
|
||||
}
|
||||
}
|
||||
|
||||
vector<DrawSettingsCSV> DrawSettingsCSV::read(gdioutput &gdi, const oEvent &oe, const wstring &fn) {
|
||||
csvparser reader;
|
||||
list<vector<wstring>> data;
|
||||
reader.parse(fn.c_str(), data);
|
||||
vector<DrawSettingsCSV> output;
|
||||
set<int> usedId;
|
||||
// Save settings with class
|
||||
int lineNo = 0;
|
||||
for (auto &row : data) {
|
||||
lineNo++;
|
||||
if (row.empty())
|
||||
continue;
|
||||
|
||||
int cid = _wtoi(row[0].c_str());
|
||||
if (!(cid > 0))
|
||||
continue;
|
||||
|
||||
DrawSettingsCSV dl;
|
||||
try {
|
||||
|
||||
if (row.size() <= 7)
|
||||
throw wstring(L"Rad X är ogiltig#" + itow(lineNo) + L": " + row[0] + L"...");
|
||||
|
||||
pClass pc = oe.getClass(cid);
|
||||
if (!pc || (!row[1].empty() && !compareClassName(pc->getName(), row[1]))) {
|
||||
pClass pcName = oe.getClass(row[1]);
|
||||
if (pcName)
|
||||
pc = pcName;
|
||||
}
|
||||
|
||||
if (!pc)
|
||||
throw wstring(L"Hittar inte klass X#" + row[0] + L"/" + row[1]);
|
||||
else if (usedId.count(pc->getId()))
|
||||
throw wstring(L"Klassen X är listad flera gånger#" + row[0] + L"/" + row[1]);
|
||||
|
||||
usedId.insert(pc->getId());
|
||||
dl.classId = pc->getId();
|
||||
|
||||
dl.firstStart = oe.getRelativeTime(row[5]);
|
||||
if (dl.firstStart <= 0)
|
||||
throw wstring(L"Ogiltig starttid X#" + row[5]);
|
||||
|
||||
dl.interval = convertAbsoluteTimeMS(row[6]);
|
||||
if (dl.interval <= 0)
|
||||
throw wstring(L"Ogiltigt startintervall X#" + row[6]);
|
||||
|
||||
dl.vacant = _wtoi(row[7].c_str());
|
||||
|
||||
output.push_back(dl);
|
||||
}
|
||||
catch (const wstring &exmsg) {
|
||||
gdi.addString("", 0, exmsg).setColor(colorRed);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void TabClass::loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstring &firstStart,
|
||||
int maxNumControl, const wstring &minInterval, const wstring &vacances,
|
||||
const set<int> &clsId) {
|
||||
|
||||
showClassSelection(gdi, bx, by, DrawClassesCB);
|
||||
|
||||
gdi.setSelection("Classes", clsId);
|
||||
|
||||
gdi.addString("", 1, "Grundinställningar");
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
|
||||
gdi.addInput("FirstStart", firstStart, 10, 0, L"Första start:");
|
||||
gdi.addInput("nFields", L"10", 10, 0, L"Max parallellt startande:");
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addSelection("MaxCommonControl", 150, 100, 0,
|
||||
L"Max antal gemensamma kontroller:");
|
||||
|
||||
vector< pair<wstring, size_t> > items;
|
||||
items.push_back(make_pair(lang.tl("Inga"), 1));
|
||||
items.push_back(make_pair(lang.tl("Första kontrollen"), 2));
|
||||
for (int k = 2; k<10; k++)
|
||||
items.push_back(make_pair(lang.tl("X kontroller#" + itos(k)), k + 1));
|
||||
items.push_back(make_pair(lang.tl("Hela banan"), 1000));
|
||||
gdi.addItem("MaxCommonControl", items);
|
||||
gdi.selectItemByData("MaxCommonControl", maxNumControl);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(4);
|
||||
gdi.fillDown();
|
||||
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, oe->getPropertyInt("DrawInterlace", 1) == 0);
|
||||
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
|
||||
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addString("", 1, "Startintervall");
|
||||
gdi.dropLine(0.4);
|
||||
gdi.fillRight();
|
||||
gdi.addInput("BaseInterval", L"1:00", 10, 0, L"Basintervall (min):");
|
||||
gdi.addInput("MinInterval", minInterval, 10, 0, L"Minsta intervall i klass:");
|
||||
gdi.addInput("MaxInterval", minInterval, 10, 0, L"Största intervall i klass:");
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(4);
|
||||
gdi.fillDown();
|
||||
gdi.addString("", 1, "Vakanser och efteranmälda");
|
||||
gdi.dropLine(0.4);
|
||||
gdi.fillRight();
|
||||
gdi.popX();
|
||||
gdi.addInput("Vacances", vacances, 6, 0, L"Andel vakanser:");
|
||||
gdi.addInput("VacancesMin", L"1", 6, 0, L"Min. vakanser (per klass):");
|
||||
gdi.addInput("VacancesMax", L"10", 6, 0, L"Max. vakanser (per klass):");
|
||||
gdi.addInput("Extra", L"0%", 6, 0, L"Förväntad andel efteranmälda:");
|
||||
|
||||
gdi.dropLine(4);
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
gdi.setRestorePoint("Setup");
|
||||
}
|
||||
|
||||
void TabClass::loadReadyToDistribute(gdioutput &gdi, int &bx, int &by) {
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
RECT rcPrepare;
|
||||
rcPrepare.left = gdi.getCX();
|
||||
rcPrepare.top = gdi.getCY();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.dropLine();
|
||||
gdi.addString("", fontMediumPlus, "Förbered lottning");
|
||||
gdi.dropLine(2.2);
|
||||
gdi.popX();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.addButton("PrepareDrawAll", "Fördela starttider...", ClassesCB).isEdit(true);
|
||||
gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(0);
|
||||
gdi.addButton("LoadSettings", "Hämta inställningar från föregående lottning", ClassesCB).isEdit(true);
|
||||
enableLoadSettings(gdi);
|
||||
|
||||
gdi.dropLine(3);
|
||||
rcPrepare.bottom = gdi.getCY();
|
||||
rcPrepare.right = gdi.getWidth();
|
||||
gdi.addRectangle(rcPrepare, colorLightGreen);
|
||||
gdi.dropLine();
|
||||
gdi.popX();
|
||||
|
||||
rcPrepare.left = gdi.getCX();
|
||||
rcPrepare.top = gdi.getCY();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.addString("", fontMediumPlus, "Efteranmälningar");
|
||||
gdi.dropLine(2.2);
|
||||
gdi.popX();
|
||||
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
||||
gdi.addButton("DrawAllBefore", "Efteranmälda (före ordinarie)", ClassesCB).isEdit(true);
|
||||
gdi.addButton("DrawAllAfter", "Efteranmälda (efter ordinarie)", ClassesCB).isEdit(true);
|
||||
|
||||
gdi.dropLine(3);
|
||||
rcPrepare.bottom = gdi.getCY();
|
||||
rcPrepare.right = gdi.getWidth();
|
||||
gdi.addRectangle(rcPrepare, colorLightBlue);
|
||||
gdi.dropLine();
|
||||
gdi.popX();
|
||||
|
||||
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
|
||||
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
|
||||
gdi.dropLine(3);
|
||||
|
||||
by = max(by, gdi.getCY());
|
||||
|
||||
gdi.setCX(bx);
|
||||
gdi.setCY(by);
|
||||
gdi.fillDown();
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.setRestorePoint("ReadyToDistribute");
|
||||
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -70,6 +70,7 @@ class TabClass :
|
||||
void save(gdioutput &gdi, bool skipReload);
|
||||
void legSetup(gdioutput &gdi);
|
||||
vector<ClassInfo> cInfo;
|
||||
void saveDrawSettings() const;
|
||||
|
||||
map<int, ClassInfo> cInfoCache;
|
||||
|
||||
@ -146,6 +147,10 @@ class TabClass :
|
||||
|
||||
void setLockForkingState(gdioutput &gdi, bool poolState, bool lockState);
|
||||
|
||||
void loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstring& firstStart,
|
||||
int maxNumControl, const wstring& minInterval, const wstring& vacances, const set<int> &clsId);
|
||||
|
||||
void loadReadyToDistribute(gdioutput &gdi, int &bx, int &by);
|
||||
public:
|
||||
|
||||
void clearCompetitionData();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -316,14 +316,14 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
|
||||
fields.push_back("Street");
|
||||
fields.push_back("Address");
|
||||
fields.push_back("EMail");
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 32);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.addString("", boldText, "Betalningsinformation");
|
||||
fields.clear();
|
||||
fields.push_back("Account");
|
||||
fields.push_back("PaymentDue");
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1504,11 +1504,12 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.dropLine();
|
||||
gdi.addString("", 1, "Behandlar tävlingsdata").setColor(colorGreen);
|
||||
set<int> noFilter;
|
||||
string noType;
|
||||
|
||||
if (createNew && id>0) {
|
||||
gdi.addString("", 1, "Skapar ny tävling");
|
||||
oe->newCompetition(L"New");
|
||||
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter);
|
||||
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter, noType);
|
||||
oe->setZeroTime(formatTimeHMS(zeroTime));
|
||||
oe->getDI().setDate("OrdinaryEntry", lastEntry);
|
||||
if (ci) {
|
||||
@ -1521,12 +1522,13 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
removeTempFile(tEvent);
|
||||
|
||||
oe->importXML_EntryData(gdi, tClass.c_str(), false, false, noFilter);
|
||||
oe->importXML_EntryData(gdi, tClass.c_str(), false, false, noFilter, noType);
|
||||
removeTempFile(tClass);
|
||||
|
||||
set<int> stageFilter;
|
||||
checkStageFilter(gdi, tEntry, stageFilter);
|
||||
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter);
|
||||
string preferredIdType;
|
||||
checkStageFilter(gdi, tEntry, stageFilter, preferredIdType);
|
||||
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter, preferredIdType);
|
||||
removeTempFile(tEntry);
|
||||
|
||||
if (!course.empty()) {
|
||||
@ -2357,7 +2359,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
|
||||
|
||||
gdi.dropLine(0.4);
|
||||
gdi.fillDown();
|
||||
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2017 Melin Software HB"));
|
||||
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2018 Melin Software HB"));
|
||||
gdi.dropLine(1);
|
||||
gdi.popX();
|
||||
|
||||
@ -2370,7 +2372,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
|
||||
gdi.clearPage(false);
|
||||
gdi.addString("", 2, makeDash(L"Om MeOS - ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue);
|
||||
gdi.dropLine(2);
|
||||
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2017 Melin Software HB"));
|
||||
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2018 Melin Software HB"));
|
||||
gdi.dropLine();
|
||||
gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright "
|
||||
"(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB,"
|
||||
@ -2389,7 +2391,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.addString("", 1, "Vi stöder MeOS");
|
||||
vector<string> supp;
|
||||
vector<wstring> supp;
|
||||
getSupporters(supp);
|
||||
for (size_t k = 0; k<supp.size(); k++)
|
||||
gdi.addStringUT(0, supp[k]);
|
||||
@ -2495,7 +2497,8 @@ bool TabCompetition::loadPage(gdioutput &gdi)
|
||||
oe->checkNecessaryFeatures();
|
||||
gdi.selectTab(tabId);
|
||||
|
||||
gdi.addString("", 3, "MeOS");
|
||||
//gdi.addString("", 3, "MeOS");
|
||||
gdi.addString("", textImage, "513");
|
||||
gdi.dropLine();
|
||||
oe->synchronize();
|
||||
|
||||
@ -3481,12 +3484,14 @@ TabCompetition::FlowOperation TabCompetition::saveEntries(gdioutput &gdi, bool r
|
||||
}
|
||||
else {
|
||||
set<int> stageFilter;
|
||||
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter);
|
||||
string preferredIdType;
|
||||
|
||||
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter, preferredIdType);
|
||||
|
||||
if (res != FlowContinue)
|
||||
return res;
|
||||
|
||||
oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter);
|
||||
oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter, preferredIdType);
|
||||
}
|
||||
if (!isGuide) {
|
||||
gdi.setWindowTitle(oe->getTitleName());
|
||||
@ -3516,23 +3521,34 @@ int stageInfoCB(gdioutput *gdi, int type, void *data)
|
||||
|
||||
void mainMessageLoop(HACCEL hAccelTable, DWORD time);
|
||||
|
||||
TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi, const wstring & fname, set<int>& filter) {
|
||||
TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
|
||||
const wstring & fname,
|
||||
set<int>& filter,
|
||||
string &preferredIdProvider) {
|
||||
xmlparser xml;
|
||||
xml.read(fname);
|
||||
xmlobject xo = xml.getObject("EntryList");
|
||||
set<int> scanFilter;
|
||||
IOF30Interface reader(oe, false);
|
||||
vector<string> idProviders;
|
||||
if (xo) {
|
||||
if (xo.getAttrib("iofVersion")) {
|
||||
IOF30Interface reader(oe, false);
|
||||
reader.prescanEntryList(xo, scanFilter);
|
||||
reader.getIdTypes(idProviders);
|
||||
}
|
||||
}
|
||||
bool stageFilter = scanFilter.size() > 1;
|
||||
bool idtype = idProviders.size() > 1;
|
||||
|
||||
if (scanFilter.size() > 1) {
|
||||
//gdi.dropLine();
|
||||
bool needUseInput = stageFilter || idtype;
|
||||
|
||||
if (needUseInput) {
|
||||
gdi.enableEditControls(false, true);
|
||||
gdi.fillDown();
|
||||
gdi.pushX();
|
||||
}
|
||||
|
||||
if (stageFilter) {
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addString("", 0, "Det finns anmälningsdata för flera etapper.");
|
||||
gdi.dropLine(0.5);
|
||||
@ -3548,7 +3564,25 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
|
||||
gdi.selectItemByData("Stage", cn);
|
||||
else
|
||||
gdi.selectItemByData("Stage", 0);
|
||||
}
|
||||
|
||||
if (idtype) {
|
||||
if (stageFilter) {
|
||||
gdi.popX();
|
||||
gdi.dropLine(2);
|
||||
}
|
||||
gdi.dropLine(0.5);
|
||||
gdi.addString("", 0, "Det finns multiplia Id-nummer för personer");
|
||||
gdi.dropLine(0.5);
|
||||
gdi.fillRight();
|
||||
gdi.addSelection("IdType", 150, 200, stageInfoCB, L"Välj vilken typ du vill importera:");
|
||||
int i = 0;
|
||||
for (string &sn : idProviders) {
|
||||
gdi.addItem("IdType", gdi.widen(sn), i++);
|
||||
}
|
||||
}
|
||||
|
||||
if (needUseInput) {
|
||||
gdi.dropLine();
|
||||
gdi.addButton("OK_Stage", "OK", stageInfoCB);
|
||||
gdi.fillDown();
|
||||
@ -3569,18 +3603,31 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
|
||||
|
||||
gdi.removeControl("OK_Stage");
|
||||
gdi.removeControl("Cancel_Stage");
|
||||
gdi.disableInput("Stage");
|
||||
if (stageFilter)
|
||||
gdi.disableInput("Stage");
|
||||
if (idtype)
|
||||
gdi.disableInput("IdType");
|
||||
}
|
||||
if (ok) {
|
||||
//OK was pressed
|
||||
int stage = gdi.getSelectedItem("Stage").first;
|
||||
if (stage > 0) {
|
||||
filter.insert(stage);
|
||||
if (oe->getStageNumber() == 0) {
|
||||
oe->setStageNumber(stage);
|
||||
oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe);
|
||||
if (scanFilter.size() > 1) {
|
||||
int stage = gdi.getSelectedItem("Stage").first;
|
||||
if (stage > 0) {
|
||||
filter.insert(stage);
|
||||
if (oe->getStageNumber() == 0) {
|
||||
oe->setStageNumber(stage);
|
||||
oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idProviders.size() > 1) {
|
||||
ListBoxInfo lbi;
|
||||
if (gdi.getSelectedItem("IdType", lbi)) {
|
||||
preferredIdProvider = gdi.narrow(lbi.text);
|
||||
}
|
||||
}
|
||||
|
||||
return FlowContinue;
|
||||
}
|
||||
else if (cancel)
|
||||
@ -3764,14 +3811,22 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.push_back("EMail");
|
||||
fields.push_back("Homepage");
|
||||
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 32);
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
gdi.addString("", 1, "Betalningsinformation");
|
||||
fields.clear();
|
||||
fields.push_back("Account");
|
||||
fields.push_back("PaymentDue");
|
||||
|
||||
oe->getDI().buildDataFields(gdi, fields, 32);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.addString("", 1, "Tidszon");
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
gdi.addCheckbox("UTC", "Exportera tider i UTC", 0,
|
||||
oe->getDCI().getInt("UTC") == 1);
|
||||
oe->getDCI().getInt("UTC") == 1);
|
||||
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.popY();
|
||||
@ -3785,7 +3840,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.push_back("EntryFee");
|
||||
fields.push_back("YouthFee");
|
||||
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 6);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
@ -3794,7 +3849,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.push_back("OrdinaryEntry");
|
||||
fields.push_back("LateEntryFactor");
|
||||
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
@ -3805,7 +3860,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.push_back("YouthAge");
|
||||
fields.push_back("SeniorAge");
|
||||
gdi.fillRight();
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
@ -3818,14 +3873,15 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.push_back("CurrencyCode");
|
||||
|
||||
gdi.fillRight();
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
gdi.addCheckbox("PreSymbol", "Valutasymbol före", 0,
|
||||
oe->getDCI().getInt("CurrencyPreSymbol") == 1);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
gdi.dropLine(2.5);
|
||||
bool useFrac = oe->getDCI().getInt("CurrencyFactor") == 100;
|
||||
gdi.addCheckbox("UseFraction", "Tillåt decimaler", CompetitionCB,
|
||||
useFrac, "Tillåt valutauttryck med decimaler");
|
||||
@ -3833,7 +3889,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
fields.clear();
|
||||
gdi.dropLine(-1);
|
||||
fields.push_back("CurrencySeparator");
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
|
||||
gdi.setInputStatus("CurrencySeparator_odc", useFrac);
|
||||
|
||||
@ -3841,23 +3897,21 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addString("", 1, "Betalningsinformation");
|
||||
fields.clear();
|
||||
fields.push_back("Account");
|
||||
fields.push_back("PaymentDue");
|
||||
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.addString("", 1, "Tävlingsregler");
|
||||
fields.clear();
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
fields.push_back("MaxTime");
|
||||
oe->getDI().buildDataFields(gdi, fields);
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining) &&
|
||||
oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) {
|
||||
fields.push_back("DiffTime");
|
||||
}
|
||||
gdi.fillDown();
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
oe->getDI().fillDataFields(gdi);
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.dropLine(1);
|
||||
int bottom = gdi.getCY();
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -128,7 +128,8 @@ class TabCompetition :
|
||||
void entryForm(gdioutput &gdi, bool isGuide);
|
||||
FlowOperation saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide);
|
||||
|
||||
FlowOperation checkStageFilter(gdioutput &gdi, const wstring &fname, set<int> &filter);
|
||||
FlowOperation checkStageFilter(gdioutput &gdi, const wstring &fname, set<int> &filter, string &preferredIdProvider);
|
||||
|
||||
void setExportOptionsStatus(gdioutput &gdi, int format) const;
|
||||
|
||||
void selectStartlistOptions(gdioutput &gdi);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -869,7 +869,8 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
|
||||
}
|
||||
else {
|
||||
set<int> noFilter;
|
||||
oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter);
|
||||
string noType;
|
||||
oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter, noType);
|
||||
}
|
||||
if (addClasses) {
|
||||
// There is specific course-class matching inside the import of each format,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -45,6 +45,8 @@
|
||||
#include "intkeymapimpl.hpp"
|
||||
#include "meosexception.h"
|
||||
#include "MeOSFeatures.h"
|
||||
#include "autocomplete.h"
|
||||
#include "RunnerDB.h"
|
||||
|
||||
int SportIdentCB(gdioutput *gdi, int type, void *data);
|
||||
|
||||
@ -183,8 +185,10 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
|
||||
gdi.setInputStatus("Bib", controlBib);
|
||||
}
|
||||
|
||||
gdi.setText("Club", r->getClub());
|
||||
|
||||
auto *ci = gdi.setText("Club", r->getClub());
|
||||
if (ci) {
|
||||
ci->setExtra(r->getClubId());
|
||||
}
|
||||
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
|
||||
gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
|
||||
gdi.selectItemByData("RClass", r->getClassId(true));
|
||||
@ -1042,6 +1046,29 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
else if (bi.id=="Check") {
|
||||
}
|
||||
}
|
||||
else if (type == GUI_INPUTCHANGE) {
|
||||
InputInfo &ii = *(InputInfo *)data;
|
||||
|
||||
if (oe->useRunnerDb() && ii.id == "Name") {
|
||||
auto &db = oe->getRunnerDatabase();
|
||||
bool show = false;
|
||||
if (ii.text.length() > 1) {
|
||||
auto dbClub = extractClub(gdi);
|
||||
auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
|
||||
if (!rw.empty()) {
|
||||
auto &ac = gdi.addAutoComplete(ii.id);
|
||||
ac.setAutoCompleteHandler(this);
|
||||
|
||||
ac.setData(TabSI::getRunnerAutoCompelete(db, rw, dbClub));
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(ii.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type==GUI_INPUT) {
|
||||
InputInfo ii=*(InputInfo *)data;
|
||||
|
||||
@ -1215,6 +1242,27 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
loadPage(gdi);
|
||||
}
|
||||
}
|
||||
else if (type == GUI_COMBOCHANGE) {
|
||||
ListBoxInfo &combo = *(ListBoxInfo *)(data);
|
||||
bool show = false;
|
||||
if (oe->useRunnerDb() && combo.id == "Club" && combo.text.length() > 1) {
|
||||
auto clubs = oe->getRunnerDatabase().getClubSuggestions(combo.text, 20);
|
||||
if (!clubs.empty()) {
|
||||
auto &ac = gdi.addAutoComplete(combo.id);
|
||||
ac.setAutoCompleteHandler(this);
|
||||
vector<AutoCompleteRecord> items;
|
||||
for (auto club : clubs)
|
||||
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
|
||||
|
||||
ac.setData(items);
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(combo.id);
|
||||
}
|
||||
}
|
||||
else if (type==GUI_CLEAR) {
|
||||
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
|
||||
if (gdi_settings)
|
||||
@ -1327,7 +1375,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
|
||||
int id = static_cast<TextInfo*>(data)->getExtraInt();
|
||||
oRunner *r = oe->getRunner(id, 0);
|
||||
|
||||
if (r==0)
|
||||
if (r == 0)
|
||||
return -1;
|
||||
|
||||
r->synchronize();
|
||||
@ -1341,19 +1389,24 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
int cardNo = gdi.getTextNo("CardNo");
|
||||
|
||||
if (cardNo!=r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo))
|
||||
if (cardNo != r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo))
|
||||
return 0;
|
||||
|
||||
wstring club = gdi.getText("Club");
|
||||
int clubId = 0;
|
||||
wstring club;
|
||||
int birthYear = 0;
|
||||
pClub pc = oe->getClubCreate(0, club);
|
||||
|
||||
r->updateFromDB(name, pc->getId(), r->getClassId(false), cardNo, birthYear);
|
||||
|
||||
if (gdi.hasField("Club")) {
|
||||
club = gdi.getText("Club");
|
||||
pClub pc = oe->getClubCreate(0, club);
|
||||
if (pc)
|
||||
clubId = pc->getId();
|
||||
}
|
||||
r->updateFromDB(name, clubId, r->getClassId(false), cardNo, birthYear);
|
||||
r->setName(name, true);
|
||||
r->setCardNo(cardNo, true);
|
||||
|
||||
r->setClub(club);
|
||||
|
||||
int fee = 0;
|
||||
if (gdi.hasField("Fee")) {
|
||||
ListBoxInfo lbi;
|
||||
@ -1870,17 +1923,19 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
|
||||
gdi.addCheckbox("RentCard", "Hyrd", 0, tsi.storedInfo.rentState);
|
||||
gdi.dropLine(-1.2);
|
||||
|
||||
gdi.addInput("Name", tsi.storedInfo.storedName, 16, 0, L"Namn:");
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
|
||||
gdi.addCombo("Club", 220, 300, RunnerCB, L"Klubb:");
|
||||
oe->fillClubs(gdi, "Club");
|
||||
gdi.setText("Club", tsi.storedInfo.storedClub);
|
||||
}
|
||||
|
||||
gdi.addCombo("Club", 220, 300, 0, L"Klubb:");
|
||||
oe->fillClubs(gdi, "Club");
|
||||
gdi.setText("Club", tsi.storedInfo.storedClub);
|
||||
gdi.addInput("Name", tsi.storedInfo.storedName, 16, RunnerCB, L"Namn:");
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
|
||||
if (!tsi.storedInfo.storedFee.empty())
|
||||
lastFee = tsi.storedInfo.storedFee;
|
||||
|
||||
gdi.addCombo("Fee", 60, 150, SportIdentCB, L"Avgift:");
|
||||
gdi.addCombo("Fee", 60, 150, 0, L"Avgift:");
|
||||
oe->fillFees(gdi, "Fee", true);
|
||||
gdi.autoGrow("Fee");
|
||||
|
||||
@ -1892,7 +1947,6 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
|
||||
}
|
||||
gdi.dropLine(1.2);
|
||||
|
||||
//gdi.addCheckbox("Paid", "Kontant betalning", 0, tsi.storedInfo.hasPaid);
|
||||
tsi.generatePayModeWidget(gdi);
|
||||
gdi.dropLine(-0.2);
|
||||
}
|
||||
@ -2384,7 +2438,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
gdi.dropLine(1);
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
gdi.addInput("Name", L"", 16, 0, L"Namn:");
|
||||
gdi.addInput("Name", L"", 16, RunnerCB, L"Namn:");
|
||||
|
||||
if (oe->hasBib(true, false)) {
|
||||
gdi.addInput("Bib", L"", 4, 0, L"Nr", L"Nummerlapp");
|
||||
@ -2394,7 +2448,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
|
||||
gdi.fillDown();
|
||||
gdi.addCombo("Club", 220, 300, 0, L"Klubb:");
|
||||
gdi.addCombo("Club", 220, 300, RunnerCB, L"Klubb:");
|
||||
oe->fillClubs(gdi, "Club");
|
||||
gdi.pushX();
|
||||
}
|
||||
@ -2946,3 +3000,43 @@ void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
|
||||
gdi.addButton("Save", "Spara").setHandler(h);
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
|
||||
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
|
||||
if (bi) {
|
||||
int ix = info.getCurrentInt();
|
||||
bi->setExtra(ix);
|
||||
if (info.getTarget() == "Name") {
|
||||
auto &db = oe->getRunnerDatabase();
|
||||
auto runner = db.getRunnerByIndex(ix);
|
||||
|
||||
if (runner && gdi.hasField("Club") && gdi.getText("Club").empty()) {
|
||||
pClub club = db.getClub(runner->dbe().clubNo);
|
||||
if (club)
|
||||
gdi.setText("Club", club->getName());
|
||||
}
|
||||
if (runner && runner->dbe().cardNo > 0 && gdi.hasField("CardNo") && gdi.getText("CardNo").empty()) {
|
||||
gdi.setText("CardNo", runner->dbe().cardNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
gdi.clearAutoComplete("");
|
||||
gdi.TabFocus(1);
|
||||
}
|
||||
|
||||
pClub TabRunner::extractClub(gdioutput &gdi) {
|
||||
oClub *dbClub = nullptr;
|
||||
if (gdi.hasField("Club")) {
|
||||
auto &db = oe->getRunnerDatabase();
|
||||
int clubId = gdi.getExtraInt("Club");
|
||||
if (clubId >= 0) {
|
||||
dbClub = db.getClub(clubId);
|
||||
if (dbClub && !stringMatch(dbClub->getName(), gdi.getText("Club")))
|
||||
dbClub = nullptr;
|
||||
}
|
||||
if (dbClub == nullptr) {
|
||||
dbClub = db.getClub(gdi.getText("Club"));
|
||||
}
|
||||
}
|
||||
return dbClub;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -22,11 +22,12 @@
|
||||
************************************************************************/
|
||||
#include "tabbase.h"
|
||||
#include "Printer.h"
|
||||
#include "autocompletehandler.h"
|
||||
|
||||
class Table;
|
||||
|
||||
class TabRunner :
|
||||
public TabBase
|
||||
public TabBase, AutoCompleteHandler
|
||||
{
|
||||
private:
|
||||
void addToolbar(gdioutput &gdi);
|
||||
@ -108,8 +109,9 @@ private:
|
||||
|
||||
protected:
|
||||
void clearCompetitionData();
|
||||
|
||||
pClub extractClub(gdioutput &gdi);
|
||||
public:
|
||||
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
|
||||
|
||||
const char * getTypeStr() const {return "TRunnerTab";}
|
||||
TabType getType() const {return TRunnerTab;}
|
||||
|
||||
235
code/TabSI.cpp
235
code/TabSI.cpp
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -46,9 +46,12 @@
|
||||
#include "MeOSFeatures.h"
|
||||
#include "RunnerDB.h"
|
||||
#include "recorder.h"
|
||||
#include "autocomplete.h"
|
||||
|
||||
TabSI::TabSI(oEvent *poe):TabBase(poe) {
|
||||
editCardData.tabSI = this;
|
||||
directEntryGUI.tabSI = this;
|
||||
|
||||
interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0;
|
||||
useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0;
|
||||
printSplits = false;
|
||||
@ -97,12 +100,12 @@ void TabSI::logCard(const SICard &card)
|
||||
getDesktopFile(file, readlog.c_str(), sf);
|
||||
logger->openOutput(file);
|
||||
vector<string> head = SICard::logHeader();
|
||||
logger->OutputRow(head);
|
||||
logger->outputRow(head);
|
||||
logcounter = 0;
|
||||
}
|
||||
|
||||
vector<string> log = card.codeLogData(++logcounter);
|
||||
logger->OutputRow(log);
|
||||
logger->outputRow(log);
|
||||
}
|
||||
|
||||
extern SportIdent *gSI;
|
||||
@ -111,8 +114,7 @@ extern pEvent gEvent;
|
||||
void LoadRunnerPage(gdioutput &gdi);
|
||||
|
||||
|
||||
int SportIdentCB(gdioutput *gdi, int type, void *data)
|
||||
{
|
||||
int SportIdentCB(gdioutput *gdi, int type, void *data) {
|
||||
TabSI &tsi = dynamic_cast<TabSI &>(*gdi->getTabs().get(TSITab));
|
||||
|
||||
return tsi.siCB(*gdi, type, data);
|
||||
@ -139,11 +141,11 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
|
||||
csvparser saver;
|
||||
saver.openOutput(file.c_str());
|
||||
vector<string> head = SICard::logHeader();
|
||||
saver.OutputRow(head);
|
||||
saver.outputRow(head);
|
||||
int count = 0;
|
||||
for (list< pair<int, SICard> >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) {
|
||||
vector<string> log = it->second.codeLogData(++count);
|
||||
saver.OutputRow(log);
|
||||
saver.outputRow(log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -880,9 +882,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
|
||||
r->setStartTimeS(gdi.getText("StartTime"));
|
||||
|
||||
wstring bib;
|
||||
if (r->autoAssignBib())
|
||||
switch (r->autoAssignBib()) {
|
||||
case oRunner::BibAssignResult::Assigned:
|
||||
bib = L", " + lang.tl(L"Nummerlapp: ") + r->getBib();
|
||||
|
||||
break;
|
||||
case oRunner::BibAssignResult::Failed:
|
||||
bib = L", " + lang.tl(L"Ingen nummerlapp");
|
||||
break;
|
||||
}
|
||||
r->synchronize();
|
||||
|
||||
gdi.restore("EntryLine");
|
||||
@ -2434,12 +2441,14 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
|
||||
|
||||
wstring name;
|
||||
wstring club;
|
||||
int age = 0;
|
||||
if (useDatabase) {
|
||||
pRunner db_r=oe->dbLookUpByCard(sic.CardNumber);
|
||||
|
||||
if (db_r) {
|
||||
name=db_r->getNameRaw();
|
||||
club=db_r->getClub();
|
||||
age = db_r->getBirthAge();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2451,12 +2460,18 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
|
||||
if (gdi.hasField("Club"))
|
||||
gdi.setText("Club", club);
|
||||
|
||||
if (name.empty())
|
||||
gdi.setInputFocus("Name");
|
||||
else if (club.empty() && gdi.hasField("Club"))
|
||||
if (club.empty() && gdi.hasField("Club"))
|
||||
gdi.setInputFocus("Club");
|
||||
else if (name.empty())
|
||||
gdi.setInputFocus("Name");
|
||||
else
|
||||
gdi.setInputFocus("Class");
|
||||
|
||||
int clsId = gdi.getSelectedItem("Class").first;
|
||||
pClass cls = oe->getClass(clsId);
|
||||
if (cls && age > 0) {
|
||||
directEntryGUI.updateFees(gdi, cls, age);
|
||||
}
|
||||
}
|
||||
|
||||
void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
|
||||
@ -2536,10 +2551,10 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
|
||||
storedInfo.checkAge();
|
||||
gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, L"Bricka:");
|
||||
|
||||
gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:");
|
||||
|
||||
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
|
||||
gdi.addCombo("Club", 180, 200, 0, L"Klubb:", L"Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben");
|
||||
gdi.addCombo("Club", 180, 200, 0, L"Klubb:",
|
||||
L"Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben")
|
||||
.setHandler(&directEntryGUI);
|
||||
oe->fillClubs(gdi, "Club");
|
||||
if (storedInfo.storedClub.empty())
|
||||
gdi.selectItemByData("Club", lastClubId);
|
||||
@ -2547,7 +2562,9 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
|
||||
gdi.setText("Club", storedInfo.storedClub);
|
||||
}
|
||||
|
||||
gdi.addSelection("Class", 150, 200, 0, L"Klass:");
|
||||
gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:").setHandler(&directEntryGUI);
|
||||
|
||||
gdi.addSelection("Class", 150, 200, 0, L"Klass:").setHandler(&directEntryGUI);
|
||||
oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect);
|
||||
if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) {
|
||||
}
|
||||
@ -3024,7 +3041,6 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
|
||||
SICard &c = getCard(cardId);
|
||||
if (c.readOutTime[0] == 0)
|
||||
@ -3600,3 +3616,188 @@ void TabSI::printSIInfo(gdioutput &gdi, const wstring &port) const {
|
||||
for (size_t j = 0; j < info.size(); j++)
|
||||
gdi.addStringUT(0, info[j]);
|
||||
}
|
||||
|
||||
oClub *TabSI::extractClub(gdioutput &gdi) const {
|
||||
auto &db = oe->getRunnerDatabase();
|
||||
oClub *dbClub = nullptr;
|
||||
if (gdi.hasField("Club")) {
|
||||
int clubId = gdi.getExtraInt("Club");
|
||||
if (clubId >= 0) {
|
||||
dbClub = db.getClub(clubId);
|
||||
if (dbClub && !stringMatch(dbClub->getName(), gdi.getText("Club")))
|
||||
dbClub = nullptr;
|
||||
}
|
||||
if (dbClub == nullptr) {
|
||||
dbClub = db.getClub(gdi.getText("Club"));
|
||||
}
|
||||
}
|
||||
return dbClub;
|
||||
}
|
||||
|
||||
RunnerWDBEntry *TabSI::extractRunner(gdioutput &gdi) const {
|
||||
auto &db = oe->getRunnerDatabase();
|
||||
|
||||
int rId = gdi.getExtraInt("Name");
|
||||
wstring name = gdi.getText("Name");
|
||||
RunnerWDBEntry *dbR = nullptr;
|
||||
if (rId >= 0) {
|
||||
dbR = db.getRunnerByIndex(rId);
|
||||
if (dbR) {
|
||||
wstring fname = dbR->getFamilyName();
|
||||
wstring gname = dbR->getGivenName();
|
||||
|
||||
if (wcsstr(name.c_str(), fname.c_str()) == nullptr || wcsstr(name.c_str(), gname.c_str()) == nullptr)
|
||||
dbR = nullptr;
|
||||
}
|
||||
}
|
||||
if (dbR == nullptr) {
|
||||
oClub * dbClub = extractClub(gdi);
|
||||
dbR = db.getRunnerByName(name, dbClub ? dbClub->getId() : 0, 0);
|
||||
}
|
||||
return dbR;
|
||||
}
|
||||
|
||||
void TabSI::DirectEntryGUI::updateFees(gdioutput &gdi, const pClass cls, int age) {
|
||||
int fee = cls->getEntryFee(getLocalDate(), age);
|
||||
auto fees = cls->getAllFees();
|
||||
gdi.addItem("Fee", fees);
|
||||
if (fee > 0) {
|
||||
gdi.selectItemByData("Fee", fee);
|
||||
gdi.setText("Fee", tabSI->oe->formatCurrency(fee));
|
||||
}
|
||||
else if (!fees.empty())
|
||||
gdi.selectFirstItem("Fee");
|
||||
|
||||
tabSI->updateEntryInfo(gdi);
|
||||
}
|
||||
|
||||
void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
|
||||
if (type == GUI_FOCUS) {
|
||||
InputInfo &ii = dynamic_cast<InputInfo &>(info);
|
||||
/*if (ii.getExtraInt()) {
|
||||
ii.setExtra(0);
|
||||
gdi.setInputFocus(ii.id, true);
|
||||
}*/
|
||||
}
|
||||
else if (type == GUI_LISTBOX) {
|
||||
ListBoxInfo &lbi = dynamic_cast<ListBoxInfo &>(info);
|
||||
if (lbi.id == "Class") {
|
||||
int clsId = lbi.data;
|
||||
pClass cls = tabSI->oe->getClass(clsId);
|
||||
if (cls) {
|
||||
int age = 0;
|
||||
auto r = tabSI->extractRunner(gdi);
|
||||
if (r) {
|
||||
int year = r->getBirthYear();
|
||||
if (year > 0)
|
||||
age = getThisYear() - year;
|
||||
}
|
||||
updateFees(gdi, cls, age);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == GUI_COMBOCHANGE) {
|
||||
ListBoxInfo &combo = dynamic_cast<ListBoxInfo &>(info);
|
||||
bool show = false;
|
||||
if (tabSI->useDatabase && combo.id == "Club" && combo.text.length() > 1) {
|
||||
auto clubs = tabSI->oe->getRunnerDatabase().getClubSuggestions(combo.text, 20);
|
||||
if (!clubs.empty()) {
|
||||
auto &ac = gdi.addAutoComplete(combo.id);
|
||||
ac.setAutoCompleteHandler(this->tabSI);
|
||||
vector<AutoCompleteRecord> items;
|
||||
for (auto club : clubs)
|
||||
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
|
||||
|
||||
ac.setData(items);
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(combo.id);
|
||||
}
|
||||
}
|
||||
else if (type == GUI_INPUTCHANGE) {
|
||||
InputInfo &ii = dynamic_cast<InputInfo &>(info);
|
||||
bool show = false;
|
||||
if (tabSI->useDatabase && ii.id == "Name") {
|
||||
auto &db = tabSI->oe->getRunnerDatabase();
|
||||
if (ii.text.length() > 1) {
|
||||
auto dbClub = tabSI->extractClub(gdi);
|
||||
auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
|
||||
if (!rw.empty()) {
|
||||
auto &ac = gdi.addAutoComplete(ii.id);
|
||||
ac.setAutoCompleteHandler(this->tabSI);
|
||||
|
||||
ac.setData(getRunnerAutoCompelete(db, rw, dbClub));
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(ii.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<AutoCompleteRecord> TabSI::getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub) {
|
||||
vector<AutoCompleteRecord> items;
|
||||
set<wstring> used;
|
||||
wstring ns;
|
||||
map<wstring, int> strCount;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bool needRerun = false;
|
||||
for (auto r : rw) {
|
||||
if (dbClub) {
|
||||
ns = r.first->getNameCstr();
|
||||
}
|
||||
else {
|
||||
ns = r.first->getNameCstr();
|
||||
int clubId = r.first->dbe().clubNo;
|
||||
auto club = db.getClub(clubId);
|
||||
if (club) {
|
||||
ns += L", " + club->getDisplayName();
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
++strCount[ns];
|
||||
|
||||
if (strCount[ns] > 1) {
|
||||
needRerun = true;
|
||||
int y = r.first->getBirthYear();
|
||||
if (y > 0)
|
||||
ns += L" (" + itow(getThisYear() - y) + L")";
|
||||
}
|
||||
|
||||
items.emplace_back(ns, r.first->getNameCstr(), r.second);
|
||||
}
|
||||
if (!needRerun)
|
||||
break;
|
||||
else if (i == 0) {
|
||||
items.clear();
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void TabSI::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
|
||||
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
|
||||
if (bi) {
|
||||
int ix = info.getCurrentInt();
|
||||
bi->setExtra(ix);
|
||||
if (bi->id == "Name") {
|
||||
auto r = oe->getRunnerDatabase().getRunnerByIndex(ix);
|
||||
int year = r ? r->getBirthYear() : 0;
|
||||
if (year > 0) {
|
||||
int clsId = gdi.getSelectedItem("Class").first;
|
||||
pClass cls = oe->getClass(clsId);
|
||||
if (cls) {
|
||||
directEntryGUI.updateFees(gdi, cls, getThisYear() - year);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gdi.clearAutoComplete("");
|
||||
gdi.TabFocus(1);
|
||||
}
|
||||
|
||||
27
code/TabSI.h
27
code/TabSI.h
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -24,11 +24,13 @@
|
||||
#include "SportIdent.h"
|
||||
#include "Printer.h"
|
||||
#include "inthashmap.h"
|
||||
#include "autocompletehandler.h"
|
||||
|
||||
struct PunchInfo;
|
||||
class csvparser;
|
||||
struct AutoCompleteRecord;
|
||||
|
||||
class TabSI : public TabBase {
|
||||
class TabSI : public TabBase, AutoCompleteHandler {
|
||||
public:
|
||||
enum SIMode {
|
||||
ModeReadOut,
|
||||
@ -166,13 +168,34 @@ private:
|
||||
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
|
||||
friend class TabSI;
|
||||
};
|
||||
|
||||
class DirectEntryGUI : public GuiHandler {
|
||||
TabSI *tabSI;
|
||||
DirectEntryGUI(const DirectEntryGUI&);
|
||||
DirectEntryGUI &operator=(const DirectEntryGUI&);
|
||||
public:
|
||||
|
||||
void updateFees(gdioutput &gdi, const pClass cls, int age);
|
||||
DirectEntryGUI() : tabSI(0) {}
|
||||
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
|
||||
friend class TabSI;
|
||||
};
|
||||
|
||||
EditCardData editCardData;
|
||||
DirectEntryGUI directEntryGUI;
|
||||
|
||||
oClub *extractClub(gdioutput &gdi) const;
|
||||
RunnerWDBEntry *extractRunner(gdioutput &gdi) const;
|
||||
|
||||
protected:
|
||||
void clearCompetitionData();
|
||||
|
||||
public:
|
||||
|
||||
static vector<AutoCompleteRecord> getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub);
|
||||
|
||||
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
|
||||
|
||||
// Returns true if a repeated check should be done (there is more to print)
|
||||
bool checkpPrintQueue(gdioutput &gdi);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1568,7 +1568,7 @@ void Table::print(gdioutput &gdi, HDC hDC, int dx, int dy)
|
||||
}
|
||||
}
|
||||
|
||||
bool Table::UpDown(gdioutput &gdi, int direction)
|
||||
bool Table::upDown(gdioutput &gdi, int direction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
14
code/Table.h
14
code/Table.h
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -56,9 +56,16 @@ class TableCell
|
||||
bool canEdit;
|
||||
CellType type;
|
||||
|
||||
|
||||
friend class TableRow;
|
||||
friend class Table;
|
||||
friend int tblSelectionCB(gdioutput *gdi, int type, void *data);
|
||||
|
||||
public:
|
||||
void update(CellType t, const wstring &str) {
|
||||
contents = str;
|
||||
type = t;
|
||||
}
|
||||
};
|
||||
|
||||
class TableRow
|
||||
@ -83,6 +90,9 @@ public:
|
||||
bool operator<(const TableRow &r){return *SortString<*r.SortString;}
|
||||
static bool cmpint(const TableRow &r1, const TableRow &r2) {return r1.sInt<r2.sInt;}
|
||||
|
||||
CellType getCellType(int index) const { return cells[index].type; }
|
||||
void updateCell(int index, CellType type, const wstring &str) { return cells[index].update(type, str); }
|
||||
|
||||
TableRow(int elem, oBase *object): sInt(0)
|
||||
{
|
||||
cells.resize(elem);
|
||||
@ -346,7 +356,7 @@ public:
|
||||
//Reload a row from data
|
||||
void reloadRow(int rowId);
|
||||
|
||||
bool UpDown(gdioutput &gdi, int direction);
|
||||
bool upDown(gdioutput &gdi, int direction);
|
||||
bool tabFocus(gdioutput &gdi, int direction);
|
||||
bool enter(gdioutput &gdi);
|
||||
void escape(gdioutput &gdi);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#endif // _MSC_VER > 1000
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
193
code/autocomplete.cpp
Normal file
193
code/autocomplete.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Melin Software HB - software@melin.nu - www.melin.nu
|
||||
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <WindowsX.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "autocomplete.h"
|
||||
#include "autocompletehandler.h"
|
||||
extern HINSTANCE hInst;
|
||||
|
||||
AutoCompleteInfo::AutoCompleteInfo(HWND hWnd, const string &widgetId, gdioutput &gdi) : hWnd(hWnd),
|
||||
widgetId(widgetId), lock(false), gdi(gdi),
|
||||
currentIx(0), handler(0), lastVisible(0), modifedAutoComplete(false) {
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
}
|
||||
|
||||
AutoCompleteInfo::~AutoCompleteInfo() {
|
||||
if (hWnd) {
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
|
||||
destoy();
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK completeProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
PAINTSTRUCT ps;
|
||||
HDC hDC;
|
||||
|
||||
void *ptr = (void *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
||||
AutoCompleteInfo *aci = (AutoCompleteInfo *)ptr;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
hDC = BeginPaint(hWnd, &ps);
|
||||
if (aci)
|
||||
aci->paint(hDC);
|
||||
//TextOut(hDC, 5, 5, L"BAE", 3);
|
||||
EndPaint(hWnd, &ps);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP: {
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
if (aci)
|
||||
aci->click(x,y);
|
||||
}
|
||||
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::registerAutoClass() {
|
||||
WNDCLASSEX wcex;
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = (WNDPROC)completeProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInst;
|
||||
wcex.hIcon = 0;// LoadIcon(hInstance, (LPCTSTR)IDI_MEOS);
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = 0;
|
||||
wcex.lpszClassName = L"AUTOCOMPLETE";
|
||||
wcex.hIconSm = 0;// LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
|
||||
|
||||
RegisterClassEx(&wcex);
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::show() {
|
||||
lock = true;
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
InvalidateRect(hWnd, nullptr, true);
|
||||
UpdateWindow(hWnd);
|
||||
lock = false;
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::paint(HDC hDC) {
|
||||
RECT rc;
|
||||
GetClientRect(hWnd, &rc);
|
||||
|
||||
SetDCBrushColor(hDC, RGB(247, 245, 250));
|
||||
SelectObject(hDC, GetStockObject(DC_BRUSH));
|
||||
Rectangle(hDC, -1, -1, rc.right+1, rc.bottom+1);
|
||||
|
||||
int h = int(gdi.getLineHeight()*1.2);
|
||||
int rows = min<int>((rc.bottom -10) / h, data.size());
|
||||
TextInfo ti;
|
||||
ti.format = 0;
|
||||
ti.format = absolutePosition;
|
||||
lastVisible = rows;
|
||||
|
||||
rendered.resize(rows);
|
||||
for (int i = 0; i < rows; i++) {
|
||||
ti.xp = 10;
|
||||
ti.yp = 10 + i * h;
|
||||
|
||||
rendered[i].first = i;
|
||||
auto &rend = rendered[i].second;
|
||||
rend.top = ti.yp-5;
|
||||
rend.bottom = ti.yp + h;
|
||||
rend.left = 5;
|
||||
rend.right = rc.right - 5;
|
||||
|
||||
if (i == currentIx) {
|
||||
ti.color = colorBlack;
|
||||
SetDCBrushColor(hDC, RGB(237, 235, 242));
|
||||
SelectObject(hDC, GetStockObject(DC_PEN));
|
||||
SetDCPenColor(hDC, RGB(165, 160, 180));
|
||||
Rectangle(hDC, rend.left, rend.top+2, rend.right, rend.bottom-2);
|
||||
}
|
||||
else
|
||||
ti.color = colorBlack;
|
||||
|
||||
gdi.RenderString(ti, data[i].display, hDC);
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::click(int x, int y) {
|
||||
POINT pt = { x,y };
|
||||
for (auto &r : rendered) {
|
||||
if (PtInRect(&r.second, pt)) {
|
||||
currentIx = r.first;
|
||||
if (handler) {
|
||||
handler->handleAutoComplete(gdi, *this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::upDown(int direction) {
|
||||
currentIx -= direction;
|
||||
if (currentIx < 0)
|
||||
currentIx = 0;
|
||||
else if (currentIx >= lastVisible)
|
||||
currentIx = lastVisible - 1;
|
||||
|
||||
modifedAutoComplete = true;
|
||||
HDC hDC = GetDC(hWnd);
|
||||
paint(hDC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::enter() {
|
||||
if (handler && currentIx >= 0 && size_t(currentIx) < data.size()) {
|
||||
handler->handleAutoComplete(gdi, *this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::setData(vector<AutoCompleteRecord> &items) {
|
||||
int newDataIx = -1;
|
||||
if (modifedAutoComplete && size_t(currentIx) < data.size()) {
|
||||
for (size_t k = 0; k < items.size(); k++) {
|
||||
if (data[currentIx].id == items[k].id)
|
||||
newDataIx = k;
|
||||
}
|
||||
}
|
||||
if (newDataIx == -1 && !items.empty()) {
|
||||
newDataIx = 0;
|
||||
modifedAutoComplete = false;
|
||||
}
|
||||
data = items;
|
||||
currentIx = newDataIx;
|
||||
}
|
||||
60
code/autocomplete.h
Normal file
60
code/autocomplete.h
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include "gdioutput.h"
|
||||
|
||||
class AutoCompleteHandler;
|
||||
|
||||
struct AutoCompleteRecord {
|
||||
AutoCompleteRecord() : id(-1) {}
|
||||
AutoCompleteRecord(const wstring &display, const wstring &name, int id) : display(display), name(name), id(id) {}
|
||||
wstring display;
|
||||
wstring name;
|
||||
int id;
|
||||
};
|
||||
|
||||
class AutoCompleteInfo {
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
AutoCompleteHandler *handler;
|
||||
HWND hWnd;
|
||||
|
||||
string widgetId;
|
||||
bool lock;
|
||||
gdioutput &gdi;
|
||||
|
||||
vector<AutoCompleteRecord> data;
|
||||
vector<pair<int, RECT>> rendered;
|
||||
|
||||
bool modifedAutoComplete; // True if the user has made a selection
|
||||
int lastVisible;
|
||||
int currentIx;
|
||||
public:
|
||||
AutoCompleteInfo(HWND hWnd, const string &widgetId, gdioutput &gdi);
|
||||
~AutoCompleteInfo();
|
||||
bool matchKey(const string &k) const { return widgetId == k; }
|
||||
|
||||
void destoy() {
|
||||
if (hWnd)
|
||||
DestroyWindow(hWnd);
|
||||
hWnd = nullptr;
|
||||
}
|
||||
|
||||
void paint(HDC hDC);
|
||||
void setData(vector<AutoCompleteRecord> &items);
|
||||
void click(int x, int y);
|
||||
void show();
|
||||
|
||||
void upDown(int direction);
|
||||
void enter();
|
||||
|
||||
bool locked() const { return lock; }
|
||||
const string &getTarget() const { return widgetId; }
|
||||
wstring getCurrent() const { if (size_t(currentIx) < data.size()) return data[currentIx].name; else return L""; }
|
||||
int getCurrentInt() const { if (size_t(currentIx) < data.size()) return data[currentIx].id; else return 0; }
|
||||
|
||||
void setAutoCompleteHandler(AutoCompleteHandler *h) { handler = h; };
|
||||
static void registerAutoClass();
|
||||
};
|
||||
|
||||
10
code/autocompletehandler.h
Normal file
10
code/autocompletehandler.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
class AutoCompleteInfo;
|
||||
class gdioutput;
|
||||
|
||||
class AutoCompleteHandler {
|
||||
public:
|
||||
virtual ~AutoCompleteHandler() = 0 {}
|
||||
virtual void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) = 0;
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -414,22 +414,28 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool csvparser::openOutput(const wstring &filename)
|
||||
bool csvparser::openOutput(const wstring &filename, bool writeUTF)
|
||||
{
|
||||
checkWriteAccess(filename);
|
||||
fout.open(filename);
|
||||
|
||||
if (fout.bad())
|
||||
return false;
|
||||
|
||||
if (writeUTF) {
|
||||
fout.put(-17);
|
||||
fout.put(-69);
|
||||
fout.put(-65);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool csvparser::OutputRow(const string &row)
|
||||
bool csvparser::outputRow(const string &row)
|
||||
{
|
||||
fout << row << endl;
|
||||
return true;
|
||||
}
|
||||
bool csvparser::OutputRow(vector<string> &out)
|
||||
bool csvparser::outputRow(const vector<string> &out)
|
||||
{
|
||||
int size=out.size();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -114,10 +114,11 @@ public:
|
||||
const map<wstring, int> &classNameToNumber,
|
||||
vector<TeamLineup> &teams);
|
||||
|
||||
bool openOutput(const wstring &file);
|
||||
bool openOutput(const wstring &file, bool writeUTF = false);
|
||||
bool closeOutput();
|
||||
bool OutputRow(vector<string> &out);
|
||||
bool OutputRow(const string &row);
|
||||
|
||||
bool outputRow(const vector<string> &out);
|
||||
bool outputRow(const string &row);
|
||||
|
||||
int nimport;
|
||||
bool importOCAD_CSV(oEvent &oe, const wstring &file, bool addClasses);
|
||||
|
||||
1994
code/danish.lng
1994
code/danish.lng
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -639,7 +639,7 @@ Minsta intabbning = Least indentation
|
||||
Minsta intervall i klass = Smallest interval in class
|
||||
Minsta startintervall = Smallest start interval
|
||||
Minsta sträcktid = Shortest leg time
|
||||
Minutstartlista = Minute Start List
|
||||
Minutstartlista = Minute start list
|
||||
Motion = Exercise
|
||||
Multipel = Multiple
|
||||
MySQL Server / IP-adress = MySQL Server / IP-address
|
||||
@ -950,10 +950,10 @@ Startblock = Start block
|
||||
Startblock: %d = Start block: %d
|
||||
Startintervall = Start Interval
|
||||
Startintervall (min) = Start interval (min)
|
||||
Startlista = Start List
|
||||
Startlista %%s - sträcka %d = Start List %%s - Leg %d
|
||||
Startlista - %s = Start List - %s
|
||||
Startlista - X = Start List - X
|
||||
Startlista = Start list
|
||||
Startlista %%s - sträcka %d = Start list %%s - Leg %d
|
||||
Startlista - %s = Start list - %s
|
||||
Startlista - X = Start list - X
|
||||
Startlista ett visst lopp = Start list for the race
|
||||
Startlista lopp X - Y = Start List Race X - Y
|
||||
Startlista, individuell = Start list, individual
|
||||
@ -1465,7 +1465,7 @@ xml-data = xml data
|
||||
åtta = eight
|
||||
åttonde = eighth
|
||||
Kopia (X) = Copy (X)
|
||||
Tillåt samma bana inom basintervall = Allow same course within base interval
|
||||
Tillåt samma bana inom basintervall = Allow same course within base interval (interlace classes)
|
||||
Välj X = Select X
|
||||
Ett startblock spänner över flera starter: X/Y = A start block spans more than one start: X/Y
|
||||
Bricka X = Card X
|
||||
@ -2298,3 +2298,18 @@ Inconsistent qualification rule, X = Inconsistent qualification rule, X
|
||||
help:LockStartList = MeOS will not update assignement to a locked class even if qualification results are altered.
|
||||
Kval-Final-Schema = Load qualification scheme
|
||||
Lås startlista = Lock start list
|
||||
FilterNoCancel = Not cancelled
|
||||
CourseStartTime = Course, start time
|
||||
Startlista, banvis = Start list, by course
|
||||
Stämplingsintervall, rogaining-patrull = Punch interval within Rogaining patrol
|
||||
Patrullresultat (STOR) = Patrol results (LARGE)
|
||||
Patrol Team Rogaining = Patrol Team Rogaining
|
||||
Rogaining results for a patrol = Rogaining results for a patrol of two or more competitors.
|
||||
Exportera ett kalkylblad med lottningsinställningar som du kan redigera och sedan läsa in igen = Export a spreadsheet with draw settings that you can edit and then import again
|
||||
Kalkylblad/csv = Spreadsheet/csv
|
||||
Importerar lottningsinställningar = Importing draw settings
|
||||
help:exportdraw = You can export a spreadsheet in csv format, containing classes, number of comptitors, and draw settings for each class. It is then possible to edit the start data and then import it back into MeOS to draw the classes accordingly.
|
||||
prefsDrawInterlace = Interlace class/course when drawing start lists
|
||||
prefsServicePort = Default service port
|
||||
Ingen nummerlapp = No bib
|
||||
Rogaining results for a team, where each team member collects points individually = Rogaining results for a team, where each team member collects points individually
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -39,6 +39,7 @@ enum gdiFonts {
|
||||
fontMediumPlus=14,
|
||||
|
||||
italicSmall = 15,
|
||||
textImage = 99,
|
||||
formatIgnore = 1000,
|
||||
};
|
||||
|
||||
@ -55,6 +56,7 @@ const int timeWithTenth = 1<<13;
|
||||
const int timeSeconds = 1<<14;
|
||||
const int timerIgnoreSign = 1<<15;
|
||||
const int Capitalize = 1<<16;
|
||||
const int absolutePosition = 1 << 17;
|
||||
|
||||
enum GDICOLOR {colorBlack = RGB(0,0,0),
|
||||
colorRed = RGB(128,0,0),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -56,7 +56,10 @@
|
||||
#include "Printer.h"
|
||||
#include "recorder.h"
|
||||
#include "animationdata.h"
|
||||
#include "image.h"
|
||||
#include "autocomplete.h"
|
||||
|
||||
extern Image image;
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -1099,12 +1102,12 @@ ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id,
|
||||
style |= BS_MULTILINE;
|
||||
height *= 2;
|
||||
}
|
||||
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY,
|
||||
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |style|BS_NOTIFY,
|
||||
x-OffsetX, y, w, height, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
}
|
||||
else {
|
||||
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY,
|
||||
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |style|BS_NOTIFY,
|
||||
x-OffsetX, y-OffsetY-1, w, height, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
}
|
||||
@ -1210,7 +1213,7 @@ ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const wstring
|
||||
ReleaseDC(hWndTarget, hDC);
|
||||
|
||||
bi.hWnd=CreateWindowEx(0,L"BUTTON", L"", WS_TABSTOP|WS_VISIBLE|
|
||||
WS_CHILD|BS_AUTOCHECKBOX|BS_NOTIFY,
|
||||
WS_CHILD | WS_CLIPSIBLINGS |BS_AUTOCHECKBOX|BS_NOTIFY,
|
||||
x-ox, y-oy + (size.cy-h)/2, h, h, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
@ -1311,7 +1314,7 @@ InputInfo &gdioutput::addInput(int x, int y, const string &id, const wstring &te
|
||||
int oy=OffsetY;
|
||||
|
||||
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(),
|
||||
WS_TABSTOP|WS_VISIBLE | WS_CHILD | 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),
|
||||
hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
@ -1365,7 +1368,7 @@ InputInfo &gdioutput::addInputBox(const string &id, int x, int y, int width, int
|
||||
int oy=OffsetY;
|
||||
|
||||
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), WS_HSCROLL|WS_VSCROLL|
|
||||
WS_TABSTOP|WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
|
||||
WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
|
||||
x-ox, y-oy, width, height, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
@ -1450,7 +1453,7 @@ ListBoxInfo &gdioutput::addListBox(int x, int y, const string &id, int width, in
|
||||
int ox=OffsetX;
|
||||
int oy=OffsetY;
|
||||
|
||||
DWORD style=WS_TABSTOP|WS_VISIBLE|WS_CHILD|WS_BORDER|LBS_USETABSTOPS|LBS_NOTIFY|WS_VSCROLL;
|
||||
DWORD style=WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|LBS_USETABSTOPS|LBS_NOTIFY|WS_VSCROLL;
|
||||
|
||||
if (multiple)
|
||||
style|=LBS_MULTIPLESEL;
|
||||
@ -1544,7 +1547,7 @@ ListBoxInfo &gdioutput::addSelection(int x, int y, const string &id, int width,
|
||||
int ox = OffsetX;
|
||||
int oy = OffsetY;
|
||||
|
||||
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL ,
|
||||
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL ,
|
||||
x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
@ -1586,7 +1589,7 @@ ListBoxInfo &gdioutput::addCombo(int x, int y, const string &id, int width, int
|
||||
int ox=OffsetX;
|
||||
int oy=OffsetY;
|
||||
|
||||
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWN |CBS_AUTOHSCROLL,
|
||||
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|CBS_DROPDOWN |CBS_AUTOHSCROLL,
|
||||
x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
@ -2035,6 +2038,7 @@ void gdioutput::processEditMessage(InputInfo &bi, DWORD wParam)
|
||||
break;
|
||||
|
||||
case EN_KILLFOCUS: {
|
||||
autoCompleteInfo.reset();
|
||||
wstring old = bi.focusText;
|
||||
getWindowText(bi.hWnd, bi.text);
|
||||
bi.synchData();
|
||||
@ -2071,6 +2075,8 @@ void gdioutput::processComboMessage(ListBoxInfo &bi, DWORD wParam)
|
||||
lockUpDown = true;
|
||||
break;
|
||||
case CBN_KILLFOCUS: {
|
||||
if (autoCompleteInfo && !autoCompleteInfo->locked())
|
||||
autoCompleteInfo.reset();
|
||||
lockUpDown = false;
|
||||
|
||||
TCHAR bf[1024];
|
||||
@ -2187,6 +2193,7 @@ void gdioutput::processListMessage(ListBoxInfo &bi, DWORD wParam)
|
||||
lockUpDown = true;
|
||||
break;
|
||||
case LBN_KILLFOCUS:
|
||||
autoCompleteInfo.reset();
|
||||
lockUpDown = false;
|
||||
break;
|
||||
case LBN_SELCHANGE:
|
||||
@ -2677,7 +2684,7 @@ InputInfo *gdioutput::getInputFocus()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gdioutput::Enter()
|
||||
void gdioutput::enter()
|
||||
{
|
||||
if (hasCommandLock())
|
||||
return;
|
||||
@ -2702,8 +2709,11 @@ void gdioutput::Enter()
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
void gdioutput::doEnter()
|
||||
{
|
||||
void gdioutput::doEnter() {
|
||||
if (autoCompleteInfo) {
|
||||
autoCompleteInfo->enter();
|
||||
return;
|
||||
}
|
||||
list<TableInfo>::iterator tit;
|
||||
|
||||
if (useTables)
|
||||
@ -2737,7 +2747,7 @@ void gdioutput::doEnter()
|
||||
}
|
||||
}
|
||||
|
||||
bool gdioutput::UpDown(int direction)
|
||||
bool gdioutput::upDown(int direction)
|
||||
{
|
||||
wstring msg;
|
||||
try {
|
||||
@ -2763,17 +2773,21 @@ bool gdioutput::UpDown(int direction)
|
||||
|
||||
bool gdioutput::doUpDown(int direction)
|
||||
{
|
||||
if (autoCompleteInfo) {
|
||||
autoCompleteInfo->upDown(direction);
|
||||
return true;
|
||||
}
|
||||
list<TableInfo>::iterator tit;
|
||||
|
||||
if (useTables)
|
||||
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
|
||||
if (tit->table->UpDown(*this, direction))
|
||||
if (tit->table->upDown(*this, direction))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void gdioutput::Escape()
|
||||
void gdioutput::escape()
|
||||
{
|
||||
if (hasCommandLock())
|
||||
return;
|
||||
@ -2804,6 +2818,11 @@ void gdioutput::doEscape()
|
||||
PostMessage(hWndTarget, WM_CLOSE, 0,0);
|
||||
}
|
||||
|
||||
if (autoCompleteInfo) {
|
||||
autoCompleteInfo.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
list<TableInfo>::iterator tit;
|
||||
|
||||
if (useTables)
|
||||
@ -3969,15 +3988,33 @@ void gdioutput::RenderString(TextInfo &ti, HDC hDC)
|
||||
hDC=hThis=GetDC(hWndTarget);
|
||||
}
|
||||
RECT rc;
|
||||
rc.left=ti.xp-OffsetX;
|
||||
rc.top=ti.yp-OffsetY;
|
||||
if ((ti.format & absolutePosition) == 0) {
|
||||
rc.left = ti.xp - OffsetX;
|
||||
rc.top = ti.yp - OffsetY;
|
||||
}
|
||||
else {
|
||||
rc.left = ti.xp;
|
||||
rc.top = ti.yp;
|
||||
}
|
||||
rc.right = rc.left;
|
||||
rc.bottom = rc.top;
|
||||
|
||||
formatString(ti, hDC);
|
||||
int format=ti.format&0xFF;
|
||||
if (format == textImage) {
|
||||
// Image
|
||||
int id = _wtoi(ti.text.c_str());
|
||||
image.loadImage(id, Image::ImageMethod::Default);
|
||||
int w = image.getWidth(id);
|
||||
int h = image.getHeight(id);
|
||||
image.drawImage(id, Image::ImageMethod::Default, hDC, rc.left, rc.top, w, h);
|
||||
|
||||
if (format != 10 && (breakLines&ti.format) == 0){
|
||||
ti.textRect.left = rc.left;
|
||||
ti.textRect.right = rc.left + w + 5;
|
||||
ti.textRect.top = rc.top;
|
||||
ti.textRect.bottom = rc.bottom + h + 5;
|
||||
}
|
||||
else if (format != 10 && (breakLines&ti.format) == 0){
|
||||
if (ti.xlimit==0){
|
||||
if (ti.format&textRight) {
|
||||
DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX);
|
||||
@ -4110,8 +4147,14 @@ void gdioutput::RenderString(TextInfo &ti, const wstring &text, HDC hDC)
|
||||
return;
|
||||
|
||||
RECT rc;
|
||||
rc.left=ti.xp-OffsetX;
|
||||
rc.top=ti.yp-OffsetY;
|
||||
if ((ti.format & absolutePosition) == 0) {
|
||||
rc.left = ti.xp - OffsetX;
|
||||
rc.top = ti.yp - OffsetY;
|
||||
}
|
||||
else {
|
||||
rc.left = ti.xp;
|
||||
rc.top = ti.yp;
|
||||
}
|
||||
rc.right = rc.left;
|
||||
rc.bottom = rc.top;
|
||||
|
||||
@ -4212,18 +4255,31 @@ void gdioutput::formatString(const TextInfo &ti, HDC hDC) const
|
||||
|
||||
void gdioutput::calcStringSize(TextInfo &ti, HDC hDC_in) const
|
||||
{
|
||||
HDC hDC=hDC_in;
|
||||
|
||||
if (!hDC) {
|
||||
// assert(hWndTarget!=0);
|
||||
hDC=GetDC(hWndTarget);
|
||||
}
|
||||
RECT rc;
|
||||
rc.left=ti.xp-OffsetX;
|
||||
rc.top=ti.yp-OffsetY;
|
||||
rc.right = rc.left;
|
||||
rc.bottom = rc.top;
|
||||
|
||||
if (ti.format == textImage) {
|
||||
// Image
|
||||
int id = _wtoi(ti.text.c_str());
|
||||
int w = image.getWidth(id);
|
||||
int h = image.getHeight(id);
|
||||
ti.textRect.left = rc.left;
|
||||
ti.textRect.right = rc.left + w + 5;
|
||||
ti.textRect.top = rc.top;
|
||||
ti.textRect.bottom = rc.bottom + h + 5;
|
||||
return;
|
||||
}
|
||||
|
||||
HDC hDC = hDC_in;
|
||||
|
||||
if (!hDC) {
|
||||
// assert(hWndTarget!=0);
|
||||
hDC = GetDC(hWndTarget);
|
||||
}
|
||||
resetLast();
|
||||
formatString(ti, hDC);
|
||||
int format=ti.format&0xFF;
|
||||
@ -6847,8 +6903,42 @@ DWORD gdioutput::selectColor(wstring &def, DWORD input) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void gdioutput::setAnimationMode(shared_ptr<AnimationData> &data) {
|
||||
if (animationData && animationData->takeOver(data))
|
||||
return;
|
||||
animationData = data;
|
||||
}
|
||||
|
||||
AutoCompleteInfo &gdioutput::addAutoComplete(const string &key) {
|
||||
BaseInfo &bi = getBaseInfo(key.c_str());
|
||||
RECT rc, rcMain;
|
||||
GetWindowRect(bi.getControlWindow(), &rc);
|
||||
GetWindowRect(hWndTarget, &rcMain);
|
||||
POINT pt;
|
||||
int height = scaleLength(200);
|
||||
pt.x = rc.right;
|
||||
pt.y = min(rc.top, rcMain.bottom-height);
|
||||
ScreenToClient(hWndTarget, &pt);
|
||||
// TODO Place window
|
||||
|
||||
if (autoCompleteInfo && autoCompleteInfo->matchKey(key)) {
|
||||
return *autoCompleteInfo;
|
||||
}
|
||||
|
||||
autoCompleteInfo.reset();
|
||||
|
||||
HWND hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"AUTOCOMPLETE", L"", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS| WS_BORDER ,
|
||||
pt.x, pt.y, scaleLength(350), height, hWndTarget, NULL,
|
||||
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
|
||||
|
||||
autoCompleteInfo.reset(new AutoCompleteInfo(hWnd, key, *this));
|
||||
|
||||
//SendMessage(hWnd, WM_SETFONT, (WPARAM)getGUIFont(), 0);
|
||||
|
||||
return *autoCompleteInfo;
|
||||
}
|
||||
|
||||
void gdioutput::clearAutoComplete(const string &key) {
|
||||
autoCompleteInfo.reset();
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -91,6 +91,8 @@ struct FontInfo {
|
||||
HFONT italic;
|
||||
};
|
||||
|
||||
class AutoCompleteInfo;
|
||||
|
||||
class Recorder;
|
||||
|
||||
class gdioutput {
|
||||
@ -280,8 +282,13 @@ protected:
|
||||
|
||||
shared_ptr<AnimationData> animationData;
|
||||
|
||||
shared_ptr<AutoCompleteInfo> autoCompleteInfo;
|
||||
int defaultCodePage;
|
||||
public:
|
||||
|
||||
AutoCompleteInfo &addAutoComplete(const string &key);
|
||||
void clearAutoComplete(const string &key);
|
||||
bool hasAutoComplete() const { return autoCompleteInfo != nullptr; }
|
||||
// Return the bounding dimension of the desktop
|
||||
void getVirtualScreenSize(RECT &rc);
|
||||
|
||||
@ -635,9 +642,9 @@ public:
|
||||
void clearPage(bool autoRefresh, bool keepToolbar = false);
|
||||
|
||||
void TabFocus(int direction=1);
|
||||
void Enter();
|
||||
void Escape();
|
||||
bool UpDown(int direction);
|
||||
void enter();
|
||||
void escape();
|
||||
bool upDown(int direction);
|
||||
void keyCommand(KeyCommandCode code);
|
||||
|
||||
LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -150,6 +150,8 @@ public:
|
||||
}
|
||||
|
||||
TextInfo &setColor(GDICOLOR c) {color = c; return *this;}
|
||||
GDICOLOR getColor() const { return GDICOLOR(color); }
|
||||
|
||||
TextInfo &changeFont(const wstring &fnt) {font = fnt; return *this;} //Note: size not updated
|
||||
|
||||
bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo; }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -221,7 +221,7 @@ void GeneralResult::sortTeamMembers(vector<oRunner *> &runners) const {
|
||||
template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const {
|
||||
PrincipalSort ps = ClassWise;
|
||||
|
||||
if (so == CourseResult)
|
||||
if (so == CourseResult || so == CourseStartTime)
|
||||
ps = CourseWise;
|
||||
|
||||
else if (so == SortByName || so == SortByFinishTimeReverse ||
|
||||
@ -952,6 +952,7 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
|
||||
parser.declareSymbol("CardControls", "Runner's card, matched control ids (-1 for unmatched punches)", true);
|
||||
|
||||
parser.declareSymbol("Course", "Runner's course", true);
|
||||
parser.declareSymbol("CourseId", "Runner's course id", false);
|
||||
parser.declareSymbol("CourseLength", "Length of course", false);
|
||||
|
||||
parser.declareSymbol("SplitTimes", "Runner's split times", true);
|
||||
@ -979,6 +980,10 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
|
||||
|
||||
parser.declareSymbol("RunnerOutputTimes", "Runner's method output times", true, true);
|
||||
parser.declareSymbol("RunnerOutputNumbers", "Runner's method output numbers", true, true);
|
||||
|
||||
parser.declareSymbol("PatrolRogainingScore", "Patrol score, rogaining", false);
|
||||
parser.declareSymbol("PatrolRogainingReduction", "Patrol score reduction", false);
|
||||
parser.declareSymbol("PatrolRogainingOvertime", "Patrol overtime", false);
|
||||
}
|
||||
|
||||
parser.declareSymbol("MaxTime", "Maximum allowed running time", false);
|
||||
@ -1111,6 +1116,7 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
|
||||
parser.removeSymbol("CardTimes");
|
||||
parser.removeSymbol("Course");
|
||||
parser.removeSymbol("CourseLength");
|
||||
parser.removeSymbol("CourseId");
|
||||
parser.removeSymbol("LegPlace");
|
||||
parser.removeSymbol("LegTimeAfter");
|
||||
parser.removeSymbol("LegTimeDeviation");
|
||||
@ -1129,6 +1135,10 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
|
||||
parser.addSymbol("RunnerFinish", finish);
|
||||
parser.addSymbol("RunnerPoints", points);
|
||||
|
||||
parser.addSymbol("PatrolRogainingScore", team.getRogainingPatrolPoints(false));
|
||||
parser.addSymbol("PatrolRogainingReduction", team.getRogainingPatrolReduction());
|
||||
parser.addSymbol("PatrolRogainingOvertime", team.getRogainingPatrolOvertime());
|
||||
|
||||
parser.addSymbol("RunnerCardPunches", team.getResultCache(oTeam::RCCCardPunches));
|
||||
parser.addSymbol("RunnerCardTimes", team.getResultCache(oTeam::RCCCardTimes));
|
||||
parser.addSymbol("RunnerCardControls", team.getResultCache(oTeam::RCCCardControls));
|
||||
@ -1229,6 +1239,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
|
||||
}
|
||||
|
||||
parser.addSymbol("CourseLength", crs->getLength());
|
||||
parser.addSymbol("CourseId", crs->getId());
|
||||
parser.addSymbol("Course", eCrs);
|
||||
parser.addSymbol("SplitTimes", eSplitTime);
|
||||
parser.addSymbol("SplitTimesAccumulated", eAccTime);
|
||||
@ -1242,6 +1253,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
|
||||
else {
|
||||
vector<int> e;
|
||||
parser.addSymbol("CourseLength", -1);
|
||||
parser.addSymbol("CourseId", 0);
|
||||
parser.addSymbol("Course", e);
|
||||
parser.addSymbol("SplitTimes", e);
|
||||
parser.addSymbol("SplitTimesAccumulated", e);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -264,7 +264,7 @@ Please refer to the MOP documentation for a complete description of all attribut
|
||||
</pre>
|
||||
|
||||
<b>Remarks:</b>
|
||||
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course/i> is included.
|
||||
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course</i> is included.
|
||||
<pre>
|
||||
*person cls="1" stat="1" st="324000" rt="72550" place="1" course=28>
|
||||
*name id="4">Jordan Griesmer*/name>
|
||||
|
||||
254
code/image.cpp
Normal file
254
code/image.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
#include "stdafx.h"
|
||||
#include "image.h"
|
||||
#include "png/png.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <Wincodec.h>
|
||||
#include <fstream>
|
||||
#include "meosexception.h"
|
||||
|
||||
FILE _iob[] = { *stdin, *stdout, *stderr };
|
||||
|
||||
extern "C" FILE * __cdecl __iob_func(void)
|
||||
{
|
||||
return _iob;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct PngData {
|
||||
vector<uint8_t> memory;
|
||||
size_t ptr;
|
||||
PngData() : ptr(0) {}
|
||||
|
||||
size_t read(uint8_t *dst, size_t count);
|
||||
};
|
||||
|
||||
void readDataFromInputStream(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
|
||||
png_voidp io_ptr = png_get_io_ptr(png_ptr);
|
||||
if (io_ptr == NULL)
|
||||
return; // add custom error handling here
|
||||
|
||||
PngData& inputStream = *(PngData*)io_ptr;
|
||||
const size_t bytesRead = inputStream.read((byte*)outBytes, (size_t)byteCountToRead);
|
||||
|
||||
if ((png_size_t)bytesRead != byteCountToRead)
|
||||
return; // add custom error handling here
|
||||
}
|
||||
}
|
||||
|
||||
size_t PngData::read(uint8_t *dst, size_t count) {
|
||||
count = min(size_t(memory.size() - ptr), count);
|
||||
memcpy(dst, &memory[ptr], count);
|
||||
ptr += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
// Creates a stream object initialized with the data from an executable resource.
|
||||
vector<uint8_t> Image::loadResourceToMemory(LPCTSTR lpName, LPCTSTR lpType) {
|
||||
vector<uint8_t> result;
|
||||
// find the resource
|
||||
HRSRC hrsrc = FindResource(NULL, lpName, lpType);
|
||||
if (hrsrc == NULL)
|
||||
return result;
|
||||
|
||||
// load the resource
|
||||
DWORD dwResourceSize = SizeofResource(NULL, hrsrc);
|
||||
HGLOBAL hglbImage = LoadResource(NULL, hrsrc);
|
||||
if (hglbImage == NULL)
|
||||
return result;
|
||||
|
||||
// lock the resource, getting a pointer to its data
|
||||
LPVOID pvSourceResourceData = LockResource(hglbImage);
|
||||
|
||||
result.resize(dwResourceSize);
|
||||
memcpy(&result[0], pvSourceResourceData, dwResourceSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png(vector<uint8_t> &inData, int &width, int &height, ImageMethod method) {
|
||||
PngData inputStream;
|
||||
inputStream.memory.swap(inData);
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png)
|
||||
return nullptr;
|
||||
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if (!info)
|
||||
return nullptr;
|
||||
|
||||
png_set_read_fn(png, &inputStream, readDataFromInputStream);
|
||||
|
||||
png_read_info(png, info);
|
||||
|
||||
width = png_get_image_width(png, info);
|
||||
height = png_get_image_height(png, info);
|
||||
int color_type = png_get_color_type(png, info);
|
||||
int bit_depth = png_get_bit_depth(png, info);
|
||||
|
||||
// Read any color_type into 8bit depth, RGBA format.
|
||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||
|
||||
if (bit_depth == 16)
|
||||
png_set_strip_16(png);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png);
|
||||
|
||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png);
|
||||
|
||||
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha(png);
|
||||
|
||||
// These color_type don't have an alpha channel then fill it with 0xff.
|
||||
if (color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png);
|
||||
|
||||
png_read_update_info(png, info);
|
||||
|
||||
int rowb = png_get_rowbytes(png, info);
|
||||
vector<vector<png_byte>> data(height, vector<png_byte>(rowb, 0));
|
||||
vector<png_bytep> row_pointers_vec(height);
|
||||
for (int y = 0; y < height; y++) {
|
||||
row_pointers_vec[y] = &data[y][0];
|
||||
}
|
||||
png_bytepp row_pointers = &row_pointers_vec[0];
|
||||
|
||||
png_read_image(png, row_pointers);
|
||||
|
||||
// initialize return value
|
||||
HBITMAP hbmp = NULL;
|
||||
|
||||
// prepare structure giving bitmap information (negative height indicates a top-down DIB)
|
||||
BITMAPINFO bminfo;
|
||||
ZeroMemory(&bminfo, sizeof(bminfo));
|
||||
bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bminfo.bmiHeader.biWidth = width;
|
||||
bminfo.bmiHeader.biHeight = ((LONG)-height);
|
||||
bminfo.bmiHeader.biPlanes = 1;
|
||||
bminfo.bmiHeader.biBitCount = 32;
|
||||
bminfo.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
// create a DIB section that can hold the image
|
||||
void * pvImageBits = NULL;
|
||||
HDC hdcScreen = GetDC(NULL);
|
||||
hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
|
||||
// extract the image into the HBITMAP
|
||||
const size_t cbStride = width * 4;
|
||||
const size_t cbImage = cbStride * height;
|
||||
byte *dst = static_cast<byte *>(pvImageBits);
|
||||
for (int y = 0; y < height; y++) {
|
||||
byte *row = dst + cbStride * y;
|
||||
byte *src = row_pointers_vec[y];
|
||||
|
||||
if (method == ImageMethod::MonoAlpha) {
|
||||
for (size_t x = 0; x < cbStride; x += 4) {
|
||||
row[x + 2] = 0;// src[x + 0]; // Red
|
||||
row[x + 1] = 0;// src[x + 1]; // Green
|
||||
row[x + 0] = 16;// src[x + 2]; // Blue
|
||||
row[x + 3] = 255 - src[x + 0];// ((x/100)%8)*31+1;// 255 - src[x + 0]; // Alpha
|
||||
|
||||
if (row[x + 3] == 0) {
|
||||
row[x + 1] = 0;
|
||||
row[x + 2] = 0;
|
||||
row[x + 0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (method == ImageMethod::Default) {
|
||||
for (size_t x = 0; x < cbStride; x += 4) {
|
||||
row[x + 2] = src[x + 0]; // Red
|
||||
row[x + 1] = src[x + 1]; // Green
|
||||
row[x + 0] = src[x + 2]; // Blue
|
||||
row[x + 3] = src[x + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png_file(const wstring &filename, int &width, int &height, ImageMethod method) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
PngData inputStream;
|
||||
inputStream.memory;
|
||||
|
||||
ifstream fin;
|
||||
fin.open(filename, ios::binary);
|
||||
fin.seekg(0, ios::end);
|
||||
int p2 = (int)fin.tellg();
|
||||
fin.seekg(0, ios::beg);
|
||||
inputStream.memory.resize(p2);
|
||||
fin.read((char *)&inputStream.memory[0], inputStream.memory.size());
|
||||
fin.close();
|
||||
return read_png(inputStream.memory, width, height, method);
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png_resource(LPCTSTR lpName, LPCTSTR lpType, int &width, int &height, ImageMethod method) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
PngData inputStream;
|
||||
inputStream.memory = loadResourceToMemory(lpName, lpType);
|
||||
if (inputStream.memory.empty())
|
||||
return nullptr;
|
||||
return read_png(inputStream.memory, width, height, method);
|
||||
}
|
||||
|
||||
Image::Image()
|
||||
{
|
||||
}
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
}
|
||||
|
||||
// Loads the PNG containing the splash image into a HBITMAP.
|
||||
HBITMAP Image::loadImage(int resource, ImageMethod method) {
|
||||
if (images.count(resource))
|
||||
return images[resource].image;
|
||||
|
||||
int width, height;
|
||||
HBITMAP hbmp = read_png_resource(MAKEINTRESOURCE(resource), _T("PNG"), width, height, method);
|
||||
if (hbmp != 0) {
|
||||
images[resource].image = hbmp;
|
||||
images[resource].width = width;
|
||||
images[resource].height = height;
|
||||
}
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
int Image::getWidth(int resource) {
|
||||
loadImage(resource, ImageMethod::Default);
|
||||
return images[resource].width;
|
||||
}
|
||||
|
||||
int Image::getHeight(int resource) {
|
||||
loadImage(resource, ImageMethod::Default);
|
||||
return images[resource].height;
|
||||
}
|
||||
|
||||
void Image::drawImage(int resource, ImageMethod method, HDC hDC, int x, int y, int width, int height) {
|
||||
HBITMAP bmp = loadImage(resource, method);
|
||||
HDC memdc = CreateCompatibleDC(hDC);
|
||||
SelectObject(memdc, bmp);
|
||||
|
||||
BLENDFUNCTION bf;
|
||||
bf.BlendOp = AC_SRC_OVER;
|
||||
bf.BlendFlags = 0;
|
||||
bf.SourceConstantAlpha =0xFF;
|
||||
bf.AlphaFormat = AC_SRC_ALPHA;
|
||||
AlphaBlend(hDC, x, y, width, height, memdc, 0, 0, width, height, bf);
|
||||
|
||||
DeleteDC(memdc);
|
||||
}
|
||||
41
code/image.h
Normal file
41
code/image.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class Image {
|
||||
public:
|
||||
enum class ImageMethod {
|
||||
Default,
|
||||
MonoAlpha
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
|
||||
static vector<uint8_t> loadResourceToMemory(LPCTSTR lpName, LPCTSTR lpType);
|
||||
static HBITMAP read_png_file(const wstring &filename, int &width, int &height, ImageMethod method);
|
||||
static HBITMAP read_png_resource(LPCTSTR lpName, LPCTSTR lpType, int &width, int &height, ImageMethod method);
|
||||
static HBITMAP read_png(vector<uint8_t> &data, int &width, int &height, ImageMethod method);
|
||||
|
||||
|
||||
|
||||
struct Bmp {
|
||||
HBITMAP image;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
map<int, Bmp> images;
|
||||
public:
|
||||
|
||||
HBITMAP loadImage(int resource, ImageMethod method);
|
||||
|
||||
int getWidth(int resource);
|
||||
int getHeight(int resource);
|
||||
void drawImage(int resource, ImageMethod method, HDC hDC, int x, int y, int width, int height);
|
||||
|
||||
Image();
|
||||
~Image();
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -35,7 +35,8 @@ void base64_encode(const vector<BYTE> &input, string &output);
|
||||
extern gdioutput *gdi_main;
|
||||
|
||||
// Encode a vector vector int {{1}, {1,2,3}, {}, {4,5}} as "1;1,2,3;;4,5"
|
||||
static void packIntInt(vector< vector<int> > v, wstring &def) {
|
||||
static void packIntInt(const vector< vector<int> > &v, wstring &def) {
|
||||
def = L"";
|
||||
for (size_t j = 0; j < v.size(); j++) {
|
||||
if (j>0)
|
||||
def += L";";
|
||||
@ -47,6 +48,16 @@ static void packIntInt(vector< vector<int> > v, wstring &def) {
|
||||
}
|
||||
}
|
||||
|
||||
// Encode a vector vector int {1,2,3} as "1,2,3"
|
||||
static void packInt(const vector<int> &v, wstring &def) {
|
||||
def = L"";
|
||||
for (size_t j = 0; j < v.size(); j++) {
|
||||
if (j>0)
|
||||
def += L",";
|
||||
def += itow(v[j]);
|
||||
}
|
||||
}
|
||||
|
||||
InfoBase::InfoBase(int idIn) : id(idIn), committed(false){
|
||||
}
|
||||
|
||||
@ -88,6 +99,7 @@ InfoBaseCompetitor::InfoBaseCompetitor(int id) : InfoBase(id) {
|
||||
InfoCompetitor::InfoCompetitor(int id) : InfoBaseCompetitor(id) {
|
||||
totalStatus = 0;
|
||||
inputTime = 0;
|
||||
course = 0;
|
||||
}
|
||||
|
||||
InfoTeam::InfoTeam(int id) : InfoBaseCompetitor(id) {
|
||||
@ -162,7 +174,7 @@ bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set<int> &incl
|
||||
map<int, InfoClass>::iterator res = classes.find(wid);
|
||||
if (res == classes.end())
|
||||
res = classes.insert(make_pair(wid, InfoClass(wid))).first;
|
||||
if (res->second.synchronize(*cls[k], ctrls))
|
||||
if (res->second.synchronize(withCourse, *cls[k], ctrls))
|
||||
needCommit(res->second);
|
||||
}
|
||||
|
||||
@ -276,13 +288,30 @@ void InfoRadioControl::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
xml.write("ctrl", prop, name);
|
||||
}
|
||||
|
||||
bool InfoClass::synchronize(oClass &c, const set<int> &ctrls) {
|
||||
bool InfoClass::synchronize(bool includeCourses, oClass &c, const set<int> &ctrls) {
|
||||
const wstring &n = c.getName();
|
||||
int no = c.getSortIndex();
|
||||
bool mod = false;
|
||||
|
||||
vector< vector<int> > rc;
|
||||
size_t s = c.getNumStages();
|
||||
|
||||
if (includeCourses) {
|
||||
set<int> crsSet;
|
||||
for (size_t i = 0; i <= s; i++) {
|
||||
vector<pCourse> crs;
|
||||
c.getCourses(i, crs);
|
||||
for (pCourse pc : crs)
|
||||
crsSet.insert(pc->getId());
|
||||
}
|
||||
vector<int> newCrs(crsSet.begin(), crsSet.end());
|
||||
|
||||
if (newCrs != courses) {
|
||||
courses = newCrs;
|
||||
mod = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (s > 0) {
|
||||
linearLegNumberToActual.clear();
|
||||
|
||||
@ -345,6 +374,10 @@ void InfoClass::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
wstring def;
|
||||
packIntInt(radioControls, def);
|
||||
prop.push_back(make_pair("radio", def));
|
||||
if (courses.size() > 0) {
|
||||
packInt(courses, def);
|
||||
prop.push_back(make_pair("crs", def));
|
||||
}
|
||||
xml.write("cls", prop, name);
|
||||
}
|
||||
|
||||
@ -373,13 +406,16 @@ void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
xml.write("competition", prop, name);
|
||||
}
|
||||
|
||||
void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) const {
|
||||
vector< pair<string, wstring> > prop;
|
||||
prop.push_back(make_pair("org", itow(organizationId)));
|
||||
prop.push_back(make_pair("cls", itow(classId)));
|
||||
prop.push_back(make_pair("stat", itow(status)));
|
||||
prop.push_back(make_pair("st", itow(startTime)));
|
||||
prop.push_back(make_pair("rt", itow(runningTime)));
|
||||
if (course != 0)
|
||||
prop.push_back(make_pair("crs", itow(course)));
|
||||
|
||||
xml.write("base", prop, name);
|
||||
}
|
||||
|
||||
@ -426,20 +462,32 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
|
||||
return ch;
|
||||
}
|
||||
|
||||
bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) {
|
||||
bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &r) {
|
||||
bool ch = synchronizeBase(r);
|
||||
changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes
|
||||
|
||||
int s = StatusOK;
|
||||
int legInput = 0;
|
||||
|
||||
int oldCourse = course;
|
||||
if (useCourse) {
|
||||
auto crs = r.getCourse(false);
|
||||
course = crs ? crs->getId() : 0;
|
||||
}
|
||||
else {
|
||||
course = 0;
|
||||
}
|
||||
|
||||
if (oldCourse != course)
|
||||
ch = true;
|
||||
|
||||
pTeam t = r.getTeam();
|
||||
if (useTotalResults) {
|
||||
legInput = r.getTotalTimeInput() * 10;
|
||||
s = r.getTotalStatusInput();
|
||||
}
|
||||
else if (t && r.getLegNumber() > 0) {
|
||||
legInput = t->getLegRunningTime(r.getLegNumber() - 1, false);
|
||||
legInput = t->getLegRunningTime(r.getLegNumber() - 1, false) * 10;
|
||||
s = t->getLegStatus(r.getLegNumber() - 1, false);
|
||||
}
|
||||
|
||||
@ -460,7 +508,9 @@ bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) {
|
||||
|
||||
bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
|
||||
bool useTotalResults = cmp.includeTotalResults();
|
||||
bool ch = synchronize(useTotalResults, r);
|
||||
bool inludeCourse = cmp.includeCourse();
|
||||
|
||||
bool ch = synchronize(useTotalResults, inludeCourse, r);
|
||||
|
||||
vector<RadioTime> newRT;
|
||||
if (r.getClassId(false) > 0) {
|
||||
@ -493,7 +543,8 @@ void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
vector< pair<string, wstring> > sprop;
|
||||
sprop.push_back(make_pair("id", itow(getId())));
|
||||
xmlbuffer &subTag = xml.startTag("cmp", sprop);
|
||||
InfoBaseCompetitor::serialize(subTag, diffOnly);
|
||||
InfoBaseCompetitor::serialize(subTag, diffOnly, course);
|
||||
|
||||
if (radioTimes.size() > 0 && (!diffOnly || changeRadio)) {
|
||||
string radio;
|
||||
radio.reserve(radioTimes.size() * 12);
|
||||
@ -553,7 +604,7 @@ void InfoTeam::serialize(xmlbuffer &xml, bool diffOnly) const {
|
||||
vector< pair<string, wstring> > prop;
|
||||
prop.push_back(make_pair("id", itow(getId())));
|
||||
xmlbuffer &sub = xml.startTag("tm", prop);
|
||||
InfoBaseCompetitor::serialize(sub, diffOnly);
|
||||
InfoBaseCompetitor::serialize(sub, diffOnly, 0);
|
||||
wstring def;
|
||||
packIntInt(competitors, def);
|
||||
prop.clear();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -114,8 +114,9 @@ class InfoClass : public InfoBase {
|
||||
int sortOrder;
|
||||
vector< vector<int> > radioControls;
|
||||
vector<int> linearLegNumberToActual;
|
||||
vector<int> courses;
|
||||
public:
|
||||
bool synchronize(oClass &c, const set<int> &ctrls);
|
||||
bool synchronize(bool includeCourses, oClass &c, const set<int> &ctrls);
|
||||
void serialize(xmlbuffer &xml, bool diffOnly) const;
|
||||
|
||||
InfoClass(int id);
|
||||
@ -155,7 +156,7 @@ class InfoBaseCompetitor : public InfoBase {
|
||||
int status;
|
||||
int startTime;
|
||||
int runningTime;
|
||||
void serialize(xmlbuffer &xml, bool diffOnly) const;
|
||||
void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
|
||||
bool synchronizeBase(oAbstractRunner &bc);
|
||||
public:
|
||||
InfoBaseCompetitor(int id);
|
||||
@ -167,11 +168,12 @@ class InfoCompetitor : public InfoBaseCompetitor {
|
||||
vector<RadioTime> radioTimes;
|
||||
int inputTime;
|
||||
int totalStatus;
|
||||
int course;
|
||||
bool synchronize(const InfoCompetition &cmp, oRunner &c);
|
||||
bool changeTotalSt;
|
||||
bool changeRadio;
|
||||
public:
|
||||
bool synchronize(bool useTotalResults, oRunner &c);
|
||||
bool synchronize(bool useTotalResults, bool useCourse, oRunner &c);
|
||||
void serialize(xmlbuffer &xml, bool diffOnly) const;
|
||||
|
||||
InfoCompetitor(int id);
|
||||
@ -203,6 +205,7 @@ protected:
|
||||
bool forceComplete;
|
||||
|
||||
bool includeTotal;
|
||||
bool withCourse;
|
||||
|
||||
list<InfoBase *> toCommit;
|
||||
|
||||
@ -217,10 +220,12 @@ protected:
|
||||
public:
|
||||
void serialize(xmlbuffer &xml, bool diffOnly) const;
|
||||
|
||||
|
||||
bool includeTotalResults() const {return includeTotal;}
|
||||
void includeTotalResults(bool inc) {includeTotal = inc;}
|
||||
|
||||
bool includeCourse() const { return withCourse; }
|
||||
void includeCourse(bool inc) { withCourse = inc; }
|
||||
|
||||
const vector<int> &getControls(int classId, int legNumber) const;
|
||||
bool synchronize(oEvent &oe, bool onlyCmp, const set<int> &classes, const set<int> &ctrls);
|
||||
bool synchronize(oEvent &oe) {
|
||||
@ -233,6 +238,5 @@ protected:
|
||||
void commitComplete();
|
||||
|
||||
InfoCompetition(int id);
|
||||
//InfoCompetition(const InfoCompetition &in);
|
||||
virtual ~InfoCompetition() {}
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1499,6 +1499,27 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
|
||||
stages.insert(r);
|
||||
}
|
||||
}
|
||||
|
||||
xmlobject person = xo.getObject("Person");
|
||||
if (!person) {
|
||||
xmlobject teamPerson = xo.getObject("TeamEntryPerson");
|
||||
if (teamPerson)
|
||||
person = teamPerson.getObject("Person");
|
||||
}
|
||||
|
||||
xmlList ids;
|
||||
if (person) {
|
||||
person.getObjects("Id", ids);
|
||||
string type;
|
||||
if (ids.size() > 1) {
|
||||
for (auto &id : ids) {
|
||||
id.getObjectString("type", type);
|
||||
if (!type.empty()) {
|
||||
idProviders.insert(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IOF30Interface::matchStageFilter(const set<int> &stageFilter, const xmlList &races) {
|
||||
@ -1705,7 +1726,33 @@ pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void IOF30Interface::readId(const xmlobject &person, int &pid, __int64 &extId) const {
|
||||
wstring sid;
|
||||
pid = 0;
|
||||
extId = 0;
|
||||
if (preferredIdProvider.empty()) {
|
||||
person.getObjectString("Id", sid);
|
||||
}
|
||||
else {
|
||||
xmlList sids;
|
||||
wstring bsid;
|
||||
person.getObjects("Id", sids);
|
||||
for (auto &x : sids) {
|
||||
auto type = x.getAttrib("type");
|
||||
if (type && type.get() == preferredIdProvider) {
|
||||
sid = x.getw();
|
||||
}
|
||||
else if (bsid.empty())
|
||||
bsid = x.getw();
|
||||
}
|
||||
if (sid.empty())
|
||||
pid = oBase::idFromExtId(oBase::converExtIdentifierString(bsid));
|
||||
}
|
||||
if (!sid.empty()) {
|
||||
extId = oBase::converExtIdentifierString(sid);
|
||||
pid = oBase::idFromExtId(extId);
|
||||
}
|
||||
}
|
||||
|
||||
pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
|
||||
|
||||
@ -1721,11 +1768,35 @@ pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
|
||||
else {
|
||||
name = lang.tl("N.N.");
|
||||
}
|
||||
|
||||
int pid = 0;
|
||||
__int64 extId = 0;
|
||||
readId(person, pid, extId);
|
||||
/*
|
||||
wstring sid;
|
||||
person.getObjectString("Id", sid);
|
||||
__int64 extId = oBase::converExtIdentifierString(sid);
|
||||
int pid = oBase::idFromExtId(extId);
|
||||
int pid = 0;
|
||||
__int64 extId = 0;
|
||||
if (preferredIdProvider.empty()) {
|
||||
person.getObjectString("Id", sid);
|
||||
}
|
||||
else {
|
||||
xmlList sids;
|
||||
wstring bsid;
|
||||
person.getObjects("Id", sids);
|
||||
for (auto &x : sids) {
|
||||
auto type = x.getAttrib("type");
|
||||
if (type && type.get() == preferredIdProvider) {
|
||||
sid = x.getw();
|
||||
}
|
||||
else if (bsid.empty())
|
||||
bsid = x.getw();
|
||||
}
|
||||
if (sid.empty())
|
||||
pid = oBase::idFromExtId(oBase::converExtIdentifierString(bsid));
|
||||
}
|
||||
if (!sid.empty()) {
|
||||
extId = oBase::converExtIdentifierString(sid);
|
||||
pid = oBase::idFromExtId(extId);
|
||||
}*/
|
||||
pRunner r = 0;
|
||||
|
||||
if (pid) {
|
||||
@ -2620,7 +2691,6 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.write("Position", r.getPlace());
|
||||
}
|
||||
else if (teamMember) {
|
||||
//int pos = r.getTeam()->getLegPlace(r.getLegNumber(), false);
|
||||
int pos = r.getPlace();
|
||||
if (pos > 0 && pos < 50000)
|
||||
xml.write("Position", "type", L"Leg", itow(pos));
|
||||
@ -2633,6 +2703,11 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
|
||||
xml.write("Status", formatStatus(r.getStatus()));
|
||||
|
||||
int rg = r.getRogainingPoints(false);
|
||||
if (rg > 0) {
|
||||
xml.write("Score", "type", L"Score", itow(rg));
|
||||
xml.write("Score", "type", L"Penalty", itow(r.getRogainingReduction()));
|
||||
}
|
||||
if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
|
||||
xml.startTag("OverallResult");
|
||||
int rt = r.getTotalRunningTime();
|
||||
@ -3612,3 +3687,11 @@ void IOF30Interface::writeClubDB(const RunnerDB &db, xmlparser &xml) const {
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
void IOF30Interface::getIdTypes(vector<string> &types) {
|
||||
types.clear();
|
||||
types.insert(types.begin(), idProviders.begin(), idProviders.end());
|
||||
}
|
||||
|
||||
void IOF30Interface::setPreferredIdType(const string &type) {
|
||||
preferredIdProvider = type;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -134,6 +134,9 @@ class IOF30Interface {
|
||||
|
||||
bool matchStageFilter(const set<int> &stageFilter, const xmlList &races);
|
||||
|
||||
set<string> idProviders;
|
||||
string preferredIdProvider;
|
||||
|
||||
void readEvent(gdioutput &gdi, const xmlobject &xo,
|
||||
map<int, vector<LegInfo> > &teamClassConfig);
|
||||
pRunner readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team,
|
||||
@ -261,10 +264,15 @@ class IOF30Interface {
|
||||
void writeFullCourse(xmlparser &xml, const oCourse &c,
|
||||
const map<int, wstring> &ctrlId2ExportId);
|
||||
|
||||
void readId(const xmlobject &person, int &pid, __int64 &extId) const;
|
||||
|
||||
public:
|
||||
IOF30Interface(oEvent *oe, bool forceSplitFee);
|
||||
virtual ~IOF30Interface() {}
|
||||
|
||||
void getIdTypes(vector<string> &types);
|
||||
void setPreferredIdType(const string &type);
|
||||
|
||||
void readEventList(gdioutput &gdi, xmlobject &xo);
|
||||
|
||||
/** Scan the entry list to find specification of stage numbers*/
|
||||
|
||||
BIN
code/lib/libpng.lib
Normal file
BIN
code/lib/libpng.lib
Normal file
Binary file not shown.
BIN
code/lib_db/zlibstat.pdb
Normal file
BIN
code/lib_db/zlibstat.pdb
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -515,7 +515,9 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
list.setExtraSpace(k, f);
|
||||
}
|
||||
|
||||
|
||||
list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo"));
|
||||
list.setSupportLegSelection(gdi.isChecked("SupportLegSelection"));
|
||||
|
||||
makeDirty(gdi, MakeDirty, MakeDirty);
|
||||
|
||||
@ -1045,6 +1047,8 @@ void ListEditor::editListProp(gdioutput &gdi, bool newList) {
|
||||
gdi.fillRight();
|
||||
gdi.addCheckbox("SupportFrom", "Support time from control", 0, list.supportFrom());
|
||||
gdi.addCheckbox("SupportTo", "Support time to control", 0, list.supportTo());
|
||||
gdi.addCheckbox("SupportLegSelection", "Support intermediate legs", 0, list.supportLegSelection());
|
||||
|
||||
gdi.dropLine(2);
|
||||
gdi.popX();
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/********************i****************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -501,3 +501,12 @@ const wstring &Localizer::tl(const string &str) const {
|
||||
}
|
||||
return linternal->tl(key);
|
||||
}
|
||||
|
||||
|
||||
const wstring Localizer::tl(const wstring &str, bool cap) const {
|
||||
wstring w = linternal->tl(str);
|
||||
if (capitalizeWords())
|
||||
::capitalizeWords(w);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -66,7 +66,8 @@ public:
|
||||
LocalizerInternal &get() {return *linternal;}
|
||||
const wstring &tl(const string &str) const;
|
||||
const wstring &tl(const wstring &str) const {return linternal->tl(str);}
|
||||
//const wstring &tlw(const wstring &str) const;
|
||||
|
||||
const wstring tl(const wstring &str, bool cap) const;
|
||||
|
||||
void init() {linternal = new LocalizerInternal();}
|
||||
void unload() {delete linternal; linternal = 0;}
|
||||
|
||||
133
code/meos.cpp
133
code/meos.cpp
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -64,7 +64,11 @@
|
||||
#include "meosexception.h"
|
||||
#include "parser.h"
|
||||
#include "restserver.h"
|
||||
#include "autocomplete.h"
|
||||
#include "image.h"
|
||||
|
||||
|
||||
Image image;
|
||||
gdioutput *gdi_main=0;
|
||||
oEvent *gEvent=0;
|
||||
SportIdent *gSI=0;
|
||||
@ -149,6 +153,9 @@ void LoadPage(gdioutput &gdi, TabType type) {
|
||||
static wchar_t settings[260];
|
||||
// Startup path
|
||||
static wchar_t programPath[MAX_PATH];
|
||||
// Exe path
|
||||
static wchar_t exePath[MAX_PATH];
|
||||
|
||||
|
||||
void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
|
||||
MSG msg;
|
||||
@ -175,12 +182,20 @@ void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
|
||||
}
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK splashDialogProc(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ UINT uMsg,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
);
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
hInst = hInstance; // Store instance handle in our global variable
|
||||
|
||||
atexit(dumpLeaks); //
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
|
||||
@ -192,6 +207,11 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
enableTests = true;
|
||||
}
|
||||
|
||||
HWND hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc);
|
||||
ShowWindow(hSplash, SW_SHOW);
|
||||
UpdateWindow(hSplash);
|
||||
DWORD splashStart = GetTickCount();
|
||||
|
||||
for (int k = 0; k < 100; k++) {
|
||||
RunnerStatusOrderMap[k] = 0;
|
||||
}
|
||||
@ -210,6 +230,19 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
|
||||
GetCurrentDirectory(MAX_PATH, programPath);
|
||||
|
||||
GetModuleFileName(NULL, exePath, MAX_PATH);
|
||||
int lastDiv = -1;
|
||||
for (int i = 0; i < MAX_PATH; i++) {
|
||||
if (exePath[i] == 0)
|
||||
break;
|
||||
if (exePath[i] == '\\' || exePath[i] == '/')
|
||||
lastDiv = i;
|
||||
}
|
||||
if (lastDiv != -1)
|
||||
exePath[lastDiv] = 0;
|
||||
else
|
||||
exePath[0] = 0;
|
||||
|
||||
getUserFile(settings, L"meoswpref.xml");
|
||||
Parser::test();
|
||||
|
||||
@ -250,9 +283,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
lang.get().addLangResource(L"Deutsch", L"105");
|
||||
lang.get().addLangResource(L"Dansk", L"106");
|
||||
lang.get().addLangResource(L"Français", L"110");
|
||||
lang.get().addLangResource(L"Russian (ISO 8859-5)", L"107");
|
||||
lang.get().addLangResource(L"English (ISO 8859-2)", L"108");
|
||||
lang.get().addLangResource(L"English (ISO 8859-8)", L"109");
|
||||
lang.get().addLangResource(L"Russian", L"107");
|
||||
|
||||
if (fileExist(L"extra.lng")) {
|
||||
lang.get().addLangResource(L"Extraspråk", L"extra.lng");
|
||||
@ -282,20 +313,37 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
}
|
||||
|
||||
try {
|
||||
vector<wstring> res;
|
||||
#ifdef _DEBUG
|
||||
expandDirectory(L".\\..\\Lists\\", L"*.lxml", res);
|
||||
expandDirectory(L".\\..\\Lists\\", L"*.listdef", res);
|
||||
#endif
|
||||
|
||||
if (exePath[0]) {
|
||||
expandDirectory(exePath, L"*.lxml", res);
|
||||
expandDirectory(exePath, L"*.listdef", res);
|
||||
}
|
||||
|
||||
expandDirectory(programPath, L"*.lxml", res);
|
||||
expandDirectory(programPath, L"*.listdef", res);
|
||||
|
||||
wchar_t listpath[MAX_PATH];
|
||||
getUserFile(listpath, L"");
|
||||
vector<wstring> res;
|
||||
expandDirectory(listpath, L"*.lxml", res);
|
||||
expandDirectory(listpath, L"*.listdef", res);
|
||||
#
|
||||
#ifdef _DEBUG
|
||||
expandDirectory(L".\\Lists\\", L"*.lxml", res);
|
||||
expandDirectory(L".\\Lists\\", L"*.listdef", res);
|
||||
#endif
|
||||
wstring err;
|
||||
|
||||
wstring err;
|
||||
set<wstring> processed;
|
||||
for (size_t k = 0; k<res.size(); k++) {
|
||||
try {
|
||||
|
||||
wchar_t filename[128];
|
||||
wchar_t ext[32];
|
||||
_wsplitpath_s(res[k].c_str(), NULL, 0, NULL, 0, filename, 128, ext, 32);
|
||||
wstring fullFile = wstring(filename) + ext;
|
||||
if (processed.count(fullFile))
|
||||
continue;
|
||||
processed.insert(fullFile);
|
||||
xmlparser xml;
|
||||
|
||||
wcscpy_s(listpath, res[k].c_str());
|
||||
@ -351,6 +399,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0),
|
||||
gEvent->getPropertyString("TextFont", L"Arial"));
|
||||
|
||||
DWORD startupToc = GetTickCount() - splashStart;
|
||||
Sleep(min<int>(1000, max<int>(0,700 - startupToc)));
|
||||
|
||||
// Perform application initialization:
|
||||
if (!InitInstance (hInstance, nCmdShow)) {
|
||||
return FALSE;
|
||||
@ -374,6 +425,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
|
||||
|
||||
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS);
|
||||
|
||||
|
||||
DestroyWindow(hSplash);
|
||||
|
||||
initMySQLCriticalSection(true);
|
||||
// Main message loop:
|
||||
mainMessageLoop(hAccelTable, 0);
|
||||
@ -466,6 +520,8 @@ ATOM MyRegisterClass(HINSTANCE hInstance)
|
||||
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
|
||||
RegisterClassEx(&wcex);
|
||||
|
||||
AutoCompleteInfo::registerAutoClass();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -550,12 +606,15 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
else if (wParam==VK_RETURN && (lParam & (1<<31))) {
|
||||
if (gdi)
|
||||
gdi->Enter();
|
||||
gdi->enter();
|
||||
}
|
||||
else if (wParam==VK_UP) {
|
||||
bool c = false;
|
||||
if (gdi && (lParam & (1<<31)))
|
||||
c = gdi->UpDown(1);
|
||||
c = gdi->upDown(1);
|
||||
|
||||
if (gdi && gdi->hasAutoComplete())
|
||||
return 1;
|
||||
|
||||
if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
|
||||
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
|
||||
@ -569,7 +628,10 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
else if (wParam==VK_DOWN) {
|
||||
bool c = false;
|
||||
if (gdi && (lParam & (1<<31)))
|
||||
c = gdi->UpDown(-1);
|
||||
c = gdi->upDown(-1);
|
||||
|
||||
if (gdi && gdi->hasAutoComplete())
|
||||
return 1;
|
||||
|
||||
if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
|
||||
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
|
||||
@ -584,7 +646,7 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
else if (wParam==VK_ESCAPE && (lParam & (1<<31))) {
|
||||
if (gdi)
|
||||
gdi->Escape();
|
||||
gdi->escape();
|
||||
}
|
||||
else if (wParam==VK_F2) {
|
||||
ProgressWindow pw(hWnd);
|
||||
@ -666,8 +728,6 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
||||
{
|
||||
HWND hWnd;
|
||||
|
||||
hInst = hInstance; // Store instance handle in our global variable
|
||||
//WS_EX_CONTROLPARENT
|
||||
HWND hDskTop=GetDesktopWindow();
|
||||
RECT rc;
|
||||
GetClientRect(hDskTop, &rc);
|
||||
@ -1638,9 +1698,9 @@ void Setup(bool overwrite, bool overwriteAll)
|
||||
wchar_t dir[260];
|
||||
GetCurrentDirectory(260, dir);
|
||||
vector<wstring> dyn;
|
||||
expandDirectory(dir, L"*.lxml", dyn);
|
||||
expandDirectory(dir, L"*.listdef", dyn);
|
||||
expandDirectory(dir, L"*.meos", dyn);
|
||||
if (overwrite)
|
||||
expandDirectory(dir, L"*.meos", dyn);
|
||||
|
||||
for (size_t k = 0; k < dyn.size(); k++)
|
||||
toInstall.push_back(make_pair(dyn[k], true));
|
||||
|
||||
@ -1802,3 +1862,36 @@ void removeTempFiles() {
|
||||
tempPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK splashDialogProc(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ UINT uMsg,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
) {
|
||||
PAINTSTRUCT ps;
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_INITDIALOG:
|
||||
// SetWindowLong(hwndDlg, GWL_EXSTYLE, GetWindowLong(hwndDlg, GWL_EXSTYLE) | WS_EX_LAYERED);
|
||||
// Make this window 40% alpha
|
||||
//SetLayeredWindowAttributes(hwndDlg, 0, (255 * 60) / 100, LWA_ALPHA);
|
||||
break;
|
||||
|
||||
case WM_PAINT: {
|
||||
HDC hdc = BeginPaint(hwndDlg, &ps);
|
||||
RECT rt;
|
||||
GetClientRect(hwndDlg, &rt);
|
||||
image.loadImage(IDI_SPLASHIMAGE, Image::ImageMethod::MonoAlpha);
|
||||
int h = image.getHeight(IDI_SPLASHIMAGE);
|
||||
int w = image.getWidth(IDI_SPLASHIMAGE);
|
||||
image.drawImage(IDI_SPLASHIMAGE, Image::ImageMethod::MonoAlpha, hdc, (rt.right - w) / 2, (rt.bottom - h) / 2, w, h);
|
||||
EndPaint(hwndDlg, &ps);
|
||||
break;
|
||||
}
|
||||
case WM_ERASEBKGND:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
code/meos.png
Normal file
BIN
code/meos.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
36
code/meos.rc
36
code/meos.rc
@ -50,7 +50,8 @@ IDB_ECO BITMAP "bmp00001.bmp"
|
||||
#endif // Neutral (Default) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
IDI_SPLASHIMAGE PNG "meos.png"
|
||||
IDI_MEOSIMAGE PNG "title.png"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
@ -168,7 +169,7 @@ BEGIN
|
||||
VALUE "FileDescription", "meos"
|
||||
VALUE "FileVersion", "3.3.0.1"
|
||||
VALUE "InternalName", "meos"
|
||||
VALUE "LegalCopyright", "Copyright © 2007-2017"
|
||||
VALUE "LegalCopyright", "Copyright © 2007-2018"
|
||||
VALUE "OriginalFilename", "meos.exe"
|
||||
VALUE "ProductName", " meos"
|
||||
VALUE "ProductVersion", "3.4.0.1"
|
||||
@ -188,6 +189,37 @@ END
|
||||
|
||||
IDR_HTML1 HTML "html1.htm"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_SPLASH DIALOGEX 0, 0, 309, 178
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_SYSMENU
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_SPLASH, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 302
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 171
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Swedish (Sweden) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1302,6 +1302,12 @@ static double stringDistance(const wchar_t *a, int al, const wchar_t *b, int bl)
|
||||
return (sqrt(dist)+mfactor*mfactor)/double(al);
|
||||
}
|
||||
|
||||
double stringDistanceAssymetric(const wstring &target, const wstring &sample) {
|
||||
double d = stringDistance(target.c_str(), target.length(), sample.c_str(), sample.length());
|
||||
return min(1.0, d);
|
||||
}
|
||||
|
||||
|
||||
double stringDistance(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int al = wcslen(a);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -160,7 +160,7 @@ wstring getMeosFullVersion();
|
||||
wstring getMajorVersion();
|
||||
wstring getMeosCompectVersion();
|
||||
|
||||
void getSupporters(vector<string> &supp);
|
||||
void getSupporters(vector<wstring> &supp);
|
||||
|
||||
int countWords(const wchar_t *p);
|
||||
|
||||
@ -191,9 +191,10 @@ int toLowerStripped(wchar_t c);
|
||||
const wchar_t *canonizeName(const wchar_t *name);
|
||||
|
||||
/** String distance between 0 and 1. 0 is equal*/
|
||||
//double stringDistance(const char *a, const char *b);
|
||||
double stringDistance(const wchar_t *a, const wchar_t *b);
|
||||
|
||||
/** Return how close sample is to target. 1.0 means equal*/
|
||||
double stringDistanceAssymetric(const wstring &target, const wstring &sample);
|
||||
|
||||
/** Get a number suffix, Start 1 -> 1. Zero for none*/
|
||||
int getNumberSuffix(const string &str);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -336,7 +336,7 @@ bool MeosSQL::createRunnerDB(oEvent *oe, Query &query)
|
||||
query.reset();
|
||||
|
||||
query << C_START_noid("dbRunner")
|
||||
<< C_STRING("Name", 40) << C_INT("CardNo")
|
||||
<< C_STRING("Name", 64) << C_INT("CardNo")
|
||||
<< C_INT("Club") << C_STRING("Nation", 3)
|
||||
<< C_STRING("Sex", 1) << C_INT("BirthYear")
|
||||
<< C_INT64("ExtId") << C_END_noindex();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -116,7 +116,7 @@
|
||||
<Culture>0x041d</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>.\Release/meos.exe</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>./lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
@ -170,7 +170,7 @@
|
||||
<Culture>0x041d</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>.\Debug/meos.exe</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>./lib_db;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
@ -240,6 +240,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="animationdata.cpp" />
|
||||
<ClCompile Include="autocomplete.cpp" />
|
||||
<ClCompile Include="autotask.cpp" />
|
||||
<ClCompile Include="classconfiginfo.cpp" />
|
||||
<ClCompile Include="csvparser.cpp">
|
||||
@ -255,6 +256,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="generalresult.cpp" />
|
||||
<ClCompile Include="HTMLWriter.cpp" />
|
||||
<ClCompile Include="image.cpp" />
|
||||
<ClCompile Include="importformats.cpp" />
|
||||
<ClCompile Include="infoserver.cpp" />
|
||||
<ClCompile Include="iof30interface.cpp" />
|
||||
@ -391,6 +393,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="animationdata.h" />
|
||||
<ClInclude Include="autocomplete.h" />
|
||||
<ClInclude Include="autocompletehandler.h" />
|
||||
<ClInclude Include="autotask.h" />
|
||||
<ClInclude Include="classconfiginfo.h" />
|
||||
<ClInclude Include="gdiconstants.h" />
|
||||
@ -399,6 +403,7 @@
|
||||
<ClInclude Include="gdistructures.h" />
|
||||
<ClInclude Include="generalresult.h" />
|
||||
<ClInclude Include="guihandler.h" />
|
||||
<ClInclude Include="image.h" />
|
||||
<ClInclude Include="infoserver.h" />
|
||||
<ClInclude Include="inthashmap.h" />
|
||||
<ClInclude Include="intkeymap.hpp" />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -16,7 +16,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Melin Software HB - software@melin.nu - www.melin.nu
|
||||
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
||||
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
||||
|
||||
************************************************************************/
|
||||
#include "stdafx.h"
|
||||
@ -29,7 +29,7 @@
|
||||
//V33: abcde
|
||||
//V35: abcde
|
||||
int getMeosBuild() {
|
||||
string revision("$Rev: 634 $");
|
||||
string revision("$Rev: 652 $");
|
||||
return 174 + atoi(revision.substr(5, string::npos).c_str());
|
||||
}
|
||||
|
||||
@ -41,12 +41,12 @@ int getMeosBuild() {
|
||||
//V33: abcdefghij
|
||||
//V34: abcdfg
|
||||
wstring getMeosDate() {
|
||||
wstring date(L"$Date: 2017-12-25 16:08:33 +0100 (må, 25 dec 2017) $");
|
||||
wstring date(L"$Date: 2018-03-04 09:44:43 +0100 (sö, 04 mar 2018) $");
|
||||
return date.substr(7,10);
|
||||
}
|
||||
|
||||
wstring getBuildType() {
|
||||
return L"Snapshot"; // No parantheses (...)
|
||||
return L"RC1"; // No parantheses (...)
|
||||
}
|
||||
|
||||
wstring getMajorVersion() {
|
||||
@ -70,114 +70,119 @@ wstring getMeosCompectVersion() {
|
||||
return getMajorVersion() + L"." + itow(getMeosBuild()) + L" (" + getBuildType() + L")";
|
||||
}
|
||||
|
||||
void getSupporters(vector<string> &supp)
|
||||
void getSupporters(vector<wstring> &supp)
|
||||
{
|
||||
supp.push_back("Centrum OK");
|
||||
supp.push_back("Ove Persson, Piteå IF");
|
||||
supp.push_back("OK Rodhen");
|
||||
supp.push_back("Täby Extreme Challenge");
|
||||
supp.push_back("Thomas Engberg, VK Uvarna");
|
||||
supp.push_back("Eilert Edin, Sidensjö IK");
|
||||
supp.push_back("Göran Nordh, Trollhättans SK");
|
||||
supp.push_back("Roger Gustavsson, OK Tisaren");
|
||||
supp.push_back("Sundsvalls OK");
|
||||
supp.push_back("OK Gipens OL-skytte");
|
||||
supp.push_back("Helsingborgs SOK");
|
||||
supp.push_back("OK Gipens OL-skytte");
|
||||
supp.push_back("Rune Thurén, Vallentuna-Össeby OL");
|
||||
supp.push_back("Roland Persson, Kalmar OK");
|
||||
supp.push_back("Robert Jessen, Främmestads IK");
|
||||
supp.push_back("Anders Platt, Järla Orientering");
|
||||
supp.push_back("Almby IK, Örebro");
|
||||
supp.push_back("Peter Rydesäter, Rehns BK");
|
||||
supp.push_back("IK Hakarpspojkarna");
|
||||
supp.push_back("Rydboholms SK");
|
||||
supp.push_back("IFK Kiruna");
|
||||
supp.push_back("Peter Andersson, Söders SOL");
|
||||
supp.push_back("Björkfors GoIF");
|
||||
supp.push_back("OK Ziemelkurzeme");
|
||||
supp.push_back("Big Foot Orienteers");
|
||||
supp.push_back("FIF Hillerød");
|
||||
supp.push_back("Anne Udd");
|
||||
supp.push_back("OK Orinto");
|
||||
supp.push_back("SOK Träff");
|
||||
supp.push_back("Gamleby OK");
|
||||
supp.push_back("Vänersborgs SK");
|
||||
supp.push_back("Henrik Ortman, Västerås SOK");
|
||||
supp.push_back("Leif Olofsson, Sjuntorp");
|
||||
supp.push_back("Vallentuna/Össeby OL");
|
||||
supp.push_back("Oskarström OK");
|
||||
supp.push_back("Skogslöparna");
|
||||
supp.push_back("OK Milan");
|
||||
supp.push_back("Tjalve IF");
|
||||
supp.push_back("OK Skärmen");
|
||||
supp.push_back("Østkredsen");
|
||||
supp.push_back("OK Roskilde");
|
||||
supp.push_back("Holbæk Orienteringsklub");
|
||||
supp.push_back("Bodens BK");
|
||||
supp.push_back("OK Tyr, Karlstad");
|
||||
supp.push_back("Göteborg-Majorna OK");
|
||||
supp.push_back("OK Järnbärarna, Kopparberg");
|
||||
supp.push_back("FK Åsen");
|
||||
supp.push_back("Ballerup OK");
|
||||
supp.push_back("Olivier Benevello, Valbonne SAO");
|
||||
supp.push_back("Tommy Wåhlin, OK Enen");
|
||||
supp.push_back("Hjobygdens OK");
|
||||
supp.push_back("Tisvilde Hegn OK");
|
||||
supp.push_back("Lindebygdens OK");
|
||||
supp.push_back("OK Flundrehof");
|
||||
supp.push_back("Vittjärvs IK");
|
||||
supp.push_back("Annebergs GIF");
|
||||
supp.push_back("Lars-Eric Gahlin, Östersunds OK");
|
||||
supp.push_back("Sundsvalls OK:s Veteraner");
|
||||
supp.push_back("OK Skogshjortarna");
|
||||
supp.push_back("Kinnaströms SK");
|
||||
supp.push_back("OK Pan Århus");
|
||||
supp.push_back("Jan Ernberg, Täby OK");
|
||||
supp.push_back("Stjärnorps SK");
|
||||
supp.push_back("Mölndal Outdoor IF");
|
||||
supp.push_back("Roland Elg, Fjärås AIK");
|
||||
supp.push_back("Tenhults SOK");
|
||||
supp.push_back("Järfälla OK");
|
||||
supp.push_back("Lars Jonasson");
|
||||
supp.push_back("Anders Larsson, OK Nackhe");
|
||||
supp.push_back("Hans Wilhelmsson");
|
||||
supp.push_back("Patrice Lavallee, Noyon Course d'Orientation");
|
||||
supp.push_back("IFK Linköpings OS");
|
||||
supp.push_back("Lars Ove Karlsson, Västerås SOK");
|
||||
supp.push_back("OK Djerf");
|
||||
supp.push_back("OK Vivill");
|
||||
supp.push_back("IFK Mora OK");
|
||||
supp.push_back("Sonny Andersson, Huskvarna");
|
||||
supp.push_back("Hässleholms OK Skolorientering");
|
||||
supp.push_back("IBM-klubben Orientering");
|
||||
supp.push_back("OK Øst, Birkerød");
|
||||
supp.push_back("OK Klemmingen");
|
||||
supp.push_back("Hans Johansson");
|
||||
supp.push_back("KOB Kysak");
|
||||
supp.push_back("Per Ivarsson, Trollhättans SOK");
|
||||
supp.push_back("Sergio Yañez, ABC TRAIL");
|
||||
supp.push_back("Western Race Services");
|
||||
supp.push_back("IK Gandvik, Skara");
|
||||
supp.push_back("IK Stern");
|
||||
supp.push_back("OK Roslagen");
|
||||
supp.push_back("TSV Malente");
|
||||
supp.push_back("Emmaboda Verda OK");
|
||||
supp.push_back("KOB ATU Košice");
|
||||
supp.push_back("Gävle OK");
|
||||
supp.push_back("Kenneth Gattmalm, Jönköpings OK");
|
||||
supp.push_back("Søllerød OK");
|
||||
supp.push_back("O-travel");
|
||||
supp.push_back("Bengt Bengtsson");
|
||||
supp.push_back("OK Landehof");
|
||||
supp.push_back("OK Orinto");
|
||||
supp.push_back("Bredaryds SOK");
|
||||
supp.push_back("Thore Nilsson, Uddevalla OK");
|
||||
supp.push_back("Timrå SOK");
|
||||
supp.push_back("Åke Larsson, OK Hedströmmen");
|
||||
supp.push_back("Avesta OK");
|
||||
supp.push_back("Motionsorientering Göteborg");
|
||||
supp.push_back("OK Måsen");
|
||||
supp.push_back("IF Thor");
|
||||
supp.push_back("SOS Jindrichuv Hradec");
|
||||
supp.push_back(L"Centrum OK");
|
||||
supp.push_back(L"Ove Persson, Piteå IF");
|
||||
supp.push_back(L"OK Rodhen");
|
||||
supp.push_back(L"Täby Extreme Challenge");
|
||||
supp.push_back(L"Thomas Engberg, VK Uvarna");
|
||||
supp.push_back(L"Eilert Edin, Sidensjö IK");
|
||||
supp.push_back(L"Göran Nordh, Trollhättans SK");
|
||||
supp.push_back(L"Roger Gustavsson, OK Tisaren");
|
||||
supp.push_back(L"Sundsvalls OK");
|
||||
supp.push_back(L"OK Gipens OL-skytte");
|
||||
supp.push_back(L"Helsingborgs SOK");
|
||||
supp.push_back(L"OK Gipens OL-skytte");
|
||||
supp.push_back(L"Rune Thurén, Vallentuna-Össeby OL");
|
||||
supp.push_back(L"Roland Persson, Kalmar OK");
|
||||
supp.push_back(L"Robert Jessen, Främmestads IK");
|
||||
supp.push_back(L"Anders Platt, Järla Orientering");
|
||||
supp.push_back(L"Almby IK, Örebro");
|
||||
supp.push_back(L"Peter Rydesäter, Rehns BK");
|
||||
supp.push_back(L"IK Hakarpspojkarna");
|
||||
supp.push_back(L"Rydboholms SK");
|
||||
supp.push_back(L"IFK Kiruna");
|
||||
supp.push_back(L"Peter Andersson, Söders SOL");
|
||||
supp.push_back(L"Björkfors GoIF");
|
||||
supp.push_back(L"OK Ziemelkurzeme");
|
||||
supp.push_back(L"Big Foot Orienteers");
|
||||
supp.push_back(L"FIF Hillerød");
|
||||
supp.push_back(L"Anne Udd");
|
||||
supp.push_back(L"OK Orinto");
|
||||
supp.push_back(L"SOK Träff");
|
||||
supp.push_back(L"Gamleby OK");
|
||||
supp.push_back(L"Vänersborgs SK");
|
||||
supp.push_back(L"Henrik Ortman, Västerås SOK");
|
||||
supp.push_back(L"Leif Olofsson, Sjuntorp");
|
||||
supp.push_back(L"Vallentuna/Össeby OL");
|
||||
supp.push_back(L"Oskarström OK");
|
||||
supp.push_back(L"Skogslöparna");
|
||||
supp.push_back(L"OK Milan");
|
||||
supp.push_back(L"Tjalve IF");
|
||||
supp.push_back(L"OK Skärmen");
|
||||
supp.push_back(L"Østkredsen");
|
||||
supp.push_back(L"OK Roskilde");
|
||||
supp.push_back(L"Holbæk Orienteringsklub");
|
||||
supp.push_back(L"Bodens BK");
|
||||
supp.push_back(L"OK Tyr, Karlstad");
|
||||
supp.push_back(L"Göteborg-Majorna OK");
|
||||
supp.push_back(L"OK Järnbärarna, Kopparberg");
|
||||
supp.push_back(L"FK Åsen");
|
||||
supp.push_back(L"Ballerup OK");
|
||||
supp.push_back(L"Olivier Benevello, Valbonne SAO");
|
||||
supp.push_back(L"Tommy Wåhlin, OK Enen");
|
||||
supp.push_back(L"Hjobygdens OK");
|
||||
supp.push_back(L"Tisvilde Hegn OK");
|
||||
supp.push_back(L"Lindebygdens OK");
|
||||
supp.push_back(L"OK Flundrehof");
|
||||
supp.push_back(L"Vittjärvs IK");
|
||||
supp.push_back(L"Annebergs GIF");
|
||||
supp.push_back(L"Lars-Eric Gahlin, Östersunds OK");
|
||||
supp.push_back(L"Sundsvalls OK:s Veteraner");
|
||||
supp.push_back(L"OK Skogshjortarna");
|
||||
supp.push_back(L"Kinnaströms SK");
|
||||
supp.push_back(L"OK Pan Århus");
|
||||
supp.push_back(L"Jan Ernberg, Täby OK");
|
||||
supp.push_back(L"Stjärnorps SK");
|
||||
supp.push_back(L"Mölndal Outdoor IF");
|
||||
supp.push_back(L"Roland Elg, Fjärås AIK");
|
||||
supp.push_back(L"Tenhults SOK");
|
||||
supp.push_back(L"Järfälla OK");
|
||||
supp.push_back(L"Lars Jonasson");
|
||||
supp.push_back(L"Anders Larsson, OK Nackhe");
|
||||
supp.push_back(L"Hans Wilhelmsson");
|
||||
supp.push_back(L"Patrice Lavallee, Noyon Course d'Orientation");
|
||||
supp.push_back(L"IFK Linköpings OS");
|
||||
supp.push_back(L"Lars Ove Karlsson, Västerås SOK");
|
||||
supp.push_back(L"OK Djerf");
|
||||
supp.push_back(L"OK Vivill");
|
||||
supp.push_back(L"IFK Mora OK");
|
||||
supp.push_back(L"Sonny Andersson, Huskvarna");
|
||||
supp.push_back(L"Hässleholms OK Skolorientering");
|
||||
supp.push_back(L"IBM-klubben Orientering");
|
||||
supp.push_back(L"OK Øst, Birkerød");
|
||||
supp.push_back(L"OK Klemmingen");
|
||||
supp.push_back(L"Hans Johansson");
|
||||
supp.push_back(L"KOB Kysak");
|
||||
supp.push_back(L"Per Ivarsson, Trollhättans SOK");
|
||||
supp.push_back(L"Sergio Yañez, ABC TRAIL");
|
||||
supp.push_back(L"Western Race Services");
|
||||
supp.push_back(L"IK Gandvik, Skara");
|
||||
supp.push_back(L"IK Stern");
|
||||
supp.push_back(L"OK Roslagen");
|
||||
supp.push_back(L"TSV Malente");
|
||||
supp.push_back(L"Emmaboda Verda OK");
|
||||
supp.push_back(L"KOB ATU Košice");
|
||||
supp.push_back(L"Gävle OK");
|
||||
supp.push_back(L"Kenneth Gattmalm, Jönköpings OK");
|
||||
supp.push_back(L"Søllerød OK");
|
||||
supp.push_back(L"O-travel");
|
||||
supp.push_back(L"Bengt Bengtsson");
|
||||
supp.push_back(L"OK Landehof");
|
||||
supp.push_back(L"OK Orinto");
|
||||
supp.push_back(L"Bredaryds SOK");
|
||||
supp.push_back(L"Thore Nilsson, Uddevalla OK");
|
||||
supp.push_back(L"Timrå SOK");
|
||||
supp.push_back(L"Åke Larsson, OK Hedströmmen");
|
||||
supp.push_back(L"Avesta OK");
|
||||
supp.push_back(L"Motionsorientering Göteborg");
|
||||
supp.push_back(L"OK Måsen");
|
||||
supp.push_back(L"IF Thor");
|
||||
supp.push_back(L"SOS Jindřichův Hradec");
|
||||
supp.push_back(L"Mats Holmberg, OK Gränsen");
|
||||
supp.push_back(L"Christoffer Ohlsson, Uddevalla OK");
|
||||
supp.push_back(L"O-Ringen AB");
|
||||
supp.push_back(L"Hans Carlstedt, Sävedalens AIK");
|
||||
supp.push_back(L"Attunda OK");
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -201,6 +201,7 @@ MetaList::MetaList() {
|
||||
sortOrder = SortByName;
|
||||
supportFromControl = false;
|
||||
supportToControl = false;
|
||||
hideLegSelection = false;
|
||||
}
|
||||
|
||||
MetaListPost::MetaListPost(EPostType type_, EPostType align_, int leg_) : type(type_),
|
||||
@ -264,6 +265,7 @@ void MetaList::initUniqueIndex() const {
|
||||
yx = yx * 31 + checksum(DynamicResult::undecorateTag(resultModule));
|
||||
yx = yx * 31 + supportFromControl;
|
||||
yx = yx * 31 + supportToControl;
|
||||
yx = yx * 37 + hideLegSelection;
|
||||
|
||||
for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it)
|
||||
yx = yx * 31 + *it;
|
||||
@ -530,7 +532,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
sampleClass = cls[0];
|
||||
}
|
||||
pair<int, bool> parLegNumber = par.getLegInfo(sampleClass);
|
||||
|
||||
bool capitalizeTitle = lang.capitalizeWords();
|
||||
resultToIndex.clear();
|
||||
/*if (large == false && par.pageBreak == false) {*/
|
||||
{
|
||||
@ -545,6 +547,9 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
|
||||
string label = "P" + itos(0*1000 + j*100 + k);
|
||||
wstring text = makeDash(encode(cline[k].text));
|
||||
if (capitalizeTitle)
|
||||
capitalizeWords(text);
|
||||
|
||||
gdiFonts font = normalText;
|
||||
if (j == 0)
|
||||
font = boldLarge;
|
||||
@ -603,7 +608,11 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
if (mp.font != formatIgnore)
|
||||
font = mp.font;
|
||||
|
||||
oPrintPost &added = li.addSubHead(oPrintPost(mp.type, encode(mp.text), font|mp.textAdjust,
|
||||
wstring text = encode(mp.text);
|
||||
if (capitalizeTitle)
|
||||
capitalizeWords(text);
|
||||
|
||||
oPrintPost &added = li.addSubHead(oPrintPost(mp.type, text, font|mp.textAdjust,
|
||||
pos.get(label, s_factor), dy + subhead_dy, cline[k].leg == -1 ? parLegNumber : make_pair(cline[k].leg, true))).
|
||||
setFontFace(fontFaces[MLSubHead].font,
|
||||
fontFaces[MLSubHead].scale);
|
||||
@ -1052,6 +1061,8 @@ void MetaList::save(xmlparser &xml, const oEvent *oe) const {
|
||||
xml.write("SupportFrom", supportFromControl);
|
||||
if (supportToControl)
|
||||
xml.write("SupportTo", supportToControl);
|
||||
if (hideLegSelection)
|
||||
xml.write("HideLegSelection", hideLegSelection);
|
||||
|
||||
for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it)
|
||||
xml.write("Filter", "name", filterToSymbol[*it]);
|
||||
@ -1107,6 +1118,7 @@ void MetaList::load(const xmlobject &xDef) {
|
||||
}
|
||||
supportFromControl = xDef.getObjectBool("SupportFrom");
|
||||
supportToControl = xDef.getObjectBool("SupportTo");
|
||||
hideLegSelection =xDef.getObjectBool("HideLegSelection");
|
||||
|
||||
string tmp;
|
||||
xDef.getObjectString("SortOrder", tmp);
|
||||
@ -1782,6 +1794,7 @@ void MetaList::initSymbols() {
|
||||
orderToSymbol[ClassTotalResult] = "ClassTotalResult";
|
||||
orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult";
|
||||
orderToSymbol[CourseResult] = "CourseResult";
|
||||
orderToSymbol[CourseStartTime] = "CourseStartTime";
|
||||
orderToSymbol[ClassTeamLeg] = "ClassTeamLeg";
|
||||
orderToSymbol[Custom] = "CustomSort";
|
||||
|
||||
@ -1801,6 +1814,7 @@ void MetaList::initSymbols() {
|
||||
filterToSymbol[EFilterRentCard] = "FilterRentCard";
|
||||
filterToSymbol[EFilterHasCard] = "FilterHasCard";
|
||||
filterToSymbol[EFilterExcludeDNS] = "FilterStarted";
|
||||
filterToSymbol[EFilterExcludeCANCEL] = "FilterNoCancel";
|
||||
filterToSymbol[EFilterVacant] = "FilterNotVacant";
|
||||
filterToSymbol[EFilterOnlyVacant] = "FilterOnlyVacant";
|
||||
filterToSymbol[EFilterHasNoCard] = "FilterNoCard";
|
||||
@ -2129,7 +2143,7 @@ void MetaListContainer::setupListInfo(int firstIndex,
|
||||
li.Name = lang.tl(ml.getListName());
|
||||
li.listType = ml.getListType();
|
||||
li.supportClasses = ml.supportClasses();
|
||||
li.supportLegs = ml.getListType() == oListInfo::EBaseTypeTeam;
|
||||
li.supportLegs = (ml.getListType() == oListInfo::EBaseTypeTeam) && ml.supportLegSelection();
|
||||
li.supportParameter = !ml.getResultModule().empty();
|
||||
li.supportLarge = true;
|
||||
li.supportFrom = ml.supportFrom();
|
||||
@ -2383,6 +2397,15 @@ MetaList &MetaList::setResultModule(const oEvent &oe, int moduleIx) {
|
||||
throw meosException("Unknown result module");
|
||||
}
|
||||
|
||||
MetaList &MetaList::setSupportLegSelection(bool state) {
|
||||
hideLegSelection = !state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool MetaList::supportLegSelection() const {
|
||||
return !hideLegSelection;
|
||||
}
|
||||
|
||||
MetaList &MetaList::setSupportFromTo(bool from, bool to) {
|
||||
supportFromControl = from;
|
||||
supportToControl = to;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -189,6 +189,7 @@ private:
|
||||
string resultModule;
|
||||
bool supportFromControl;
|
||||
bool supportToControl;
|
||||
bool hideLegSelection;
|
||||
|
||||
enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3};
|
||||
MetaListPost &add(ListIndex ix, const MetaListPost &post);
|
||||
@ -251,6 +252,9 @@ public:
|
||||
void getResultModule(const oEvent &oe, vector< pair<wstring, size_t> > &modules, int ¤tModule) const;
|
||||
const string &getResultModule() const {return resultModule;}
|
||||
|
||||
MetaList &setSupportLegSelection(bool state);
|
||||
bool supportLegSelection() const;
|
||||
|
||||
MetaList &setSupportFromTo(bool from, bool to);
|
||||
bool supportFrom() const {return supportFromControl;}
|
||||
bool supportTo() const {return supportToControl;}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2017 Melin Software HB
|
||||
Copyright (C) 2009-2018 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -64,6 +64,7 @@ enum SortOrder {ClassStartTime,
|
||||
SortByFinishTimeReverse,
|
||||
SortByStartTime,
|
||||
CourseResult,
|
||||
CourseStartTime,
|
||||
SortByEntryTime,
|
||||
Custom,
|
||||
SortEnumLastItem};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user