MeOS version 3.5.826 RC1

This commit is contained in:
erikmelin 2018-03-05 22:07:20 +01:00
parent 4da3c93866
commit 34c8f1e29c
172 changed files with 8426 additions and 1734 deletions

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -4,7 +4,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -41,6 +41,7 @@
extern gdioutput *gdi_main;
int RunnerDB::cellEntryIndex = -1;
RunnerDB::RunnerDB(oEvent *oe_): oe(oe_)
{
@ -107,12 +108,22 @@ RunnerDBEntryV2::RunnerDBEntryV2()
memset(this, 0, sizeof(RunnerDBEntryV2));
}
RunnerDBEntryV3::RunnerDBEntryV3()
{
memset(this, 0, sizeof(RunnerDBEntryV3));
}
void RunnerWDBEntry::getName(wstring &n) const
{
initName();
n=name;
}
const wchar_t *RunnerWDBEntry::getNameCstr() const {
initName();
return name;
}
void RunnerWDBEntry::setName(const wchar_t *n)
{
const int blen = min<int>(wcslen(n)+1, baseNameLength);
@ -230,6 +241,22 @@ void RunnerDBEntry::init(const RunnerDBEntryV2 &dbe)
extId = dbe.extId;
}
void RunnerDBEntry::init(const RunnerDBEntryV3 &dbe)
{
memcpy(name, dbe.name, 56);
cardNo = dbe.cardNo;
clubNo = dbe.clubNo;
national[0] = dbe.national[0];
national[1] = dbe.national[1];
national[2] = dbe.national[2];
sex = dbe.sex;
birthYear = dbe.birthYear;
reserved = dbe.reserved;
extId = dbe.extId;
}
void RunnerWDBEntry::init(RunnerDB *p, size_t ixin) {
owner = p;
@ -386,6 +413,7 @@ void RunnerDB::importClub(oClub &club, bool matchName)
void RunnerDB::compactifyClubs()
{
chash.clear();
clubHash.clear();
freeCIx = 0;
map<int, int> clubmap;
@ -611,11 +639,7 @@ bool RunnerDB::getClub(int clubId, wstring &club) const
return false;
}
oClub *RunnerDB::getClub(int clubId) const
{
//map<int,int>::const_iterator it = chash.find(clubId);
//if (it!=chash.end())
oClub *RunnerDB::getClub(int clubId) const {
int value;
if (chash.lookup(clubId, value))
return pClub(&cdb[value]);
@ -760,7 +784,7 @@ void RunnerDB::saveRunners(const wstring &file)
_SH_DENYWR, _S_IREAD|_S_IWRITE);
if (f!=-1) {
int version = 5460003;
int version = 5460004;
_write(f, &version, 4);
_write(f, &dataDate, 4);
_write(f, &dataTime, 4);
@ -839,61 +863,83 @@ void RunnerDB::loadRunners(const wstring &file)
loadedFromServer = false;
int len = _filelength(f);
if ( (len%sizeof(RunnerDBEntryV1) != 0) && (len % sizeof(RunnerDBEntry) != 12)) {
if ( (len%sizeof(RunnerDBEntryV1) != 0) && (len % sizeof(RunnerDBEntryV3) != 12) && (len % sizeof(RunnerDBEntry) != 12)) {
_close(f);
return;//Failed
}
int nentry = 0;
if (len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntry) == 12) {
int version;
version = 0;
dataDate = 0;
dataTime = 0;
int version;
if (len % sizeof(RunnerDBEntry) == 12 || len % sizeof(RunnerDBEntryV2) == 12 || len % sizeof(RunnerDBEntryV3) == 12) {
_read(f, &version, 4);
_read(f, &dataDate, 4);
_read(f, &dataTime, 4);
}
if (version == 5460002 || version == 5460003 || version == 5460004) {
bool migrateV2 = false;
bool migrateV3 = false;
if (version == 5460002) {
migrateV2 = true;
nentry = (len-12) / sizeof(RunnerDBEntryV2);
nentry = (len - 12) / sizeof(RunnerDBEntryV2);
}
else if (version == 5460003) {
nentry = (len-12) / sizeof(RunnerDBEntry);
nentry = (len - 12) / sizeof(RunnerDBEntryV3);
migrateV3 = true;
}
else if (version == 5460004) {
nentry = (len - 12) / sizeof(RunnerDBEntry);
}
// Else unknown version: fail
rdb.resize(nentry);
if (rdb.empty()) {
_close(f);
_close(f);
return;
}
rwdb.resize(rdb.size());
if (!migrateV2) {
_read(f, &rdb[0], len-12);
if (!migrateV2 && !migrateV3) {
_read(f, &rdb[0], len - 12);
_close(f);
}
else {
else if (migrateV2) {
vector<RunnerDBEntryV2> rdbV2(nentry);
_read(f, &rdbV2[0], len-12);
_read(f, &rdbV2[0], len - 12);
_close(f);
for (int k=0;k<nentry;k++) {
for (int k = 0; k < nentry; k++) {
rdb[k].init(rdbV2[k]);
rwdb[k].init(this, k);
if (!check(rdb[k]))
throw meosException(ex);
}
}
else if (migrateV3) {
vector<RunnerDBEntryV3> rdbV3(nentry);
_read(f, &rdbV3[0], len - 12);
_close(f);
for (int k=0;k<nentry;k++) {
for (int k = 0; k < nentry; k++) {
rdb[k].init(rdbV3[k]);
rwdb[k].init(this, k);
if (!check(rdb[k]))
throw meosException(ex);
}
}
for (int k = 0; k < nentry; k++) {
rwdb[k].init(this, k);
if (!check(rdb[k]))
throw meosException(ex);
}
}
else {
else { //V1
dataDate = 0;
dataTime = 0;
@ -905,7 +951,7 @@ void RunnerDB::loadRunners(const wstring &file)
return;
}
vector<RunnerDBEntryV1> rdbV1(nentry);
_lseek(f, 0, SEEK_SET);
_read(f, &rdbV1[0], len);
_close(f);
rwdb.resize(rdb.size());
@ -986,7 +1032,23 @@ void RunnerDB::updateAdd(const oRunner &r, map<int, int> &clubIdMap)
RunnerWDBEntry *dbe = getRunnerByCard(r.getCardNo());
if (dbe == 0) {
if (dbe == nullptr) {
// Lookup by name
setupNameHash();
vector<int> ix;
wstring cname(canonizeName(r.getName().c_str()));
auto it = nhash.find(cname);
while (it != nhash.end() && cname == it->first) {
auto &dbr = rwdb[it->second];
if (dbr.dbe().clubNo == localClubId) {
dbe = &dbr;
break;
}
}
}
if (dbe == nullptr) {
dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo());
if (dbe)
dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
@ -1020,6 +1082,7 @@ void RunnerDB::clearClubs()
clearRunners(); // Runners refer to clubs. Clear runners
cnhash.clear();
chash.clear();
clubHash.clear(); // Autocomplete
freeCIx = 0;
cdb.clear();
if (clubTable)
@ -1032,6 +1095,8 @@ void RunnerDB::clearRunners()
nhash.clear();
idhash.clear();
rhash.clear();
runnerHash.clear(); // Autocomplete
runnerHashByClub.clear(); // Autocomplete
rdb.clear();
rwdb.clear();
if (runnerTable)
@ -1193,11 +1258,27 @@ void RunnerDB::refreshClubTableData(Table &table) {
}
void RunnerDB::refreshRunnerTableData(Table &table) {
oe->getDBRunnersInEvent(runnerInEvent); //XXX
for (size_t k = 0; k<oRDB.size(); k++){
if (!oRDB[k].isRemoved()) {
TableRow *row = table.getRowById(oRDB[k].getIndex() + 1);
if (row)
if (row) {
row->setObject(oRDB[k]);
oClass *val = 0;
bool found = false;
if (rdb[k].extId != 0)
found = runnerInEvent.lookup(rdb[k].extId, val);
if (found && row->getCellType(cellEntryIndex) == cellAction) {
row->updateCell(cellEntryIndex, cellEdit, val->getName());
}
else if (!found && row->getCellType(cellEntryIndex) == cellEdit) {
row->updateCell(cellEntryIndex, cellAction, L"@+");
}
}
}
}
}
@ -1282,6 +1363,7 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
else
table.setTableProp(0);
RunnerDB::cellEntryIndex = row;
if (!found)
table.set(row++, it, TID_ENTER, L"@+", false, cellAction);
else
@ -1307,6 +1389,8 @@ bool oDBRunnerEntry::inputData(int id, const wstring &input,
r.setName(input.c_str());
r.getName(output);
db->nhash.clear();
db->runnerHash.clear();
db->runnerHashByClub.clear();
return true;
case TID_CARD:
db->rhash.remove(rd.cardNo);
@ -1459,3 +1543,271 @@ const RunnerDBEntry &RunnerWDBEntry::dbe() const {
RunnerDBEntry &RunnerWDBEntry::dbe() {
return owner->rdb[ix];
}
void RunnerDB::ClubNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key, const wstring &skey) const {
for (size_t k = 0; k < index.size(); k++) {
int x = index[k];
if (db.cdb[x].isRemoved())
continue;
const wstring &n = db.cdb[x].getCanonizedName();
int nMatch = 0;
for (size_t k = 0; k < key.size(); k++) {
const wchar_t *str = wcsstr(n.c_str(), key[k].c_str());
if (str != nullptr)
nMatch++;
}
if (wcsstr(db.cdb[x].getCanonizedNameExact().c_str(), skey.c_str()) != nullptr)
nMatch += 3;
if (nMatch > 0)
ix.insert(make_pair(nMatch, x));
}
}
void RunnerDB::ClubNodeHash::setupHash(const wstring &key, int keyOffset, int ix) {
index.push_back(ix);
}
void RunnerDB::RunnerClubNodeHash::setupHash(const wchar_t *key, int keyOffset, int ix) {
index.push_back(ix);
}
void RunnerDB::RunnerClubNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const {
wchar_t bf[256];
for (size_t k = 0; k < index.size(); k++) {
int x = index[k];
if (db.rdb[x].isRemoved())
continue;
const wchar_t *n = db.rwdb[x].getNameCstr();
int i = 0, di = 0;
while (n[i]) {
if (n[i] == ',') {
i++;
continue;
}
bf[di++] = toLowerStripped(n[i++]);
}
bf[di] = 0;
int nMatch = 0;
for (size_t k = 0; k < key.size(); k++) {
const wchar_t *ref = key[k].c_str();
const wchar_t *str = wcsstr(bf, ref);
int add = 0;
if (str == bf || (str != nullptr && (iswspace(str[-1]) || str[-1]=='-'))) {
//Beginning of string or beginning of word
int len = 0;
while (str[len] && !iswspace(str[len]))
len++;
if (wcsncmp(ref, str, max<int>(len, key[k].length())) == 0)
add = 3; // Points for full name
else
add = 2; // Points for matching beginning of name
/*if (k > 0 && k + 1 == key.size()) {
add *= 2; // Last is full string
}*/
}
else if (str != nullptr && key[k].length() > 3) { // Inner part of name
add = 1;
}
if (nMatch > 1 && add > 1)
nMatch = 10 * nMatch + add;
else
nMatch += add;
}
if (nMatch > 0)
ix.insert(make_pair(nMatch, x));
}
}
void RunnerDB::RunnerNodeHash::setupHash(const wchar_t *key, int keyOffset, int ix) {
index.push_back(ix);
}
void RunnerDB::RunnerNodeHash::match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const {
RunnerDB::RunnerClubNodeHash::match(db, ix, key);
}
void RunnerDB::setupAutoCompleteHash(AutoHashMode mode) {
vector<wstring> names;
if (mode == AutoHashMode::Clubs) {
if (!clubHash.empty())
return;
for (size_t k = 0; k < cdb.size(); k++) {
auto &c = cdb[k];
canonizeSplitName(c.getName(), names);
wstring ccn, ccne;
ccne = canonizeName(c.getName().c_str());
for (size_t j = 0; j < names.size(); j++) {
const wstring &n = names[j];
if (j > 0)
ccn.append(L" ");
ccn += n;
int ikey = keyFromString(n, 0);
clubHash[ikey].setupHash(n, 2, k);
}
c.setCanonizedName(std::move(ccn), std::move(ccne));
}
}
else if (mode == AutoHashMode::RunnerClub) {
if (!runnerHashByClub.empty())
return;
for (size_t k = 0; k < rwdb.size(); k++) {
int key = rwdb[k].dbe().clubNo;
if (key > 0) {
runnerHashByClub[key].setupHash(rwdb[k].getNameCstr(), 2, k);
}
}
}
else if (mode == AutoHashMode::Runners) {
if (!runnerHash.empty())
return;
wstring tn;
wchar_t bf[256];
vector<int> ps;
for (size_t k = 0; k < rwdb.size(); k++) {
auto &r = rwdb[k];
const wchar_t *name = r.getNameCstr();
int ix = 0, iy = 0;
ps.resize(1, 0);
while (name[ix]) {
if (name[ix] != ',') {
if (name[ix] == '-' || name[ix] == ' ') {
bf[iy] = 0;
ps.push_back(iy+1);
}
else
bf[iy] = toLowerStripped(name[ix]);
iy++;
}
ix++;
}
bf[iy] = 0;
for (int j : ps) {
if (j < iy) {
int ikey = keyFromString(bf + j);
runnerHash[ikey].setupHash(bf, 2, k);
}
}
}
}
}
vector<pClub> RunnerDB::getClubSuggestions(const wstring &key, int limit) {
setupAutoCompleteHash(AutoHashMode::Clubs);
set<pair<int, int>> ix;
vector<wstring> nn;
wstring cankey = canonizeName(key.c_str());
canonizeSplitName(key, nn);
for (wstring &part : nn) {
int ikey = keyFromString(part, 0);
auto res = clubHash.find(ikey);
if (res != clubHash.end()) {
res->second.match(*this, ix, nn, cankey);
}
}
vector<pClub> ret;
vector< pair<int, int> > outOrder;
outOrder.reserve(ix.size());
for (const pair<int, int> &x : ix) {
const wstring &name = cdb[x.second].getCanonizedNameExact();
double sd = stringDistanceAssymetric(name, cankey);
outOrder.emplace_back(-(int(10000.0*(10 * x.first - sd))), x.second);
}
sort(outOrder.begin(), outOrder.end());
for (const pair<int, int> &x : outOrder) {
ret.push_back(&cdb[x.second]);
if (ret.size() > size_t(limit))
break;
}
return ret;
}
vector<pair<RunnerWDBEntry *, int>> RunnerDB::getRunnerSuggestions(const wstring &key, int clubId, int limit) {
if (clubId > 0)
setupAutoCompleteHash(AutoHashMode::RunnerClub);
else
setupAutoCompleteHash(AutoHashMode::Runners);
vector< pair<int, int> > outOrder;
set<pair<int, int>> ix;
wchar_t bf[256];
int iy = 0;
for (size_t k = 0; k < key.length(); k++) {
if (key[k] != ',') {
if (key[k] == '-')
bf[k] = ' ';
else
bf[k] = toLowerStripped(key[k]);
iy++;
if (iy >= 255) {
break;
}
}
}
bf[iy] = 0;
wstring cankey = trim(bf);
vector<pair<RunnerWDBEntry *, int>> ret;
vector<wstring> nameParts;
split(cankey, L" ", nameParts);
// if (nameParts.size() > 1)
// nameParts.push_back(cankey);
if (clubId > 0) {
auto res = runnerHashByClub.find(clubId);
if (res != runnerHashByClub.end()) {
res->second.match(*this, ix, nameParts);
}
}
else {
int np = nameParts.size();
if (np > 1)
np--;// Last is full string.
for (int k = 0; k < np; k++) {
wstring &part = nameParts[k];
int ikey = keyFromString(part, 0);
auto res = runnerHash.find(ikey);
if (res != runnerHash.end())
res->second.match(*this, ix, nameParts);
}
}
if (ix.empty())
return ret;
outOrder.reserve(ix.size());
wstring tname;
int maxP = 0;
for (auto itr = ix.rbegin(); itr != ix.rend(); ++itr) {
auto &x = *itr;
maxP = max(maxP, x.first);
if (x.first <= (maxP - 10) || (outOrder.size() > size_t(limit) && x.first < maxP))
break;
const wchar_t *name = rwdb[x.second].getNameCstr();
const wchar_t *cname = canonizeName(name);
tname = cname;
double sd = stringDistanceAssymetric(tname, cankey);
outOrder.emplace_back(-(int(10000.0*(10 * x.first - sd))), x.second);
}
// Fine-sort on string distance
sort(outOrder.begin(), outOrder.end());
for (const pair<int, int> &x : outOrder) {
ret.emplace_back(&rwdb[x.second], x.second);
if (ret.size() > size_t(limit))
break;
}
return ret;
}

View File

@ -2,18 +2,16 @@
#include <vector>
#include <map>
#include <set>
#include "inthashmap.h"
#include "oclub.h"
#ifdef OLD
#include <hash_set>
#else
#include <unordered_set>
#endif
#include <unordered_map>
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -33,8 +31,8 @@
************************************************************************/
const int baseNameLength=40;
const int baseNameLengthUTF=56;
const int baseNameLength = 64;
const int baseNameLengthUTF = 96;
//Has 0-clearing constructor. Must not contain any
//dynamic data etc.
@ -65,18 +63,29 @@ struct RunnerDBEntryV2 {
short int reserved;
/** End of V1*/
__int64 extId;
bool isRemoved() const {return (reserved & 1) == 1;}
void remove() {reserved |= 1;}
bool isUTF() const {return (reserved & 2) == 2;}
void setUTF() {reserved |= 2;}
};
struct RunnerDBEntryV3 {
// Init from old struct
RunnerDBEntryV3();
char name[56];
int cardNo;
int clubNo;
char national[3];
char sex;
short int birthYear;
short int reserved;
/** End of V1*/
__int64 extId;
};
struct RunnerDBEntry {
// Init from old struct
void init(const RunnerDBEntryV2 &dbe);
void init(const RunnerDBEntryV3 &dbe);
RunnerDBEntry();
// 8 it versions
@ -93,11 +102,11 @@ struct RunnerDBEntry {
/** End of V1*/
__int64 extId;
bool isRemoved() const {return (reserved & 1) == 1;}
void remove() {reserved |= 1;}
bool isRemoved() const { return (reserved & 1) == 1; }
void remove() { reserved |= 1; }
bool isUTF() const {return (reserved & 2) == 2;}
void setUTF() {reserved |= 2;}
bool isUTF() const { return (reserved & 2) == 2; }
void setUTF() { reserved |= 2; }
};
class RunnerDB;
@ -125,6 +134,9 @@ public:
void setName(const wchar_t *name);
void setNameUTF(const char *name);
const wchar_t *RunnerWDBEntry::getNameCstr() const;
wstring getGivenName() const;
wstring getFamilyName() const;
@ -152,6 +164,8 @@ private:
Table *runnerTable;
Table *clubTable;
static int cellEntryIndex;
bool check(const RunnerDBEntry &rde) const;
intkeymap<oClass *, __int64> runnerInEvent;
@ -197,8 +211,74 @@ private:
void fillClubs(vector< pair<wstring, size_t> > &out) const;
class ClubNodeHash {
//map<wchar_t, ClubNodeHash> hash;
vector<int> index;
public:
void setupHash(const wstring &key, int keyOffset, int ix);
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key, const wstring &skey) const;
};
class RunnerClubNodeHash {
protected:
vector<int> index;
public:
void setupHash(const wchar_t *key, int keyOffset, int ix);
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const;
};
class RunnerNodeHash : public RunnerClubNodeHash {
map<wchar_t, RunnerNodeHash> hash;
public: // Note: Non virtual. No reference by parent type
void setupHash(const wchar_t *key, int keyOffset, int ix);
void match(RunnerDB &db, set< pair<int, int> > &ix, const vector<wstring> &key) const;
};
unordered_map<int, ClubNodeHash> clubHash;
unordered_map<int, RunnerNodeHash> runnerHash;
unordered_map<int, RunnerClubNodeHash> runnerHashByClub;
enum class AutoHashMode {
Clubs, Runners, RunnerClub
};
void setupAutoCompleteHash(AutoHashMode mode);
static int keyFromString(const wstring &n, size_t offset) {
pair<wchar_t, wchar_t> key;
//static_assert(sizeof(key) == sizeof int);
if (n.length() == 1 + offset) {
key.first = n[offset];
key.second = 0;
}
else if (n.length() > 1 + offset) {
key.first = n[offset];
key.second = n[offset+1];
}
int *ikey = static_cast<int *>((void *)&key);
return *ikey;
}
static int keyFromString(const wchar_t *n) {
pair<wchar_t, wchar_t> key;
if (n[0] == 0)
return 0;
else {
key.first = n[0];
key.second = n[1];
}
int *ikey = static_cast<int *>((void *)&key);
return *ikey;
}
public:
vector<pClub> getClubSuggestions(const wstring &key, int limit);
vector<pair<RunnerWDBEntry *, int>> getRunnerSuggestions(const wstring &name, int clubId, int limit);
void generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry);
void generateClubTableData(Table &table, oClub *addEntry);
@ -306,7 +386,21 @@ class oDBClubEntry : public oClub {
private:
int index;
RunnerDB *db;
wstring canonizedName;
wstring canonizedNameExact;
public:
void setCanonizedName(wstring &&n, wstring &&nExact) {
canonizedName = n;
canonizedNameExact = nExact;
}
const wstring &getCanonizedName() {
return canonizedName;
}
const wstring &getCanonizedNameExact() {
return canonizedNameExact;
}
oDBClubEntry(oEvent *oe, int id, int index, RunnerDB *db);
oDBClubEntry(const oClub &c, int index, RunnerDB *db);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -11,7 +11,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -46,6 +46,22 @@
extern pEvent gEvent;
const char *visualDrawWindow = "visualdraw";
struct DrawSettingsCSV {
int classId;
wstring cls;
int nCmp;
wstring crs;
int ctrl;
int firstStart;
int interval;
int vacant;
static void write(gdioutput &gdi, const oEvent &oe, const wstring &fn, vector<DrawSettingsCSV> &arg);
static vector<DrawSettingsCSV> read(gdioutput &gdi, const oEvent &oe, const wstring &fn);
};
TabClass::TabClass(oEvent *poe):TabBase(poe)
{
handleCloseWindow.tabClass = this;
@ -133,12 +149,31 @@ int DrawClassesCB(gdioutput *gdi, int type, void *data)
InputInfo &ii = *(InputInfo *)data;
if (ii.id.length() > 1) {
int id = atoi(ii.id.substr(1).c_str());
if (id > 0 && ii.changed()) {
if (id > 0 ) {
bool changed = false;
string key = "C" + itos(id);
TextInfo &ti = dynamic_cast<TextInfo&>(gdi->getBaseInfo(key.c_str()));
ti.setColor(colorRed);
gdi->enableInput("DrawAdjust");
gdi->refreshFast();
if (ii.changed()) {
changed = changed || ti.getColor() != colorRed;
ti.setColor(colorRed);
if (ii.getBgColor() != colorLightCyan) {
ii.setBgColor(colorLightCyan).refresh();
}
gdi->enableInput("DrawAdjust");
}
else {
GDICOLOR def = GDICOLOR(ti.getExtraInt());
if (def != ti.getColor()) {
ti.setColor(def); // Restore
changed = true;
}
GDICOLOR nColor = ii.getExtraInt() != 0 ? GDICOLOR(ii.getExtraInt()) : colorDefault;
if (nColor != ii.getBgColor()) {
ii.setBgColor(nColor).refresh();
}
}
if (changed)
gdi->refreshFast();
}
}
}
@ -652,18 +687,171 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id=="SaveDrawSettings") {
readClassSettings(gdi);
for(size_t k=0; k<cInfo.size(); k++) {
const ClassInfo &ci = cInfo[k];
if (ci.pc) {
saveDrawSettings();
}
else if (bi.id == "ExportDrawSettings") {
int fi;
wstring fn = gdi.browseForSave({ make_pair(lang.tl("Kalkylblad/csv"), L"*.csv") }, L"csv", fi);
if (fn.empty())
return false;
vector<DrawSettingsCSV> res;
if (bi.getExtraInt() == 1) {
vector<pClass> cls;
oe->getClasses(cls, true);
for (pClass pc : cls) {
if (pc->hasFreeStart())
continue;
DrawSettingsCSV ds;
ds.classId = pc->getId();
ds.cls = pc->getName();
ds.nCmp = pc->getNumRunners(1, false, false);
pCourse crs = pc->getCourse();
pControl ctrl = nullptr;
if (crs) {
ds.crs = crs->getName();
ctrl = crs->getControl(0);
}
if (ctrl) {
ds.ctrl = ctrl->getId();
}
else ds.ctrl = 0;
// Save settings with class
ci.pc->synchronize(false);
ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart);
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
ci.pc->setDrawVacant(ci.nVacant);
ci.pc->setDrawNumReserved(ci.nExtra);
ci.pc->synchronize(true);
ds.firstStart = 3600;
ds.interval = 120;
ds.vacant = 1;
res.push_back(ds);
}
}
else {
readClassSettings(gdi);
for (size_t k = 0; k < cInfo.size(); k++) {
const ClassInfo &ci = cInfo[k];
if (ci.pc) {
DrawSettingsCSV ds;
ds.classId = ci.pc->getId();
ds.cls = ci.pc->getName();
ds.nCmp = ci.pc->getNumRunners(1, false, false);
pCourse crs = ci.pc->getCourse();
pControl ctrl = nullptr;
if (crs) {
ds.crs = crs->getName();
ctrl = crs->getControl(0);
}
if (ctrl) {
ds.ctrl = ctrl->getId();
}
else ds.ctrl = 0;
// Save settings with class
ds.firstStart = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
ds.interval = ci.interval * drawInfo.baseInterval;
ds.vacant = ci.nVacant;
res.push_back(ds);
}
}
}
DrawSettingsCSV::write(gdi, *oe, fn, res);
/*csvparser writer;
writer.openOutput(fn.c_str());
vector<string> header;
writer.outputRow(header);
header.emplace_back("ClassId");
header.emplace_back("Class");
header.emplace_back("Competitors");
header.emplace_back("Course");
header.emplace_back("First Control");
header.emplace_back("First Start");
header.emplace_back("Interval");
header.emplace_back("Vacant");
writer.outputRow(header);
vector<string> line;
for (size_t k = 0; k<cInfo.size(); k++) {
const ClassInfo &ci = cInfo[k];
if (ci.pc) {
line.clear();
line.push_back(itos(ci.pc->getId()));
line.push_back(gdi.toUTF8(ci.pc->getName()));
line.push_back(itos(ci.pc->getNumRunners(1, false, false)));
pCourse crs = ci.pc->getCourse();
pControl ctrl = nullptr;
if (crs) {
line.push_back(gdi.toUTF8(crs->getName()));
ctrl = crs->getControl(0);
}
else line.emplace_back("");
if (ctrl) {
line.push_back(itos(ctrl->getId()));
}
else line.emplace_back("");
// Save settings with class
line.push_back(gdi.narrow(oe->getAbsTime(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart)));
line.push_back(gdi.narrow(formatTime(ci.interval * drawInfo.baseInterval)));
line.push_back(itos(ci.nVacant));
writer.outputRow(line);
}
}*/
}
else if (bi.id == "ImportDrawSettings") {
wstring fn = gdi.browseForOpen({ make_pair(lang.tl("Kalkylblad/csv"), L"*.csv") }, L"csv");
if (fn.empty())
return false;
wstring firstStart = gdi.getText("FirstStart");
wstring minInterval = gdi.getText("MinInterval");
wstring vacances = gdi.getText("Vacances");
clearPage(gdi, false);
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.dropLine(0.5);
gdi.addString("", 0, "Importerar lottningsinställningar...");
set<int> classes;
for (auto &ds : DrawSettingsCSV::read(gdi, *oe, fn)) {
pClass pc = oe->getClass(ds.classId);
if (pc) {
classes.insert(ds.classId);
pc->setDrawFirstStart(ds.firstStart);
pc->setDrawInterval(ds.interval);
pc->setDrawVacant(ds.vacant);
pc->setDrawNumReserved(0);
pc->setDrawSpecification({ oClass::DrawSpecified::FixedTime, oClass::DrawSpecified::Vacant});
}
}
if (classes.empty()) {
throw meosException("Ingen klass vald.");
}
int by = 0;
int bx = gdi.getCX();
loadBasicDrawSetup(gdi, bx, by, firstStart, 1, minInterval, vacances, classes);
loadReadyToDistribute(gdi, bx, by);
oe->loadDrawSettings(classes, drawInfo, cInfo);
writeDrawInfo(gdi, drawInfo);
gdi.enableEditControls(false);
showClassSettings(gdi);
}
else if (bi.id=="DoDrawAll") {
readClassSettings(gdi);
@ -675,19 +863,10 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
int maxST = 0;
map<int, vector<ClassDrawSpecification> > specs;
saveDrawSettings();
for(size_t k=0; k<cInfo.size(); k++) {
const ClassInfo &ci=cInfo[k];
if (ci.pc) {
// Save settings with class
ci.pc->synchronize(false);
int stloc = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
maxST = max(maxST, stloc);
ci.pc->setDrawFirstStart(stloc);
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
ci.pc->setDrawVacant(ci.nVacant);
ci.pc->setDrawNumReserved(ci.nExtra);
ci.pc->synchronize(true);
}
ClassDrawSpecification cds(ci.classId, 0, drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart,
drawInfo.baseInterval * ci.interval, ci.nVacant);
if (drawCoursebased) {
@ -791,7 +970,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.popX();
gdi.fillRight();
gdi.addButton("AutomaticDraw", "Automatisk lottning", ClassesCB).setDefault();
gdi.addButton("AutomaticDraw", "Automatisk lottning", ClassesCB);
gdi.addButton("DrawAll", "Manuell lottning", ClassesCB).setExtra(1);
gdi.addButton("Simultaneous", "Gemensam start", ClassesCB);
@ -802,7 +981,24 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.addButton("Cancel", "Återgå", ClassesCB).setCancel();
gdi.dropLine(3);
gdi.popX();
int xs = gdi.getCX();
int ys = gdi.getCY();
gdi.dropLine();
gdi.setCX(xs + gdi.getLineHeight());
gdi.fillDown();
gdi.addString("", 10, "help:exportdraw");
gdi.dropLine(0.5);
gdi.fillRight();
gdi.addButton("ExportDrawSettings", "Exportera", ClassesCB).setExtra(1);
gdi.addButton("ImportDrawSettings", "Importera", ClassesCB);
gdi.dropLine(2.5);
RECT rc = {xs, ys, gdi.getWidth(), gdi.getCY()};
gdi.addRectangle(rc, colorLightCyan);
gdi.newColumn();
@ -996,11 +1192,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
}
clearPage(gdi, false);
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.dropLine(0.5);
showClassSelection(gdi, bx, by, DrawClassesCB);
vector<pClass> cls;
oe->getClasses(cls, false);
set<int> clsId;
@ -1012,64 +1203,11 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
clsId.insert(cls[k]->getId());
}
gdi.setSelection("Classes", clsId);
gdi.addString("", 1, "Grundinställningar");
gdi.pushX();
gdi.fillRight();
gdi.addInput("FirstStart", firstStart, 10, 0, L"Första start:");
gdi.addInput("nFields", L"10", 10, 0, L"Max parallellt startande:");
gdi.popX();
gdi.dropLine(3);
gdi.addSelection("MaxCommonControl", 150, 100, 0,
L"Max antal gemensamma kontroller:");
vector< pair<wstring, size_t> > items;
items.push_back(make_pair(lang.tl("Inga"), 1));
items.push_back(make_pair(lang.tl("Första kontrollen"), 2));
for (int k = 2; k<10; k++)
items.push_back(make_pair(lang.tl("X kontroller#" + itos(k)), k+1));
items.push_back(make_pair(lang.tl("Hela banan"), 1000));
gdi.addItem("MaxCommonControl", items);
gdi.selectItemByData("MaxCommonControl", maxNumControl);
gdi.popX();
gdi.dropLine(4);
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, true);
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
gdi.popX();
gdi.dropLine(2);
gdi.addString("", 1, "Startintervall");
gdi.dropLine(1.4);
gdi.popX();
gdi.fillRight();
gdi.addInput("BaseInterval", L"1:00", 10, 0, L"Basintervall (min):");
gdi.addInput("MinInterval", minInterval, 10, 0, L"Minsta intervall i klass:");
gdi.addInput("MaxInterval", minInterval, 10, 0, L"Största intervall i klass:");
gdi.popX();
gdi.dropLine(4);
gdi.addString("", 1, "Vakanser och efteranmälda");
gdi.dropLine(1.4);
gdi.popX();
gdi.addInput("Vacances", vacances, 10, 0, L"Andel vakanser:");
gdi.addInput("VacancesMin", L"1", 10, 0, L"Min. vakanser (per klass):");
gdi.addInput("VacancesMax", L"10", 10, 0, L"Max. vakanser (per klass):");
gdi.popX();
gdi.dropLine(3);
gdi.addInput("Extra", L"0%", 10, 0, L"Förväntad andel efteranmälda:");
gdi.dropLine(4);
gdi.fillDown();
gdi.popX();
gdi.setRestorePoint("Setup");
clearPage(gdi, false);
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.dropLine(0.5);
loadBasicDrawSetup(gdi, bx, by, firstStart, maxNumControl, minInterval, vacances, clsId);
}
else {
gdi.restore("Setup");
@ -1077,51 +1215,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.enableEditControls(true);
}
gdi.fillRight();
gdi.pushX();
RECT rcPrepare;
rcPrepare.left = gdi.getCX();
rcPrepare.top = gdi.getCY();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Förbered lottning");
gdi.dropLine(2.5);
gdi.popX();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.addButton("PrepareDrawAll", "Fördela starttider...", ClassesCB).isEdit(true).setDefault();
gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(0);
gdi.addButton("LoadSettings", "Hämta inställningar från föregående lottning", ClassesCB).isEdit(true);
enableLoadSettings(gdi);
gdi.dropLine(3);
rcPrepare.bottom = gdi.getCY();
rcPrepare.right = gdi.getWidth();
gdi.addRectangle(rcPrepare, colorLightGreen);
gdi.dropLine();
gdi.popX();
gdi.addString("", 1, "Efteranmälningar");
gdi.dropLine(1.5);
gdi.popX();
gdi.addButton("DrawAllBefore", "Efteranmälda (före ordinarie)", ClassesCB).isEdit(true);
gdi.addButton("DrawAllAfter", "Efteranmälda (efter ordinarie)", ClassesCB).isEdit(true);
gdi.dropLine(4);
gdi.popX();
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
gdi.dropLine(3);
by = max(by, gdi.getCY());
gdi.setCX(bx);
gdi.setCY(by);
gdi.fillDown();
gdi.dropLine();
gdi.setRestorePoint("ReadyToDistribute");
gdi.refresh();
loadReadyToDistribute(gdi, bx, by);
}
else if (bi.id == "HelpDraw") {
@ -1145,6 +1239,12 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
throw meosException("Ingen klass vald.");
}
gdi.restore("ReadyToDistribute");
/*
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
gdi.dropLine(3);
*/
drawInfo.classes.clear();
for (set<int>::iterator it = classes.begin(); it!=classes.end();++it) {
@ -1194,62 +1294,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.restore("ReadyToDistribute");
oe->loadDrawSettings(classes, drawInfo, cInfo);
/*
drawInfo.firstStart = 3600 * 22;
drawInfo.minClassInterval = 3600;
drawInfo.maxClassInterval = 1;
drawInfo.minVacancy = 10;
set<int> reducedStart;
for (set<int>::iterator it = classes.begin(); it != classes.end(); ++it) {
pClass pc = oe->getClass(*it);
if (pc) {
int fs = pc->getDrawFirstStart();
int iv = pc->getDrawInterval();
if (iv > 0 && fs > 0) {
drawInfo.firstStart = min(drawInfo.firstStart, fs);
drawInfo.minClassInterval = min(drawInfo.minClassInterval, iv);
drawInfo.maxClassInterval = max(drawInfo.maxClassInterval, iv);
drawInfo.minVacancy = min(drawInfo.minVacancy, pc->getDrawVacant());
drawInfo.maxVacancy = max(drawInfo.maxVacancy, pc->getDrawVacant());
reducedStart.insert(fs%iv);
}
}
}
drawInfo.baseInterval = drawInfo.minClassInterval;
int lastStart = -1;
for (set<int>::iterator it = reducedStart.begin(); it != reducedStart.end(); ++it) {
if (lastStart == -1)
lastStart = *it;
else {
drawInfo.baseInterval = min(drawInfo.baseInterval, *it-lastStart);
lastStart = *it;
}
}
cInfo.clear();
cInfo.resize(classes.size());
int i = 0;
for (set<int>::iterator it = classes.begin(); it != classes.end(); ++it) {
pClass pc = oe->getClass(*it);
if (pc) {
int fs = pc->getDrawFirstStart();
int iv = pc->getDrawInterval();
cInfo[i].pc = pc;
cInfo[i].classId = *it;
cInfo[i].courseId = pc->getCourseId();
cInfo[i].firstStart = fs;
cInfo[i].unique = pc->getCourseId();
if (cInfo[i].unique == 0)
cInfo[i].unique = pc->getId() * 10000;
cInfo[i].firstStart = (fs - drawInfo.firstStart) / drawInfo.baseInterval;
cInfo[i].interval = iv / drawInfo.baseInterval;
cInfo[i].nVacant = pc->getDrawVacant();
i++;
}
}
*/
writeDrawInfo(gdi, drawInfo);
gdi.enableEditControls(false);
@ -1272,6 +1316,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi_new->addButton("CloseWindow", "Stäng", ClassesCB);
gdi_new->registerEvent("CloseWindow", 0).setHandler(&handleCloseWindow);
gdi_new->refresh();
gdi.refreshFast();
}
else if (bi.id == "EraseStartAll") {
set<int> classes;
@ -1872,7 +1917,6 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
}
save(gdi, true);
pClass pc = oe->addClass(oe->getAutoClassName(), 0);
if (pc) {
@ -2136,13 +2180,29 @@ void TabClass::showClassSettings(gdioutput &gdi)
gdi.fillRight();
int id = ci.classId;
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2);
y = gdi.getCY();
gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB);
gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
gdi.addInput(xp+300+width*2, y, "V"+itos(id), itow(ci.nVacant), 7, DrawClassesCB);
gdi.addInput(xp+300+width*3, y, "R"+itos(id), itow(ci.nExtra), 7, DrawClassesCB);
GDICOLOR clr = ci.hasFixedTime || ci.nExtraSpecified || ci.nVacantSpecified ? colorDarkGreen : colorBlack;
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2).setColor(clr).setExtra(clr);
y = gdi.getCY();
InputInfo *ii;
GDICOLOR fixedColor = colorLightGreen;
ii = &gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB);
if (ci.hasFixedTime) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
ii = &gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
if (ci.hasFixedTime) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
ii = &gdi.addInput(xp+300+width*2, y, "V"+itos(id), itow(ci.nVacant), 7, DrawClassesCB);
if (ci.nVacantSpecified) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
ii = &gdi.addInput(xp+300+width*3, y, "R"+itos(id), itow(ci.nExtra), 7, DrawClassesCB);
if (ci.nExtraSpecified) {
ii->setBgColor(fixedColor).setExtra(fixedColor);
}
if (k%5 == 4)
gdi.dropLine(1);
@ -2161,6 +2221,10 @@ void TabClass::showClassSettings(gdioutput &gdi)
gdi.addButton("SaveDrawSettings", "Spara starttider", ClassesCB,
"Spara inmatade tider i tävlingen utan att tilldela starttider.");
gdi.addButton("ExportDrawSettings", "Exportera...", ClassesCB,
"Exportera ett kalkylblad med lottningsinställningar som du kan redigera och sedan läsa in igen.");
gdi.addButton("DrawAllAdjust", "Ändra inställningar", ClassesCB,
"Ändra grundläggande inställningar och gör en ny fördelning").setExtra(13);
@ -2169,6 +2233,7 @@ void TabClass::showClassSettings(gdioutput &gdi)
"Uppdatera fördelningen av starttider med hänsyn till manuella ändringar ovan");
gdi.disableInput("DrawAdjust");
}
gdi.popX();
gdi.dropLine(3);
@ -3454,7 +3519,7 @@ void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK
gdi.pushY();
int cx = gdi.getCX();
int width = gdi.scaleLength(230);
gdi.addListBox("Classes", 200, 400, classesCB, L"Klasser:", L"", true);
gdi.addListBox("Classes", 200, 480, classesCB, L"Klasser:", L"", true);
gdi.setTabStops("Classes", 185);
gdi.fillRight();
gdi.pushX();
@ -4051,13 +4116,28 @@ vector< pair<wstring, size_t> > TabClass::getPairOptions() {
void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfoOut) {
drawInfoOut.maxCommonControl = gdi.getSelectedItem("MaxCommonControl").first;
drawInfoOut.maxVacancy=gdi.getTextNo("VacancesMax");
drawInfoOut.minVacancy=gdi.getTextNo("VacancesMin");
drawInfoOut.vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
drawInfoOut.extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
int maxVacancy = gdi.getTextNo("VacancesMax");
int minVacancy = gdi.getTextNo("VacancesMin");
double vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
double extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
drawInfoOut.changedVacancyInfo = drawInfoOut.maxVacancy != maxVacancy ||
drawInfoOut.minVacancy != minVacancy ||
drawInfoOut.vacancyFactor != vacancyFactor;
drawInfoOut.maxVacancy = maxVacancy;
drawInfoOut.minVacancy = minVacancy;
drawInfoOut.vacancyFactor = vacancyFactor;
drawInfoOut.changedExtraInfo = drawInfoOut.extraFactor != extraFactor;
drawInfoOut.extraFactor = extraFactor;
drawInfoOut.baseInterval=convertAbsoluteTimeMS(gdi.getText("BaseInterval"));
drawInfoOut.allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
oe->setProperty("DrawInterlace", drawInfoOut.allowNeighbourSameCourse ? 1 : 0);
drawInfoOut.coursesTogether = gdi.isChecked("CoursesTogether");
drawInfoOut.minClassInterval = convertAbsoluteTimeMS(gdi.getText("MinInterval"));
drawInfoOut.maxClassInterval = convertAbsoluteTimeMS(gdi.getText("MaxInterval"));
@ -4115,3 +4195,246 @@ void TabClass::clearPage(gdioutput &gdi, bool autoRefresh) {
gdi.clearPage(autoRefresh);
gdi.setData("ClassPageLoaded", 1);
}
void TabClass::saveDrawSettings() const {
for (size_t k = 0; k<cInfo.size(); k++) {
const ClassInfo &ci = cInfo[k];
if (ci.pc) {
// Save settings with class
ci.pc->synchronize(false);
ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart);
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
ci.pc->setDrawVacant(ci.nVacant);
ci.pc->setDrawNumReserved(ci.nExtra);
vector<oClass::DrawSpecified> ds;
if (ci.nExtraSpecified)
ds.push_back(oClass::DrawSpecified::Extra);
if (ci.hasFixedTime)
ds.push_back(oClass::DrawSpecified::FixedTime);
if (ci.nVacantSpecified)
ds.push_back(oClass::DrawSpecified::Vacant);
ci.pc->setDrawSpecification(ds);
ci.pc->synchronize(true);
}
}
}
void DrawSettingsCSV::write(gdioutput &gdi, const oEvent &oe, const wstring &fn, vector<DrawSettingsCSV> &cInfo) {
csvparser writer;
writer.openOutput(fn.c_str(), true);
vector<string> header, line;
header.emplace_back("ClassId");
header.emplace_back("Class");
header.emplace_back("Competitors");
header.emplace_back("Course");
header.emplace_back("First Control");
header.emplace_back("First Start");
header.emplace_back("Interval");
header.emplace_back("Vacant");
// Save settings with class
writer.outputRow(header);
for (size_t k = 0; k<cInfo.size(); k++) {
auto &ci = cInfo[k];
line.clear();
line.push_back(itos(ci.classId));
line.push_back(gdi.toUTF8(ci.cls));
line.push_back(itos(ci.nCmp));
if (!ci.crs.empty()) {
line.push_back(gdi.toUTF8(ci.crs));
}
else line.emplace_back("");
if (ci.ctrl) {
line.push_back(itos(ci.ctrl));
}
else line.emplace_back("");
line.push_back(gdi.narrow(oe.getAbsTime(ci.firstStart)));
line.push_back(gdi.narrow(formatTime(ci.interval)));
line.push_back(itos(ci.vacant));
writer.outputRow(line);
}
}
vector<DrawSettingsCSV> DrawSettingsCSV::read(gdioutput &gdi, const oEvent &oe, const wstring &fn) {
csvparser reader;
list<vector<wstring>> data;
reader.parse(fn.c_str(), data);
vector<DrawSettingsCSV> output;
set<int> usedId;
// Save settings with class
int lineNo = 0;
for (auto &row : data) {
lineNo++;
if (row.empty())
continue;
int cid = _wtoi(row[0].c_str());
if (!(cid > 0))
continue;
DrawSettingsCSV dl;
try {
if (row.size() <= 7)
throw wstring(L"Rad X är ogiltig#" + itow(lineNo) + L": " + row[0] + L"...");
pClass pc = oe.getClass(cid);
if (!pc || (!row[1].empty() && !compareClassName(pc->getName(), row[1]))) {
pClass pcName = oe.getClass(row[1]);
if (pcName)
pc = pcName;
}
if (!pc)
throw wstring(L"Hittar inte klass X#" + row[0] + L"/" + row[1]);
else if (usedId.count(pc->getId()))
throw wstring(L"Klassen X är listad flera gånger#" + row[0] + L"/" + row[1]);
usedId.insert(pc->getId());
dl.classId = pc->getId();
dl.firstStart = oe.getRelativeTime(row[5]);
if (dl.firstStart <= 0)
throw wstring(L"Ogiltig starttid X#" + row[5]);
dl.interval = convertAbsoluteTimeMS(row[6]);
if (dl.interval <= 0)
throw wstring(L"Ogiltigt startintervall X#" + row[6]);
dl.vacant = _wtoi(row[7].c_str());
output.push_back(dl);
}
catch (const wstring &exmsg) {
gdi.addString("", 0, exmsg).setColor(colorRed);
}
}
return output;
}
void TabClass::loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstring &firstStart,
int maxNumControl, const wstring &minInterval, const wstring &vacances,
const set<int> &clsId) {
showClassSelection(gdi, bx, by, DrawClassesCB);
gdi.setSelection("Classes", clsId);
gdi.addString("", 1, "Grundinställningar");
gdi.pushX();
gdi.fillRight();
gdi.addInput("FirstStart", firstStart, 10, 0, L"Första start:");
gdi.addInput("nFields", L"10", 10, 0, L"Max parallellt startande:");
gdi.popX();
gdi.dropLine(3);
gdi.addSelection("MaxCommonControl", 150, 100, 0,
L"Max antal gemensamma kontroller:");
vector< pair<wstring, size_t> > items;
items.push_back(make_pair(lang.tl("Inga"), 1));
items.push_back(make_pair(lang.tl("Första kontrollen"), 2));
for (int k = 2; k<10; k++)
items.push_back(make_pair(lang.tl("X kontroller#" + itos(k)), k + 1));
items.push_back(make_pair(lang.tl("Hela banan"), 1000));
gdi.addItem("MaxCommonControl", items);
gdi.selectItemByData("MaxCommonControl", maxNumControl);
gdi.popX();
gdi.dropLine(4);
gdi.fillDown();
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, oe->getPropertyInt("DrawInterlace", 1) == 0);
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
gdi.dropLine(0.5);
gdi.addString("", 1, "Startintervall");
gdi.dropLine(0.4);
gdi.fillRight();
gdi.addInput("BaseInterval", L"1:00", 10, 0, L"Basintervall (min):");
gdi.addInput("MinInterval", minInterval, 10, 0, L"Minsta intervall i klass:");
gdi.addInput("MaxInterval", minInterval, 10, 0, L"Största intervall i klass:");
gdi.popX();
gdi.dropLine(4);
gdi.fillDown();
gdi.addString("", 1, "Vakanser och efteranmälda");
gdi.dropLine(0.4);
gdi.fillRight();
gdi.popX();
gdi.addInput("Vacances", vacances, 6, 0, L"Andel vakanser:");
gdi.addInput("VacancesMin", L"1", 6, 0, L"Min. vakanser (per klass):");
gdi.addInput("VacancesMax", L"10", 6, 0, L"Max. vakanser (per klass):");
gdi.addInput("Extra", L"0%", 6, 0, L"Förväntad andel efteranmälda:");
gdi.dropLine(4);
gdi.fillDown();
gdi.popX();
gdi.setRestorePoint("Setup");
}
void TabClass::loadReadyToDistribute(gdioutput &gdi, int &bx, int &by) {
gdi.fillRight();
gdi.pushX();
RECT rcPrepare;
rcPrepare.left = gdi.getCX();
rcPrepare.top = gdi.getCY();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Förbered lottning");
gdi.dropLine(2.2);
gdi.popX();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.addButton("PrepareDrawAll", "Fördela starttider...", ClassesCB).isEdit(true);
gdi.addButton("EraseStartAll", "Radera starttider...", ClassesCB).isEdit(true).setExtra(0);
gdi.addButton("LoadSettings", "Hämta inställningar från föregående lottning", ClassesCB).isEdit(true);
enableLoadSettings(gdi);
gdi.dropLine(3);
rcPrepare.bottom = gdi.getCY();
rcPrepare.right = gdi.getWidth();
gdi.addRectangle(rcPrepare, colorLightGreen);
gdi.dropLine();
gdi.popX();
rcPrepare.left = gdi.getCX();
rcPrepare.top = gdi.getCY();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Efteranmälningar");
gdi.dropLine(2.2);
gdi.popX();
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
gdi.addButton("DrawAllBefore", "Efteranmälda (före ordinarie)", ClassesCB).isEdit(true);
gdi.addButton("DrawAllAfter", "Efteranmälda (efter ordinarie)", ClassesCB).isEdit(true);
gdi.dropLine(3);
rcPrepare.bottom = gdi.getCY();
rcPrepare.right = gdi.getWidth();
gdi.addRectangle(rcPrepare, colorLightBlue);
gdi.dropLine();
gdi.popX();
gdi.addButton("Cancel", "Avbryt", ClassesCB).setCancel();
gdi.addButton("HelpDraw", "Hjälp...", ClassesCB, "");
gdi.dropLine(3);
by = max(by, gdi.getCY());
gdi.setCX(bx);
gdi.setCY(by);
gdi.fillDown();
gdi.dropLine();
gdi.setRestorePoint("ReadyToDistribute");
gdi.refresh();
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -70,6 +70,7 @@ class TabClass :
void save(gdioutput &gdi, bool skipReload);
void legSetup(gdioutput &gdi);
vector<ClassInfo> cInfo;
void saveDrawSettings() const;
map<int, ClassInfo> cInfoCache;
@ -146,6 +147,10 @@ class TabClass :
void setLockForkingState(gdioutput &gdi, bool poolState, bool lockState);
void loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstring& firstStart,
int maxNumControl, const wstring& minInterval, const wstring& vacances, const set<int> &clsId);
void loadReadyToDistribute(gdioutput &gdi, int &bx, int &by);
public:
void clearCompetitionData();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -316,14 +316,14 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
fields.push_back("Street");
fields.push_back("Address");
fields.push_back("EMail");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine();
gdi.addString("", boldText, "Betalningsinformation");
fields.clear();
fields.push_back("Account");
fields.push_back("PaymentDue");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 10);
gdi.pushX();
gdi.fillRight();

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1504,11 +1504,12 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.dropLine();
gdi.addString("", 1, "Behandlar tävlingsdata").setColor(colorGreen);
set<int> noFilter;
string noType;
if (createNew && id>0) {
gdi.addString("", 1, "Skapar ny tävling");
oe->newCompetition(L"New");
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter);
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter, noType);
oe->setZeroTime(formatTimeHMS(zeroTime));
oe->getDI().setDate("OrdinaryEntry", lastEntry);
if (ci) {
@ -1521,12 +1522,13 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
removeTempFile(tEvent);
oe->importXML_EntryData(gdi, tClass.c_str(), false, false, noFilter);
oe->importXML_EntryData(gdi, tClass.c_str(), false, false, noFilter, noType);
removeTempFile(tClass);
set<int> stageFilter;
checkStageFilter(gdi, tEntry, stageFilter);
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter);
string preferredIdType;
checkStageFilter(gdi, tEntry, stageFilter, preferredIdType);
oe->importXML_EntryData(gdi, tEntry.c_str(), false, removeRemoved, stageFilter, preferredIdType);
removeTempFile(tEntry);
if (!course.empty()) {
@ -2357,7 +2359,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
gdi.dropLine(0.4);
gdi.fillDown();
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2017 Melin Software HB"));
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2018 Melin Software HB"));
gdi.dropLine(1);
gdi.popX();
@ -2370,7 +2372,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.clearPage(false);
gdi.addString("", 2, makeDash(L"Om MeOS - ett Mycket Enkelt OrienteringsSystem")).setColor(colorDarkBlue);
gdi.dropLine(2);
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2017 Melin Software HB"));
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2018 Melin Software HB"));
gdi.dropLine();
gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright "
"(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB,"
@ -2389,7 +2391,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.dropLine();
gdi.addString("", 1, "Vi stöder MeOS");
vector<string> supp;
vector<wstring> supp;
getSupporters(supp);
for (size_t k = 0; k<supp.size(); k++)
gdi.addStringUT(0, supp[k]);
@ -2495,7 +2497,8 @@ bool TabCompetition::loadPage(gdioutput &gdi)
oe->checkNecessaryFeatures();
gdi.selectTab(tabId);
gdi.addString("", 3, "MeOS");
//gdi.addString("", 3, "MeOS");
gdi.addString("", textImage, "513");
gdi.dropLine();
oe->synchronize();
@ -3481,12 +3484,14 @@ TabCompetition::FlowOperation TabCompetition::saveEntries(gdioutput &gdi, bool r
}
else {
set<int> stageFilter;
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter);
string preferredIdType;
FlowOperation res = checkStageFilter(gdi, filename[i], stageFilter, preferredIdType);
if (res != FlowContinue)
return res;
oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter);
oe->importXML_EntryData(gdi, filename[i], false, removeRemoved, stageFilter, preferredIdType);
}
if (!isGuide) {
gdi.setWindowTitle(oe->getTitleName());
@ -3516,23 +3521,34 @@ int stageInfoCB(gdioutput *gdi, int type, void *data)
void mainMessageLoop(HACCEL hAccelTable, DWORD time);
TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi, const wstring & fname, set<int>& filter) {
TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
const wstring & fname,
set<int>& filter,
string &preferredIdProvider) {
xmlparser xml;
xml.read(fname);
xmlobject xo = xml.getObject("EntryList");
set<int> scanFilter;
IOF30Interface reader(oe, false);
vector<string> idProviders;
if (xo) {
if (xo.getAttrib("iofVersion")) {
IOF30Interface reader(oe, false);
reader.prescanEntryList(xo, scanFilter);
reader.getIdTypes(idProviders);
}
}
bool stageFilter = scanFilter.size() > 1;
bool idtype = idProviders.size() > 1;
if (scanFilter.size() > 1) {
//gdi.dropLine();
bool needUseInput = stageFilter || idtype;
if (needUseInput) {
gdi.enableEditControls(false, true);
gdi.fillDown();
gdi.pushX();
}
if (stageFilter) {
gdi.dropLine(0.5);
gdi.addString("", 0, "Det finns anmälningsdata för flera etapper.");
gdi.dropLine(0.5);
@ -3548,7 +3564,25 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.selectItemByData("Stage", cn);
else
gdi.selectItemByData("Stage", 0);
}
if (idtype) {
if (stageFilter) {
gdi.popX();
gdi.dropLine(2);
}
gdi.dropLine(0.5);
gdi.addString("", 0, "Det finns multiplia Id-nummer för personer");
gdi.dropLine(0.5);
gdi.fillRight();
gdi.addSelection("IdType", 150, 200, stageInfoCB, L"Välj vilken typ du vill importera:");
int i = 0;
for (string &sn : idProviders) {
gdi.addItem("IdType", gdi.widen(sn), i++);
}
}
if (needUseInput) {
gdi.dropLine();
gdi.addButton("OK_Stage", "OK", stageInfoCB);
gdi.fillDown();
@ -3569,18 +3603,31 @@ TabCompetition::FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
gdi.removeControl("OK_Stage");
gdi.removeControl("Cancel_Stage");
gdi.disableInput("Stage");
if (stageFilter)
gdi.disableInput("Stage");
if (idtype)
gdi.disableInput("IdType");
}
if (ok) {
//OK was pressed
int stage = gdi.getSelectedItem("Stage").first;
if (stage > 0) {
filter.insert(stage);
if (oe->getStageNumber() == 0) {
oe->setStageNumber(stage);
oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe);
if (scanFilter.size() > 1) {
int stage = gdi.getSelectedItem("Stage").first;
if (stage > 0) {
filter.insert(stage);
if (oe->getStageNumber() == 0) {
oe->setStageNumber(stage);
oe->getMeOSFeatures().useFeature(MeOSFeatures::SeveralStages, true, *oe);
}
}
}
if (idProviders.size() > 1) {
ListBoxInfo lbi;
if (gdi.getSelectedItem("IdType", lbi)) {
preferredIdProvider = gdi.narrow(lbi.text);
}
}
return FlowContinue;
}
else if (cancel)
@ -3764,14 +3811,22 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("EMail");
fields.push_back("Homepage");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine(0.3);
gdi.addString("", 1, "Betalningsinformation");
fields.clear();
fields.push_back("Account");
fields.push_back("PaymentDue");
oe->getDI().buildDataFields(gdi, fields, 32);
gdi.dropLine();
gdi.addString("", 1, "Tidszon");
gdi.dropLine(0.3);
gdi.addCheckbox("UTC", "Exportera tider i UTC", 0,
oe->getDCI().getInt("UTC") == 1);
oe->getDCI().getInt("UTC") == 1);
gdi.newColumn();
gdi.popY();
@ -3785,7 +3840,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("EntryFee");
fields.push_back("YouthFee");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 6);
gdi.popX();
gdi.dropLine(3);
@ -3794,7 +3849,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("OrdinaryEntry");
fields.push_back("LateEntryFactor");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 10);
gdi.fillDown();
gdi.popX();
@ -3805,7 +3860,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("YouthAge");
fields.push_back("SeniorAge");
gdi.fillRight();
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 10);
gdi.fillDown();
gdi.popX();
@ -3818,14 +3873,15 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.push_back("CurrencyCode");
gdi.fillRight();
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 10);
gdi.dropLine();
gdi.popX();
gdi.dropLine(3);
gdi.addCheckbox("PreSymbol", "Valutasymbol före", 0,
oe->getDCI().getInt("CurrencyPreSymbol") == 1);
gdi.popX();
gdi.dropLine(3);
gdi.dropLine(2.5);
bool useFrac = oe->getDCI().getInt("CurrencyFactor") == 100;
gdi.addCheckbox("UseFraction", "Tillåt decimaler", CompetitionCB,
useFrac, "Tillåt valutauttryck med decimaler");
@ -3833,7 +3889,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
fields.clear();
gdi.dropLine(-1);
fields.push_back("CurrencySeparator");
oe->getDI().buildDataFields(gdi, fields);
oe->getDI().buildDataFields(gdi, fields, 10);
gdi.setInputStatus("CurrencySeparator_odc", useFrac);
@ -3841,23 +3897,21 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
gdi.popX();
gdi.dropLine(3);
gdi.addString("", 1, "Betalningsinformation");
fields.clear();
fields.push_back("Account");
fields.push_back("PaymentDue");
oe->getDI().buildDataFields(gdi, fields);
gdi.fillDown();
gdi.addString("", 1, "Tävlingsregler");
fields.clear();
gdi.fillRight();
gdi.pushX();
fields.push_back("MaxTime");
oe->getDI().buildDataFields(gdi, fields);
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining) &&
oe->getMeOSFeatures().hasFeature(MeOSFeatures::Patrol)) {
fields.push_back("DiffTime");
}
gdi.fillDown();
oe->getDI().buildDataFields(gdi, fields, 10);
oe->getDI().fillDataFields(gdi);
gdi.dropLine(3);
gdi.dropLine(1);
int bottom = gdi.getCY();

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -128,7 +128,8 @@ class TabCompetition :
void entryForm(gdioutput &gdi, bool isGuide);
FlowOperation saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide);
FlowOperation checkStageFilter(gdioutput &gdi, const wstring &fname, set<int> &filter);
FlowOperation checkStageFilter(gdioutput &gdi, const wstring &fname, set<int> &filter, string &preferredIdProvider);
void setExportOptionsStatus(gdioutput &gdi, int format) const;
void selectStartlistOptions(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -869,7 +869,8 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
}
else {
set<int> noFilter;
oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter);
string noType;
oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter, noType);
}
if (addClasses) {
// There is specific course-class matching inside the import of each format,

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -45,6 +45,8 @@
#include "intkeymapimpl.hpp"
#include "meosexception.h"
#include "MeOSFeatures.h"
#include "autocomplete.h"
#include "RunnerDB.h"
int SportIdentCB(gdioutput *gdi, int type, void *data);
@ -183,8 +185,10 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.setInputStatus("Bib", controlBib);
}
gdi.setText("Club", r->getClub());
auto *ci = gdi.setText("Club", r->getClub());
if (ci) {
ci->setExtra(r->getClubId());
}
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
gdi.selectItemByData("RClass", r->getClassId(true));
@ -1042,6 +1046,29 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
else if (bi.id=="Check") {
}
}
else if (type == GUI_INPUTCHANGE) {
InputInfo &ii = *(InputInfo *)data;
if (oe->useRunnerDb() && ii.id == "Name") {
auto &db = oe->getRunnerDatabase();
bool show = false;
if (ii.text.length() > 1) {
auto dbClub = extractClub(gdi);
auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
if (!rw.empty()) {
auto &ac = gdi.addAutoComplete(ii.id);
ac.setAutoCompleteHandler(this);
ac.setData(TabSI::getRunnerAutoCompelete(db, rw, dbClub));
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(ii.id);
}
}
}
else if (type==GUI_INPUT) {
InputInfo ii=*(InputInfo *)data;
@ -1215,6 +1242,27 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
loadPage(gdi);
}
}
else if (type == GUI_COMBOCHANGE) {
ListBoxInfo &combo = *(ListBoxInfo *)(data);
bool show = false;
if (oe->useRunnerDb() && combo.id == "Club" && combo.text.length() > 1) {
auto clubs = oe->getRunnerDatabase().getClubSuggestions(combo.text, 20);
if (!clubs.empty()) {
auto &ac = gdi.addAutoComplete(combo.id);
ac.setAutoCompleteHandler(this);
vector<AutoCompleteRecord> items;
for (auto club : clubs)
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
ac.setData(items);
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(combo.id);
}
}
else if (type==GUI_CLEAR) {
gdioutput *gdi_settings = getExtraWindow("ecosettings", false);
if (gdi_settings)
@ -1327,7 +1375,7 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
int id = static_cast<TextInfo*>(data)->getExtraInt();
oRunner *r = oe->getRunner(id, 0);
if (r==0)
if (r == 0)
return -1;
r->synchronize();
@ -1341,19 +1389,24 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
int cardNo = gdi.getTextNo("CardNo");
if (cardNo!=r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo))
if (cardNo != r->getCardNo() && oe->checkCardUsed(gdi, *r, cardNo))
return 0;
wstring club = gdi.getText("Club");
int clubId = 0;
wstring club;
int birthYear = 0;
pClub pc = oe->getClubCreate(0, club);
r->updateFromDB(name, pc->getId(), r->getClassId(false), cardNo, birthYear);
if (gdi.hasField("Club")) {
club = gdi.getText("Club");
pClub pc = oe->getClubCreate(0, club);
if (pc)
clubId = pc->getId();
}
r->updateFromDB(name, clubId, r->getClassId(false), cardNo, birthYear);
r->setName(name, true);
r->setCardNo(cardNo, true);
r->setClub(club);
int fee = 0;
if (gdi.hasField("Fee")) {
ListBoxInfo lbi;
@ -1870,17 +1923,19 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
gdi.addCheckbox("RentCard", "Hyrd", 0, tsi.storedInfo.rentState);
gdi.dropLine(-1.2);
gdi.addInput("Name", tsi.storedInfo.storedName, 16, 0, L"Namn:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
gdi.addCombo("Club", 220, 300, RunnerCB, L"Klubb:");
oe->fillClubs(gdi, "Club");
gdi.setText("Club", tsi.storedInfo.storedClub);
}
gdi.addCombo("Club", 220, 300, 0, L"Klubb:");
oe->fillClubs(gdi, "Club");
gdi.setText("Club", tsi.storedInfo.storedClub);
gdi.addInput("Name", tsi.storedInfo.storedName, 16, RunnerCB, L"Namn:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
if (!tsi.storedInfo.storedFee.empty())
lastFee = tsi.storedInfo.storedFee;
gdi.addCombo("Fee", 60, 150, SportIdentCB, L"Avgift:");
gdi.addCombo("Fee", 60, 150, 0, L"Avgift:");
oe->fillFees(gdi, "Fee", true);
gdi.autoGrow("Fee");
@ -1892,7 +1947,6 @@ void TabRunner::showVacancyList(gdioutput &gdi, const string &method, int classI
}
gdi.dropLine(1.2);
//gdi.addCheckbox("Paid", "Kontant betalning", 0, tsi.storedInfo.hasPaid);
tsi.generatePayModeWidget(gdi);
gdi.dropLine(-0.2);
}
@ -2384,7 +2438,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.dropLine(1);
gdi.fillRight();
gdi.pushX();
gdi.addInput("Name", L"", 16, 0, L"Namn:");
gdi.addInput("Name", L"", 16, RunnerCB, L"Namn:");
if (oe->hasBib(true, false)) {
gdi.addInput("Bib", L"", 4, 0, L"Nr", L"Nummerlapp");
@ -2394,7 +2448,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
gdi.fillDown();
gdi.addCombo("Club", 220, 300, 0, L"Klubb:");
gdi.addCombo("Club", 220, 300, RunnerCB, L"Klubb:");
oe->fillClubs(gdi, "Club");
gdi.pushX();
}
@ -2946,3 +3000,43 @@ void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
gdi.addButton("Save", "Spara").setHandler(h);
gdi.refresh();
}
void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
if (bi) {
int ix = info.getCurrentInt();
bi->setExtra(ix);
if (info.getTarget() == "Name") {
auto &db = oe->getRunnerDatabase();
auto runner = db.getRunnerByIndex(ix);
if (runner && gdi.hasField("Club") && gdi.getText("Club").empty()) {
pClub club = db.getClub(runner->dbe().clubNo);
if (club)
gdi.setText("Club", club->getName());
}
if (runner && runner->dbe().cardNo > 0 && gdi.hasField("CardNo") && gdi.getText("CardNo").empty()) {
gdi.setText("CardNo", runner->dbe().cardNo);
}
}
}
gdi.clearAutoComplete("");
gdi.TabFocus(1);
}
pClub TabRunner::extractClub(gdioutput &gdi) {
oClub *dbClub = nullptr;
if (gdi.hasField("Club")) {
auto &db = oe->getRunnerDatabase();
int clubId = gdi.getExtraInt("Club");
if (clubId >= 0) {
dbClub = db.getClub(clubId);
if (dbClub && !stringMatch(dbClub->getName(), gdi.getText("Club")))
dbClub = nullptr;
}
if (dbClub == nullptr) {
dbClub = db.getClub(gdi.getText("Club"));
}
}
return dbClub;
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,11 +22,12 @@
************************************************************************/
#include "tabbase.h"
#include "Printer.h"
#include "autocompletehandler.h"
class Table;
class TabRunner :
public TabBase
public TabBase, AutoCompleteHandler
{
private:
void addToolbar(gdioutput &gdi);
@ -108,8 +109,9 @@ private:
protected:
void clearCompetitionData();
pClub extractClub(gdioutput &gdi);
public:
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
const char * getTypeStr() const {return "TRunnerTab";}
TabType getType() const {return TRunnerTab;}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -46,9 +46,12 @@
#include "MeOSFeatures.h"
#include "RunnerDB.h"
#include "recorder.h"
#include "autocomplete.h"
TabSI::TabSI(oEvent *poe):TabBase(poe) {
editCardData.tabSI = this;
directEntryGUI.tabSI = this;
interactiveReadout=poe->getPropertyInt("Interactive", 1)!=0;
useDatabase=poe->useRunnerDb() && poe->getPropertyInt("Database", 1)!=0;
printSplits = false;
@ -97,12 +100,12 @@ void TabSI::logCard(const SICard &card)
getDesktopFile(file, readlog.c_str(), sf);
logger->openOutput(file);
vector<string> head = SICard::logHeader();
logger->OutputRow(head);
logger->outputRow(head);
logcounter = 0;
}
vector<string> log = card.codeLogData(++logcounter);
logger->OutputRow(log);
logger->outputRow(log);
}
extern SportIdent *gSI;
@ -111,8 +114,7 @@ extern pEvent gEvent;
void LoadRunnerPage(gdioutput &gdi);
int SportIdentCB(gdioutput *gdi, int type, void *data)
{
int SportIdentCB(gdioutput *gdi, int type, void *data) {
TabSI &tsi = dynamic_cast<TabSI &>(*gdi->getTabs().get(TSITab));
return tsi.siCB(*gdi, type, data);
@ -139,11 +141,11 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
csvparser saver;
saver.openOutput(file.c_str());
vector<string> head = SICard::logHeader();
saver.OutputRow(head);
saver.outputRow(head);
int count = 0;
for (list< pair<int, SICard> >::const_iterator it = savedCards.begin(); it != savedCards.end(); ++it) {
vector<string> log = it->second.codeLogData(++count);
saver.OutputRow(log);
saver.outputRow(log);
}
}
}
@ -880,9 +882,14 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
r->setStartTimeS(gdi.getText("StartTime"));
wstring bib;
if (r->autoAssignBib())
switch (r->autoAssignBib()) {
case oRunner::BibAssignResult::Assigned:
bib = L", " + lang.tl(L"Nummerlapp: ") + r->getBib();
break;
case oRunner::BibAssignResult::Failed:
bib = L", " + lang.tl(L"Ingen nummerlapp");
break;
}
r->synchronize();
gdi.restore("EntryLine");
@ -2434,12 +2441,14 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
wstring name;
wstring club;
int age = 0;
if (useDatabase) {
pRunner db_r=oe->dbLookUpByCard(sic.CardNumber);
if (db_r) {
name=db_r->getNameRaw();
club=db_r->getClub();
age = db_r->getBirthAge();
}
}
@ -2451,12 +2460,18 @@ void TabSI::entryCard(gdioutput &gdi, const SICard &sic)
if (gdi.hasField("Club"))
gdi.setText("Club", club);
if (name.empty())
gdi.setInputFocus("Name");
else if (club.empty() && gdi.hasField("Club"))
if (club.empty() && gdi.hasField("Club"))
gdi.setInputFocus("Club");
else if (name.empty())
gdi.setInputFocus("Name");
else
gdi.setInputFocus("Class");
int clsId = gdi.getSelectedItem("Class").first;
pClass cls = oe->getClass(clsId);
if (cls && age > 0) {
directEntryGUI.updateFees(gdi, cls, age);
}
}
void TabSI::assignCard(gdioutput &gdi, const SICard &sic)
@ -2536,10 +2551,10 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
storedInfo.checkAge();
gdi.addInput("CardNo", storedInfo.storedCardNo, 8, SportIdentCB, L"Bricka:");
gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:");
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
gdi.addCombo("Club", 180, 200, 0, L"Klubb:", L"Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben");
gdi.addCombo("Club", 180, 200, 0, L"Klubb:",
L"Skriv första bokstaven i klubbens namn och tryck pil-ner för att leta efter klubben")
.setHandler(&directEntryGUI);
oe->fillClubs(gdi, "Club");
if (storedInfo.storedClub.empty())
gdi.selectItemByData("Club", lastClubId);
@ -2547,7 +2562,9 @@ void TabSI::generateEntryLine(gdioutput &gdi, pRunner r)
gdi.setText("Club", storedInfo.storedClub);
}
gdi.addSelection("Class", 150, 200, 0, L"Klass:");
gdi.addInput("Name", storedInfo.storedName, 16, 0, L"Namn:").setHandler(&directEntryGUI);
gdi.addSelection("Class", 150, 200, 0, L"Klass:").setHandler(&directEntryGUI);
oe->fillClasses(gdi, "Class", oEvent::extraNumMaps, oEvent::filterOnlyDirect);
if (storedInfo.storedClassId > 0 && gdi.selectItemByData("Class", storedInfo.storedClassId)) {
}
@ -3024,7 +3041,6 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
}
}
void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
SICard &c = getCard(cardId);
if (c.readOutTime[0] == 0)
@ -3600,3 +3616,188 @@ void TabSI::printSIInfo(gdioutput &gdi, const wstring &port) const {
for (size_t j = 0; j < info.size(); j++)
gdi.addStringUT(0, info[j]);
}
oClub *TabSI::extractClub(gdioutput &gdi) const {
auto &db = oe->getRunnerDatabase();
oClub *dbClub = nullptr;
if (gdi.hasField("Club")) {
int clubId = gdi.getExtraInt("Club");
if (clubId >= 0) {
dbClub = db.getClub(clubId);
if (dbClub && !stringMatch(dbClub->getName(), gdi.getText("Club")))
dbClub = nullptr;
}
if (dbClub == nullptr) {
dbClub = db.getClub(gdi.getText("Club"));
}
}
return dbClub;
}
RunnerWDBEntry *TabSI::extractRunner(gdioutput &gdi) const {
auto &db = oe->getRunnerDatabase();
int rId = gdi.getExtraInt("Name");
wstring name = gdi.getText("Name");
RunnerWDBEntry *dbR = nullptr;
if (rId >= 0) {
dbR = db.getRunnerByIndex(rId);
if (dbR) {
wstring fname = dbR->getFamilyName();
wstring gname = dbR->getGivenName();
if (wcsstr(name.c_str(), fname.c_str()) == nullptr || wcsstr(name.c_str(), gname.c_str()) == nullptr)
dbR = nullptr;
}
}
if (dbR == nullptr) {
oClub * dbClub = extractClub(gdi);
dbR = db.getRunnerByName(name, dbClub ? dbClub->getId() : 0, 0);
}
return dbR;
}
void TabSI::DirectEntryGUI::updateFees(gdioutput &gdi, const pClass cls, int age) {
int fee = cls->getEntryFee(getLocalDate(), age);
auto fees = cls->getAllFees();
gdi.addItem("Fee", fees);
if (fee > 0) {
gdi.selectItemByData("Fee", fee);
gdi.setText("Fee", tabSI->oe->formatCurrency(fee));
}
else if (!fees.empty())
gdi.selectFirstItem("Fee");
tabSI->updateEntryInfo(gdi);
}
void TabSI::DirectEntryGUI::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
if (type == GUI_FOCUS) {
InputInfo &ii = dynamic_cast<InputInfo &>(info);
/*if (ii.getExtraInt()) {
ii.setExtra(0);
gdi.setInputFocus(ii.id, true);
}*/
}
else if (type == GUI_LISTBOX) {
ListBoxInfo &lbi = dynamic_cast<ListBoxInfo &>(info);
if (lbi.id == "Class") {
int clsId = lbi.data;
pClass cls = tabSI->oe->getClass(clsId);
if (cls) {
int age = 0;
auto r = tabSI->extractRunner(gdi);
if (r) {
int year = r->getBirthYear();
if (year > 0)
age = getThisYear() - year;
}
updateFees(gdi, cls, age);
}
}
}
else if (type == GUI_COMBOCHANGE) {
ListBoxInfo &combo = dynamic_cast<ListBoxInfo &>(info);
bool show = false;
if (tabSI->useDatabase && combo.id == "Club" && combo.text.length() > 1) {
auto clubs = tabSI->oe->getRunnerDatabase().getClubSuggestions(combo.text, 20);
if (!clubs.empty()) {
auto &ac = gdi.addAutoComplete(combo.id);
ac.setAutoCompleteHandler(this->tabSI);
vector<AutoCompleteRecord> items;
for (auto club : clubs)
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
ac.setData(items);
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(combo.id);
}
}
else if (type == GUI_INPUTCHANGE) {
InputInfo &ii = dynamic_cast<InputInfo &>(info);
bool show = false;
if (tabSI->useDatabase && ii.id == "Name") {
auto &db = tabSI->oe->getRunnerDatabase();
if (ii.text.length() > 1) {
auto dbClub = tabSI->extractClub(gdi);
auto rw = db.getRunnerSuggestions(ii.text, dbClub ? dbClub->getId() : 0, 10);
if (!rw.empty()) {
auto &ac = gdi.addAutoComplete(ii.id);
ac.setAutoCompleteHandler(this->tabSI);
ac.setData(getRunnerAutoCompelete(db, rw, dbClub));
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(ii.id);
}
}
}
}
vector<AutoCompleteRecord> TabSI::getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub) {
vector<AutoCompleteRecord> items;
set<wstring> used;
wstring ns;
map<wstring, int> strCount;
for (int i = 0; i < 2; i++) {
bool needRerun = false;
for (auto r : rw) {
if (dbClub) {
ns = r.first->getNameCstr();
}
else {
ns = r.first->getNameCstr();
int clubId = r.first->dbe().clubNo;
auto club = db.getClub(clubId);
if (club) {
ns += L", " + club->getDisplayName();
}
}
if (i == 0)
++strCount[ns];
if (strCount[ns] > 1) {
needRerun = true;
int y = r.first->getBirthYear();
if (y > 0)
ns += L" (" + itow(getThisYear() - y) + L")";
}
items.emplace_back(ns, r.first->getNameCstr(), r.second);
}
if (!needRerun)
break;
else if (i == 0) {
items.clear();
}
}
return items;
}
void TabSI::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
if (bi) {
int ix = info.getCurrentInt();
bi->setExtra(ix);
if (bi->id == "Name") {
auto r = oe->getRunnerDatabase().getRunnerByIndex(ix);
int year = r ? r->getBirthYear() : 0;
if (year > 0) {
int clsId = gdi.getSelectedItem("Class").first;
pClass cls = oe->getClass(clsId);
if (cls) {
directEntryGUI.updateFees(gdi, cls, getThisYear() - year);
}
}
}
}
gdi.clearAutoComplete("");
gdi.TabFocus(1);
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -24,11 +24,13 @@
#include "SportIdent.h"
#include "Printer.h"
#include "inthashmap.h"
#include "autocompletehandler.h"
struct PunchInfo;
class csvparser;
struct AutoCompleteRecord;
class TabSI : public TabBase {
class TabSI : public TabBase, AutoCompleteHandler {
public:
enum SIMode {
ModeReadOut,
@ -166,13 +168,34 @@ private:
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
friend class TabSI;
};
class DirectEntryGUI : public GuiHandler {
TabSI *tabSI;
DirectEntryGUI(const DirectEntryGUI&);
DirectEntryGUI &operator=(const DirectEntryGUI&);
public:
void updateFees(gdioutput &gdi, const pClass cls, int age);
DirectEntryGUI() : tabSI(0) {}
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
friend class TabSI;
};
EditCardData editCardData;
DirectEntryGUI directEntryGUI;
oClub *extractClub(gdioutput &gdi) const;
RunnerWDBEntry *extractRunner(gdioutput &gdi) const;
protected:
void clearCompetitionData();
public:
static vector<AutoCompleteRecord> getRunnerAutoCompelete(RunnerDB &db, const vector< pair<RunnerWDBEntry *, int>> &rw, pClub dbClub);
void handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) override;
// Returns true if a repeated check should be done (there is more to print)
bool checkpPrintQueue(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1568,7 +1568,7 @@ void Table::print(gdioutput &gdi, HDC hDC, int dx, int dy)
}
}
bool Table::UpDown(gdioutput &gdi, int direction)
bool Table::upDown(gdioutput &gdi, int direction)
{
return false;
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -56,9 +56,16 @@ class TableCell
bool canEdit;
CellType type;
friend class TableRow;
friend class Table;
friend int tblSelectionCB(gdioutput *gdi, int type, void *data);
public:
void update(CellType t, const wstring &str) {
contents = str;
type = t;
}
};
class TableRow
@ -83,6 +90,9 @@ public:
bool operator<(const TableRow &r){return *SortString<*r.SortString;}
static bool cmpint(const TableRow &r1, const TableRow &r2) {return r1.sInt<r2.sInt;}
CellType getCellType(int index) const { return cells[index].type; }
void updateCell(int index, CellType type, const wstring &str) { return cells[index].update(type, str); }
TableRow(int elem, oBase *object): sInt(0)
{
cells.resize(elem);
@ -346,7 +356,7 @@ public:
//Reload a row from data
void reloadRow(int rowId);
bool UpDown(gdioutput &gdi, int direction);
bool upDown(gdioutput &gdi, int direction);
bool tabFocus(gdioutput &gdi, int direction);
bool enter(gdioutput &gdi);
void escape(gdioutput &gdi);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -10,7 +10,7 @@
#endif // _MSC_VER > 1000
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

193
code/autocomplete.cpp Normal file
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
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -414,22 +414,28 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
return true;
}
bool csvparser::openOutput(const wstring &filename)
bool csvparser::openOutput(const wstring &filename, bool writeUTF)
{
checkWriteAccess(filename);
fout.open(filename);
if (fout.bad())
return false;
if (writeUTF) {
fout.put(-17);
fout.put(-69);
fout.put(-65);
}
return true;
}
bool csvparser::OutputRow(const string &row)
bool csvparser::outputRow(const string &row)
{
fout << row << endl;
return true;
}
bool csvparser::OutputRow(vector<string> &out)
bool csvparser::outputRow(const vector<string> &out)
{
int size=out.size();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -114,10 +114,11 @@ public:
const map<wstring, int> &classNameToNumber,
vector<TeamLineup> &teams);
bool openOutput(const wstring &file);
bool openOutput(const wstring &file, bool writeUTF = false);
bool closeOutput();
bool OutputRow(vector<string> &out);
bool OutputRow(const string &row);
bool outputRow(const vector<string> &out);
bool outputRow(const string &row);
int nimport;
bool importOCAD_CSV(oEvent &oe, const wstring &file, bool addClasses);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -7,7 +7,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -639,7 +639,7 @@ Minsta intabbning = Least indentation
Minsta intervall i klass = Smallest interval in class
Minsta startintervall = Smallest start interval
Minsta sträcktid = Shortest leg time
Minutstartlista = Minute Start List
Minutstartlista = Minute start list
Motion = Exercise
Multipel = Multiple
MySQL Server / IP-adress = MySQL Server / IP-address
@ -950,10 +950,10 @@ Startblock = Start block
Startblock: %d = Start block: %d
Startintervall = Start Interval
Startintervall (min) = Start interval (min)
Startlista = Start List
Startlista %%s - sträcka %d = Start List %%s - Leg %d
Startlista - %s = Start List - %s
Startlista - X = Start List - X
Startlista = Start list
Startlista %%s - sträcka %d = Start list %%s - Leg %d
Startlista - %s = Start list - %s
Startlista - X = Start list - X
Startlista ett visst lopp = Start list for the race
Startlista lopp X - Y = Start List Race X - Y
Startlista, individuell = Start list, individual
@ -1465,7 +1465,7 @@ xml-data = xml data
åtta = eight
åttonde = eighth
Kopia (X) = Copy (X)
Tillåt samma bana inom basintervall = Allow same course within base interval
Tillåt samma bana inom basintervall = Allow same course within base interval (interlace classes)
Välj X = Select X
Ett startblock spänner över flera starter: X/Y = A start block spans more than one start: X/Y
Bricka X = Card X
@ -2298,3 +2298,18 @@ Inconsistent qualification rule, X = Inconsistent qualification rule, X
help:LockStartList = MeOS will not update assignement to a locked class even if qualification results are altered.
Kval-Final-Schema = Load qualification scheme
Lås startlista = Lock start list
FilterNoCancel = Not cancelled
CourseStartTime = Course, start time
Startlista, banvis = Start list, by course
Stämplingsintervall, rogaining-patrull = Punch interval within Rogaining patrol
Patrullresultat (STOR) = Patrol results (LARGE)
Patrol Team Rogaining = Patrol Team Rogaining
Rogaining results for a patrol = Rogaining results for a patrol of two or more competitors.
Exportera ett kalkylblad med lottningsinställningar som du kan redigera och sedan läsa in igen = Export a spreadsheet with draw settings that you can edit and then import again
Kalkylblad/csv = Spreadsheet/csv
Importerar lottningsinställningar = Importing draw settings
help:exportdraw = You can export a spreadsheet in csv format, containing classes, number of comptitors, and draw settings for each class. It is then possible to edit the start data and then import it back into MeOS to draw the classes accordingly.
prefsDrawInterlace = Interlace class/course when drawing start lists
prefsServicePort = Default service port
Ingen nummerlapp = No bib
Rogaining results for a team, where each team member collects points individually = Rogaining results for a team, where each team member collects points individually

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

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

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -56,7 +56,10 @@
#include "Printer.h"
#include "recorder.h"
#include "animationdata.h"
#include "image.h"
#include "autocomplete.h"
extern Image image;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@ -1099,12 +1102,12 @@ ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id,
style |= BS_MULTILINE;
height *= 2;
}
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY,
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |style|BS_NOTIFY,
x-OffsetX, y, w, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
}
else {
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD|style|BS_NOTIFY,
bi.hWnd=CreateWindow(L"BUTTON", ttext.c_str(), WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |style|BS_NOTIFY,
x-OffsetX, y-OffsetY-1, w, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
}
@ -1210,7 +1213,7 @@ ButtonInfo &gdioutput::addCheckbox(int x, int y, const string &id, const wstring
ReleaseDC(hWndTarget, hDC);
bi.hWnd=CreateWindowEx(0,L"BUTTON", L"", WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_AUTOCHECKBOX|BS_NOTIFY,
WS_CHILD | WS_CLIPSIBLINGS |BS_AUTOCHECKBOX|BS_NOTIFY,
x-ox, y-oy + (size.cy-h)/2, h, h, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -1311,7 +1314,7 @@ InputInfo &gdioutput::addInput(int x, int y, const string &id, const wstring &te
int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(),
WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_BORDER,
WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | ES_AUTOHSCROLL | WS_BORDER,
x-ox, y-oy, length*size.cx+scaleLength(8), size.cy+scaleLength(6),
hWndTarget, NULL, (HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -1365,7 +1368,7 @@ InputInfo &gdioutput::addInputBox(const string &id, int x, int y, int width, int
int oy=OffsetY;
ii.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", text.c_str(), WS_HSCROLL|WS_VSCROLL|
WS_TABSTOP|WS_VISIBLE|WS_CHILD|ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |ES_AUTOHSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER,
x-ox, y-oy, width, height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -1450,7 +1453,7 @@ ListBoxInfo &gdioutput::addListBox(int x, int y, const string &id, int width, in
int ox=OffsetX;
int oy=OffsetY;
DWORD style=WS_TABSTOP|WS_VISIBLE|WS_CHILD|WS_BORDER|LBS_USETABSTOPS|LBS_NOTIFY|WS_VSCROLL;
DWORD style=WS_TABSTOP|WS_VISIBLE|WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|LBS_USETABSTOPS|LBS_NOTIFY|WS_VSCROLL;
if (multiple)
style|=LBS_MULTIPLESEL;
@ -1544,7 +1547,7 @@ ListBoxInfo &gdioutput::addSelection(int x, int y, const string &id, int width,
int ox = OffsetX;
int oy = OffsetY;
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL ,
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL ,
x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -1586,7 +1589,7 @@ ListBoxInfo &gdioutput::addCombo(int x, int y, const string &id, int width, int
int ox=OffsetX;
int oy=OffsetY;
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD |WS_BORDER|CBS_DROPDOWN |CBS_AUTOHSCROLL,
lbi.hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"", WS_TABSTOP|WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |WS_BORDER|CBS_DROPDOWN |CBS_AUTOHSCROLL,
x-ox, y-oy, int(scale*width), int(scale*height), hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
@ -2035,6 +2038,7 @@ void gdioutput::processEditMessage(InputInfo &bi, DWORD wParam)
break;
case EN_KILLFOCUS: {
autoCompleteInfo.reset();
wstring old = bi.focusText;
getWindowText(bi.hWnd, bi.text);
bi.synchData();
@ -2071,6 +2075,8 @@ void gdioutput::processComboMessage(ListBoxInfo &bi, DWORD wParam)
lockUpDown = true;
break;
case CBN_KILLFOCUS: {
if (autoCompleteInfo && !autoCompleteInfo->locked())
autoCompleteInfo.reset();
lockUpDown = false;
TCHAR bf[1024];
@ -2187,6 +2193,7 @@ void gdioutput::processListMessage(ListBoxInfo &bi, DWORD wParam)
lockUpDown = true;
break;
case LBN_KILLFOCUS:
autoCompleteInfo.reset();
lockUpDown = false;
break;
case LBN_SELCHANGE:
@ -2677,7 +2684,7 @@ InputInfo *gdioutput::getInputFocus()
return 0;
}
void gdioutput::Enter()
void gdioutput::enter()
{
if (hasCommandLock())
return;
@ -2702,8 +2709,11 @@ void gdioutput::Enter()
alert(msg);
}
void gdioutput::doEnter()
{
void gdioutput::doEnter() {
if (autoCompleteInfo) {
autoCompleteInfo->enter();
return;
}
list<TableInfo>::iterator tit;
if (useTables)
@ -2737,7 +2747,7 @@ void gdioutput::doEnter()
}
}
bool gdioutput::UpDown(int direction)
bool gdioutput::upDown(int direction)
{
wstring msg;
try {
@ -2763,17 +2773,21 @@ bool gdioutput::UpDown(int direction)
bool gdioutput::doUpDown(int direction)
{
if (autoCompleteInfo) {
autoCompleteInfo->upDown(direction);
return true;
}
list<TableInfo>::iterator tit;
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
if (tit->table->UpDown(*this, direction))
if (tit->table->upDown(*this, direction))
return true;
return false;
}
void gdioutput::Escape()
void gdioutput::escape()
{
if (hasCommandLock())
return;
@ -2804,6 +2818,11 @@ void gdioutput::doEscape()
PostMessage(hWndTarget, WM_CLOSE, 0,0);
}
if (autoCompleteInfo) {
autoCompleteInfo.reset();
return;
}
list<TableInfo>::iterator tit;
if (useTables)
@ -3969,15 +3988,33 @@ void gdioutput::RenderString(TextInfo &ti, HDC hDC)
hDC=hThis=GetDC(hWndTarget);
}
RECT rc;
rc.left=ti.xp-OffsetX;
rc.top=ti.yp-OffsetY;
if ((ti.format & absolutePosition) == 0) {
rc.left = ti.xp - OffsetX;
rc.top = ti.yp - OffsetY;
}
else {
rc.left = ti.xp;
rc.top = ti.yp;
}
rc.right = rc.left;
rc.bottom = rc.top;
formatString(ti, hDC);
int format=ti.format&0xFF;
if (format == textImage) {
// Image
int id = _wtoi(ti.text.c_str());
image.loadImage(id, Image::ImageMethod::Default);
int w = image.getWidth(id);
int h = image.getHeight(id);
image.drawImage(id, Image::ImageMethod::Default, hDC, rc.left, rc.top, w, h);
if (format != 10 && (breakLines&ti.format) == 0){
ti.textRect.left = rc.left;
ti.textRect.right = rc.left + w + 5;
ti.textRect.top = rc.top;
ti.textRect.bottom = rc.bottom + h + 5;
}
else if (format != 10 && (breakLines&ti.format) == 0){
if (ti.xlimit==0){
if (ti.format&textRight) {
DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_CALCRECT|DT_NOPREFIX);
@ -4110,8 +4147,14 @@ void gdioutput::RenderString(TextInfo &ti, const wstring &text, HDC hDC)
return;
RECT rc;
rc.left=ti.xp-OffsetX;
rc.top=ti.yp-OffsetY;
if ((ti.format & absolutePosition) == 0) {
rc.left = ti.xp - OffsetX;
rc.top = ti.yp - OffsetY;
}
else {
rc.left = ti.xp;
rc.top = ti.yp;
}
rc.right = rc.left;
rc.bottom = rc.top;
@ -4212,18 +4255,31 @@ void gdioutput::formatString(const TextInfo &ti, HDC hDC) const
void gdioutput::calcStringSize(TextInfo &ti, HDC hDC_in) const
{
HDC hDC=hDC_in;
if (!hDC) {
// assert(hWndTarget!=0);
hDC=GetDC(hWndTarget);
}
RECT rc;
rc.left=ti.xp-OffsetX;
rc.top=ti.yp-OffsetY;
rc.right = rc.left;
rc.bottom = rc.top;
if (ti.format == textImage) {
// Image
int id = _wtoi(ti.text.c_str());
int w = image.getWidth(id);
int h = image.getHeight(id);
ti.textRect.left = rc.left;
ti.textRect.right = rc.left + w + 5;
ti.textRect.top = rc.top;
ti.textRect.bottom = rc.bottom + h + 5;
return;
}
HDC hDC = hDC_in;
if (!hDC) {
// assert(hWndTarget!=0);
hDC = GetDC(hWndTarget);
}
resetLast();
formatString(ti, hDC);
int format=ti.format&0xFF;
@ -6847,8 +6903,42 @@ DWORD gdioutput::selectColor(wstring &def, DWORD input) {
return -1;
}
void gdioutput::setAnimationMode(shared_ptr<AnimationData> &data) {
if (animationData && animationData->takeOver(data))
return;
animationData = data;
}
AutoCompleteInfo &gdioutput::addAutoComplete(const string &key) {
BaseInfo &bi = getBaseInfo(key.c_str());
RECT rc, rcMain;
GetWindowRect(bi.getControlWindow(), &rc);
GetWindowRect(hWndTarget, &rcMain);
POINT pt;
int height = scaleLength(200);
pt.x = rc.right;
pt.y = min(rc.top, rcMain.bottom-height);
ScreenToClient(hWndTarget, &pt);
// TODO Place window
if (autoCompleteInfo && autoCompleteInfo->matchKey(key)) {
return *autoCompleteInfo;
}
autoCompleteInfo.reset();
HWND hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"AUTOCOMPLETE", L"", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS| WS_BORDER ,
pt.x, pt.y, scaleLength(350), height, hWndTarget, NULL,
(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE), NULL);
autoCompleteInfo.reset(new AutoCompleteInfo(hWnd, key, *this));
//SendMessage(hWnd, WM_SETFONT, (WPARAM)getGUIFont(), 0);
return *autoCompleteInfo;
}
void gdioutput::clearAutoComplete(const string &key) {
autoCompleteInfo.reset();
}

View File

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

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -150,6 +150,8 @@ public:
}
TextInfo &setColor(GDICOLOR c) {color = c; return *this;}
GDICOLOR getColor() const { return GDICOLOR(color); }
TextInfo &changeFont(const wstring &fnt) {font = fnt; return *this;} //Note: size not updated
bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo; }

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -221,7 +221,7 @@ void GeneralResult::sortTeamMembers(vector<oRunner *> &runners) const {
template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const {
PrincipalSort ps = ClassWise;
if (so == CourseResult)
if (so == CourseResult || so == CourseStartTime)
ps = CourseWise;
else if (so == SortByName || so == SortByFinishTimeReverse ||
@ -952,6 +952,7 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
parser.declareSymbol("CardControls", "Runner's card, matched control ids (-1 for unmatched punches)", true);
parser.declareSymbol("Course", "Runner's course", true);
parser.declareSymbol("CourseId", "Runner's course id", false);
parser.declareSymbol("CourseLength", "Length of course", false);
parser.declareSymbol("SplitTimes", "Runner's split times", true);
@ -979,6 +980,10 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
parser.declareSymbol("RunnerOutputTimes", "Runner's method output times", true, true);
parser.declareSymbol("RunnerOutputNumbers", "Runner's method output numbers", true, true);
parser.declareSymbol("PatrolRogainingScore", "Patrol score, rogaining", false);
parser.declareSymbol("PatrolRogainingReduction", "Patrol score reduction", false);
parser.declareSymbol("PatrolRogainingOvertime", "Patrol overtime", false);
}
parser.declareSymbol("MaxTime", "Maximum allowed running time", false);
@ -1111,6 +1116,7 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.removeSymbol("CardTimes");
parser.removeSymbol("Course");
parser.removeSymbol("CourseLength");
parser.removeSymbol("CourseId");
parser.removeSymbol("LegPlace");
parser.removeSymbol("LegTimeAfter");
parser.removeSymbol("LegTimeDeviation");
@ -1129,6 +1135,10 @@ void DynamicResult::prepareCalculations(oTeam &team) const {
parser.addSymbol("RunnerFinish", finish);
parser.addSymbol("RunnerPoints", points);
parser.addSymbol("PatrolRogainingScore", team.getRogainingPatrolPoints(false));
parser.addSymbol("PatrolRogainingReduction", team.getRogainingPatrolReduction());
parser.addSymbol("PatrolRogainingOvertime", team.getRogainingPatrolOvertime());
parser.addSymbol("RunnerCardPunches", team.getResultCache(oTeam::RCCCardPunches));
parser.addSymbol("RunnerCardTimes", team.getResultCache(oTeam::RCCCardTimes));
parser.addSymbol("RunnerCardControls", team.getResultCache(oTeam::RCCCardControls));
@ -1229,6 +1239,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
}
parser.addSymbol("CourseLength", crs->getLength());
parser.addSymbol("CourseId", crs->getId());
parser.addSymbol("Course", eCrs);
parser.addSymbol("SplitTimes", eSplitTime);
parser.addSymbol("SplitTimesAccumulated", eAccTime);
@ -1242,6 +1253,7 @@ void DynamicResult::prepareCalculations(oRunner &runner) const {
else {
vector<int> e;
parser.addSymbol("CourseLength", -1);
parser.addSymbol("CourseId", 0);
parser.addSymbol("Course", e);
parser.addSymbol("SplitTimes", e);
parser.addSymbol("SplitTimesAccumulated", e);

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -264,7 +264,7 @@ Please refer to the MOP documentation for a complete description of all attribut
</pre>
<b>Remarks:</b>
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course/i> is included.
When and only when the type is <b>CourseIndividual</b>, the attribute <i>course</i> is included.
<pre>
*person cls="1" stat="1" st="324000" rt="72550" place="1" course=28>
*name id="4">Jordan Griesmer*/name>

254
code/image.cpp Normal file
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
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -35,7 +35,8 @@ void base64_encode(const vector<BYTE> &input, string &output);
extern gdioutput *gdi_main;
// Encode a vector vector int {{1}, {1,2,3}, {}, {4,5}} as "1;1,2,3;;4,5"
static void packIntInt(vector< vector<int> > v, wstring &def) {
static void packIntInt(const vector< vector<int> > &v, wstring &def) {
def = L"";
for (size_t j = 0; j < v.size(); j++) {
if (j>0)
def += L";";
@ -47,6 +48,16 @@ static void packIntInt(vector< vector<int> > v, wstring &def) {
}
}
// Encode a vector vector int {1,2,3} as "1,2,3"
static void packInt(const vector<int> &v, wstring &def) {
def = L"";
for (size_t j = 0; j < v.size(); j++) {
if (j>0)
def += L",";
def += itow(v[j]);
}
}
InfoBase::InfoBase(int idIn) : id(idIn), committed(false){
}
@ -88,6 +99,7 @@ InfoBaseCompetitor::InfoBaseCompetitor(int id) : InfoBase(id) {
InfoCompetitor::InfoCompetitor(int id) : InfoBaseCompetitor(id) {
totalStatus = 0;
inputTime = 0;
course = 0;
}
InfoTeam::InfoTeam(int id) : InfoBaseCompetitor(id) {
@ -162,7 +174,7 @@ bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set<int> &incl
map<int, InfoClass>::iterator res = classes.find(wid);
if (res == classes.end())
res = classes.insert(make_pair(wid, InfoClass(wid))).first;
if (res->second.synchronize(*cls[k], ctrls))
if (res->second.synchronize(withCourse, *cls[k], ctrls))
needCommit(res->second);
}
@ -276,13 +288,30 @@ void InfoRadioControl::serialize(xmlbuffer &xml, bool diffOnly) const {
xml.write("ctrl", prop, name);
}
bool InfoClass::synchronize(oClass &c, const set<int> &ctrls) {
bool InfoClass::synchronize(bool includeCourses, oClass &c, const set<int> &ctrls) {
const wstring &n = c.getName();
int no = c.getSortIndex();
bool mod = false;
vector< vector<int> > rc;
size_t s = c.getNumStages();
if (includeCourses) {
set<int> crsSet;
for (size_t i = 0; i <= s; i++) {
vector<pCourse> crs;
c.getCourses(i, crs);
for (pCourse pc : crs)
crsSet.insert(pc->getId());
}
vector<int> newCrs(crsSet.begin(), crsSet.end());
if (newCrs != courses) {
courses = newCrs;
mod = true;
}
}
if (s > 0) {
linearLegNumberToActual.clear();
@ -345,6 +374,10 @@ void InfoClass::serialize(xmlbuffer &xml, bool diffOnly) const {
wstring def;
packIntInt(radioControls, def);
prop.push_back(make_pair("radio", def));
if (courses.size() > 0) {
packInt(courses, def);
prop.push_back(make_pair("crs", def));
}
xml.write("cls", prop, name);
}
@ -373,13 +406,16 @@ void InfoCompetition::serialize(xmlbuffer &xml, bool diffOnly) const {
xml.write("competition", prop, name);
}
void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
void InfoBaseCompetitor::serialize(xmlbuffer &xml, bool diffOnly, int course) const {
vector< pair<string, wstring> > prop;
prop.push_back(make_pair("org", itow(organizationId)));
prop.push_back(make_pair("cls", itow(classId)));
prop.push_back(make_pair("stat", itow(status)));
prop.push_back(make_pair("st", itow(startTime)));
prop.push_back(make_pair("rt", itow(runningTime)));
if (course != 0)
prop.push_back(make_pair("crs", itow(course)));
xml.write("base", prop, name);
}
@ -426,20 +462,32 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
return ch;
}
bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) {
bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &r) {
bool ch = synchronizeBase(r);
changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes
int s = StatusOK;
int legInput = 0;
int oldCourse = course;
if (useCourse) {
auto crs = r.getCourse(false);
course = crs ? crs->getId() : 0;
}
else {
course = 0;
}
if (oldCourse != course)
ch = true;
pTeam t = r.getTeam();
if (useTotalResults) {
legInput = r.getTotalTimeInput() * 10;
s = r.getTotalStatusInput();
}
else if (t && r.getLegNumber() > 0) {
legInput = t->getLegRunningTime(r.getLegNumber() - 1, false);
legInput = t->getLegRunningTime(r.getLegNumber() - 1, false) * 10;
s = t->getLegStatus(r.getLegNumber() - 1, false);
}
@ -460,7 +508,9 @@ bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) {
bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
bool useTotalResults = cmp.includeTotalResults();
bool ch = synchronize(useTotalResults, r);
bool inludeCourse = cmp.includeCourse();
bool ch = synchronize(useTotalResults, inludeCourse, r);
vector<RadioTime> newRT;
if (r.getClassId(false) > 0) {
@ -493,7 +543,8 @@ void InfoCompetitor::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > sprop;
sprop.push_back(make_pair("id", itow(getId())));
xmlbuffer &subTag = xml.startTag("cmp", sprop);
InfoBaseCompetitor::serialize(subTag, diffOnly);
InfoBaseCompetitor::serialize(subTag, diffOnly, course);
if (radioTimes.size() > 0 && (!diffOnly || changeRadio)) {
string radio;
radio.reserve(radioTimes.size() * 12);
@ -553,7 +604,7 @@ void InfoTeam::serialize(xmlbuffer &xml, bool diffOnly) const {
vector< pair<string, wstring> > prop;
prop.push_back(make_pair("id", itow(getId())));
xmlbuffer &sub = xml.startTag("tm", prop);
InfoBaseCompetitor::serialize(sub, diffOnly);
InfoBaseCompetitor::serialize(sub, diffOnly, 0);
wstring def;
packIntInt(competitors, def);
prop.clear();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -114,8 +114,9 @@ class InfoClass : public InfoBase {
int sortOrder;
vector< vector<int> > radioControls;
vector<int> linearLegNumberToActual;
vector<int> courses;
public:
bool synchronize(oClass &c, const set<int> &ctrls);
bool synchronize(bool includeCourses, oClass &c, const set<int> &ctrls);
void serialize(xmlbuffer &xml, bool diffOnly) const;
InfoClass(int id);
@ -155,7 +156,7 @@ class InfoBaseCompetitor : public InfoBase {
int status;
int startTime;
int runningTime;
void serialize(xmlbuffer &xml, bool diffOnly) const;
void serialize(xmlbuffer &xml, bool diffOnly, int course) const;
bool synchronizeBase(oAbstractRunner &bc);
public:
InfoBaseCompetitor(int id);
@ -167,11 +168,12 @@ class InfoCompetitor : public InfoBaseCompetitor {
vector<RadioTime> radioTimes;
int inputTime;
int totalStatus;
int course;
bool synchronize(const InfoCompetition &cmp, oRunner &c);
bool changeTotalSt;
bool changeRadio;
public:
bool synchronize(bool useTotalResults, oRunner &c);
bool synchronize(bool useTotalResults, bool useCourse, oRunner &c);
void serialize(xmlbuffer &xml, bool diffOnly) const;
InfoCompetitor(int id);
@ -203,6 +205,7 @@ protected:
bool forceComplete;
bool includeTotal;
bool withCourse;
list<InfoBase *> toCommit;
@ -217,10 +220,12 @@ protected:
public:
void serialize(xmlbuffer &xml, bool diffOnly) const;
bool includeTotalResults() const {return includeTotal;}
void includeTotalResults(bool inc) {includeTotal = inc;}
bool includeCourse() const { return withCourse; }
void includeCourse(bool inc) { withCourse = inc; }
const vector<int> &getControls(int classId, int legNumber) const;
bool synchronize(oEvent &oe, bool onlyCmp, const set<int> &classes, const set<int> &ctrls);
bool synchronize(oEvent &oe) {
@ -233,6 +238,5 @@ protected:
void commitComplete();
InfoCompetition(int id);
//InfoCompetition(const InfoCompetition &in);
virtual ~InfoCompetition() {}
};

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1499,6 +1499,27 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set<int> &stages) {
stages.insert(r);
}
}
xmlobject person = xo.getObject("Person");
if (!person) {
xmlobject teamPerson = xo.getObject("TeamEntryPerson");
if (teamPerson)
person = teamPerson.getObject("Person");
}
xmlList ids;
if (person) {
person.getObjects("Id", ids);
string type;
if (ids.size() > 1) {
for (auto &id : ids) {
id.getObjectString("type", type);
if (!type.empty()) {
idProviders.insert(type);
}
}
}
}
}
bool IOF30Interface::matchStageFilter(const set<int> &stageFilter, const xmlList &races) {
@ -1705,7 +1726,33 @@ pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo
return r;
}
void IOF30Interface::readId(const xmlobject &person, int &pid, __int64 &extId) const {
wstring sid;
pid = 0;
extId = 0;
if (preferredIdProvider.empty()) {
person.getObjectString("Id", sid);
}
else {
xmlList sids;
wstring bsid;
person.getObjects("Id", sids);
for (auto &x : sids) {
auto type = x.getAttrib("type");
if (type && type.get() == preferredIdProvider) {
sid = x.getw();
}
else if (bsid.empty())
bsid = x.getw();
}
if (sid.empty())
pid = oBase::idFromExtId(oBase::converExtIdentifierString(bsid));
}
if (!sid.empty()) {
extId = oBase::converExtIdentifierString(sid);
pid = oBase::idFromExtId(extId);
}
}
pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
@ -1721,11 +1768,35 @@ pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
else {
name = lang.tl("N.N.");
}
int pid = 0;
__int64 extId = 0;
readId(person, pid, extId);
/*
wstring sid;
person.getObjectString("Id", sid);
__int64 extId = oBase::converExtIdentifierString(sid);
int pid = oBase::idFromExtId(extId);
int pid = 0;
__int64 extId = 0;
if (preferredIdProvider.empty()) {
person.getObjectString("Id", sid);
}
else {
xmlList sids;
wstring bsid;
person.getObjects("Id", sids);
for (auto &x : sids) {
auto type = x.getAttrib("type");
if (type && type.get() == preferredIdProvider) {
sid = x.getw();
}
else if (bsid.empty())
bsid = x.getw();
}
if (sid.empty())
pid = oBase::idFromExtId(oBase::converExtIdentifierString(bsid));
}
if (!sid.empty()) {
extId = oBase::converExtIdentifierString(sid);
pid = oBase::idFromExtId(extId);
}*/
pRunner r = 0;
if (pid) {
@ -2620,7 +2691,6 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Position", r.getPlace());
}
else if (teamMember) {
//int pos = r.getTeam()->getLegPlace(r.getLegNumber(), false);
int pos = r.getPlace();
if (pos > 0 && pos < 50000)
xml.write("Position", "type", L"Leg", itow(pos));
@ -2633,6 +2703,11 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
xml.write("Status", formatStatus(r.getStatus()));
int rg = r.getRogainingPoints(false);
if (rg > 0) {
xml.write("Score", "type", L"Score", itow(rg));
xml.write("Score", "type", L"Penalty", itow(r.getRogainingReduction()));
}
if ( (r.getTeam() && r.getClassRef(false)->getClassType() != oClassPatrol && !teamsAsIndividual) || hasInputTime) {
xml.startTag("OverallResult");
int rt = r.getTotalRunningTime();
@ -3612,3 +3687,11 @@ void IOF30Interface::writeClubDB(const RunnerDB &db, xmlparser &xml) const {
xml.endTag();
}
void IOF30Interface::getIdTypes(vector<string> &types) {
types.clear();
types.insert(types.begin(), idProviders.begin(), idProviders.end());
}
void IOF30Interface::setPreferredIdType(const string &type) {
preferredIdProvider = type;
}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -134,6 +134,9 @@ class IOF30Interface {
bool matchStageFilter(const set<int> &stageFilter, const xmlList &races);
set<string> idProviders;
string preferredIdProvider;
void readEvent(gdioutput &gdi, const xmlobject &xo,
map<int, vector<LegInfo> > &teamClassConfig);
pRunner readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam team,
@ -261,10 +264,15 @@ class IOF30Interface {
void writeFullCourse(xmlparser &xml, const oCourse &c,
const map<int, wstring> &ctrlId2ExportId);
void readId(const xmlobject &person, int &pid, __int64 &extId) const;
public:
IOF30Interface(oEvent *oe, bool forceSplitFee);
virtual ~IOF30Interface() {}
void getIdTypes(vector<string> &types);
void setPreferredIdType(const string &type);
void readEventList(gdioutput &gdi, xmlobject &xo);
/** Scan the entry list to find specification of stage numbers*/

BIN
code/lib/libpng.lib Normal file

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
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -515,7 +515,9 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
list.setExtraSpace(k, f);
}
list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo"));
list.setSupportLegSelection(gdi.isChecked("SupportLegSelection"));
makeDirty(gdi, MakeDirty, MakeDirty);
@ -1045,6 +1047,8 @@ void ListEditor::editListProp(gdioutput &gdi, bool newList) {
gdi.fillRight();
gdi.addCheckbox("SupportFrom", "Support time from control", 0, list.supportFrom());
gdi.addCheckbox("SupportTo", "Support time to control", 0, list.supportTo());
gdi.addCheckbox("SupportLegSelection", "Support intermediate legs", 0, list.supportLegSelection());
gdi.dropLine(2);
gdi.popX();

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/********************i****************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -501,3 +501,12 @@ const wstring &Localizer::tl(const string &str) const {
}
return linternal->tl(key);
}
const wstring Localizer::tl(const wstring &str, bool cap) const {
wstring w = linternal->tl(str);
if (capitalizeWords())
::capitalizeWords(w);
return w;
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -66,7 +66,8 @@ public:
LocalizerInternal &get() {return *linternal;}
const wstring &tl(const string &str) const;
const wstring &tl(const wstring &str) const {return linternal->tl(str);}
//const wstring &tlw(const wstring &str) const;
const wstring tl(const wstring &str, bool cap) const;
void init() {linternal = new LocalizerInternal();}
void unload() {delete linternal; linternal = 0;}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -64,7 +64,11 @@
#include "meosexception.h"
#include "parser.h"
#include "restserver.h"
#include "autocomplete.h"
#include "image.h"
Image image;
gdioutput *gdi_main=0;
oEvent *gEvent=0;
SportIdent *gSI=0;
@ -149,6 +153,9 @@ void LoadPage(gdioutput &gdi, TabType type) {
static wchar_t settings[260];
// Startup path
static wchar_t programPath[MAX_PATH];
// Exe path
static wchar_t exePath[MAX_PATH];
void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
MSG msg;
@ -175,12 +182,20 @@ void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
}
}
INT_PTR CALLBACK splashDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
atexit(dumpLeaks); //
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@ -192,6 +207,11 @@ int APIENTRY WinMain(HINSTANCE hInstance,
enableTests = true;
}
HWND hSplash = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_SPLASH), nullptr, splashDialogProc);
ShowWindow(hSplash, SW_SHOW);
UpdateWindow(hSplash);
DWORD splashStart = GetTickCount();
for (int k = 0; k < 100; k++) {
RunnerStatusOrderMap[k] = 0;
}
@ -210,6 +230,19 @@ int APIENTRY WinMain(HINSTANCE hInstance,
GetCurrentDirectory(MAX_PATH, programPath);
GetModuleFileName(NULL, exePath, MAX_PATH);
int lastDiv = -1;
for (int i = 0; i < MAX_PATH; i++) {
if (exePath[i] == 0)
break;
if (exePath[i] == '\\' || exePath[i] == '/')
lastDiv = i;
}
if (lastDiv != -1)
exePath[lastDiv] = 0;
else
exePath[0] = 0;
getUserFile(settings, L"meoswpref.xml");
Parser::test();
@ -250,9 +283,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
lang.get().addLangResource(L"Deutsch", L"105");
lang.get().addLangResource(L"Dansk", L"106");
lang.get().addLangResource(L"Français", L"110");
lang.get().addLangResource(L"Russian (ISO 8859-5)", L"107");
lang.get().addLangResource(L"English (ISO 8859-2)", L"108");
lang.get().addLangResource(L"English (ISO 8859-8)", L"109");
lang.get().addLangResource(L"Russian", L"107");
if (fileExist(L"extra.lng")) {
lang.get().addLangResource(L"Extraspråk", L"extra.lng");
@ -282,20 +313,37 @@ int APIENTRY WinMain(HINSTANCE hInstance,
}
try {
vector<wstring> res;
#ifdef _DEBUG
expandDirectory(L".\\..\\Lists\\", L"*.lxml", res);
expandDirectory(L".\\..\\Lists\\", L"*.listdef", res);
#endif
if (exePath[0]) {
expandDirectory(exePath, L"*.lxml", res);
expandDirectory(exePath, L"*.listdef", res);
}
expandDirectory(programPath, L"*.lxml", res);
expandDirectory(programPath, L"*.listdef", res);
wchar_t listpath[MAX_PATH];
getUserFile(listpath, L"");
vector<wstring> res;
expandDirectory(listpath, L"*.lxml", res);
expandDirectory(listpath, L"*.listdef", res);
#
#ifdef _DEBUG
expandDirectory(L".\\Lists\\", L"*.lxml", res);
expandDirectory(L".\\Lists\\", L"*.listdef", res);
#endif
wstring err;
wstring err;
set<wstring> processed;
for (size_t k = 0; k<res.size(); k++) {
try {
wchar_t filename[128];
wchar_t ext[32];
_wsplitpath_s(res[k].c_str(), NULL, 0, NULL, 0, filename, 128, ext, 32);
wstring fullFile = wstring(filename) + ext;
if (processed.count(fullFile))
continue;
processed.insert(fullFile);
xmlparser xml;
wcscpy_s(listpath, res[k].c_str());
@ -351,6 +399,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
gdi_main->setFont(gEvent->getPropertyInt("TextSize", 0),
gEvent->getPropertyString("TextFont", L"Arial"));
DWORD startupToc = GetTickCount() - splashStart;
Sleep(min<int>(1000, max<int>(0,700 - startupToc)));
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow)) {
return FALSE;
@ -374,6 +425,9 @@ int APIENTRY WinMain(HINSTANCE hInstance,
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEOS);
DestroyWindow(hSplash);
initMySQLCriticalSection(true);
// Main message loop:
mainMessageLoop(hAccelTable, 0);
@ -466,6 +520,8 @@ ATOM MyRegisterClass(HINSTANCE hInstance)
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex);
AutoCompleteInfo::registerAutoClass();
return true;
}
@ -550,12 +606,15 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
}
else if (wParam==VK_RETURN && (lParam & (1<<31))) {
if (gdi)
gdi->Enter();
gdi->enter();
}
else if (wParam==VK_UP) {
bool c = false;
if (gdi && (lParam & (1<<31)))
c = gdi->UpDown(1);
c = gdi->upDown(1);
if (gdi && gdi->hasAutoComplete())
return 1;
if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
@ -569,7 +628,10 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
else if (wParam==VK_DOWN) {
bool c = false;
if (gdi && (lParam & (1<<31)))
c = gdi->UpDown(-1);
c = gdi->upDown(-1);
if (gdi && gdi->hasAutoComplete())
return 1;
if (!c && !(lParam & (1<<31)) && !(gdi && gdi->lockUpDown))
SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
@ -584,7 +646,7 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
}
else if (wParam==VK_ESCAPE && (lParam & (1<<31))) {
if (gdi)
gdi->Escape();
gdi->escape();
}
else if (wParam==VK_F2) {
ProgressWindow pw(hWnd);
@ -666,8 +728,6 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
//WS_EX_CONTROLPARENT
HWND hDskTop=GetDesktopWindow();
RECT rc;
GetClientRect(hDskTop, &rc);
@ -1638,9 +1698,9 @@ void Setup(bool overwrite, bool overwriteAll)
wchar_t dir[260];
GetCurrentDirectory(260, dir);
vector<wstring> dyn;
expandDirectory(dir, L"*.lxml", dyn);
expandDirectory(dir, L"*.listdef", dyn);
expandDirectory(dir, L"*.meos", dyn);
if (overwrite)
expandDirectory(dir, L"*.meos", dyn);
for (size_t k = 0; k < dyn.size(); k++)
toInstall.push_back(make_pair(dyn[k], true));
@ -1802,3 +1862,36 @@ void removeTempFiles() {
tempPath.clear();
}
}
INT_PTR CALLBACK splashDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
) {
PAINTSTRUCT ps;
switch (uMsg) {
case WM_INITDIALOG:
// SetWindowLong(hwndDlg, GWL_EXSTYLE, GetWindowLong(hwndDlg, GWL_EXSTYLE) | WS_EX_LAYERED);
// Make this window 40% alpha
//SetLayeredWindowAttributes(hwndDlg, 0, (255 * 60) / 100, LWA_ALPHA);
break;
case WM_PAINT: {
HDC hdc = BeginPaint(hwndDlg, &ps);
RECT rt;
GetClientRect(hwndDlg, &rt);
image.loadImage(IDI_SPLASHIMAGE, Image::ImageMethod::MonoAlpha);
int h = image.getHeight(IDI_SPLASHIMAGE);
int w = image.getWidth(IDI_SPLASHIMAGE);
image.drawImage(IDI_SPLASHIMAGE, Image::ImageMethod::MonoAlpha, hdc, (rt.right - w) / 2, (rt.bottom - h) / 2, w, h);
EndPaint(hwndDlg, &ps);
break;
}
case WM_ERASEBKGND:
return 1;
}
return 0;
}

BIN
code/meos.png Normal file

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
/////////////////////////////////////////////////////////////////////////////
IDI_SPLASHIMAGE PNG "meos.png"
IDI_MEOSIMAGE PNG "title.png"
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
@ -168,7 +169,7 @@ BEGIN
VALUE "FileDescription", "meos"
VALUE "FileVersion", "3.3.0.1"
VALUE "InternalName", "meos"
VALUE "LegalCopyright", "Copyright © 2007-2017"
VALUE "LegalCopyright", "Copyright © 2007-2018"
VALUE "OriginalFilename", "meos.exe"
VALUE "ProductName", " meos"
VALUE "ProductVersion", "3.4.0.1"
@ -188,6 +189,37 @@ END
IDR_HTML1 HTML "html1.htm"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SPLASH DIALOGEX 0, 0, 309, 178
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_SPLASH, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 171
END
END
#endif // APSTUDIO_INVOKED
#endif // Swedish (Sweden) resources
/////////////////////////////////////////////////////////////////////////////

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1302,6 +1302,12 @@ static double stringDistance(const wchar_t *a, int al, const wchar_t *b, int bl)
return (sqrt(dist)+mfactor*mfactor)/double(al);
}
double stringDistanceAssymetric(const wstring &target, const wstring &sample) {
double d = stringDistance(target.c_str(), target.length(), sample.c_str(), sample.length());
return min(1.0, d);
}
double stringDistance(const wchar_t *a, const wchar_t *b)
{
int al = wcslen(a);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -160,7 +160,7 @@ wstring getMeosFullVersion();
wstring getMajorVersion();
wstring getMeosCompectVersion();
void getSupporters(vector<string> &supp);
void getSupporters(vector<wstring> &supp);
int countWords(const wchar_t *p);
@ -191,9 +191,10 @@ int toLowerStripped(wchar_t c);
const wchar_t *canonizeName(const wchar_t *name);
/** String distance between 0 and 1. 0 is equal*/
//double stringDistance(const char *a, const char *b);
double stringDistance(const wchar_t *a, const wchar_t *b);
/** Return how close sample is to target. 1.0 means equal*/
double stringDistanceAssymetric(const wstring &target, const wstring &sample);
/** Get a number suffix, Start 1 -> 1. Zero for none*/
int getNumberSuffix(const string &str);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -336,7 +336,7 @@ bool MeosSQL::createRunnerDB(oEvent *oe, Query &query)
query.reset();
query << C_START_noid("dbRunner")
<< C_STRING("Name", 40) << C_INT("CardNo")
<< C_STRING("Name", 64) << C_INT("CardNo")
<< C_INT("Club") << C_STRING("Nation", 3)
<< C_STRING("Sex", 1) << C_INT("BirthYear")
<< C_INT64("ExtId") << C_END_noindex();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -116,7 +116,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Release/meos.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>./lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -170,7 +170,7 @@
<Culture>0x041d</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Msimg32.lib;comctl32.lib;odbc32.lib;odbccp32.lib;winmm.lib;ws2_32.lib;wininet.lib;zlibstat_vc15.lib;mysqlpp_vc15.lib;libhpdf.lib;RestBed.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>.\Debug/meos.exe</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>./lib_db;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -240,6 +240,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="animationdata.cpp" />
<ClCompile Include="autocomplete.cpp" />
<ClCompile Include="autotask.cpp" />
<ClCompile Include="classconfiginfo.cpp" />
<ClCompile Include="csvparser.cpp">
@ -255,6 +256,7 @@
</ClCompile>
<ClCompile Include="generalresult.cpp" />
<ClCompile Include="HTMLWriter.cpp" />
<ClCompile Include="image.cpp" />
<ClCompile Include="importformats.cpp" />
<ClCompile Include="infoserver.cpp" />
<ClCompile Include="iof30interface.cpp" />
@ -391,6 +393,8 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="animationdata.h" />
<ClInclude Include="autocomplete.h" />
<ClInclude Include="autocompletehandler.h" />
<ClInclude Include="autotask.h" />
<ClInclude Include="classconfiginfo.h" />
<ClInclude Include="gdiconstants.h" />
@ -399,6 +403,7 @@
<ClInclude Include="gdistructures.h" />
<ClInclude Include="generalresult.h" />
<ClInclude Include="guihandler.h" />
<ClInclude Include="image.h" />
<ClInclude Include="infoserver.h" />
<ClInclude Include="inthashmap.h" />
<ClInclude Include="intkeymap.hpp" />

View File

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

View File

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

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -189,6 +189,7 @@ private:
string resultModule;
bool supportFromControl;
bool supportToControl;
bool hideLegSelection;
enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3};
MetaListPost &add(ListIndex ix, const MetaListPost &post);
@ -251,6 +252,9 @@ public:
void getResultModule(const oEvent &oe, vector< pair<wstring, size_t> > &modules, int &currentModule) const;
const string &getResultModule() const {return resultModule;}
MetaList &setSupportLegSelection(bool state);
bool supportLegSelection() const;
MetaList &setSupportFromTo(bool from, bool to);
bool supportFrom() const {return supportFromControl;}
bool supportTo() const {return supportToControl;}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -11,7 +11,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2017 Melin Software HB
Copyright (C) 2009-2018 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -64,6 +64,7 @@ enum SortOrder {ClassStartTime,
SortByFinishTimeReverse,
SortByStartTime,
CourseResult,
CourseStartTime,
SortByEntryTime,
Custom,
SortEnumLastItem};

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