Merge remote-tracking branch 'melinsoftware/master'

This commit is contained in:
jmonclard 2018-03-15 17:56:42 +01:00
commit a773922c46
172 changed files with 8426 additions and 1734 deletions

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -4,7 +4,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -41,6 +41,7 @@
extern gdioutput *gdi_main; extern gdioutput *gdi_main;
int RunnerDB::cellEntryIndex = -1;
RunnerDB::RunnerDB(oEvent *oe_): oe(oe_) RunnerDB::RunnerDB(oEvent *oe_): oe(oe_)
{ {
@ -107,12 +108,22 @@ RunnerDBEntryV2::RunnerDBEntryV2()
memset(this, 0, sizeof(RunnerDBEntryV2)); memset(this, 0, sizeof(RunnerDBEntryV2));
} }
RunnerDBEntryV3::RunnerDBEntryV3()
{
memset(this, 0, sizeof(RunnerDBEntryV3));
}
void RunnerWDBEntry::getName(wstring &n) const void RunnerWDBEntry::getName(wstring &n) const
{ {
initName(); initName();
n=name; n=name;
} }
const wchar_t *RunnerWDBEntry::getNameCstr() const {
initName();
return name;
}
void RunnerWDBEntry::setName(const wchar_t *n) void RunnerWDBEntry::setName(const wchar_t *n)
{ {
const int blen = min<int>(wcslen(n)+1, baseNameLength); const int blen = min<int>(wcslen(n)+1, baseNameLength);
@ -230,6 +241,22 @@ void RunnerDBEntry::init(const RunnerDBEntryV2 &dbe)
extId = dbe.extId; 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) { void RunnerWDBEntry::init(RunnerDB *p, size_t ixin) {
owner = p; owner = p;
@ -386,6 +413,7 @@ void RunnerDB::importClub(oClub &club, bool matchName)
void RunnerDB::compactifyClubs() void RunnerDB::compactifyClubs()
{ {
chash.clear(); chash.clear();
clubHash.clear();
freeCIx = 0; freeCIx = 0;
map<int, int> clubmap; map<int, int> clubmap;
@ -611,11 +639,7 @@ bool RunnerDB::getClub(int clubId, wstring &club) const
return false; return false;
} }
oClub *RunnerDB::getClub(int clubId) const oClub *RunnerDB::getClub(int clubId) const {
{
//map<int,int>::const_iterator it = chash.find(clubId);
//if (it!=chash.end())
int value; int value;
if (chash.lookup(clubId, value)) if (chash.lookup(clubId, value))
return pClub(&cdb[value]); return pClub(&cdb[value]);
@ -760,7 +784,7 @@ void RunnerDB::saveRunners(const wstring &file)
_SH_DENYWR, _S_IREAD|_S_IWRITE); _SH_DENYWR, _S_IREAD|_S_IWRITE);
if (f!=-1) { if (f!=-1) {
int version = 5460003; int version = 5460004;
_write(f, &version, 4); _write(f, &version, 4);
_write(f, &dataDate, 4); _write(f, &dataDate, 4);
_write(f, &dataTime, 4); _write(f, &dataTime, 4);
@ -839,29 +863,39 @@ void RunnerDB::loadRunners(const wstring &file)
loadedFromServer = false; loadedFromServer = false;
int len = _filelength(f); 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); _close(f);
return;//Failed return;//Failed
} }
int nentry = 0; int nentry = 0;
if (len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntry) == 12) {
int version; int version;
version = 0;
dataDate = 0;
dataTime = 0;
if (len % sizeof(RunnerDBEntry) == 12 || len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntryV3) == 12) {
_read(f, &version, 4); _read(f, &version, 4);
_read(f, &dataDate, 4); _read(f, &dataDate, 4);
_read(f, &dataTime, 4); _read(f, &dataTime, 4);
}
if (version == 5460002 || version == 5460003 || version == 5460004) {
bool migrateV2 = false; bool migrateV2 = false;
bool migrateV3 = false;
if (version == 5460002) { if (version == 5460002) {
migrateV2 = true; migrateV2 = true;
nentry = (len - 12) / sizeof(RunnerDBEntryV2); nentry = (len - 12) / sizeof(RunnerDBEntryV2);
} }
else if (version == 5460003) { else if (version == 5460003) {
nentry = (len - 12) / sizeof(RunnerDBEntryV3);
migrateV3 = true;
}
else if (version == 5460004) {
nentry = (len - 12) / sizeof(RunnerDBEntry); nentry = (len - 12) / sizeof(RunnerDBEntry);
} }
// Else unknown version: fail
rdb.resize(nentry); rdb.resize(nentry);
if (rdb.empty()) { if (rdb.empty()) {
@ -870,11 +904,11 @@ void RunnerDB::loadRunners(const wstring &file)
} }
rwdb.resize(rdb.size()); rwdb.resize(rdb.size());
if (!migrateV2) { if (!migrateV2 && !migrateV3) {
_read(f, &rdb[0], len - 12); _read(f, &rdb[0], len - 12);
_close(f); _close(f);
} }
else { else if (migrateV2) {
vector<RunnerDBEntryV2> rdbV2(nentry); vector<RunnerDBEntryV2> rdbV2(nentry);
_read(f, &rdbV2[0], len - 12); _read(f, &rdbV2[0], len - 12);
_close(f); _close(f);
@ -886,6 +920,18 @@ void RunnerDB::loadRunners(const wstring &file)
throw meosException(ex); 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++) {
rdb[k].init(rdbV3[k]);
rwdb[k].init(this, k);
if (!check(rdb[k]))
throw meosException(ex);
}
}
for (int k = 0; k < nentry; k++) { for (int k = 0; k < nentry; k++) {
rwdb[k].init(this, k); rwdb[k].init(this, k);
@ -893,7 +939,7 @@ void RunnerDB::loadRunners(const wstring &file)
throw meosException(ex); throw meosException(ex);
} }
} }
else { else { //V1
dataDate = 0; dataDate = 0;
dataTime = 0; dataTime = 0;
@ -905,7 +951,7 @@ void RunnerDB::loadRunners(const wstring &file)
return; return;
} }
vector<RunnerDBEntryV1> rdbV1(nentry); vector<RunnerDBEntryV1> rdbV1(nentry);
_lseek(f, 0, SEEK_SET);
_read(f, &rdbV1[0], len); _read(f, &rdbV1[0], len);
_close(f); _close(f);
rwdb.resize(rdb.size()); rwdb.resize(rdb.size());
@ -986,7 +1032,23 @@ void RunnerDB::updateAdd(const oRunner &r, map<int, int> &clubIdMap)
RunnerWDBEntry *dbe = getRunnerByCard(r.getCardNo()); 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()); dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo());
if (dbe) if (dbe)
dbe->dbe().birthYear = r.getDCI().getInt("BirthYear"); dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
@ -1020,6 +1082,7 @@ void RunnerDB::clearClubs()
clearRunners(); // Runners refer to clubs. Clear runners clearRunners(); // Runners refer to clubs. Clear runners
cnhash.clear(); cnhash.clear();
chash.clear(); chash.clear();
clubHash.clear(); // Autocomplete
freeCIx = 0; freeCIx = 0;
cdb.clear(); cdb.clear();
if (clubTable) if (clubTable)
@ -1032,6 +1095,8 @@ void RunnerDB::clearRunners()
nhash.clear(); nhash.clear();
idhash.clear(); idhash.clear();
rhash.clear(); rhash.clear();
runnerHash.clear(); // Autocomplete
runnerHashByClub.clear(); // Autocomplete
rdb.clear(); rdb.clear();
rwdb.clear(); rwdb.clear();
if (runnerTable) if (runnerTable)
@ -1193,11 +1258,27 @@ void RunnerDB::refreshClubTableData(Table &table) {
} }
void RunnerDB::refreshRunnerTableData(Table &table) { void RunnerDB::refreshRunnerTableData(Table &table) {
oe->getDBRunnersInEvent(runnerInEvent); //XXX
for (size_t k = 0; k<oRDB.size(); k++){ for (size_t k = 0; k<oRDB.size(); k++){
if (!oRDB[k].isRemoved()) { if (!oRDB[k].isRemoved()) {
TableRow *row = table.getRowById(oRDB[k].getIndex() + 1); TableRow *row = table.getRowById(oRDB[k].getIndex() + 1);
if (row) if (row) {
row->setObject(oRDB[k]); 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 else
table.setTableProp(0); table.setTableProp(0);
RunnerDB::cellEntryIndex = row;
if (!found) if (!found)
table.set(row++, it, TID_ENTER, L"@+", false, cellAction); table.set(row++, it, TID_ENTER, L"@+", false, cellAction);
else else
@ -1307,6 +1389,8 @@ bool oDBRunnerEntry::inputData(int id, const wstring &input,
r.setName(input.c_str()); r.setName(input.c_str());
r.getName(output); r.getName(output);
db->nhash.clear(); db->nhash.clear();
db->runnerHash.clear();
db->runnerHashByClub.clear();
return true; return true;
case TID_CARD: case TID_CARD:
db->rhash.remove(rd.cardNo); db->rhash.remove(rd.cardNo);
@ -1459,3 +1543,271 @@ const RunnerDBEntry &RunnerWDBEntry::dbe() const {
RunnerDBEntry &RunnerWDBEntry::dbe() { RunnerDBEntry &RunnerWDBEntry::dbe() {
return owner->rdb[ix]; 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;
}

View File

@ -2,18 +2,16 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <set>
#include "inthashmap.h" #include "inthashmap.h"
#include "oclub.h" #include "oclub.h"
#ifdef OLD
#include <hash_set>
#else
#include <unordered_set> #include <unordered_set>
#endif #include <unordered_map>
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -33,8 +31,8 @@
************************************************************************/ ************************************************************************/
const int baseNameLength=40; const int baseNameLength = 64;
const int baseNameLengthUTF=56; const int baseNameLengthUTF = 96;
//Has 0-clearing constructor. Must not contain any //Has 0-clearing constructor. Must not contain any
//dynamic data etc. //dynamic data etc.
@ -65,18 +63,29 @@ struct RunnerDBEntryV2 {
short int reserved; short int reserved;
/** End of V1*/ /** End of V1*/
__int64 extId; __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 { struct RunnerDBEntry {
// Init from old struct // Init from old struct
void init(const RunnerDBEntryV2 &dbe); void init(const RunnerDBEntryV2 &dbe);
void init(const RunnerDBEntryV3 &dbe);
RunnerDBEntry(); RunnerDBEntry();
// 8 it versions // 8 it versions
@ -125,6 +134,9 @@ public:
void setName(const wchar_t *name); void setName(const wchar_t *name);
void setNameUTF(const char *name); void setNameUTF(const char *name);
const wchar_t *RunnerWDBEntry::getNameCstr() const;
wstring getGivenName() const; wstring getGivenName() const;
wstring getFamilyName() const; wstring getFamilyName() const;
@ -152,6 +164,8 @@ private:
Table *runnerTable; Table *runnerTable;
Table *clubTable; Table *clubTable;
static int cellEntryIndex;
bool check(const RunnerDBEntry &rde) const; bool check(const RunnerDBEntry &rde) const;
intkeymap<oClass *, __int64> runnerInEvent; intkeymap<oClass *, __int64> runnerInEvent;
@ -197,7 +211,73 @@ private:
void fillClubs(vector< pair<wstring, size_t> > &out) const; void fillClubs(vector< pair<wstring, size_t> > &out) const;
class ClubNodeHash {
//map<wchar_t, ClubNodeHash> hash;
vector<int> index;
public: 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 generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry);
void generateClubTableData(Table &table, oClub *addEntry); void generateClubTableData(Table &table, oClub *addEntry);
@ -306,7 +386,21 @@ class oDBClubEntry : public oClub {
private: private:
int index; int index;
RunnerDB *db; RunnerDB *db;
wstring canonizedName;
wstring canonizedNameExact;
public: 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(oEvent *oe, int id, int index, RunnerDB *db);
oDBClubEntry(const oClub &c, int index, RunnerDB *db); oDBClubEntry(const oClub &c, int index, RunnerDB *db);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -11,7 +11,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -46,6 +46,22 @@
extern pEvent gEvent; extern pEvent gEvent;
const char *visualDrawWindow = "visualdraw"; 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) TabClass::TabClass(oEvent *poe):TabBase(poe)
{ {
handleCloseWindow.tabClass = this; handleCloseWindow.tabClass = this;
@ -133,11 +149,30 @@ int DrawClassesCB(gdioutput *gdi, int type, void *data)
InputInfo &ii = *(InputInfo *)data; InputInfo &ii = *(InputInfo *)data;
if (ii.id.length() > 1) { if (ii.id.length() > 1) {
int id = atoi(ii.id.substr(1).c_str()); 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); string key = "C" + itos(id);
TextInfo &ti = dynamic_cast<TextInfo&>(gdi->getBaseInfo(key.c_str())); TextInfo &ti = dynamic_cast<TextInfo&>(gdi->getBaseInfo(key.c_str()));
if (ii.changed()) {
changed = changed || ti.getColor() != colorRed;
ti.setColor(colorRed); ti.setColor(colorRed);
if (ii.getBgColor() != colorLightCyan) {
ii.setBgColor(colorLightCyan).refresh();
}
gdi->enableInput("DrawAdjust"); 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(); gdi->refreshFast();
} }
} }
@ -651,20 +686,173 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.refresh(); gdi.refresh();
} }
else if (bi.id=="SaveDrawSettings") { else if (bi.id=="SaveDrawSettings") {
readClassSettings(gdi);
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
ds.firstStart = 3600;
ds.interval = 120;
ds.vacant = 1;
res.push_back(ds);
}
}
else {
readClassSettings(gdi); readClassSettings(gdi);
for (size_t k = 0; k < cInfo.size(); k++) { for (size_t k = 0; k < cInfo.size(); k++) {
const ClassInfo &ci = cInfo[k]; const ClassInfo &ci = cInfo[k];
if (ci.pc) { 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 // Save settings with class
ci.pc->synchronize(false); ds.firstStart = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart); ds.interval = ci.interval * drawInfo.baseInterval;
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval); ds.vacant = ci.nVacant;
ci.pc->setDrawVacant(ci.nVacant);
ci.pc->setDrawNumReserved(ci.nExtra); res.push_back(ds);
ci.pc->synchronize(true);
} }
} }
} }
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") { else if (bi.id=="DoDrawAll") {
readClassSettings(gdi); readClassSettings(gdi);
int method = gdi.getSelectedItem("Method").first; int method = gdi.getSelectedItem("Method").first;
@ -675,19 +863,10 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
int maxST = 0; int maxST = 0;
map<int, vector<ClassDrawSpecification> > specs; map<int, vector<ClassDrawSpecification> > specs;
saveDrawSettings();
for(size_t k=0; k<cInfo.size(); k++) { for(size_t k=0; k<cInfo.size(); k++) {
const ClassInfo &ci=cInfo[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, ClassDrawSpecification cds(ci.classId, 0, drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart,
drawInfo.baseInterval * ci.interval, ci.nVacant); drawInfo.baseInterval * ci.interval, ci.nVacant);
if (drawCoursebased) { if (drawCoursebased) {
@ -791,7 +970,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.popX(); gdi.popX();
gdi.fillRight(); 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("DrawAll", "Manuell lottning", ClassesCB).setExtra(1);
gdi.addButton("Simultaneous", "Gemensam start", ClassesCB); 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.addButton("Cancel", "Återgå", ClassesCB).setCancel();
gdi.dropLine(3); 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(); 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; vector<pClass> cls;
oe->getClasses(cls, false); oe->getClasses(cls, false);
set<int> clsId; set<int> clsId;
@ -1012,64 +1203,11 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
clsId.insert(cls[k]->getId()); clsId.insert(cls[k]->getId());
} }
gdi.setSelection("Classes", clsId); clearPage(gdi, false);
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.addString("", 1, "Grundinställningar"); gdi.dropLine(0.5);
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");
loadBasicDrawSetup(gdi, bx, by, firstStart, maxNumControl, minInterval, vacances, clsId);
} }
else { else {
gdi.restore("Setup"); gdi.restore("Setup");
@ -1077,51 +1215,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.enableEditControls(true); gdi.enableEditControls(true);
} }
gdi.fillRight(); loadReadyToDistribute(gdi, bx, by);
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();
} }
else if (bi.id == "HelpDraw") { else if (bi.id == "HelpDraw") {
@ -1145,6 +1239,12 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
throw meosException("Ingen klass vald."); throw meosException("Ingen klass vald.");
} }
gdi.restore("ReadyToDistribute"); gdi.restore("ReadyToDistribute");
/*
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
gdi.dropLine(3);
*/
drawInfo.classes.clear(); drawInfo.classes.clear();
for (set<int>::iterator it = classes.begin(); it!=classes.end();++it) { 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"); gdi.restore("ReadyToDistribute");
oe->loadDrawSettings(classes, drawInfo, cInfo); 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); writeDrawInfo(gdi, drawInfo);
gdi.enableEditControls(false); 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->addButton("CloseWindow", "Stäng", ClassesCB);
gdi_new->registerEvent("CloseWindow", 0).setHandler(&handleCloseWindow); gdi_new->registerEvent("CloseWindow", 0).setHandler(&handleCloseWindow);
gdi_new->refresh(); gdi_new->refresh();
gdi.refreshFast();
} }
else if (bi.id == "EraseStartAll") { else if (bi.id == "EraseStartAll") {
set<int> classes; set<int> classes;
@ -1872,7 +1917,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
} }
} }
save(gdi, true); save(gdi, true);
pClass pc = oe->addClass(oe->getAutoClassName(), 0); pClass pc = oe->addClass(oe->getAutoClassName(), 0);
if (pc) { if (pc) {
@ -2136,13 +2180,29 @@ void TabClass::showClassSettings(gdioutput &gdi)
gdi.fillRight(); gdi.fillRight();
int id = ci.classId; int id = ci.classId;
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2); GDICOLOR clr = ci.hasFixedTime || ci.nExtraSpecified || ci.nVacantSpecified ? colorDarkGreen : colorBlack;
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);
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) if (k%5 == 4)
gdi.dropLine(1); gdi.dropLine(1);
@ -2161,6 +2221,10 @@ void TabClass::showClassSettings(gdioutput &gdi)
gdi.addButton("SaveDrawSettings", "Spara starttider", ClassesCB, gdi.addButton("SaveDrawSettings", "Spara starttider", ClassesCB,
"Spara inmatade tider i tävlingen utan att tilldela starttider."); "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, gdi.addButton("DrawAllAdjust", "Ändra inställningar", ClassesCB,
"Ändra grundläggande inställningar och gör en ny fördelning").setExtra(13); "Ä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"); "Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan");
gdi.disableInput("DrawAdjust"); gdi.disableInput("DrawAdjust");
} }
gdi.popX(); gdi.popX();
gdi.dropLine(3); gdi.dropLine(3);
@ -3454,7 +3519,7 @@ void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK
gdi.pushY(); gdi.pushY();
int cx = gdi.getCX(); int cx = gdi.getCX();
int width = gdi.scaleLength(230); 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.setTabStops("Classes", 185);
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); gdi.pushX();
@ -4051,13 +4116,28 @@ vector< pair<wstring, size_t> > TabClass::getPairOptions() {
void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfoOut) { void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfoOut) {
drawInfoOut.maxCommonControl = gdi.getSelectedItem("MaxCommonControl").first; drawInfoOut.maxCommonControl = gdi.getSelectedItem("MaxCommonControl").first;
drawInfoOut.maxVacancy=gdi.getTextNo("VacancesMax"); int maxVacancy = gdi.getTextNo("VacancesMax");
drawInfoOut.minVacancy=gdi.getTextNo("VacancesMin"); int minVacancy = gdi.getTextNo("VacancesMin");
drawInfoOut.vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str()); double vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
drawInfoOut.extraFactor = 0.01*_wtof(gdi.getText("Extra").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.baseInterval=convertAbsoluteTimeMS(gdi.getText("BaseInterval"));
drawInfoOut.allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours"); drawInfoOut.allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
oe->setProperty("DrawInterlace", drawInfoOut.allowNeighbourSameCourse ? 1 : 0);
drawInfoOut.coursesTogether = gdi.isChecked("CoursesTogether"); drawInfoOut.coursesTogether = gdi.isChecked("CoursesTogether");
drawInfoOut.minClassInterval = convertAbsoluteTimeMS(gdi.getText("MinInterval")); drawInfoOut.minClassInterval = convertAbsoluteTimeMS(gdi.getText("MinInterval"));
drawInfoOut.maxClassInterval = convertAbsoluteTimeMS(gdi.getText("MaxInterval")); drawInfoOut.maxClassInterval = convertAbsoluteTimeMS(gdi.getText("MaxInterval"));
@ -4115,3 +4195,246 @@ void TabClass::clearPage(gdioutput &gdi, bool autoRefresh) {
gdi.clearPage(autoRefresh); gdi.clearPage(autoRefresh);
gdi.setData("ClassPageLoaded", 1); 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();
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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 save(gdioutput &gdi, bool skipReload);
void legSetup(gdioutput &gdi); void legSetup(gdioutput &gdi);
vector<ClassInfo> cInfo; vector<ClassInfo> cInfo;
void saveDrawSettings() const;
map<int, ClassInfo> cInfoCache; map<int, ClassInfo> cInfoCache;
@ -146,6 +147,10 @@ class TabClass :
void setLockForkingState(gdioutput &gdi, bool poolState, bool lockState); 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: public:
void clearCompetitionData(); void clearCompetitionData();

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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("Street");
fields.push_back("Address"); fields.push_back("Address");
fields.push_back("EMail"); fields.push_back("EMail");
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine(); gdi.dropLine();
gdi.addString("", boldText, "Betalningsinformation"); gdi.addString("", boldText, "Betalningsinformation");
fields.clear(); fields.clear();
fields.push_back("Account"); fields.push_back("Account");
fields.push_back("PaymentDue"); fields.push_back("PaymentDue");
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 10);
gdi.pushX(); gdi.pushX();
gdi.fillRight(); gdi.fillRight();

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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.dropLine();
gdi.addString("", 1, "Behandlar tävlingsdata").setColor(colorGreen); gdi.addString("", 1, "Behandlar tävlingsdata").setColor(colorGreen);
set<int> noFilter; set<int> noFilter;
string noType;
if (createNew && id>0) { if (createNew && id>0) {
gdi.addString("", 1, "Skapar ny tävling"); gdi.addString("", 1, "Skapar ny tävling");
oe->newCompetition(L"New"); 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->setZeroTime(formatTimeHMS(zeroTime));
oe->getDI().setDate("OrdinaryEntry", lastEntry); oe->getDI().setDate("OrdinaryEntry", lastEntry);
if (ci) { if (ci) {
@ -1521,12 +1522,13 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
} }
removeTempFile(tEvent); 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); removeTempFile(tClass);
set<int> stageFilter; set<int> stageFilter;
checkStageFilter(gdi, tEntry, stageFilter); string preferredIdType;
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter); checkStageFilter(gdi, tEntry, stageFilter, preferredIdType);
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter, preferredIdType);
removeTempFile(tEntry); removeTempFile(tEntry);
if (!course.empty()) { if (!course.empty()) {
@ -2357,7 +2359,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
gdi.dropLine(0.4); gdi.dropLine(0.4);
gdi.fillDown(); 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.dropLine(1);
gdi.popX(); gdi.popX();
@ -2370,7 +2372,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.clearPage(false); gdi.clearPage(false);
gdi.addString("", 2, makeDash(L"Om MeOS - ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue); gdi.addString("", 2, makeDash(L"Om MeOS - ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue);
gdi.dropLine(2); 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.dropLine();
gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright " gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright "
"(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB," "(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.dropLine();
gdi.addString("", 1, "Vi stöder MeOS"); gdi.addString("", 1, "Vi stöder MeOS");
vector<string> supp; vector<wstring> supp;
getSupporters(supp); getSupporters(supp);
for (size_t k = 0; k<supp.size(); k++) for (size_t k = 0; k<supp.size(); k++)
gdi.addStringUT(0, supp[k]); gdi.addStringUT(0, supp[k]);
@ -2495,7 +2497,8 @@ bool TabCompetition::loadPage(gdioutput &gdi)
oe->checkNecessaryFeatures(); oe->checkNecessaryFeatures();
gdi.selectTab(tabId); gdi.selectTab(tabId);
gdi.addString("", 3, "MeOS"); //gdi.addString("", 3, "MeOS");
gdi.addString("", textImage, "513");
gdi.dropLine(); gdi.dropLine();
oe->synchronize(); oe->synchronize();
@ -3481,12 +3484,14 @@ TabCompetition::FlowOperation TabCompetition::saveEntries(gdioutput &gdi, bool r
} }
else { else {
set<int> stageFilter; set<int> stageFilter;
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter); string preferredIdType;
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter, preferredIdType);
if (res != FlowContinue) if (res != FlowContinue)
return res; return res;
oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter); oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter, preferredIdType);
} }
if (!isGuide) { if (!isGuide) {
gdi.setWindowTitle(oe->getTitleName()); gdi.setWindowTitle(oe->getTitleName());
@ -3516,23 +3521,34 @@ int stageInfoCB(gdioutput *gdi, int type, void *data)
void mainMessageLoop(HACCEL hAccelTable, DWORD time); 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; xmlparser xml;
xml.read(fname); xml.read(fname);
xmlobject xo = xml.getObject("EntryList"); xmlobject xo = xml.getObject("EntryList");
set<int> scanFilter; set<int> scanFilter;
IOF30Interface reader(oe, false);
vector<string> idProviders;
if (xo) { if (xo) {
if (xo.getAttrib("iofVersion")) { if (xo.getAttrib("iofVersion")) {
IOF30Interface reader(oe, false);
reader.prescanEntryList(xo, scanFilter); reader.prescanEntryList(xo, scanFilter);
reader.getIdTypes(idProviders);
} }
} }
bool stageFilter = scanFilter.size() > 1;
bool idtype = idProviders.size() > 1;
if (scanFilter.size() > 1) { bool needUseInput = stageFilter || idtype;
//gdi.dropLine();
if (needUseInput) {
gdi.enableEditControls(false, true); gdi.enableEditControls(false, true);
gdi.fillDown(); gdi.fillDown();
gdi.pushX(); gdi.pushX();
}
if (stageFilter) {
gdi.dropLine(0.5); gdi.dropLine(0.5);
gdi.addString("", 0, "Det finns anmälningsdata för flera etapper."); gdi.addString("", 0, "Det finns anmälningsdata för flera etapper.");
gdi.dropLine(0.5); gdi.dropLine(0.5);
@ -3548,7 +3564,25 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.selectItemByData("Stage", cn); gdi.selectItemByData("Stage", cn);
else else
gdi.selectItemByData("Stage", 0); 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.dropLine();
gdi.addButton("OK_Stage", "OK", stageInfoCB); gdi.addButton("OK_Stage", "OK", stageInfoCB);
gdi.fillDown(); gdi.fillDown();
@ -3569,10 +3603,14 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.removeControl("OK_Stage"); gdi.removeControl("OK_Stage");
gdi.removeControl("Cancel_Stage"); gdi.removeControl("Cancel_Stage");
if (stageFilter)
gdi.disableInput("Stage"); gdi.disableInput("Stage");
if (idtype)
gdi.disableInput("IdType");
} }
if (ok) { if (ok) {
//OK was pressed //OK was pressed
if (scanFilter.size() > 1) {
int stage = gdi.getSelectedItem("Stage").first; int stage = gdi.getSelectedItem("Stage").first;
if (stage > 0) { if (stage > 0) {
filter.insert(stage); filter.insert(stage);
@ -3581,6 +3619,15 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe); 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; return FlowContinue;
} }
else if (cancel) else if (cancel)
@ -3764,15 +3811,23 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("EMail"); fields.push_back("EMail");
fields.push_back("Homepage"); 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.addString("", 1, "Tidszon");
gdi.dropLine(0.3); gdi.dropLine(0.3);
gdi.addCheckbox("UTC", "Exportera tider i UTC", 0, gdi.addCheckbox("UTC", "Exportera tider i UTC", 0,
oe->getDCI().getInt("UTC") == 1); oe->getDCI().getInt("UTC") == 1);
gdi.newColumn(); gdi.newColumn();
gdi.popY(); gdi.popY();
@ -3785,7 +3840,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("EntryFee"); fields.push_back("EntryFee");
fields.push_back("YouthFee"); fields.push_back("YouthFee");
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 6);
gdi.popX(); gdi.popX();
gdi.dropLine(3); gdi.dropLine(3);
@ -3794,7 +3849,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("OrdinaryEntry"); fields.push_back("OrdinaryEntry");
fields.push_back("LateEntryFactor"); fields.push_back("LateEntryFactor");
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 10);
gdi.fillDown(); gdi.fillDown();
gdi.popX(); gdi.popX();
@ -3805,7 +3860,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("YouthAge"); fields.push_back("YouthAge");
fields.push_back("SeniorAge"); fields.push_back("SeniorAge");
gdi.fillRight(); gdi.fillRight();
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 10);
gdi.fillDown(); gdi.fillDown();
gdi.popX(); gdi.popX();
@ -3818,14 +3873,15 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("CurrencyCode"); fields.push_back("CurrencyCode");
gdi.fillRight(); 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, gdi.addCheckbox("PreSymbol", "Valutasymbol före", 0,
oe->getDCI().getInt("CurrencyPreSymbol") == 1); oe->getDCI().getInt("CurrencyPreSymbol") == 1);
gdi.popX(); gdi.popX();
gdi.dropLine(3); gdi.dropLine(2.5);
bool useFrac = oe->getDCI().getInt("CurrencyFactor") == 100; bool useFrac = oe->getDCI().getInt("CurrencyFactor") == 100;
gdi.addCheckbox("UseFraction", "Tillåt decimaler", CompetitionCB, gdi.addCheckbox("UseFraction", "Tillåt decimaler", CompetitionCB,
useFrac, "Tillåt valutauttryck med decimaler"); useFrac, "Tillåt valutauttryck med decimaler");
@ -3833,7 +3889,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.clear(); fields.clear();
gdi.dropLine(-1); gdi.dropLine(-1);
fields.push_back("CurrencySeparator"); fields.push_back("CurrencySeparator");
oe->getDI().buildDataFields(gdi, fields); oe->getDI().buildDataFields(gdi, fields, 10);
gdi.setInputStatus("CurrencySeparator_odc", useFrac); gdi.setInputStatus("CurrencySeparator_odc", useFrac);
@ -3841,23 +3897,21 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
gdi.popX(); gdi.popX();
gdi.dropLine(3); 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.fillDown();
gdi.addString("", 1, "Tävlingsregler"); gdi.addString("", 1, "Tävlingsregler");
fields.clear(); fields.clear();
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); gdi.pushX();
fields.push_back("MaxTime"); 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); oe->getDI().fillDataFields(gdi);
gdi.dropLine(3); gdi.dropLine(1);
int bottom = gdi.getCY(); int bottom = gdi.getCY();

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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); void entryForm(gdioutput &gdi, bool isGuide);
FlowOperation saveEntries(gdioutput &gdi, bool removeRemoved, 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 setExportOptionsStatus(gdioutput &gdi, int format) const;
void selectStartlistOptions(gdioutput &gdi); void selectStartlistOptions(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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 { else {
set<int> noFilter; 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) { if (addClasses) {
// There is specific course-class matching inside the import of each format, // There is specific course-class matching inside the import of each format,

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -45,6 +45,8 @@
#include "intkeymapimpl.hpp" #include "intkeymapimpl.hpp"
#include "meosexception.h" #include "meosexception.h"
#include "MeOSFeatures.h" #include "MeOSFeatures.h"
#include "autocomplete.h"
#include "RunnerDB.h"
int SportIdentCB(gdioutput *gdi, int type, void *data); int SportIdentCB(gdioutput *gdi, int type, void *data);
@ -183,8 +185,10 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.setInputStatus("Bib", controlBib); 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); oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0); gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
gdi.selectItemByData("RClass", r->getClassId(true)); 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 (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) { else if (type==GUI_INPUT) {
InputInfo ii=*(InputInfo *)data; InputInfo ii=*(InputInfo *)data;
@ -1215,6 +1242,27 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
loadPage(gdi); 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) { else if (type==GUI_CLEAR) {
gdioutput *gdi_settings = getExtraWindow("ecosettings", false); gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings) if (gdi_settings)
@ -1344,16 +1392,21 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
if (cardNo != r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo)) if (cardNo != r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo))
return 0; return 0;
wstring club = gdi.getText("Club"); int clubId = 0;
wstring club;
int birthYear = 0; int birthYear = 0;
if (gdi.hasField("Club")) {
club = gdi.getText("Club");
pClub pc = oe->getClubCreate(0, club); pClub pc = oe->getClubCreate(0, club);
if (pc)
r->updateFromDB(name, pc->getId(), r->getClassId(false), cardNo, birthYear); clubId = pc->getId();
}
r->updateFromDB(name, clubId, r->getClassId(false), cardNo, birthYear);
r->setName(name, true); r->setName(name, true);
r->setCardNo(cardNo, true); r->setCardNo(cardNo, true);
r->setClub(club); r->setClub(club);
int fee = 0; int fee = 0;
if (gdi.hasField("Fee")) { if (gdi.hasField("Fee")) {
ListBoxInfo lbi; 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.addCheckbox("RentCard", "Hyrd", 0, tsi.storedInfo.rentState);
gdi.dropLine(-1.2); 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:");
gdi.addCombo("Club", 220, 300, 0, L"Klubb:");
oe->fillClubs(gdi, "Club"); oe->fillClubs(gdi, "Club");
gdi.setText("Club", tsi.storedInfo.storedClub); gdi.setText("Club", tsi.storedInfo.storedClub);
}
gdi.addInput("Name", tsi.storedInfo.storedName, 16, RunnerCB, L"Namn:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) { if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
if (!tsi.storedInfo.storedFee.empty()) if (!tsi.storedInfo.storedFee.empty())
lastFee = tsi.storedInfo.storedFee; 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); oe->fillFees(gdi, "Fee", true);
gdi.autoGrow("Fee"); gdi.autoGrow("Fee");
@ -1892,7 +1947,6 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
} }
gdi.dropLine(1.2); gdi.dropLine(1.2);
//gdi.addCheckbox("Paid", "Kontant betalning", 0, tsi.storedInfo.hasPaid);
tsi.generatePayModeWidget(gdi); tsi.generatePayModeWidget(gdi);
gdi.dropLine(-0.2); gdi.dropLine(-0.2);
} }
@ -2384,7 +2438,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.dropLine(1); gdi.dropLine(1);
gdi.fillRight(); gdi.fillRight();
gdi.pushX(); gdi.pushX();
gdi.addInput("Name", L"", 16, 0, L"Namn:"); gdi.addInput("Name", L"", 16, RunnerCB, L"Namn:");
if (oe->hasBib(true, false)) { if (oe->hasBib(true, false)) {
gdi.addInput("Bib", L"", 4, 0, L"Nr", L"Nummerlapp"); 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)) { if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
gdi.fillDown(); gdi.fillDown();
gdi.addCombo("Club", 220, 300, 0, L"Klubb:"); gdi.addCombo("Club", 220, 300, RunnerCB, L"Klubb:");
oe->fillClubs(gdi, "Club"); oe->fillClubs(gdi, "Club");
gdi.pushX(); gdi.pushX();
} }
@ -2946,3 +3000,43 @@ void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
gdi.addButton("Save", "Spara").setHandler(h); gdi.addButton("Save", "Spara").setHandler(h);
gdi.refresh(); 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;
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -22,11 +22,12 @@
************************************************************************/ ************************************************************************/
#include "tabbase.h" #include "tabbase.h"
#include "Printer.h" #include "Printer.h"
#include "autocompletehandler.h"
class Table; class Table;
class TabRunner : class TabRunner :
public TabBase public TabBase, AutoCompleteHandler
{ {
private: private:
void addToolbar(gdioutput &gdi); void addToolbar(gdioutput &gdi);
@ -108,8 +109,9 @@ private:
protected: protected:
void clearCompetitionData(); void clearCompetitionData();
pClub extractClub(gdioutput &gdi);
public: public:
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
const char * getTypeStr() const {return "TRunnerTab";} const char * getTypeStr() const {return "TRunnerTab";}
TabType getType() const {return TRunnerTab;} TabType getType() const {return TRunnerTab;}

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -46,9 +46,12 @@
#include "MeOSFeatures.h" #include "MeOSFeatures.h"
#include "RunnerDB.h" #include "RunnerDB.h"
#include "recorder.h" #include "recorder.h"
#include "autocomplete.h"
TabSI::TabSI(oEvent *poe):TabBase(poe) { TabSI::TabSI(oEvent *poe):TabBase(poe) {
editCardData.tabSI = this; editCardData.tabSI = this;
directEntryGUI.tabSI = this;
interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0; interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0;
useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0; useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0;
printSplits = false; printSplits = false;
@ -97,12 +100,12 @@ void TabSI::logCard(const SICard &card)
getDesktopFile(file, readlog.c_str(), sf); getDesktopFile(file, readlog.c_str(), sf);
logger->openOutput(file); logger->openOutput(file);
vector<string> head = SICard::logHeader(); vector<string> head = SICard::logHeader();
logger->OutputRow(head); logger->outputRow(head);
logcounter = 0; logcounter = 0;
} }
vector<string> log = card.codeLogData(++logcounter); vector<string> log = card.codeLogData(++logcounter);
logger->OutputRow(log); logger->outputRow(log);
} }
extern SportIdent *gSI; extern SportIdent *gSI;
@ -111,8 +114,7 @@ extern pEvent gEvent;
void LoadRunnerPage(gdioutput &gdi); 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)); TabSI &tsi = dynamic_cast<TabSI &>(*gdi->getTabs().get(TSITab));
return tsi.siCB(*gdi, type, data); return tsi.siCB(*gdi, type, data);
@ -139,11 +141,11 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
csvparser saver; csvparser saver;
saver.openOutput(file.c_str()); saver.openOutput(file.c_str());
vector<string> head = SICard::logHeader(); vector<string> head = SICard::logHeader();
saver.OutputRow(head); saver.outputRow(head);
int count = 0; int count = 0;
for (list< pair<int, SICard> >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) { for (list< pair<int, SICard> >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) {
vector<string> log = it->second.codeLogData(++count); 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")); r->setStartTimeS(gdi.getText("StartTime"));
wstring bib; wstring bib;
if (r->autoAssignBib()) switch (r->autoAssignBib()) {
case oRunner::BibAssignResult::Assigned:
bib = L", " + lang.tl(L"Nummerlapp: ") + r->getBib(); bib = L", " + lang.tl(L"Nummerlapp: ") + r->getBib();
break;
case oRunner::BibAssignResult::Failed:
bib = L", " + lang.tl(L"Ingen nummerlapp");
break;
}
r->synchronize(); r->synchronize();
gdi.restore("EntryLine"); gdi.restore("EntryLine");
@ -2434,12 +2441,14 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
wstring name; wstring name;
wstring club; wstring club;
int age = 0;
if (useDatabase) { if (useDatabase) {
pRunner db_r=oe->dbLookUpByCard(sic.CardNumber); pRunner db_r=oe->dbLookUpByCard(sic.CardNumber);
if (db_r) { if (db_r) {
name=db_r->getNameRaw(); name=db_r->getNameRaw();
club=db_r->getClub(); club=db_r->getClub();
age = db_r->getBirthAge();
} }
} }
@ -2451,12 +2460,18 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
if (gdi.hasField("Club")) if (gdi.hasField("Club"))
gdi.setText("Club", club); gdi.setText("Club", club);
if (name.empty()) if (club.empty() && gdi.hasField("Club"))
gdi.setInputFocus("Name");
else if (club.empty() && gdi.hasField("Club"))
gdi.setInputFocus("Club"); gdi.setInputFocus("Club");
else if (name.empty())
gdi.setInputFocus("Name");
else else
gdi.setInputFocus("Class"); 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) void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
@ -2536,10 +2551,10 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
storedInfo.checkAge(); storedInfo.checkAge();
gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, L"Bricka:"); gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, L"Bricka:");
gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) { 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"); oe->fillClubs(gdi, "Club");
if (storedInfo.storedClub.empty()) if (storedInfo.storedClub.empty())
gdi.selectItemByData("Club", lastClubId); gdi.selectItemByData("Club", lastClubId);
@ -2547,7 +2562,9 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
gdi.setText("Club", storedInfo.storedClub); 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); oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect);
if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) { 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 { void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
SICard &c = getCard(cardId); SICard &c = getCard(cardId);
if (c.readOutTime[0] == 0) 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++) for (size_t j = 0; j < info.size(); j++)
gdi.addStringUT(0, info[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);
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -24,11 +24,13 @@
#include "SportIdent.h" #include "SportIdent.h"
#include "Printer.h" #include "Printer.h"
#include "inthashmap.h" #include "inthashmap.h"
#include "autocompletehandler.h"
struct PunchInfo; struct PunchInfo;
class csvparser; class csvparser;
struct AutoCompleteRecord;
class TabSI : public TabBase { class TabSI : public TabBase, AutoCompleteHandler {
public: public:
enum SIMode { enum SIMode {
ModeReadOut, ModeReadOut,
@ -166,13 +168,34 @@ private:
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type); void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
friend class TabSI; 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; EditCardData editCardData;
DirectEntryGUI directEntryGUI;
oClub *extractClub(gdioutput &gdi) const;
RunnerWDBEntry *extractRunner(gdioutput &gdi) const;
protected: protected:
void clearCompetitionData(); void clearCompetitionData();
public: 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) // Returns true if a repeated check should be done (there is more to print)
bool checkpPrintQueue(gdioutput &gdi); bool checkpPrintQueue(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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; return false;
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -56,9 +56,16 @@ class TableCell
bool canEdit; bool canEdit;
CellType type; CellType type;
friend class TableRow; friend class TableRow;
friend class Table; friend class Table;
friend int tblSelectionCB(gdioutput *gdi, int type, void *data); friend int tblSelectionCB(gdioutput *gdi, int type, void *data);
public:
void update(CellType t, const wstring &str) {
contents = str;
type = t;
}
}; };
class TableRow class TableRow
@ -83,6 +90,9 @@ public:
bool operator<(const TableRow &r){return *SortString<*r.SortString;} bool operator<(const TableRow &r){return *SortString<*r.SortString;}
static bool cmpint(const TableRow &r1, const TableRow &r2) {return r1.sInt<r2.sInt;} 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) TableRow(int elem, oBase *object): sInt(0)
{ {
cells.resize(elem); cells.resize(elem);
@ -346,7 +356,7 @@ public:
//Reload a row from data //Reload a row from data
void reloadRow(int rowId); void reloadRow(int rowId);
bool UpDown(gdioutput &gdi, int direction); bool upDown(gdioutput &gdi, int direction);
bool tabFocus(gdioutput &gdi, int direction); bool tabFocus(gdioutput &gdi, int direction);
bool enter(gdioutput &gdi); bool enter(gdioutput &gdi);
void escape(gdioutput &gdi); void escape(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -10,7 +10,7 @@
#endif // _MSC_VER > 1000 #endif // _MSC_VER > 1000
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

193
code/autocomplete.cpp Normal file
View 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
View 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();
};

View 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;
};

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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; return true;
} }
bool csvparser::openOutput(const wstring &filename) bool csvparser::openOutput(const wstring &filename, bool writeUTF)
{ {
checkWriteAccess(filename); checkWriteAccess(filename);
fout.open(filename); fout.open(filename);
if (fout.bad()) if (fout.bad())
return false; return false;
if (writeUTF) {
fout.put(-17);
fout.put(-69);
fout.put(-65);
}
return true; return true;
} }
bool csvparser::OutputRow(const string &row) bool csvparser::outputRow(const string &row)
{ {
fout << row << endl; fout << row << endl;
return true; return true;
} }
bool csvparser::OutputRow(vector<string> &out) bool csvparser::outputRow(const vector<string> &out)
{ {
int size=out.size(); int size=out.size();

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -114,10 +114,11 @@ public:
const map<wstring, int> &classNameToNumber, const map<wstring, int> &classNameToNumber,
vector<TeamLineup> &teams); vector<TeamLineup> &teams);
bool openOutput(const wstring &file); bool openOutput(const wstring &file, bool writeUTF = false);
bool closeOutput(); 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; int nimport;
bool importOCAD_CSV(oEvent &oe, const wstring &file, bool addClasses); bool importOCAD_CSV(oEvent &oe, const wstring &file, bool addClasses);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -7,7 +7,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -639,7 +639,7 @@ Minsta intabbning = Least indentation
Minsta intervall i klass = Smallest interval in class Minsta intervall i klass = Smallest interval in class
Minsta startintervall = Smallest start interval Minsta startintervall = Smallest start interval
Minsta sträcktid = Shortest leg time Minsta sträcktid = Shortest leg time
Minutstartlista = Minute Start List Minutstartlista = Minute start list
Motion = Exercise Motion = Exercise
Multipel = Multiple Multipel = Multiple
MySQL Server / IP-adress = MySQL Server / IP-address MySQL Server / IP-adress = MySQL Server / IP-address
@ -950,10 +950,10 @@ Startblock = Start block
Startblock: %d = Start block: %d Startblock: %d = Start block: %d
Startintervall = Start Interval Startintervall = Start Interval
Startintervall (min) = Start interval (min) Startintervall (min) = Start interval (min)
Startlista = Start List Startlista = Start list
Startlista %%s - sträcka %d = Start List %%s - Leg %d Startlista %%s - sträcka %d = Start list %%s - Leg %d
Startlista - %s = Start List - %s Startlista - %s = Start list - %s
Startlista - X = Start List - X Startlista - X = Start list - X
Startlista ett visst lopp = Start list for the race Startlista ett visst lopp = Start list for the race
Startlista lopp X - Y = Start List Race X - Y Startlista lopp X - Y = Start List Race X - Y
Startlista, individuell = Start list, individual Startlista, individuell = Start list, individual
@ -1465,7 +1465,7 @@ xml-data = xml data
åtta = eight åtta = eight
åttonde = eighth åttonde = eighth
Kopia (X) = Copy (X) 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 Välj X = Select X
Ett startblock spänner över flera starter: X/Y = A start block spans more than one start: X/Y Ett startblock spänner över flera starter: X/Y = A start block spans more than one start: X/Y
Bricka X = Card X 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. help:LockStartList = MeOS will not update assignement to a locked class even if qualification results are altered.
Kval-Final-Schema = Load qualification scheme Kval-Final-Schema = Load qualification scheme
Lås startlista = Lock start list 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

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -39,6 +39,7 @@ enum gdiFonts {
fontMediumPlus=14, fontMediumPlus=14,
italicSmall = 15, italicSmall = 15,
textImage = 99,
formatIgnore = 1000, formatIgnore = 1000,
}; };
@ -55,6 +56,7 @@ const int timeWithTenth = 1<<13;
const int timeSeconds = 1<<14; const int timeSeconds = 1<<14;
const int timerIgnoreSign = 1<<15; const int timerIgnoreSign = 1<<15;
const int Capitalize = 1<<16; const int Capitalize = 1<<16;
const int absolutePosition = 1 << 17;
enum GDICOLOR {colorBlack = RGB(0,0,0), enum GDICOLOR {colorBlack = RGB(0,0,0),
colorRed = RGB(128,0,0), colorRed = RGB(128,0,0),

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -56,7 +56,10 @@
#include "Printer.h" #include "Printer.h"
#include "recorder.h" #include "recorder.h"
#include "animationdata.h" #include "animationdata.h"
#include "image.h"
#include "autocomplete.h"
extern Image image;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Construction/Destruction // Construction/Destruction
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -1099,12 +1102,12 @@ ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id,
style |= BS_MULTILINE; style |= BS_MULTILINE;
height *= 2; 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, x-OffsetX, y, w, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
} }
else { 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, x-OffsetX, y-OffsetY-1, w, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), 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); ReleaseDC(hWndTarget, hDC);
bi.hWnd=CreateWindowEx(0,L"BUTTON", L"", WS_TABSTOP|WS_VISIBLE| 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, x-ox, y-oy + (size.cy-h)/2, h, h, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), 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; int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(),
WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_BORDER, WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | ES_AUTOHSCROLL | WS_BORDER,
x-ox, y-oy, length*size.cx+scaleLength(8), size.cy+scaleLength(6), x-ox, y-oy, length*size.cx+scaleLength(8), size.cy+scaleLength(6),
hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); 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; int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), WS_HSCROLL|WS_VSCROLL| 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, x-ox, y-oy, width, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), 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 ox=OffsetX;
int oy=OffsetY; 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) if (multiple)
style|=LBS_MULTIPLESEL; style|=LBS_MULTIPLESEL;
@ -1544,7 +1547,7 @@ ListBoxInfo &gdioutput::addSelection(int x, int y, const string &id, int width,
int ox = OffsetX; int ox = OffsetX;
int oy = OffsetY; 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, x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), 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 ox=OffsetX;
int oy=OffsetY; 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, x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL); (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -2035,6 +2038,7 @@ void gdioutput::processEditMessage(InputInfo &bi, DWORD wParam)
break; break;
case EN_KILLFOCUS: { case EN_KILLFOCUS: {
autoCompleteInfo.reset();
wstring old = bi.focusText; wstring old = bi.focusText;
getWindowText(bi.hWnd, bi.text); getWindowText(bi.hWnd, bi.text);
bi.synchData(); bi.synchData();
@ -2071,6 +2075,8 @@ void gdioutput::processComboMessage(ListBoxInfo &bi, DWORD wParam)
lockUpDown = true; lockUpDown = true;
break; break;
case CBN_KILLFOCUS: { case CBN_KILLFOCUS: {
if (autoCompleteInfo && !autoCompleteInfo->locked())
autoCompleteInfo.reset();
lockUpDown = false; lockUpDown = false;
TCHAR bf[1024]; TCHAR bf[1024];
@ -2187,6 +2193,7 @@ void gdioutput::processListMessage(ListBoxInfo &bi, DWORD wParam)
lockUpDown = true; lockUpDown = true;
break; break;
case LBN_KILLFOCUS: case LBN_KILLFOCUS:
autoCompleteInfo.reset();
lockUpDown = false; lockUpDown = false;
break; break;
case LBN_SELCHANGE: case LBN_SELCHANGE:
@ -2677,7 +2684,7 @@ InputInfo *gdioutput::getInputFocus()
return 0; return 0;
} }
void gdioutput::Enter() void gdioutput::enter()
{ {
if (hasCommandLock()) if (hasCommandLock())
return; return;
@ -2702,8 +2709,11 @@ void gdioutput::Enter()
alert(msg); alert(msg);
} }
void gdioutput::doEnter() void gdioutput::doEnter() {
{ if (autoCompleteInfo) {
autoCompleteInfo->enter();
return;
}
list<TableInfo>::iterator tit; list<TableInfo>::iterator tit;
if (useTables) if (useTables)
@ -2737,7 +2747,7 @@ void gdioutput::doEnter()
} }
} }
bool gdioutput::UpDown(int direction) bool gdioutput::upDown(int direction)
{ {
wstring msg; wstring msg;
try { try {
@ -2763,17 +2773,21 @@ bool gdioutput::UpDown(int direction)
bool gdioutput::doUpDown(int direction) bool gdioutput::doUpDown(int direction)
{ {
if (autoCompleteInfo) {
autoCompleteInfo->upDown(direction);
return true;
}
list<TableInfo>::iterator tit; list<TableInfo>::iterator tit;
if (useTables) if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit) for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
if (tit->table->UpDown(*this, direction)) if (tit->table->upDown(*this, direction))
return true; return true;
return false; return false;
} }
void gdioutput::Escape() void gdioutput::escape()
{ {
if (hasCommandLock()) if (hasCommandLock())
return; return;
@ -2804,6 +2818,11 @@ void gdioutput::doEscape()
PostMessage(hWndTarget, WM_CLOSE, 0,0); PostMessage(hWndTarget, WM_CLOSE, 0,0);
} }
if (autoCompleteInfo) {
autoCompleteInfo.reset();
return;
}
list<TableInfo>::iterator tit; list<TableInfo>::iterator tit;
if (useTables) if (useTables)
@ -3969,15 +3988,33 @@ void gdioutput::RenderString(TextInfo &ti, HDC hDC)
hDC=hThis=GetDC(hWndTarget); hDC=hThis=GetDC(hWndTarget);
} }
RECT rc; RECT rc;
if ((ti.format & absolutePosition) == 0) {
rc.left = ti.xp - OffsetX; rc.left = ti.xp - OffsetX;
rc.top = ti.yp - OffsetY; rc.top = ti.yp - OffsetY;
}
else {
rc.left = ti.xp;
rc.top = ti.yp;
}
rc.right = rc.left; rc.right = rc.left;
rc.bottom = rc.top; rc.bottom = rc.top;
formatString(ti, hDC); formatString(ti, hDC);
int format=ti.format&0xFF; 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.xlimit==0){
if (ti.format&textRight) { if (ti.format&textRight) {
DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX); 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; return;
RECT rc; RECT rc;
if ((ti.format & absolutePosition) == 0) {
rc.left = ti.xp - OffsetX; rc.left = ti.xp - OffsetX;
rc.top = ti.yp - OffsetY; rc.top = ti.yp - OffsetY;
}
else {
rc.left = ti.xp;
rc.top = ti.yp;
}
rc.right = rc.left; rc.right = rc.left;
rc.bottom = rc.top; 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 void gdioutput::calcStringSize(TextInfo &ti, HDC hDC_in) const
{ {
HDC hDC=hDC_in;
if (!hDC) {
// assert(hWndTarget!=0);
hDC=GetDC(hWndTarget);
}
RECT rc; RECT rc;
rc.left=ti.xp-OffsetX; rc.left=ti.xp-OffsetX;
rc.top=ti.yp-OffsetY; rc.top=ti.yp-OffsetY;
rc.right = rc.left; rc.right = rc.left;
rc.bottom = rc.top; 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(); resetLast();
formatString(ti, hDC); formatString(ti, hDC);
int format=ti.format&0xFF; int format=ti.format&0xFF;
@ -6847,8 +6903,42 @@ DWORD gdioutput::selectColor(wstring &def, DWORD input) {
return -1; return -1;
} }
void gdioutput::setAnimationMode(shared_ptr<AnimationData> &data) { void gdioutput::setAnimationMode(shared_ptr<AnimationData> &data) {
if (animationData && animationData->takeOver(data)) if (animationData && animationData->takeOver(data))
return; return;
animationData = data; 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();
}

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -91,6 +91,8 @@ struct FontInfo {
HFONT italic; HFONT italic;
}; };
class AutoCompleteInfo;
class Recorder; class Recorder;
class gdioutput { class gdioutput {
@ -280,8 +282,13 @@ protected:
shared_ptr<AnimationData> animationData; shared_ptr<AnimationData> animationData;
shared_ptr<AutoCompleteInfo> autoCompleteInfo;
int defaultCodePage; int defaultCodePage;
public: public:
AutoCompleteInfo &addAutoComplete(const string &key);
void clearAutoComplete(const string &key);
bool hasAutoComplete() const { return autoCompleteInfo != nullptr; }
// Return the bounding dimension of the desktop // Return the bounding dimension of the desktop
void getVirtualScreenSize(RECT &rc); void getVirtualScreenSize(RECT &rc);
@ -635,9 +642,9 @@ public:
void clearPage(bool autoRefresh, bool keepToolbar = false); void clearPage(bool autoRefresh, bool keepToolbar = false);
void TabFocus(int direction=1); void TabFocus(int direction=1);
void Enter(); void enter();
void Escape(); void escape();
bool UpDown(int direction); bool upDown(int direction);
void keyCommand(KeyCommandCode code); void keyCommand(KeyCommandCode code);
LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam); LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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;} 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 TextInfo &changeFont(const wstring &fnt) {font = fnt; return *this;} //Note: size not updated
bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo; } bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo; }

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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 { template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const {
PrincipalSort ps = ClassWise; PrincipalSort ps = ClassWise;
if (so == CourseResult) if (so == CourseResult || so == CourseStartTime)
ps = CourseWise; ps = CourseWise;
else if (so == SortByName || so == SortByFinishTimeReverse || 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("CardControls", "Runner's card, matched control ids (-1 for unmatched punches)", true);
parser.declareSymbol("Course", "Runner's course", 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("CourseLength", "Length of course", false);
parser.declareSymbol("SplitTimes", "Runner's split times", true); 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("RunnerOutputTimes", "Runner's method output times", true, true);
parser.declareSymbol("RunnerOutputNumbers", "Runner's method output numbers", 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); parser.declareSymbol("MaxTime", "Maximum allowed running time", false);
@ -1111,6 +1116,7 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.removeSymbol("CardTimes"); parser.removeSymbol("CardTimes");
parser.removeSymbol("Course"); parser.removeSymbol("Course");
parser.removeSymbol("CourseLength"); parser.removeSymbol("CourseLength");
parser.removeSymbol("CourseId");
parser.removeSymbol("LegPlace"); parser.removeSymbol("LegPlace");
parser.removeSymbol("LegTimeAfter"); parser.removeSymbol("LegTimeAfter");
parser.removeSymbol("LegTimeDeviation"); parser.removeSymbol("LegTimeDeviation");
@ -1129,6 +1135,10 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.addSymbol("RunnerFinish", finish); parser.addSymbol("RunnerFinish", finish);
parser.addSymbol("RunnerPoints", points); 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("RunnerCardPunches", team.getResultCache(oTeam::RCCCardPunches));
parser.addSymbol("RunnerCardTimes", team.getResultCache(oTeam::RCCCardTimes)); parser.addSymbol("RunnerCardTimes", team.getResultCache(oTeam::RCCCardTimes));
parser.addSymbol("RunnerCardControls", team.getResultCache(oTeam::RCCCardControls)); parser.addSymbol("RunnerCardControls", team.getResultCache(oTeam::RCCCardControls));
@ -1229,6 +1239,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
} }
parser.addSymbol("CourseLength", crs->getLength()); parser.addSymbol("CourseLength", crs->getLength());
parser.addSymbol("CourseId", crs->getId());
parser.addSymbol("Course", eCrs); parser.addSymbol("Course", eCrs);
parser.addSymbol("SplitTimes", eSplitTime); parser.addSymbol("SplitTimes", eSplitTime);
parser.addSymbol("SplitTimesAccumulated", eAccTime); parser.addSymbol("SplitTimesAccumulated", eAccTime);
@ -1242,6 +1253,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
else { else {
vector<int> e; vector<int> e;
parser.addSymbol("CourseLength", -1); parser.addSymbol("CourseLength", -1);
parser.addSymbol("CourseId", 0);
parser.addSymbol("Course", e); parser.addSymbol("Course", e);
parser.addSymbol("SplitTimes", e); parser.addSymbol("SplitTimes", e);
parser.addSymbol("SplitTimesAccumulated", e); parser.addSymbol("SplitTimesAccumulated", e);

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -264,7 +264,7 @@ Please refer to the MOP documentation for a complete description of all attribut
</pre> </pre>
<b>Remarks:</b> <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> <pre>
*person cls="1" stat="1" st="324000" rt="72550" place="1" course=28> *person cls="1" stat="1" st="324000" rt="72550" place="1" course=28>
*name id="4">Jordan Griesmer*/name> *name id="4">Jordan Griesmer*/name>

254
code/image.cpp Normal file
View 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
View 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();
};

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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; extern gdioutput *gdi_main;
// Encode a vector vector int {{1}, {1,2,3}, {}, {4,5}} as "1;1,2,3;;4,5" // 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++) { for (size_t j = 0; j < v.size(); j++) {
if (j>0) if (j>0)
def += L";"; 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){ InfoBase::InfoBase(int idIn) : id(idIn), committed(false){
} }
@ -88,6 +99,7 @@ InfoBaseCompetitor::InfoBaseCompetitor(int id) : InfoBase(id) {
InfoCompetitor::InfoCompetitor(int id) : InfoBaseCompetitor(id) { InfoCompetitor::InfoCompetitor(int id) : InfoBaseCompetitor(id) {
totalStatus = 0; totalStatus = 0;
inputTime = 0; inputTime = 0;
course = 0;
} }
InfoTeam::InfoTeam(int id) : InfoBaseCompetitor(id) { 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); map<int, InfoClass>::iterator res = classes.find(wid);
if (res == classes.end()) if (res == classes.end())
res = classes.insert(make_pair(wid, InfoClass(wid))).first; 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); needCommit(res->second);
} }
@ -276,13 +288,30 @@ void InfoRadioControl::serialize(xmlbuffer &xml, bool diffOnly) const {
xml.write("ctrl", prop, name); 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(); const wstring &n = c.getName();
int no = c.getSortIndex(); int no = c.getSortIndex();
bool mod = false; bool mod = false;
vector< vector<int> > rc; vector< vector<int> > rc;
size_t s = c.getNumStages(); 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) { if (s > 0) {
linearLegNumberToActual.clear(); linearLegNumberToActual.clear();
@ -345,6 +374,10 @@ void InfoClass::serialize(xmlbuffer &xml, bool diffOnly) const {
wstring def; wstring def;
packIntInt(radioControls, def); packIntInt(radioControls, def);
prop.push_back(make_pair("radio", 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); xml.write("cls", prop, name);
} }
@ -373,13 +406,16 @@ void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const {
xml.write("competition", prop, name); 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; vector< pair<string, wstring> > prop;
prop.push_back(make_pair("org", itow(organizationId))); prop.push_back(make_pair("org", itow(organizationId)));
prop.push_back(make_pair("cls", itow(classId))); prop.push_back(make_pair("cls", itow(classId)));
prop.push_back(make_pair("stat", itow(status))); prop.push_back(make_pair("stat", itow(status)));
prop.push_back(make_pair("st", itow(startTime))); prop.push_back(make_pair("st", itow(startTime)));
prop.push_back(make_pair("rt", itow(runningTime))); prop.push_back(make_pair("rt", itow(runningTime)));
if (course != 0)
prop.push_back(make_pair("crs", itow(course)));
xml.write("base", prop, name); xml.write("base", prop, name);
} }
@ -426,20 +462,32 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
return ch; return ch;
} }
bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) { bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &r) {
bool ch = synchronizeBase(r); bool ch = synchronizeBase(r);
changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes
int s = StatusOK; int s = StatusOK;
int legInput = 0; 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(); pTeam t = r.getTeam();
if (useTotalResults) { if (useTotalResults) {
legInput = r.getTotalTimeInput() * 10; legInput = r.getTotalTimeInput() * 10;
s = r.getTotalStatusInput(); s = r.getTotalStatusInput();
} }
else if (t && r.getLegNumber() > 0) { 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); 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 InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
bool useTotalResults = cmp.includeTotalResults(); bool useTotalResults = cmp.includeTotalResults();
bool ch = synchronize(useTotalResults, r); bool inludeCourse = cmp.includeCourse();
bool ch = synchronize(useTotalResults, inludeCourse, r);
vector<RadioTime> newRT; vector<RadioTime> newRT;
if (r.getClassId(false) > 0) { if (r.getClassId(false) > 0) {
@ -493,7 +543,8 @@ void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > sprop; vector< pair<string, wstring> > sprop;
sprop.push_back(make_pair("id", itow(getId()))); sprop.push_back(make_pair("id", itow(getId())));
xmlbuffer &subTag = xml.startTag("cmp", sprop); xmlbuffer &subTag = xml.startTag("cmp", sprop);
InfoBaseCompetitor::serialize(subTag, diffOnly); InfoBaseCompetitor::serialize(subTag, diffOnly, course);
if (radioTimes.size() > 0 && (!diffOnly || changeRadio)) { if (radioTimes.size() > 0 && (!diffOnly || changeRadio)) {
string radio; string radio;
radio.reserve(radioTimes.size() * 12); radio.reserve(radioTimes.size() * 12);
@ -553,7 +604,7 @@ void InfoTeam::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > prop; vector< pair<string, wstring> > prop;
prop.push_back(make_pair("id", itow(getId()))); prop.push_back(make_pair("id", itow(getId())));
xmlbuffer &sub = xml.startTag("tm", prop); xmlbuffer &sub = xml.startTag("tm", prop);
InfoBaseCompetitor::serialize(sub, diffOnly); InfoBaseCompetitor::serialize(sub, diffOnly, 0);
wstring def; wstring def;
packIntInt(competitors, def); packIntInt(competitors, def);
prop.clear(); prop.clear();

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -114,8 +114,9 @@ class InfoClass : public InfoBase {
int sortOrder; int sortOrder;
vector< vector<int> > radioControls; vector< vector<int> > radioControls;
vector<int> linearLegNumberToActual; vector<int> linearLegNumberToActual;
vector<int> courses;
public: 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; void serialize(xmlbuffer &xml, bool diffOnly) const;
InfoClass(int id); InfoClass(int id);
@ -155,7 +156,7 @@ class InfoBaseCompetitor : public InfoBase {
int status; int status;
int startTime; int startTime;
int runningTime; int runningTime;
void serialize(xmlbuffer &xml, bool diffOnly) const; void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
bool synchronizeBase(oAbstractRunner &bc); bool synchronizeBase(oAbstractRunner &bc);
public: public:
InfoBaseCompetitor(int id); InfoBaseCompetitor(int id);
@ -167,11 +168,12 @@ class InfoCompetitor : public InfoBaseCompetitor {
vector<RadioTime> radioTimes; vector<RadioTime> radioTimes;
int inputTime; int inputTime;
int totalStatus; int totalStatus;
int course;
bool synchronize(const InfoCompetition &cmp, oRunner &c); bool synchronize(const InfoCompetition &cmp, oRunner &c);
bool changeTotalSt; bool changeTotalSt;
bool changeRadio; bool changeRadio;
public: public:
bool synchronize(bool useTotalResults, oRunner &c); bool synchronize(bool useTotalResults, bool useCourse, oRunner &c);
void serialize(xmlbuffer &xml, bool diffOnly) const; void serialize(xmlbuffer &xml, bool diffOnly) const;
InfoCompetitor(int id); InfoCompetitor(int id);
@ -203,6 +205,7 @@ protected:
bool forceComplete; bool forceComplete;
bool includeTotal; bool includeTotal;
bool withCourse;
list<InfoBase *> toCommit; list<InfoBase *> toCommit;
@ -217,10 +220,12 @@ protected:
public: public:
void serialize(xmlbuffer &xml, bool diffOnly) const; void serialize(xmlbuffer &xml, bool diffOnly) const;
bool includeTotalResults() const {return includeTotal;} bool includeTotalResults() const {return includeTotal;}
void includeTotalResults(bool inc) {includeTotal = inc;} 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; 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, bool onlyCmp, const set<int> &classes, const set<int> &ctrls);
bool synchronize(oEvent &oe) { bool synchronize(oEvent &oe) {
@ -233,6 +238,5 @@ protected:
void commitComplete(); void commitComplete();
InfoCompetition(int id); InfoCompetition(int id);
//InfoCompetition(const InfoCompetition &in);
virtual ~InfoCompetition() {} virtual ~InfoCompetition() {}
}; };

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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); 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) { 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; 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) { pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
@ -1721,11 +1768,35 @@ pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
else { else {
name = lang.tl("N.N."); name = lang.tl("N.N.");
} }
int pid = 0;
__int64 extId = 0;
readId(person, pid, extId);
/*
wstring sid; wstring sid;
int pid = 0;
__int64 extId = 0;
if (preferredIdProvider.empty()) {
person.getObjectString("Id", sid); person.getObjectString("Id", sid);
__int64 extId = oBase::converExtIdentifierString(sid); }
int pid = oBase::idFromExtId(extId); 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; pRunner r = 0;
if (pid) { if (pid) {
@ -2620,7 +2691,6 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Position", r.getPlace()); xml.write("Position", r.getPlace());
} }
else if (teamMember) { else if (teamMember) {
//int pos = r.getTeam()->getLegPlace(r.getLegNumber(), false);
int pos = r.getPlace(); int pos = r.getPlace();
if (pos > 0 && pos < 50000) if (pos > 0 && pos < 50000)
xml.write("Position", "type", L"Leg", itow(pos)); 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())); 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) { if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult"); xml.startTag("OverallResult");
int rt = r.getTotalRunningTime(); int rt = r.getTotalRunningTime();
@ -3612,3 +3687,11 @@ void IOF30Interface::writeClubDB(const RunnerDB &db, xmlparser &xml) const {
xml.endTag(); 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;
}

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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); bool matchStageFilter(const set<int> &stageFilter, const xmlList &races);
set<string> idProviders;
string preferredIdProvider;
void readEvent(gdioutput &gdi, const xmlobject &xo, void readEvent(gdioutput &gdi, const xmlobject &xo,
map<int, vector<LegInfo> > &teamClassConfig); map<int, vector<LegInfo> > &teamClassConfig);
pRunner readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team, pRunner readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team,
@ -261,10 +264,15 @@ class IOF30Interface {
void writeFullCourse(xmlparser &xml, const oCourse &c, void writeFullCourse(xmlparser &xml, const oCourse &c,
const map<int, wstring> &ctrlId2ExportId); const map<int, wstring> &ctrlId2ExportId);
void readId(const xmlobject &person, int &pid, __int64 &extId) const;
public: public:
IOF30Interface(oEvent *oe, bool forceSplitFee); IOF30Interface(oEvent *oe, bool forceSplitFee);
virtual ~IOF30Interface() {} virtual ~IOF30Interface() {}
void getIdTypes(vector<string> &types);
void setPreferredIdType(const string &type);
void readEventList(gdioutput &gdi, xmlobject &xo); void readEventList(gdioutput &gdi, xmlobject &xo);
/** Scan the entry list to find specification of stage numbers*/ /** Scan the entry list to find specification of stage numbers*/

BIN
code/lib/libpng.lib Normal file

Binary file not shown.

BIN
code/lib_db/zlibstat.pdb Normal file

Binary file not shown.

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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.setExtraSpace(k, f);
} }
list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo")); list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo"));
list.setSupportLegSelection(gdi.isChecked("SupportLegSelection"));
makeDirty(gdi, MakeDirty, MakeDirty); makeDirty(gdi, MakeDirty, MakeDirty);
@ -1045,6 +1047,8 @@ void ListEditor::editListProp(gdioutput &gdi, bool newList) {
gdi.fillRight(); gdi.fillRight();
gdi.addCheckbox("SupportFrom", "Support time from control", 0, list.supportFrom()); gdi.addCheckbox("SupportFrom", "Support time from control", 0, list.supportFrom());
gdi.addCheckbox("SupportTo", "Support time to control", 0, list.supportTo()); gdi.addCheckbox("SupportTo", "Support time to control", 0, list.supportTo());
gdi.addCheckbox("SupportLegSelection", "Support intermediate legs", 0, list.supportLegSelection());
gdi.dropLine(2); gdi.dropLine(2);
gdi.popX(); gdi.popX();

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/********************i**************************************************** /********************i****************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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); 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;
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -66,7 +66,8 @@ public:
LocalizerInternal &get() {return *linternal;} LocalizerInternal &get() {return *linternal;}
const wstring &tl(const string &str) const; const wstring &tl(const string &str) const;
const wstring &tl(const wstring &str) const {return linternal->tl(str);} 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 init() {linternal = new LocalizerInternal();}
void unload() {delete linternal; linternal = 0;} void unload() {delete linternal; linternal = 0;}

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -64,7 +64,11 @@
#include "meosexception.h" #include "meosexception.h"
#include "parser.h" #include "parser.h"
#include "restserver.h" #include "restserver.h"
#include "autocomplete.h"
#include "image.h"
Image image;
gdioutput *gdi_main=0; gdioutput *gdi_main=0;
oEvent *gEvent=0; oEvent *gEvent=0;
SportIdent *gSI=0; SportIdent *gSI=0;
@ -149,6 +153,9 @@ void LoadPage(gdioutput &gdi, TabType type) {
static wchar_t settings[260]; static wchar_t settings[260];
// Startup path // Startup path
static wchar_t programPath[MAX_PATH]; static wchar_t programPath[MAX_PATH];
// Exe path
static wchar_t exePath[MAX_PATH];
void mainMessageLoop(HACCEL hAccelTable, DWORD time) { void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
MSG msg; 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, int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, LPSTR lpCmdLine,
int nCmdShow) int nCmdShow)
{ {
hInst = hInstance; // Store instance handle in our global variable
atexit(dumpLeaks); // atexit(dumpLeaks); //
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@ -192,6 +207,11 @@ int APIENTRY WinMain(HINSTANCE hInstance,
enableTests = true; 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++) { for (int k = 0; k < 100; k++) {
RunnerStatusOrderMap[k] = 0; RunnerStatusOrderMap[k] = 0;
} }
@ -210,6 +230,19 @@ int APIENTRY WinMain(HINSTANCE hInstance,
GetCurrentDirectory(MAX_PATH, programPath); 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"); getUserFile(settings, L"meoswpref.xml");
Parser::test(); Parser::test();
@ -250,9 +283,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
lang.get().addLangResource(L"Deutsch", L"105"); lang.get().addLangResource(L"Deutsch", L"105");
lang.get().addLangResource(L"Dansk", L"106"); lang.get().addLangResource(L"Dansk", L"106");
lang.get().addLangResource(L"Français", L"110"); lang.get().addLangResource(L"Français", L"110");
lang.get().addLangResource(L"Russian (ISO 8859-5)", L"107"); lang.get().addLangResource(L"Russian", L"107");
lang.get().addLangResource(L"English (ISO 8859-2)", L"108");
lang.get().addLangResource(L"English (ISO 8859-8)", L"109");
if (fileExist(L"extra.lng")) { if (fileExist(L"extra.lng")) {
lang.get().addLangResource(L"Extraspråk", L"extra.lng"); lang.get().addLangResource(L"Extraspråk", L"extra.lng");
@ -282,20 +313,37 @@ int APIENTRY WinMain(HINSTANCE hInstance,
} }
try { 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]; wchar_t listpath[MAX_PATH];
getUserFile(listpath, L""); getUserFile(listpath, L"");
vector<wstring> res;
expandDirectory(listpath, L"*.lxml", res); expandDirectory(listpath, L"*.lxml", res);
expandDirectory(listpath, L"*.listdef", 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++) { for (size_t k = 0; k<res.size(); k++) {
try { 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; xmlparser xml;
wcscpy_s(listpath, res[k].c_str()); wcscpy_s(listpath, res[k].c_str());
@ -351,6 +399,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0), gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0),
gEvent->getPropertyString("TextFont", L"Arial")); gEvent->getPropertyString("TextFont", L"Arial"));
DWORD startupToc = GetTickCount() - splashStart;
Sleep(min<int>(1000, max<int>(0,700 - startupToc)));
// Perform application initialization: // Perform application initialization:
if (!InitInstance (hInstance, nCmdShow)) { if (!InitInstance (hInstance, nCmdShow)) {
return FALSE; return FALSE;
@ -374,6 +425,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS); hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS);
DestroyWindow(hSplash);
initMySQLCriticalSection(true); initMySQLCriticalSection(true);
// Main message loop: // Main message loop:
mainMessageLoop(hAccelTable, 0); mainMessageLoop(hAccelTable, 0);
@ -466,6 +520,8 @@ ATOM MyRegisterClass(HINSTANCE hInstance)
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex); RegisterClassEx(&wcex);
AutoCompleteInfo::registerAutoClass();
return true; return true;
} }
@ -550,12 +606,15 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
} }
else if (wParam==VK_RETURN && (lParam & (1<<31))) { else if (wParam==VK_RETURN && (lParam & (1<<31))) {
if (gdi) if (gdi)
gdi->Enter(); gdi->enter();
} }
else if (wParam==VK_UP) { else if (wParam==VK_UP) {
bool c = false; bool c = false;
if (gdi && (lParam & (1<<31))) 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)) if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); 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) { else if (wParam==VK_DOWN) {
bool c = false; bool c = false;
if (gdi && (lParam & (1<<31))) 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)) if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); 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))) { else if (wParam==VK_ESCAPE && (lParam & (1<<31))) {
if (gdi) if (gdi)
gdi->Escape(); gdi->escape();
} }
else if (wParam==VK_F2) { else if (wParam==VK_F2) {
ProgressWindow pw(hWnd); ProgressWindow pw(hWnd);
@ -666,8 +728,6 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{ {
HWND hWnd; HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
//WS_EX_CONTROLPARENT
HWND hDskTop=GetDesktopWindow(); HWND hDskTop=GetDesktopWindow();
RECT rc; RECT rc;
GetClientRect(hDskTop, &rc); GetClientRect(hDskTop, &rc);
@ -1638,9 +1698,9 @@ void Setup(bool overwrite, bool overwriteAll)
wchar_t dir[260]; wchar_t dir[260];
GetCurrentDirectory(260, dir); GetCurrentDirectory(260, dir);
vector<wstring> dyn; vector<wstring> dyn;
expandDirectory(dir, L"*.lxml", dyn); if (overwrite)
expandDirectory(dir, L"*.listdef", dyn);
expandDirectory(dir, L"*.meos", dyn); expandDirectory(dir, L"*.meos", dyn);
for (size_t k = 0; k < dyn.size(); k++) for (size_t k = 0; k < dyn.size(); k++)
toInstall.push_back(make_pair(dyn[k], true)); toInstall.push_back(make_pair(dyn[k], true));
@ -1802,3 +1862,36 @@ void removeTempFiles() {
tempPath.clear(); 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -50,7 +50,8 @@ IDB_ECO BITMAP "bmp00001.bmp"
#endif // Neutral (Default) resources #endif // Neutral (Default) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
IDI_SPLASHIMAGE PNG "meos.png"
IDI_MEOSIMAGE PNG "title.png"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// English (United States) resources // English (United States) resources
@ -168,7 +169,7 @@ BEGIN
VALUE "FileDescription", "meos" VALUE "FileDescription", "meos"
VALUE "FileVersion", "3.3.0.1" VALUE "FileVersion", "3.3.0.1"
VALUE "InternalName", "meos" VALUE "InternalName", "meos"
VALUE "LegalCopyright", "Copyright © 2007-2017" VALUE "LegalCopyright", "Copyright © 2007-2018"
VALUE "OriginalFilename", "meos.exe" VALUE "OriginalFilename", "meos.exe"
VALUE "ProductName", " meos" VALUE "ProductName", " meos"
VALUE "ProductVersion", "3.4.0.1" VALUE "ProductVersion", "3.4.0.1"
@ -188,6 +189,37 @@ END
IDR_HTML1 HTML "html1.htm" 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 #endif // Swedish (Sweden) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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); 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) double stringDistance(const wchar_t *a, const wchar_t *b)
{ {
int al = wcslen(a); int al = wcslen(a);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -160,7 +160,7 @@ wstring getMeosFullVersion();
wstring getMajorVersion(); wstring getMajorVersion();
wstring getMeosCompectVersion(); wstring getMeosCompectVersion();
void getSupporters(vector<string> &supp); void getSupporters(vector<wstring> &supp);
int countWords(const wchar_t *p); int countWords(const wchar_t *p);
@ -191,9 +191,10 @@ int toLowerStripped(wchar_t c);
const wchar_t *canonizeName(const wchar_t *name); const wchar_t *canonizeName(const wchar_t *name);
/** String distance between 0 and 1. 0 is equal*/ /** 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); 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*/ /** Get a number suffix, Start 1 -> 1. Zero for none*/
int getNumberSuffix(const string &str); int getNumberSuffix(const string &str);

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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.reset();
query << C_START_noid("dbRunner") 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_INT("Club") << C_STRING("Nation", 3)
<< C_STRING("Sex", 1) << C_INT("BirthYear") << C_STRING("Sex", 1) << C_INT("BirthYear")
<< C_INT64("ExtId") << C_END_noindex(); << C_INT64("ExtId") << C_END_noindex();

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -116,7 +116,7 @@
<Culture>0x041d</Culture> <Culture>0x041d</Culture>
</ResourceCompile> </ResourceCompile>
<Link> <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> <OutputFile>.\Release/meos.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>./lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>./lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -170,7 +170,7 @@
<Culture>0x041d</Culture> <Culture>0x041d</Culture>
</ResourceCompile> </ResourceCompile>
<Link> <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> <OutputFile>.\Debug/meos.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>./lib_db;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>./lib_db;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -240,6 +240,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="animationdata.cpp" /> <ClCompile Include="animationdata.cpp" />
<ClCompile Include="autocomplete.cpp" />
<ClCompile Include="autotask.cpp" /> <ClCompile Include="autotask.cpp" />
<ClCompile Include="classconfiginfo.cpp" /> <ClCompile Include="classconfiginfo.cpp" />
<ClCompile Include="csvparser.cpp"> <ClCompile Include="csvparser.cpp">
@ -255,6 +256,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="generalresult.cpp" /> <ClCompile Include="generalresult.cpp" />
<ClCompile Include="HTMLWriter.cpp" /> <ClCompile Include="HTMLWriter.cpp" />
<ClCompile Include="image.cpp" />
<ClCompile Include="importformats.cpp" /> <ClCompile Include="importformats.cpp" />
<ClCompile Include="infoserver.cpp" /> <ClCompile Include="infoserver.cpp" />
<ClCompile Include="iof30interface.cpp" /> <ClCompile Include="iof30interface.cpp" />
@ -391,6 +393,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="animationdata.h" /> <ClInclude Include="animationdata.h" />
<ClInclude Include="autocomplete.h" />
<ClInclude Include="autocompletehandler.h" />
<ClInclude Include="autotask.h" /> <ClInclude Include="autotask.h" />
<ClInclude Include="classconfiginfo.h" /> <ClInclude Include="classconfiginfo.h" />
<ClInclude Include="gdiconstants.h" /> <ClInclude Include="gdiconstants.h" />
@ -399,6 +403,7 @@
<ClInclude Include="gdistructures.h" /> <ClInclude Include="gdistructures.h" />
<ClInclude Include="generalresult.h" /> <ClInclude Include="generalresult.h" />
<ClInclude Include="guihandler.h" /> <ClInclude Include="guihandler.h" />
<ClInclude Include="image.h" />
<ClInclude Include="infoserver.h" /> <ClInclude Include="infoserver.h" />
<ClInclude Include="inthashmap.h" /> <ClInclude Include="inthashmap.h" />
<ClInclude Include="intkeymap.hpp" /> <ClInclude Include="intkeymap.hpp" />

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
Melin Software HB - software@melin.nu - www.melin.nu 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" #include "stdafx.h"
@ -29,7 +29,7 @@
//V33: abcde //V33: abcde
//V35: abcde //V35: abcde
int getMeosBuild() { int getMeosBuild() {
string revision("$Rev: 634 $"); string revision("$Rev: 652 $");
return 174 + atoi(revision.substr(5, string::npos).c_str()); return 174 + atoi(revision.substr(5, string::npos).c_str());
} }
@ -41,12 +41,12 @@ int getMeosBuild() {
//V33: abcdefghij //V33: abcdefghij
//V34: abcdfg //V34: abcdfg
wstring getMeosDate() { 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); return date.substr(7,10);
} }
wstring getBuildType() { wstring getBuildType() {
return L"Snapshot"; // No parantheses (...) return L"RC1"; // No parantheses (...)
} }
wstring getMajorVersion() { wstring getMajorVersion() {
@ -70,114 +70,119 @@ wstring getMeosCompectVersion() {
return getMajorVersion() + L"." + itow(getMeosBuild()) + L" (" + getBuildType() + L")"; 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(L"Centrum OK");
supp.push_back("Ove Persson, Piteå IF"); supp.push_back(L"Ove Persson, Piteå IF");
supp.push_back("OK Rodhen"); supp.push_back(L"OK Rodhen");
supp.push_back("Täby Extreme Challenge"); supp.push_back(L"Täby Extreme Challenge");
supp.push_back("Thomas Engberg, VK Uvarna"); supp.push_back(L"Thomas Engberg, VK Uvarna");
supp.push_back("Eilert Edin, Sidensjö IK"); supp.push_back(L"Eilert Edin, Sidensjö IK");
supp.push_back("Göran Nordh, Trollhättans SK"); supp.push_back(L"Göran Nordh, Trollhättans SK");
supp.push_back("Roger Gustavsson, OK Tisaren"); supp.push_back(L"Roger Gustavsson, OK Tisaren");
supp.push_back("Sundsvalls OK"); supp.push_back(L"Sundsvalls OK");
supp.push_back("OK Gipens OL-skytte"); supp.push_back(L"OK Gipens OL-skytte");
supp.push_back("Helsingborgs SOK"); supp.push_back(L"Helsingborgs SOK");
supp.push_back("OK Gipens OL-skytte"); supp.push_back(L"OK Gipens OL-skytte");
supp.push_back("Rune Thurén, Vallentuna-Össeby OL"); supp.push_back(L"Rune Thurén, Vallentuna-Össeby OL");
supp.push_back("Roland Persson, Kalmar OK"); supp.push_back(L"Roland Persson, Kalmar OK");
supp.push_back("Robert Jessen, Främmestads IK"); supp.push_back(L"Robert Jessen, Främmestads IK");
supp.push_back("Anders Platt, Järla Orientering"); supp.push_back(L"Anders Platt, Järla Orientering");
supp.push_back("Almby IK, Örebro"); supp.push_back(L"Almby IK, Örebro");
supp.push_back("Peter Rydesäter, Rehns BK"); supp.push_back(L"Peter Rydesäter, Rehns BK");
supp.push_back("IK Hakarpspojkarna"); supp.push_back(L"IK Hakarpspojkarna");
supp.push_back("Rydboholms SK"); supp.push_back(L"Rydboholms SK");
supp.push_back("IFK Kiruna"); supp.push_back(L"IFK Kiruna");
supp.push_back("Peter Andersson, Söders SOL"); supp.push_back(L"Peter Andersson, Söders SOL");
supp.push_back("Björkfors GoIF"); supp.push_back(L"Björkfors GoIF");
supp.push_back("OK Ziemelkurzeme"); supp.push_back(L"OK Ziemelkurzeme");
supp.push_back("Big Foot Orienteers"); supp.push_back(L"Big Foot Orienteers");
supp.push_back("FIF Hillerød"); supp.push_back(L"FIF Hillerød");
supp.push_back("Anne Udd"); supp.push_back(L"Anne Udd");
supp.push_back("OK Orinto"); supp.push_back(L"OK Orinto");
supp.push_back("SOK Träff"); supp.push_back(L"SOK Träff");
supp.push_back("Gamleby OK"); supp.push_back(L"Gamleby OK");
supp.push_back("Vänersborgs SK"); supp.push_back(L"Vänersborgs SK");
supp.push_back("Henrik Ortman, Västerås SOK"); supp.push_back(L"Henrik Ortman, Västerås SOK");
supp.push_back("Leif Olofsson, Sjuntorp"); supp.push_back(L"Leif Olofsson, Sjuntorp");
supp.push_back("Vallentuna/Össeby OL"); supp.push_back(L"Vallentuna/Össeby OL");
supp.push_back("Oskarström OK"); supp.push_back(L"Oskarström OK");
supp.push_back("Skogslöparna"); supp.push_back(L"Skogslöparna");
supp.push_back("OK Milan"); supp.push_back(L"OK Milan");
supp.push_back("Tjalve IF"); supp.push_back(L"Tjalve IF");
supp.push_back("OK Skärmen"); supp.push_back(L"OK Skärmen");
supp.push_back("Østkredsen"); supp.push_back(L"Østkredsen");
supp.push_back("OK Roskilde"); supp.push_back(L"OK Roskilde");
supp.push_back("Holbæk Orienteringsklub"); supp.push_back(L"Holbæk Orienteringsklub");
supp.push_back("Bodens BK"); supp.push_back(L"Bodens BK");
supp.push_back("OK Tyr, Karlstad"); supp.push_back(L"OK Tyr, Karlstad");
supp.push_back("Göteborg-Majorna OK"); supp.push_back(L"Göteborg-Majorna OK");
supp.push_back("OK Järnbärarna, Kopparberg"); supp.push_back(L"OK Järnbärarna, Kopparberg");
supp.push_back("FK Åsen"); supp.push_back(L"FK Åsen");
supp.push_back("Ballerup OK"); supp.push_back(L"Ballerup OK");
supp.push_back("Olivier Benevello, Valbonne SAO"); supp.push_back(L"Olivier Benevello, Valbonne SAO");
supp.push_back("Tommy Wåhlin, OK Enen"); supp.push_back(L"Tommy Wåhlin, OK Enen");
supp.push_back("Hjobygdens OK"); supp.push_back(L"Hjobygdens OK");
supp.push_back("Tisvilde Hegn OK"); supp.push_back(L"Tisvilde Hegn OK");
supp.push_back("Lindebygdens OK"); supp.push_back(L"Lindebygdens OK");
supp.push_back("OK Flundrehof"); supp.push_back(L"OK Flundrehof");
supp.push_back("Vittjärvs IK"); supp.push_back(L"Vittjärvs IK");
supp.push_back("Annebergs GIF"); supp.push_back(L"Annebergs GIF");
supp.push_back("Lars-Eric Gahlin, Östersunds OK"); supp.push_back(L"Lars-Eric Gahlin, Östersunds OK");
supp.push_back("Sundsvalls OK:s Veteraner"); supp.push_back(L"Sundsvalls OK:s Veteraner");
supp.push_back("OK Skogshjortarna"); supp.push_back(L"OK Skogshjortarna");
supp.push_back("Kinnaströms SK"); supp.push_back(L"Kinnaströms SK");
supp.push_back("OK Pan Århus"); supp.push_back(L"OK Pan Århus");
supp.push_back("Jan Ernberg, Täby OK"); supp.push_back(L"Jan Ernberg, Täby OK");
supp.push_back("Stjärnorps SK"); supp.push_back(L"Stjärnorps SK");
supp.push_back("Mölndal Outdoor IF"); supp.push_back(L"Mölndal Outdoor IF");
supp.push_back("Roland Elg, Fjärås AIK"); supp.push_back(L"Roland Elg, Fjärås AIK");
supp.push_back("Tenhults SOK"); supp.push_back(L"Tenhults SOK");
supp.push_back("Järfälla OK"); supp.push_back(L"Järfälla OK");
supp.push_back("Lars Jonasson"); supp.push_back(L"Lars Jonasson");
supp.push_back("Anders Larsson, OK Nackhe"); supp.push_back(L"Anders Larsson, OK Nackhe");
supp.push_back("Hans Wilhelmsson"); supp.push_back(L"Hans Wilhelmsson");
supp.push_back("Patrice Lavallee, Noyon Course d'Orientation"); supp.push_back(L"Patrice Lavallee, Noyon Course d'Orientation");
supp.push_back("IFK Linköpings OS"); supp.push_back(L"IFK Linköpings OS");
supp.push_back("Lars Ove Karlsson, Västerås SOK"); supp.push_back(L"Lars Ove Karlsson, Västerås SOK");
supp.push_back("OK Djerf"); supp.push_back(L"OK Djerf");
supp.push_back("OK Vivill"); supp.push_back(L"OK Vivill");
supp.push_back("IFK Mora OK"); supp.push_back(L"IFK Mora OK");
supp.push_back("Sonny Andersson, Huskvarna"); supp.push_back(L"Sonny Andersson, Huskvarna");
supp.push_back("Hässleholms OK Skolorientering"); supp.push_back(L"Hässleholms OK Skolorientering");
supp.push_back("IBM-klubben Orientering"); supp.push_back(L"IBM-klubben Orientering");
supp.push_back("OK Øst, Birkerød"); supp.push_back(L"OK Øst, Birkerød");
supp.push_back("OK Klemmingen"); supp.push_back(L"OK Klemmingen");
supp.push_back("Hans Johansson"); supp.push_back(L"Hans Johansson");
supp.push_back("KOB Kysak"); supp.push_back(L"KOB Kysak");
supp.push_back("Per Ivarsson, Trollhättans SOK"); supp.push_back(L"Per Ivarsson, Trollhättans SOK");
supp.push_back("Sergio Yañez, ABC TRAIL"); supp.push_back(L"Sergio Yañez, ABC TRAIL");
supp.push_back("Western Race Services"); supp.push_back(L"Western Race Services");
supp.push_back("IK Gandvik, Skara"); supp.push_back(L"IK Gandvik, Skara");
supp.push_back("IK Stern"); supp.push_back(L"IK Stern");
supp.push_back("OK Roslagen"); supp.push_back(L"OK Roslagen");
supp.push_back("TSV Malente"); supp.push_back(L"TSV Malente");
supp.push_back("Emmaboda Verda OK"); supp.push_back(L"Emmaboda Verda OK");
supp.push_back("KOB ATU Košice"); supp.push_back(L"KOB ATU Košice");
supp.push_back("Gävle OK"); supp.push_back(L"Gävle OK");
supp.push_back("Kenneth Gattmalm, Jönköpings OK"); supp.push_back(L"Kenneth Gattmalm, Jönköpings OK");
supp.push_back("Søllerød OK"); supp.push_back(L"Søllerød OK");
supp.push_back("O-travel"); supp.push_back(L"O-travel");
supp.push_back("Bengt Bengtsson"); supp.push_back(L"Bengt Bengtsson");
supp.push_back("OK Landehof"); supp.push_back(L"OK Landehof");
supp.push_back("OK Orinto"); supp.push_back(L"OK Orinto");
supp.push_back("Bredaryds SOK"); supp.push_back(L"Bredaryds SOK");
supp.push_back("Thore Nilsson, Uddevalla OK"); supp.push_back(L"Thore Nilsson, Uddevalla OK");
supp.push_back("Timrå SOK"); supp.push_back(L"Timrå SOK");
supp.push_back("Åke Larsson, OK Hedströmmen"); supp.push_back(L"Åke Larsson, OK Hedströmmen");
supp.push_back("Avesta OK"); supp.push_back(L"Avesta OK");
supp.push_back("Motionsorientering Göteborg"); supp.push_back(L"Motionsorientering Göteborg");
supp.push_back("OK Måsen"); supp.push_back(L"OK Måsen");
supp.push_back("IF Thor"); supp.push_back(L"IF Thor");
supp.push_back("SOS Jindrichuv Hradec"); 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");
} }

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -201,6 +201,7 @@ MetaList::MetaList() {
sortOrder = SortByName; sortOrder = SortByName;
supportFromControl = false; supportFromControl = false;
supportToControl = false; supportToControl = false;
hideLegSelection = false;
} }
MetaListPost::MetaListPost(EPostType type_, EPostType align_, int leg_) : type(type_), 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 + checksum(DynamicResult::undecorateTag(resultModule));
yx = yx * 31 + supportFromControl; yx = yx * 31 + supportFromControl;
yx = yx * 31 + supportToControl; yx = yx * 31 + supportToControl;
yx = yx * 37 + hideLegSelection;
for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it) for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it)
yx = yx * 31 + *it; yx = yx * 31 + *it;
@ -530,7 +532,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
sampleClass = cls[0]; sampleClass = cls[0];
} }
pair<int, bool> parLegNumber = par.getLegInfo(sampleClass); pair<int, bool> parLegNumber = par.getLegInfo(sampleClass);
bool capitalizeTitle = lang.capitalizeWords();
resultToIndex.clear(); resultToIndex.clear();
/*if (large == false && par.pageBreak == false) {*/ /*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); string label = "P" + itos(0*1000 + j*100 + k);
wstring text = makeDash(encode(cline[k].text)); wstring text = makeDash(encode(cline[k].text));
if (capitalizeTitle)
capitalizeWords(text);
gdiFonts font = normalText; gdiFonts font = normalText;
if (j == 0) if (j == 0)
font = boldLarge; font = boldLarge;
@ -603,7 +608,11 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
if (mp.font != formatIgnore) if (mp.font != formatIgnore)
font = mp.font; 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))). pos.get(label, s_factor), dy + subhead_dy, cline[k].leg == -1 ? parLegNumber : make_pair(cline[k].leg, true))).
setFontFace(fontFaces[MLSubHead].font, setFontFace(fontFaces[MLSubHead].font,
fontFaces[MLSubHead].scale); fontFaces[MLSubHead].scale);
@ -1052,6 +1061,8 @@ void MetaList::save(xmlparser &xml, const oEvent *oe) const {
xml.write("SupportFrom", supportFromControl); xml.write("SupportFrom", supportFromControl);
if (supportToControl) if (supportToControl)
xml.write("SupportTo", supportToControl); xml.write("SupportTo", supportToControl);
if (hideLegSelection)
xml.write("HideLegSelection", hideLegSelection);
for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it) for (set<EFilterList>::const_iterator it = filter.begin(); it != filter.end(); ++it)
xml.write("Filter", "name", filterToSymbol[*it]); xml.write("Filter", "name", filterToSymbol[*it]);
@ -1107,6 +1118,7 @@ void MetaList::load(const xmlobject &xDef) {
} }
supportFromControl = xDef.getObjectBool("SupportFrom"); supportFromControl = xDef.getObjectBool("SupportFrom");
supportToControl = xDef.getObjectBool("SupportTo"); supportToControl = xDef.getObjectBool("SupportTo");
hideLegSelection =xDef.getObjectBool("HideLegSelection");
string tmp; string tmp;
xDef.getObjectString("SortOrder", tmp); xDef.getObjectString("SortOrder", tmp);
@ -1782,6 +1794,7 @@ void MetaList::initSymbols() {
orderToSymbol[ClassTotalResult] = "ClassTotalResult"; orderToSymbol[ClassTotalResult] = "ClassTotalResult";
orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult"; orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult";
orderToSymbol[CourseResult] = "CourseResult"; orderToSymbol[CourseResult] = "CourseResult";
orderToSymbol[CourseStartTime] = "CourseStartTime";
orderToSymbol[ClassTeamLeg] = "ClassTeamLeg"; orderToSymbol[ClassTeamLeg] = "ClassTeamLeg";
orderToSymbol[Custom] = "CustomSort"; orderToSymbol[Custom] = "CustomSort";
@ -1801,6 +1814,7 @@ void MetaList::initSymbols() {
filterToSymbol[EFilterRentCard] = "FilterRentCard"; filterToSymbol[EFilterRentCard] = "FilterRentCard";
filterToSymbol[EFilterHasCard] = "FilterHasCard"; filterToSymbol[EFilterHasCard] = "FilterHasCard";
filterToSymbol[EFilterExcludeDNS] = "FilterStarted"; filterToSymbol[EFilterExcludeDNS] = "FilterStarted";
filterToSymbol[EFilterExcludeCANCEL] = "FilterNoCancel";
filterToSymbol[EFilterVacant] = "FilterNotVacant"; filterToSymbol[EFilterVacant] = "FilterNotVacant";
filterToSymbol[EFilterOnlyVacant] = "FilterOnlyVacant"; filterToSymbol[EFilterOnlyVacant] = "FilterOnlyVacant";
filterToSymbol[EFilterHasNoCard] = "FilterNoCard"; filterToSymbol[EFilterHasNoCard] = "FilterNoCard";
@ -2129,7 +2143,7 @@ void MetaListContainer::setupListInfo(int firstIndex,
li.Name = lang.tl(ml.getListName()); li.Name = lang.tl(ml.getListName());
li.listType = ml.getListType(); li.listType = ml.getListType();
li.supportClasses = ml.supportClasses(); li.supportClasses = ml.supportClasses();
li.supportLegs = ml.getListType() == oListInfo::EBaseTypeTeam; li.supportLegs = (ml.getListType() == oListInfo::EBaseTypeTeam) && ml.supportLegSelection();
li.supportParameter = !ml.getResultModule().empty(); li.supportParameter = !ml.getResultModule().empty();
li.supportLarge = true; li.supportLarge = true;
li.supportFrom = ml.supportFrom(); li.supportFrom = ml.supportFrom();
@ -2383,6 +2397,15 @@ MetaList &MetaList::setResultModule(const oEvent &oe, int moduleIx) {
throw meosException("Unknown result module"); 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) { MetaList &MetaList::setSupportFromTo(bool from, bool to) {
supportFromControl = from; supportFromControl = from;
supportToControl = to; supportToControl = to;

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -189,6 +189,7 @@ private:
string resultModule; string resultModule;
bool supportFromControl; bool supportFromControl;
bool supportToControl; bool supportToControl;
bool hideLegSelection;
enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3}; enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3};
MetaListPost &add(ListIndex ix, const MetaListPost &post); MetaListPost &add(ListIndex ix, const MetaListPost &post);
@ -251,6 +252,9 @@ public:
void getResultModule(const oEvent &oe, vector< pair<wstring, size_t> > &modules, int &currentModule) const; void getResultModule(const oEvent &oe, vector< pair<wstring, size_t> > &modules, int &currentModule) const;
const string &getResultModule() const {return resultModule;} const string &getResultModule() const {return resultModule;}
MetaList &setSupportLegSelection(bool state);
bool supportLegSelection() const;
MetaList &setSupportFromTo(bool from, bool to); MetaList &setSupportFromTo(bool from, bool to);
bool supportFrom() const {return supportFromControl;} bool supportFrom() const {return supportFromControl;}
bool supportTo() const {return supportToControl;} bool supportTo() const {return supportToControl;}

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by

View File

@ -11,7 +11,7 @@
/************************************************************************ /************************************************************************
MeOS - Orienteering Software 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 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 it under the terms of the GNU General Public License as published by
@ -64,6 +64,7 @@ enum SortOrder {ClassStartTime,
SortByFinishTimeReverse, SortByFinishTimeReverse,
SortByStartTime, SortByStartTime,
CourseResult, CourseResult,
CourseStartTime,
SortByEntryTime, SortByEntryTime,
Custom, Custom,
SortEnumLastItem}; SortEnumLastItem};

Some files were not shown because too many files have changed in this diff Show More