MeOS version 3.8.1277 RC1

This commit is contained in:
Erik Melin 2021-12-13 19:28:59 +01:00
parent 67e7e24bd5
commit 62a69d2e1f
175 changed files with 4404 additions and 2191 deletions

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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,6 +35,7 @@
#include "RunnerDB.h"
#include "progress.h"
#include "metalist.h"
#include "machinecontainer.h"
#include "MeOSFeatures.h"
#include "meosexception.h"
#include "generalresult.h"
@ -419,6 +420,11 @@ void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) {
sql = sql.substr(0, sql.length() - 2);
query.execute(sql);
}
if (!eCol.count("Machine")) {
string sql = "ALTER TABLE oEvent ADD COLUMN " + C_MTEXT("Machine");
sql = sql.substr(0, sql.length() - 2);
query.execute(sql);
}
}
else if (db == "oCourse") {
if (!eCol.count("Legs")) {
@ -556,7 +562,8 @@ bool MeosSQL::openDB(oEvent *oe)
<< C_STRING("NameId", 64)
<< C_UINT("BuildVersion")
<< oe->getDI().generateSQLDefinition()
<< C_MTEXT("Lists") << C_END();
<< C_MTEXT("Lists")
<< C_MTEXT("Machine") << C_END();
query.execute();
// Upgrade oEvent
@ -818,7 +825,8 @@ OpFailStatus MeosSQL::SyncUpdate(oEvent *oe)
<< " NameId=" << quote << toString(oe->currentNameId) << ", "
<< " ZeroTime=" << unsigned(oe->ZeroTime) << ", "
<< " BuildVersion=" << buildVersion << ", "
<< " Lists=" << quote << listEnc
<< " Lists=" << quote << listEnc << ", "
<< " Machine=" <<quote << oe->getMachineContainer().save()
<< oe->getDI().generateSQLSet(true);
if (syncUpdate(queryset, "oEvent", oe) == opStatusFail)
@ -1185,6 +1193,9 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
retValue = opStatusWarning;
}
const string &mRaw = row.raw_string(res.field_num("Machine"));
oe->getMachineContainer().load(mRaw);
oDataInterface odi=oe->getDI();
storeData(odi, row, oe->dataRevision);
oe->changed = false;
@ -2589,7 +2600,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oClub *c)
}
try {
auto query = con->query();
query << "SELECT * FROM oClub WHERE Id=" << c->Id;
query << "SELECT * FROM oClub WHERE Id=" << c->Id << andWhereOld(c);
auto res = query.store();
RowWrapper row;
@ -2611,8 +2622,7 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oClub *c)
return syncUpdate(c, false);
}
}
else {
//Something is wrong!? Deleted?
else if (c->changed) {
return syncUpdate(c, true);
}
return opStatusOK;
@ -3097,6 +3107,9 @@ OpFailStatus MeosSQL::SyncEvent(oEvent *oe) {
catch (std::exception &ex) {
alert(ex.what());
}
const string &mRaw = row.raw_string(res.field_num("Machine"));
oe->getMachineContainer().load(mRaw);
oe->counter = counter;
oDataInterface odi=oe->getDI();
storeData(odi, row, oe->dataRevision);
@ -3124,7 +3137,8 @@ OpFailStatus MeosSQL::SyncEvent(oEvent *oe) {
<< " ZeroTime=" << unsigned(oe->ZeroTime) << ", "
<< " BuildVersion=if (BuildVersion<" <<
buildVersion << "," << buildVersion << ",BuildVersion), "
<< " Lists=" << quote << listEnc
<< " Lists=" << quote << listEnc << ", "
<< " Machine=" << quote << oe->getMachineContainer().save()
<< oe->getDI().generateSQLSet(false);
syncUpdate(queryset, "oEvent", oe);
@ -3156,7 +3170,8 @@ OpFailStatus MeosSQL::SyncEvent(oEvent *oe) {
<< " ZeroTime=" << unsigned(oe->ZeroTime) << ","
<< " BuildVersion=if (BuildVersion<" <<
buildVersion << "," << buildVersion << ",BuildVersion),"
<< " Lists=" << quote << listEnc
<< " Lists=" << quote << listEnc << ", "
<< " Machine=" << quote << oe->getMachineContainer().save()
<< oe->getDI().generateSQLSet(false);
syncUpdate(queryset, "oEvent", oe);
@ -3223,7 +3238,7 @@ bool MeosSQL::syncListRunner(oEvent *oe)
st = OpFailStatus::opStatusOK;
oRunner *r=oe->getRunner(Id, 0);
if (r) {
if (r && !r->Removed) {
r->Removed=true;
if (r->tInTeam)
r->tInTeam->correctRemove(r);
@ -3233,6 +3248,8 @@ bool MeosSQL::syncListRunner(oEvent *oe)
}
r->changedObject();
r->changed = false;
oe->dataRevision++;
}
}
else{
@ -3290,9 +3307,11 @@ bool MeosSQL::syncListClass(oEvent *oe) {
if (int(row["Removed"])) {
st = OpFailStatus::opStatusOK;
oClass *c = oe->getClass(Id);
if (c) {
if (c && !c->Removed) {
c->changedObject();
c->Removed = true;
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3355,9 +3374,11 @@ bool MeosSQL::syncListClub(oEvent *oe)
st = opStatusOK;
oClub *c = oe->getClub(Id);
if (c) {
if (c && !c->Removed) {
c->Removed = true;
c->changedObject();
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3413,9 +3434,11 @@ bool MeosSQL::syncListCourse(oEvent *oe) {
st = opStatusOK;
oCourse *c = oe->getCourse(Id);
if (c) {
if (c && !c->Removed) {
c->Removed = true;
c->changedObject();
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3469,9 +3492,11 @@ bool MeosSQL::syncListCard(oEvent *oe)
if (int(row["Removed"])) {
st = opStatusOK;
oCard *c = oe->getCard(Id);
if (c) {
if (c && !c->Removed) {
c->changedObject();
c->Removed = true;
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3529,9 +3554,11 @@ bool MeosSQL::syncListControl(oEvent *oe) {
st = opStatusOK;
oControl *c = oe->getControl(Id, false);
if (c) {
if (c && !c->Removed) {
c->Removed = true;
c->changedObject();
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3588,13 +3615,16 @@ bool MeosSQL::syncListPunch(oEvent *oe)
if (int(row["Removed"])) {
st = OpFailStatus::opStatusOK;
oFreePunch *c=oe->getPunch(Id);
if (c) {
if (c && !c->Removed) {
c->Removed=true;
int cid = c->getControlId();
oFreePunch::rehashPunches(*oe, c->CardNo, 0);
pRunner r = oe->getRunner(c->tRunnerId, 0);
if (r)
r->markClassChanged(cid);
c->changed = false;
oe->dataRevision++;
}
}
else {
@ -3653,10 +3683,12 @@ bool MeosSQL::syncListTeam(oEvent *oe) {
if (int(row["Removed"])) {
st = OpFailStatus::opStatusOK;
oTeam *t = oe->getTeam(Id);
if (t) {
if (t && !t->Removed) {
t->changedObject();
t->prepareRemove();
t->Removed = true;
t->changed = false;
oe->dataRevision++;
}
}
else {
@ -3696,15 +3728,19 @@ bool MeosSQL::syncListTeam(oEvent *oe) {
string MeosSQL::selectUpdated(const char *oTable, const SqlUpdated &updated) {
string p1 = string("SELECT Id, Counter, Modified, Removed FROM ") + oTable;
string cond1 = p1 + " WHERE Counter>" + itos(updated.counter);
if (updated.updated.empty())
return cond1;
string q = "(" + p1 + " WHERE Counter>" + itos(updated.counter) + ") UNION ALL ("+
string q = "(" + cond1 + ") UNION ALL ("+
p1 + " WHERE Modified>'" + updated.updated + "' AND Counter<=" + itos(updated.counter) + ")";
return q;
}
bool MeosSQL::checkConnection(oEvent *oe)
{
if (!con->connected())
return false;
errorMessage.clear();
if (!oe) {

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -40,7 +40,9 @@ RestService::~RestService() {
}
}
void RestService::save(oEvent &oe, gdioutput &gdi) {
void RestService::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
if (!server) {
server = RestServer::construct();
@ -49,7 +51,8 @@ void RestService::save(oEvent &oe, gdioutput &gdi) {
oe.setProperty("ServicePort", xport);
port = xport;
server->startService(port);
if (doProcess)
server->startService(port);
}
else
throw meosException("Invalid port number");
@ -74,7 +77,7 @@ void RestService::save(oEvent &oe, gdioutput &gdi) {
void ListIpAddresses(vector<string>& ip);
void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
void RestService::settings(gdioutput &gdi, oEvent &oe, State state) {
if (port == -1) {
port = oe.getPropertyInt("ServicePort", 2009);
rootMap = oe.getPropertyString("ServiceRootMap", "");
@ -100,7 +103,7 @@ void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
gdi.addInput("RootMap", gdi.recodeToWide(rootMap));
gdi.setInputStatus("RootMap", !rootMap.empty());
startCancelInterval(gdi, "Save", created, IntervalNone, L"");
startCancelInterval(gdi, "Save", state, IntervalNone, L"");
if (!server) {
gdi.addInput("Port", itow(port), 10, 0, L"Port:", L"#http://localhost:[PORT]/meos");
@ -128,8 +131,7 @@ void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
}
void RestService::status(gdioutput &gdi) {
gdi.pushX();
gdi.addString("", 1, name);
AutoMachine::status(gdi);
if (server) {
gdi.addString("", 0, "Server startad på X#" + itos(port));

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -34,8 +34,8 @@ class RestService :
string rootMap;
public:
void save(oEvent &oe, gdioutput &gdi) override;
void settings(gdioutput &gdi, oEvent &oe, bool created) override;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) override;
void settings(gdioutput &gdi, oEvent &oe, State state) override;
RestService *clone() const override { return new RestService(*this); }
void status(gdioutput &gdi) override;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) override;

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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

@ -13,7 +13,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -44,6 +44,7 @@
#include "gdiconstants.h"
#include "meosexception.h"
#include "machinecontainer.h"
#include "HTMLWriter.h"
static TabAuto *tabAuto = 0;
@ -98,6 +99,18 @@ AutoMachine *TabAuto::getMachine(int id) {
throw meosException("Service X not found.#" + itos(id));
}
void AutoMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
machineName = gdi.getText("MachineName");
}
void AutoMachine::status(gdioutput &gdi) {
gdi.pushX();
if (machineName.empty())
gdi.addString("", 1, name);
else
gdi.addString("", 1, L"#" + lang.tl(name) + L" (" + machineName + L")");
}
TabAuto::~TabAuto(void)
{
list<AutoMachine *>::iterator it;
@ -108,27 +121,41 @@ TabAuto::~TabAuto(void)
tabAuto=0;
}
void tabAutoKillMachines()
void TabAuto::tabAutoKillMachines()
{
if (tabAuto)
tabAuto->killMachines();
}
void tabAutoRegister(TabAuto *ta)
void TabAuto::tabAutoRegister(TabAuto *ta)
{
tabAuto=ta;
}
void tabAutoAddMachinge(const AutoMachine &am)
AutoMachine &TabAuto::tabAutoAddMachinge(const AutoMachine &am)
{
if (tabAuto) {
tabAuto->addMachine(am);
}
if (tabAuto)
return tabAuto->addMachine(am);
throw meosException("Internal error");
}
void tabForceSync(gdioutput &gdi, pEvent oe)
bool TabAuto::hasActiveReconnectionMachine()
{
if (tabAuto)
return tabAuto->hasActiveReconnection();
return false;
}
bool TabAuto::hasActiveReconnection() const {
for (auto am : machines) {
if (am->getType() == Machines::mMySQLReconnect)
return true;
}
return false;
}
void tabForceSync(gdioutput &gdi, pEvent oe) {
if (tabAuto)
tabAuto->syncCallback(gdi);
}
@ -152,31 +179,38 @@ int AutomaticCB(gdioutput *gdi, int type, void *data)
return 0;
}
void TabAuto::syncCallback(gdioutput &gdi)
void TabAuto::syncCallback(gdioutput& gdi)
{
list<AutoMachine*> toRemove;
wstring msg;
try {
list<AutoMachine *>::iterator it;
for (it=machines.begin(); it!=machines.end(); ++it) {
AutoMachine *am=*it;
list<AutoMachine*>::iterator it;
for (it = machines.begin(); it != machines.end(); ++it) {
try {
AutoMachine* am = *it;
if (am && am->synchronize && !am->isEditMode())
am->process(gdi, oe, SyncDataUp);
if (am->removeMe())
toRemove.push_back(am);
}
catch (meosException& ex) {
msg = ex.wwhat();
}
catch (std::exception& ex) {
msg = gdi.widen(ex.what());
}
catch (...) {
msg = L"Ett okänt fel inträffade.";
}
}
catch (meosException &ex) {
msg = ex.wwhat();
}
catch(std::exception &ex) {
msg = gdi.widen(ex.what());
}
catch(...) {
msg = L"Ett okänt fel inträffade.";
for (auto* r : toRemove) {
stopMachine(r);
}
if (!msg.empty()) {
gdi.alert(msg);
gdi.setWaitCursor(false);
}
}
void TabAuto::updateSyncInfo()
@ -195,25 +229,45 @@ void TabAuto::updateSyncInfo()
}
}
void TabAuto::timerCallback(gdioutput &gdi)
{
void TabAuto::timerCallback(gdioutput &gdi) {
DWORD tc=GetTickCount();
list<AutoMachine *>::iterator it;
bool reload=false;
list<AutoMachine*> toRemove;
wstring msg;
for (it=machines.begin(); it!=machines.end(); ++it) {
AutoMachine *am=*it;
for (it = machines.begin(); it != machines.end(); ++it) {
AutoMachine* am = *it;
if (am && am->interval && tc >= am->timeout && !am->isEditMode()) {
am->process(gdi, oe, SyncTimer);
setTimer(am);
reload=true;
try {
am->process(gdi, oe, SyncTimer);
}
catch (meosException& ex) {
msg = ex.wwhat();
}
catch (std::exception& ex) {
msg = gdi.widen(ex.what());
}
catch (...) {
msg = L"Ett okänt fel inträffade.";
}
reload = true;
if (am->removeMe())
toRemove.push_back(am);
else
setTimer(am);
}
}
for (auto* r : toRemove) {
stopMachine(r);
}
DWORD d=0;
if (reload && !editMode && gdi.getData("AutoPage", d) && d)
loadPage(gdi, false);
if (!msg.empty())
throw meosException(msg);
}
void TabAuto::setTimer(AutoMachine *am)
@ -255,16 +309,8 @@ int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu)
if (!newPath.empty())
gdi.setText(edit, newPath);
}
else if (bu.id == "StartBackup") {
SaveMachine *sm=dynamic_cast<SaveMachine*>(getMachine(bu.getExtraInt()));
if (sm)
sm->saveSettings(gdi);
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id=="Result") {
PrintResultMachine *sm=dynamic_cast<PrintResultMachine*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mPrintResultsMachine);
settings(gdi, getMachine(bu.getExtraInt()), AutoMachine::State::Create, mPrintResultsMachine);
}
else if (bu.id == "BrowseFile") {
static int index = 0;
@ -302,168 +348,37 @@ int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu)
}
else if (bu.id=="Splits") {
SplitsMachine *sm=dynamic_cast<SplitsMachine*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mSplitsMachine);
settings(gdi, sm, AutoMachine::State::Create, mSplitsMachine);
}
else if (bu.id=="Prewarning") {
PrewarningMachine *sm=dynamic_cast<PrewarningMachine*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mPrewarningMachine);
settings(gdi, sm, AutoMachine::State::Create, mPrewarningMachine);
}
else if (bu.id=="Punches") {
PunchMachine *sm=dynamic_cast<PunchMachine*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mPunchMachine);
settings(gdi, sm, AutoMachine::State::Create, mPunchMachine);
}
else if (bu.id=="OnlineResults") {
OnlineResults *sm=dynamic_cast<OnlineResults*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mOnlineResults);
settings(gdi, getMachine(bu.getExtraInt()), AutoMachine::State::Create, mOnlineResults);
}
else if (bu.id=="OnlineInput") {
OnlineInput *sm=dynamic_cast<OnlineInput*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mOnlineInput);
settings(gdi, getMachine(bu.getExtraInt()), AutoMachine::State::Create, mOnlineInput);
}
else if (bu.id=="SaveBackup") {
SaveMachine *sm=dynamic_cast<SaveMachine*>(getMachine(bu.getExtraInt()));
settings(gdi, sm, mSaveBackup);
settings(gdi, getMachine(bu.getExtraInt()), AutoMachine::State::Create, mSaveBackup);
}
else if (bu.id == "InfoService") {
settings(gdi, getMachine(bu.getExtraInt()), mInfoService);
}
else if (bu.id=="StartResult") {
#ifndef MEOSDB
wstring minute=gdi.getText("Interval");
int t=convertAbsoluteTimeMS(minute);
if (t<2 || t>7200) {
gdi.alert("Intervallet måste anges på formen MM:SS.");
}
else {
PrintResultMachine *prm=dynamic_cast<PrintResultMachine*>(getMachine(bu.getExtraInt()));
if (prm) {
prm->interval = t;
prm->doExport = gdi.isChecked("DoExport");
prm->doPrint = gdi.isChecked("DoPrint");
prm->exportFile = gdi.getText("ExportFile");
prm->exportScript = gdi.getText("ExportScript");
if (!prm->readOnly) {
prm->structuredExport = gdi.isChecked("StructuredExport");
prm->htmlRefresh = gdi.isChecked("HTMLRefresh") ? t : 0;
gdi.getSelection("Classes", prm->classesToPrint);
ListBoxInfo lbi;
if (gdi.getSelectedItem("ListType", lbi)) {
oListParam par;
par.selection=prm->classesToPrint;
par.listCode = EStdListType(lbi.data);
par.pageBreak = gdi.isChecked("PageBreak");
par.showHeader = gdi.isChecked("ShowHeader");
par.showInterTimes = gdi.isChecked("ShowInterResults");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
int legNr = gdi.getSelectedItem("LegNumber").first;
if (legNr >= 0)
par.setLegNumberCoded(legNr);
else
par.setLegNumberCoded(0);
oe->generateListInfo(par, prm->listInfo);
}
}
prm->po.onlyChanged = gdi.isChecked("OnlyChanged");
prm->pageBreak = gdi.isChecked("PageBreak");
prm->showHeader = gdi.isChecked("ShowHeader");
prm->showInterResult = gdi.isChecked("ShowInterResults");
prm->splitAnalysis = gdi.isChecked("SplitAnalysis");
prm->synchronize=true; //To force continuos data sync.
setTimer(prm);
}
updateSyncInfo();
loadPage(gdi, false);
}
#endif
}
else if (bu.id=="StartSplits") {
wstring ivt = gdi.getText("Interval");
int iv = gdi.getTextNo("Interval");
const wstring &file=gdi.getText("FileName");
if (!ivt.empty() && (iv < 1 || iv > 7200)) {
throw meosException(L"Ogiltigt antal sekunder: X#" + gdi.getText("Interval"));
}
if (file.empty()) {
throw meosException("Filnamnet får inte vara tomt");
}
//Try exporting.
oe->exportIOFSplits(oEvent::IOF20, file.c_str(), true, false,
set<int>(), -1, false, true, true, false);
SplitsMachine *sm=dynamic_cast<SplitsMachine*>(getMachine(bu.getExtraInt()));
if (sm) {
sm->interval=iv;
sm->file=file;
sm->synchronize=true;
setTimer(sm);
}
updateSyncInfo();
loadPage(gdi, false);
settings(gdi, getMachine(bu.getExtraInt()), AutoMachine::State::Create, mInfoService);
}
else if (bu.id=="Save") { // General save
AutoMachine *sm=getMachine(bu.getExtraInt());
if (sm) {
sm->save(*oe, gdi);
sm->save(*oe, gdi, true);
setTimer(sm);
}
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id=="StartPrewarning") {
PrewarningMachine *pwm=dynamic_cast<PrewarningMachine*>(getMachine(bu.getExtraInt()));
if (pwm) {
pwm->waveFolder=gdi.getText("WaveFolder");
gdi.getSelection("Controls", pwm->controls);
oe->synchronizeList(oListId::oLPunchId);
oe->clearPrewarningSounds();
pwm->synchronizePunches=true;
pwm->controlsSI.clear();
for (set<int>::iterator it=pwm->controls.begin();it!=pwm->controls.end();++it) {
pControl pc=oe->getControl(*it, false);
if (pc)
pwm->controlsSI.insert(pc->Numbers, pc->Numbers+pc->nNumbers);
}
}
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id=="StartPunch") {
wstring minute=gdi.getText("Interval");
int t=_wtoi(minute.c_str());
if (t<1 || t>7200) {
throw meosException(L"Ogiltigt antal sekunder: X#" + minute);
}
else {
PunchMachine *pm=dynamic_cast<PunchMachine*>(getMachine(bu.getExtraInt()));
if (pm) {
pm->interval=t;
pm->radio=gdi.getTextNo("Radio");
setTimer(pm);
}
}
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id == "Cancel") {
loadPage(gdi, false);
}
@ -474,6 +389,40 @@ int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu)
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id == "SaveMachine") {
auto sm = getMachine(bu.getExtraInt());
sm->save(*oe, gdi, false);
wstring iv;
if (gdi.hasWidget("Interval"))
iv = gdi.getText("Interval");
sm->saveMachine(*oe, iv);
oe->updateChanged();
oe->synchronize(false);
}
else if (bu.id == "Erase") {
auto sm = getMachine(bu.getExtraInt());
if (sm) {
oe->getMachineContainer().erase(sm->getTypeString(), sm->getMachineName());
oe->updateChanged();
oe->synchronize();
stopMachine(sm);
}
updateSyncInfo();
loadPage(gdi, false);
}
else if (bu.id == "CreateLoad") {
auto sm = oe->getMachineContainer().enumerate();
int ix = bu.getExtraInt();
if (ix < sm.size()) {
auto &m = sm[ix];
Machines type = AutoMachine::getType(m.first);
AutoMachine *am = AutoMachine::construct(type);
machines.push_back(am);
am->loadMachine(*oe, m.second);
settings(gdi, am, AutoMachine::State::Load, am->getType());
}
}
else if (bu.id == "PrinterSetup") {
PrintResultMachine *prm =
dynamic_cast<PrintResultMachine*>(getMachine(bu.getExtraInt()));
@ -548,13 +497,16 @@ bool TabAuto::stopMachine(AutoMachine *am)
return false;
}
void TabAuto::settings(gdioutput &gdi, AutoMachine *sm, Machines ms) {
void TabAuto::settings(gdioutput &gdi, AutoMachine *sm, AutoMachine::State state, Machines ms) {
editMode=true;
bool createNew = (sm==0) || (ms == Machines::Unknown);
if (sm) {
if (state == AutoMachine::State::Create)
state = AutoMachine::State::Edit;
ms = sm->getType();
}
else {
state = AutoMachine::State::Create;
sm = AutoMachine::construct(ms);
machines.push_back(sm);
}
@ -566,7 +518,7 @@ void TabAuto::settings(gdioutput &gdi, AutoMachine *sm, Machines ms) {
int d = gdi.scaleLength(6);
gdi.setCX(cx + d);
sm->setEditMode(true);
sm->settings(gdi, *oe, createNew);
sm->settings(gdi, *oe, state);
int w = gdi.getWidth();
int h = gdi.getHeight();
@ -592,6 +544,7 @@ void TabAuto::killMachines()
bool TabAuto::loadPage(gdioutput &gdi, bool showSettingsLast)
{
oe->checkDB();
oe->synchronize();
tabAuto=this;
editMode=false;
gdi.selectTab(tabId);
@ -608,34 +561,74 @@ bool TabAuto::loadPage(gdioutput &gdi, bool showSettingsLast)
gdi.setData("AutoPage", 1);
gdi.addString("", boldLarge, "Automater");
gdi.setRestorePoint();
gdi.fillDown();
gdi.pushX();
gdi.addString("", 10, "help:10000");
auto sm = oe->getMachineContainer().enumerate();
set<pair<string, wstring>> startedMachines;
for (auto &m : machines) {
string t;
m->getType(t);
startedMachines.emplace(t, m->machineName);
}
decltype(sm) sm2;
for (auto &m : sm) {
if (startedMachines.count(m) == 0)
sm2.push_back(m);
}
sm2.swap(sm);
if (sm.size() > 0) {
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Sparade automater").setColor(colorDarkBlue);
gdi.dropLine(0.3);
gdi.fillRight();
for (int ix = 0; ix < sm.size(); ix++) {
if (ix > 0 && ix % 3 == 0) {
gdi.dropLine(2.5);
gdi.popX();
}
auto &m = sm[ix];
Machines type = AutoMachine::getType(m.first);
if (m.second == L"default")
gdi.addButton("CreateLoad", AutoMachine::getDescription(type), AutomaticCB).setExtra(ix);
else
gdi.addButton("CreateLoad", L"#" + lang.tl(AutoMachine::getDescription(type))
+ L" (" + m.second + L")", AutomaticCB).setExtra(ix);
}
gdi.popX();
gdi.dropLine(2);
gdi.fillDown();
}
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Tillgängliga automater").setColor(colorDarkBlue);
gdi.dropLine();
gdi.dropLine(0.3);
gdi.fillRight();
gdi.pushX();
gdi.addButton("Result", "Resultatutskrift / export", AutomaticCB, "tooltip:resultprint");
gdi.addButton("OnlineResults", "Resultat online", AutomaticCB, "Publicera resultat direkt på nätet");
gdi.addButton("OnlineInput", "Inmatning online", AutomaticCB, "Hämta stämplingar m.m. från nätet");
gdi.addButton("Result", AutoMachine::getDescription(Machines::mPrintResultsMachine), AutomaticCB, "tooltip:resultprint");
gdi.addButton("OnlineResults", AutoMachine::getDescription(Machines::mOnlineResults), AutomaticCB, "Publicera resultat direkt på nätet");
gdi.addButton("OnlineInput", AutoMachine::getDescription(Machines::mOnlineInput), AutomaticCB, "Hämta stämplingar m.m. från nätet");
gdi.popX();
gdi.dropLine(2.5);
gdi.addButton("SaveBackup", "Säkerhetskopiering", AutomaticCB);
gdi.addButton("InfoService", "Informationsserver", AutomaticCB);
gdi.addButton("Punches", "Stämplingstest", AutomaticCB, "Simulera inläsning av stämplar");
gdi.addButton("SaveBackup", AutoMachine::getDescription(Machines::mSaveBackup), AutomaticCB);
gdi.addButton("InfoService", AutoMachine::getDescription(Machines::mInfoService), AutomaticCB);
gdi.addButton("Punches", AutoMachine::getDescription(Machines::mPunchMachine), AutomaticCB, "Simulera inläsning av stämplar");
gdi.popX();
gdi.dropLine(2.5);
gdi.addButton("Splits", "Sträcktider (WinSplits)", AutomaticCB, "Spara sträcktider till en fil för automatisk synkronisering med WinSplits");
gdi.addButton("Prewarning", "Förvarningsröst", AutomaticCB, "tooltip:voice");
gdi.addButton("Splits", AutoMachine::getDescription(Machines::mSplitsMachine), AutomaticCB, "Spara sträcktider till en fil för automatisk synkronisering med WinSplits");
gdi.addButton("Prewarning", AutoMachine::getDescription(Machines::mPrewarningMachine), AutomaticCB, "tooltip:voice");
gdi.fillDown();
gdi.dropLine(3);
gdi.popX();
if (!machines.empty()) {
gdi.addString("", fontMediumPlus, "Startade automater").setColor(colorDarkBlue);;
gdi.addString("", fontMediumPlus, "Startade automater").setColor(colorDarkBlue);
list<AutoMachine *>::iterator it;
int baseX = gdi.getCX();
@ -666,30 +659,44 @@ bool TabAuto::loadPage(gdioutput &gdi, bool showSettingsLast)
gdi.setOffset(storedOY, storedOY, true);
}
if (showSettingsLast && !machines.empty())
settings(gdi, *machines.rbegin(), Machines::Unknown);
settings(gdi, *machines.rbegin(), AutoMachine::State::Edit, Machines::Unknown);
gdi.refresh();
return true;
}
void AutoMachine::settingsTitle(gdioutput &gdi, char *title) {
gdi.fillDown();
gdi.dropLine(0.5);
gdi.addString("", fontMediumPlus, title).setColor(colorDarkBlue);
gdi.dropLine(0.5);
}
void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, bool created, IntervalType type, const wstring &intervalIn) {
void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, State state, IntervalType type, const wstring &intervalIn) {
gdi.pushX();
gdi.fillRight();
gdi.addInput("MachineName", machineName, 10, nullptr, L"Namn", L"Om du vill kan du namnge automaten");
if (type == IntervalMinute)
gdi.addInput("Interval", intervalIn, 7, 0, L"Tidsintervall (MM:SS):");
else if (type == IntervalSecond)
gdi.addInput("Interval", intervalIn, 7, 0, L"Tidsintervall (sekunder):");
gdi.dropLine(1);
gdi.addButton(startCommand, created ? "Starta automaten" : "OK", AutomaticCB).setExtra(getId());
if (!created)
gdi.addButton(startCommand,
(state == State::Create || state == State::Load) ? "Starta automaten" : "OK", AutomaticCB).setExtra(getId());
if (hasSaveMachine())
gdi.addButton("SaveMachine", "Spara inställningar", AutomaticCB).setExtra(getId());
if (state == State::Load)
gdi.addButton("Erase", "Radera", AutomaticCB).setExtra(getId());
if (state == State::Edit)
gdi.addButton("Cancel", "Avbryt", AutomaticCB).setExtra(getId());
gdi.addButton("Stop", created ? "Avbryt" : "Stoppa automaten", AutomaticCB).setExtra(getId());
gdi.addButton("Stop", (state == State::Create || state == State::Load) ? "Avbryt" : "Stoppa automaten", AutomaticCB).setExtra(getId());
gdi.popX();
gdi.fillDown();
@ -704,13 +711,12 @@ void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, bool c
gdi.dropLine();
}
void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Resultatutskrift / export");
wstring time = (created && interval <= 0) ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "StartResult", created, IntervalMinute, time);
wstring time = (state == State::Create && interval <= 0) ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
if (created) {
if (state == State::Create) {
oe.getAllClasses(classesToPrint);
}
@ -813,6 +819,55 @@ void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
}
}
void PrintResultMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
wstring minute = gdi.getText("Interval");
int t = convertAbsoluteTimeMS(minute);
if (t < 2 || t>7200) {
throw meosException("Intervallet måste anges på formen MM:SS.");
}
doExport = gdi.isChecked("DoExport");
doPrint = gdi.isChecked("DoPrint");
exportFile = gdi.getText("ExportFile");
exportScript = gdi.getText("ExportScript");
if (!readOnly) {
structuredExport = gdi.isChecked("StructuredExport");
htmlRefresh = gdi.isChecked("HTMLRefresh") ? t : 0;
gdi.getSelection("Classes", classesToPrint);
ListBoxInfo lbi;
if (gdi.getSelectedItem("ListType", lbi)) {
oListParam par;
par.selection = classesToPrint;
par.listCode = EStdListType(lbi.data);
par.pageBreak = gdi.isChecked("PageBreak");
par.showHeader = gdi.isChecked("ShowHeader");
par.showInterTimes = gdi.isChecked("ShowInterResults");
par.splitAnalysis = gdi.isChecked("SplitAnalysis");
int legNr = gdi.getSelectedItem("LegNumber").first;
if (legNr >= 0)
par.setLegNumberCoded(legNr);
else
par.setLegNumberCoded(0);
oe.generateListInfo(par, listInfo);
}
}
po.onlyChanged = gdi.isChecked("OnlyChanged");
pageBreak = gdi.isChecked("PageBreak");
showHeader = gdi.isChecked("ShowHeader");
showInterResult = gdi.isChecked("ShowInterResults");
splitAnalysis = gdi.isChecked("SplitAnalysis");
if (doProcess) {
interval = t;
synchronize = true; //To force continuos data sync.
}
}
void PrintResultMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
{
if (lock)
@ -876,7 +931,7 @@ void PrintResultMachine::status(gdioutput &gdi)
{
gdi.fillRight();
gdi.pushX();
gdi.addString("", 0, name);
AutoMachine::status(gdi);
gdi.addString("", 0, listInfo.getName());
gdi.dropLine();
if (doExport) {
@ -903,9 +958,9 @@ void PrintResultMachine::status(gdioutput &gdi)
gdi.popX();
}
void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Förvarningsröst");
startCancelInterval(gdi, "StartPrewarning", created, IntervalNone, L"");
startCancelInterval(gdi, "Save", state, IntervalNone, L"");
gdi.addString("", 10, "help:computer_voice");
@ -930,6 +985,27 @@ void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
gdi.popX();
}
void PrewarningMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
waveFolder = gdi.getText("WaveFolder");
gdi.getSelection("Controls", controls);
oe.synchronizeList(oListId::oLPunchId);
oe.clearPrewarningSounds();
controlsSI.clear();
for (set<int>::iterator it = controls.begin(); it != controls.end(); ++it) {
pControl pc = oe.getControl(*it, false);
if (pc) {
vector<int> n;
pc->getNumbers(n);
controlsSI.insert(n.begin(), n.end());
}
}
if (doProcess)
synchronizePunches = true;
}
void PrewarningMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
{
oe->playPrewarningSounds(waveFolder, controlsSI);
@ -937,7 +1013,7 @@ void PrewarningMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
void PrewarningMachine::status(gdioutput &gdi)
{
gdi.addString("", 1, name);
AutoMachine::status(gdi);
string info="Förvarning på (SI-kod): ";
bool first=true;
@ -968,10 +1044,10 @@ void PrewarningMachine::status(gdioutput &gdi)
gdi.popX();
}
void PunchMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
void PunchMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Test av stämplingsinläsningar");
wstring time=created ? L"10" : itow(interval);
startCancelInterval(gdi, "StartPunch", created, IntervalSecond, time);
wstring time = state == State::Create ? L"10" : itow(interval);
startCancelInterval(gdi, "Save", state, IntervalSecond, time);
gdi.addString("", 10, "help:simulate");
@ -995,9 +1071,23 @@ void PunchMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
gdi.addButton("GenerateCMP", "Generera testtävling", AutomaticCB);
}
void PunchMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
wstring minute = gdi.getText("Interval");
int t = _wtoi(minute.c_str());
if (t<1 || t>7200) {
throw meosException(L"Ogiltigt antal sekunder: X#" + minute);
}
else {
interval = t;
radio = gdi.getTextNo("Radio");
}
}
void PunchMachine::status(gdioutput &gdi)
{
gdi.addString("", 1, name);
AutoMachine::status(gdi);
gdi.fillRight();
gdi.pushX();
if (interval>0){
@ -1066,15 +1156,15 @@ void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
#endif
}
void SplitsMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
void SplitsMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
wstring time;
if (interval>0)
time = itow(interval);
else if (created)
else if (state == State::Create)
time = L"30";
settingsTitle(gdi, "Sträcktider / WinSplits");
startCancelInterval(gdi, "StartSplits", created, IntervalSecond, time);
startCancelInterval(gdi, "Save", state, IntervalSecond, time);
gdi.addString("", 0, "Intervall (sekunder). Lämna blankt för att uppdatera när "
"tävlingsdata ändras.");
@ -1094,9 +1184,33 @@ void SplitsMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
}
void SplitsMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
wstring ivt = gdi.getText("Interval");
int iv = gdi.getTextNo("Interval");
file = gdi.getText("FileName");
if (!ivt.empty() && (iv < 1 || iv > 7200)) {
throw meosException(L"Ogiltigt antal sekunder: X#" + gdi.getText("Interval"));
}
if (file.empty()) {
throw meosException("Filnamnet får inte vara tomt");
}
if (doProcess) {
//Try exporting.
oe.exportIOFSplits(oEvent::IOF20, file.c_str(), true, false,
set<int>(), -1, false, true, true, false);
interval = iv;
synchronize = true;
}
}
void SplitsMachine::status(gdioutput &gdi)
{
gdi.addString("", 1, name);
AutoMachine::status(gdi);
if (!file.empty()) {
gdi.fillRight();
gdi.pushX();
@ -1133,7 +1247,8 @@ void SplitsMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
}
void SaveMachine::status(gdioutput &gdi) {
gdi.addString("", 1, name);
AutoMachine::status(gdi);
if (!baseFile.empty()) {
gdi.fillRight();
gdi.pushX();
@ -1165,10 +1280,10 @@ void SaveMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
}
}
void SaveMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
void SaveMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
settingsTitle(gdi, "Säkerhetskopiering");
wstring time=created ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "StartBackup", created, IntervalMinute, time);
wstring time=state == State::Create ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
int cx = gdi.getCX();
gdi.addInput("BaseFile", baseFile, 32, 0, L"Mapp:");
@ -1177,8 +1292,8 @@ void SaveMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
gdi.setCX(cx);
}
void SaveMachine::saveSettings(gdioutput &gdi) {
void SaveMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
AutoMachine::save(oe, gdi, doProcess);
wstring minute=gdi.getText("Interval");
int t=convertAbsoluteTimeMS(minute);
@ -1193,23 +1308,83 @@ void SaveMachine::saveSettings(gdioutput &gdi) {
if (*f.rbegin() != '\\' && *f.rbegin() != '/')
f += L"\\";
wstring sample = f + L"sample.txt";
ofstream fout(sample.c_str(), ios_base::trunc|ios_base::out);
bool bad = false;
if (fout.bad())
bad = true;
else {
fout << "foo" << endl;
fout.close();
bad = fout.bad();
_wremove(sample.c_str());
}
if (bad)
throw meosException(L"Ogiltig destination X#" + f);
if (doProcess) {
wstring sample = f + L"sample.txt";
ofstream fout(sample.c_str(), ios_base::trunc | ios_base::out);
bool bad = false;
if (fout.bad())
bad = true;
else {
fout << "foo" << endl;
fout.close();
bad = fout.bad();
_wremove(sample.c_str());
}
if (bad)
throw meosException(L"Ogiltig destination X#" + f);
interval = t;
}
baseFile = f;
interval = t;
}
void TabAuto::clearCompetitionData() {
}
Machines AutoMachine::getType(const string &typeStr) {
if (typeStr == "onlineinput")
return Machines::mOnlineInput;
else if (typeStr == "onlineresults")
return Machines::mOnlineResults;
return Machines::Unknown;
}
string AutoMachine::getDescription(Machines type) {
switch (type) {
case mPrintResultsMachine:
return "Resultatutskrift / export";
case mPunchMachine:
return "Stämplingstest";
case mSplitsMachine:
return "Sträcktider (WinSplits)";
case mPrewarningMachine:
return "Förvarningsröst";
case mOnlineResults:
return "Resultat online";
case mOnlineInput:
return "Inmatning online";
case mSaveBackup:
return "Säkerhetskopiering";
case mInfoService:
return "Informationsserver";
case mMySQLReconnect:
return "MySQL reconnect";
default:
return "???";
}
}
string AutoMachine::getTypeString(Machines type) {
switch (type) {
case mPrintResultsMachine:
return "printresult";
case mPunchMachine:
return "punchtest";
case mSplitsMachine:
return "splits";
case mPrewarningMachine:
return "prewarning";
case mOnlineResults:
return "onlineresults";
case mOnlineInput:
return "onlineinput";
case mSaveBackup:
return "backup";
case mInfoService:
return "infoserver";
case mMySQLReconnect:
return "reconnect";
default:
return "???";
}
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -51,6 +51,14 @@ enum Machines {
class AutoMachine
{
public:
enum class State {
Edit,
Create,
Load
};
private:
int myid;
static int uniqueId;
@ -61,21 +69,47 @@ protected:
void settingsTitle(gdioutput &gdi, char *title);
enum IntervalType {IntervalNone, IntervalMinute, IntervalSecond};
void startCancelInterval(gdioutput &gdi, char *startCommand, bool created, IntervalType type, const wstring &interval);
void startCancelInterval(gdioutput &gdi, char *startCommand, State state, IntervalType type, const wstring &interval);
virtual bool hasSaveMachine() const {
return false;
}
public:
virtual void saveMachine(oEvent &oe, const wstring &guiInterval) {
}
virtual void loadMachine(oEvent &oe, const wstring &name) {
}
// Return true to auto-remove
virtual bool removeMe() const {
return false;
}
static AutoMachine *getMachine(int id);
static void resetGlobalId() {uniqueId = 1;}
int getId() const {return myid;}
static AutoMachine* construct(Machines);
static Machines getType(const string &typeStr);
static string getDescription(Machines type);
static string getTypeString(Machines type);
string getTypeString() const { return getTypeString(type); }
wstring getMachineName() const {
return machineName.empty() ? L"default" : machineName;
}
void setEditMode(bool em) {editMode = em;}
string name;
wstring machineName;
DWORD interval; //Interval seconds
DWORD timeout; //Timeout (TickCount)
bool synchronize;
bool synchronizePunches;
virtual void settings(gdioutput &gdi, oEvent &oe, bool created) = 0;
virtual void save(oEvent &oe, gdioutput &gdi) {}
virtual void settings(gdioutput &gdi, oEvent &oe, State state) = 0;
virtual void save(oEvent &oe, gdioutput &gdi, bool doProcess) = 0;
virtual void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) = 0;
virtual bool isEditMode() const {return editMode;}
virtual void status(gdioutput &gdi) = 0;
@ -119,9 +153,10 @@ public:
prm->errorLock = false;
return prm;
}
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void settings(gdioutput &gdi, oEvent &oe, bool created);
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
void settings(gdioutput &gdi, oEvent &oe, State state) final;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final;
void setHTML(const wstring &file, int timeout) {
exportFile = file;
@ -176,10 +211,10 @@ public:
return prm;
}
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void settings(gdioutput &gdi, oEvent &oe, bool created);
void saveSettings(gdioutput &gdi);
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
void settings(gdioutput &gdi, oEvent &oe, State state) final;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final;
SaveMachine():AutoMachine("Säkerhetskopiera", Machines::mSaveBackup) , saveIter(0) {
}
@ -194,10 +229,12 @@ protected:
set<int> controls;
set<int> controlsSI;
public:
void settings(gdioutput &gdi, oEvent &oe, bool created);
void settings(gdioutput &gdi, oEvent &oe, State state);
PrewarningMachine *clone() const {return new PrewarningMachine(*this);}
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final;
PrewarningMachine():AutoMachine("Förvarningsröst", Machines::mPrewarningMachine) {}
friend class TabAuto;
};
@ -210,12 +247,21 @@ protected:
wstring timeError;
wstring timeReconnect;
HANDLE hThread;
bool toRemove = false;
public:
void settings(gdioutput &gdi, oEvent &oe, bool created);
void settings(gdioutput &gdi, oEvent &oe, State state);
MySQLReconnect *clone() const {return new MySQLReconnect(*this);}
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
bool stop();
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final {
}
bool removeMe() const final {
return toRemove;
}
MySQLReconnect(const wstring &error);
virtual ~MySQLReconnect();
friend class TabAuto;
@ -230,9 +276,11 @@ protected:
int radio;
public:
PunchMachine *clone() const {return new PunchMachine(*this);}
void settings(gdioutput &gdi, oEvent &oe, bool created);
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void settings(gdioutput &gdi, oEvent &oe, State state) final;
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final;
PunchMachine():AutoMachine("Stämplingsautomat", Machines::mPunchMachine), radio(0) {}
friend class TabAuto;
};
@ -246,9 +294,11 @@ protected:
int leg;
public:
SplitsMachine *clone() const {return new SplitsMachine(*this);}
void settings(gdioutput &gdi, oEvent &oe, bool created);
void status(gdioutput &gdi);
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast);
void settings(gdioutput &gdi, oEvent &oe, State state) final;
void status(gdioutput &gdi) final;
void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) final;
void save(oEvent &oe, gdioutput &gdi, bool doProcess) final;
SplitsMachine() : AutoMachine("Sträcktider/WinSplits", Machines::mSplitsMachine), leg(-1) {}
friend class TabAuto;
};
@ -273,20 +323,22 @@ private:
void timerCallback(gdioutput &gdi);
void syncCallback(gdioutput &gdi);
void settings(gdioutput &gdi, AutoMachine *sm, Machines type);
void settings(gdioutput &gdi, AutoMachine *sm, AutoMachine::State state, Machines type);
protected:
void clearCompetitionData();
bool hasActiveReconnection() const;
public:
AutoMachine *getMachine(int id);
//AutoMachine *getMachine(const string &name);
bool stopMachine(AutoMachine *am);
void killMachines();
void addMachine(const AutoMachine &am) {
AutoMachine &addMachine(const AutoMachine &am) {
machines.push_back(am.clone());
setTimer(machines.back());
return *machines.back();
}
int processButton(gdioutput &gdi, const ButtonInfo &bu);
@ -305,8 +357,10 @@ public:
friend class AutoTask;
friend void tabForceSync(gdioutput &gdi, pEvent oe);
static void tabAutoKillMachines();
static void tabAutoRegister(TabAuto* ta);
static AutoMachine& tabAutoAddMachinge(const AutoMachine& am);
static bool hasActiveReconnectionMachine();
};
void tabAutoKillMachines();
void tabAutoRegister(TabAuto *ta);
void tabAutoAddMachinge(const AutoMachine &am);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -310,89 +310,94 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
else if (bi.id == "ShowForking") {
if (!checkClassSelected(gdi))
return false;
pClass pc=oe->getClass(ClassId);
pClass pc = oe->getClass(ClassId);
if (!pc)
throw std::exception("Klassen finns ej.");
vector< vector<int> > forks;
set< pair<int, int> > unfairLegs;
vector< vector<int> > legOrder;
pc->checkForking(legOrder, forks, unfairLegs);
gdioutput *gdi_new = getExtraWindow("fork", true);
wstring title = lang.tl(L"Forkings for X#" + pc->getName());
if (!gdi_new)
gdi_new = createExtraWindow("fork", title,
gdi.scaleLength(1024) );
gdi.scaleLength(1024));
else
gdi_new->setWindowTitle(title);
gdi_new->clearPage(false);
gdi_new->addString("", fontMediumPlus, "Forkings");
for (size_t k = 0; k < forks.size(); k++) {
gdi_new->dropLine(0.7);
wstring ver = itow(k+1) + L": ";
for (size_t j = 0; j < legOrder[k].size(); j++) {
pCourse crs = oe->getCourse(legOrder[k][j]);
if (crs) {
if (j>0)
ver += L", ";
ver += crs->getName();
}
}
gdi_new->addStringUT(1, ver);
gdi_new->pushX();
gdi_new->fillRight();
for (size_t j = 0; j < forks[k].size(); j++) {
wstring ctrl;
if (forks[k][j] > 0)
ctrl += itow(forks[k][j]);
else {
if (j == 0)
ctrl += lang.tl("Start");
else if (j + 1 == forks[k].size())
ctrl += lang.tl("Mål");
else
ctrl += lang.tl("Växel");
}
int next = -100;
if (j + 1 < forks[k].size()) {
ctrl += L",";
next = forks[k][j+1];
}
int prev = j>0 ? forks[k][j-1] : -100;
bool warn = unfairLegs.count(make_pair(prev, forks[k][j])) != 0;// ||
//unfairLegs.count(make_pair(forks[k][j], next)) != 0;
TextInfo &ti = gdi_new->addStringUT(italicText, ctrl);
if (warn) {
ti.setColor(colorRed);
ti.format = boldText;
}
gdi.setCX(gdi.getCX() - gdi.scaleLength(4));
}
gdi_new->popX();
gdi_new->fillDown();
gdi_new->dropLine();
if (pc->hasCoursePool()) {
gdi_new->addString("", fontMediumPlus, "Klassen använder banpool");
}
else {
vector< vector<int> > forks;
set< pair<int, int> > unfairLegs;
vector< vector<int> > legOrder;
if (!unfairLegs.empty()) {
gdi_new->dropLine();
gdi_new->addString("", fontMediumPlus, "Unfair control legs");
gdi_new->dropLine(0.5);
for (set< pair<int, int> >::const_iterator p = unfairLegs.begin();
p != unfairLegs.end(); ++p) {
pc->checkForking(legOrder, forks, unfairLegs);
wstring f = p->first > 0 ? itow(p->first) : lang.tl("Växel");
wstring s = p->second > 0 ? itow(p->second) : lang.tl("Växel");
gdi_new->addStringUT(0, makeDash(f + L" - " + s));
gdi_new->addString("", fontMediumPlus, "Forkings");
for (size_t k = 0; k < forks.size(); k++) {
gdi_new->dropLine(0.7);
wstring ver = itow(k + 1) + L": ";
for (size_t j = 0; j < legOrder[k].size(); j++) {
pCourse crs = oe->getCourse(legOrder[k][j]);
if (crs) {
if (j > 0)
ver += L", ";
ver += crs->getName();
}
}
gdi_new->addStringUT(1, ver);
gdi_new->pushX();
gdi_new->fillRight();
for (size_t j = 0; j < forks[k].size(); j++) {
wstring ctrl;
if (forks[k][j] > 0)
ctrl += itow(forks[k][j]);
else {
if (j == 0)
ctrl += lang.tl("Start");
else if (j + 1 == forks[k].size())
ctrl += lang.tl("Mål");
else
ctrl += lang.tl("Växel");
}
int next = -100;
if (j + 1 < forks[k].size()) {
ctrl += L",";
next = forks[k][j + 1];
}
int prev = j > 0 ? forks[k][j - 1] : -100;
bool warn = unfairLegs.count(make_pair(prev, forks[k][j])) != 0;// ||
//unfairLegs.count(make_pair(forks[k][j], next)) != 0;
TextInfo &ti = gdi_new->addStringUT(italicText, ctrl);
if (warn) {
ti.setColor(colorRed);
ti.format = boldText;
}
gdi.setCX(gdi.getCX() - gdi.scaleLength(4));
}
gdi_new->popX();
gdi_new->fillDown();
gdi_new->dropLine();
}
if (!unfairLegs.empty()) {
gdi_new->dropLine();
gdi_new->addString("", fontMediumPlus, "Unfair control legs");
gdi_new->dropLine(0.5);
for (set< pair<int, int> >::const_iterator p = unfairLegs.begin();
p != unfairLegs.end(); ++p) {
wstring f = p->first > 0 ? itow(p->first) : lang.tl("Växel");
wstring s = p->second > 0 ? itow(p->second) : lang.tl("Växel");
gdi_new->addStringUT(0, makeDash(f + L" - " + s));
}
}
}
gdi_new->dropLine();
gdi_new->addButton("CloseWindow", "Stäng", ClassesCB);
gdi_new->refresh();
@ -1923,7 +1928,37 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
gdi.refresh();
return 0;
}
else if (bi.id=="Split") {
else if (bi.id == "Duplicate") {
save(gdi, true);
if (!checkClassSelected(gdi))
return false;
pClass pc = oe->getClass(ClassId);
if (!pc)
throw std::exception("Class not found");
oClass copyClass(*pc);
copyClass.clearDuplicate();
wstring name = pc->getName();
wstring dup = lang.tl(" (kopia)");
size_t pos = name.find(dup);
wstring base;
if (pos > 0 && pos < string::npos)
base = name.substr(0, pos);
else
base = name;
name = base + dup;
int cnt = 1;
while (oe->getClass(name) != nullptr)
name = base + dup + L" " + itow(++cnt);
copyClass.setName(name, true);
pc = oe->addClass(copyClass);
oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone);
selectClass(gdi, pc->getId());
gdi.setInputFocus("Name", true);
}
else if (bi.id == "Split") {
save(gdi, true);
if (!checkClassSelected(gdi))
return false;
@ -3463,7 +3498,7 @@ bool TabClass::loadPage(gdioutput &gdi)
func.push_back(ButtonData("Merge", "Slå ihop klasser...", false));
func.push_back(ButtonData("Split", "Dela klassen...", false));
}
func.emplace_back("Duplicate", "Duplicera", false);
if (showAdvanced && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) {
vector<pRunner> rr;
@ -4185,11 +4220,18 @@ void TabClass::selectCourses(gdioutput &gdi, int legNo) {
void TabClass::updateFairForking(gdioutput &gdi, pClass pc) const {
if (!gdi.hasWidget("FairForking"))
return;
BaseInfo *bi = gdi.setText("FairForking", gdi.getText("FairForking"), false);
TextInfo &text = dynamic_cast<TextInfo &>(*bi);
if (pc->hasCoursePool()) {
text.setColor(colorBlack);
gdi.setText("FairForking", L"", true);
return;
}
vector< vector<int> > forks;
vector< vector<int> > forksC;
set< pair<int, int> > unfairLegs;
BaseInfo *bi = gdi.setText("FairForking", gdi.getText("FairForking"), false);
TextInfo &text = dynamic_cast<TextInfo &>(*bi);
if (pc->checkForking(forksC, forks, unfairLegs)) {
text.setColor(colorGreen);
gdi.setText("FairForking", lang.tl("The forking is fair."), true);

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -157,8 +157,8 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
{
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"xml-data", L"*.xml;*.bu?"));
wstring fileName = gdi.browseForOpen(ext, L"xml");
ext.push_back(make_pair(L"MeOS-data", L"*.meosxml;*.xml;*.bu?"));
wstring fileName = gdi.browseForOpen(ext, L"meosxml");
if (fileName.empty())
return false;
@ -182,8 +182,8 @@ bool TabCompetition::exportFileAs(HWND hWnd, gdioutput &gdi)
{
int ix = 0;
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"xml-data", L"*.xml"));
wstring fileName = gdi.browseForSave(ext, L"xml", ix);
ext.push_back(make_pair(L"MeOS-data", L"*.meosxml"));
wstring fileName = gdi.browseForSave(ext, L"meosxml", ix);
if (fileName.empty())
return false;
@ -779,7 +779,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
wstring base = constructBase(L"base", L"");
wchar_t newBase[_MAX_PATH];
getUserFile(newBase, base.c_str());
if (!fileExist(newBase))
if (!fileExists(newBase))
oe->save(newBase);
loadConnectionPage(gdi);
@ -2382,7 +2382,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
gdi.dropLine(0.4);
gdi.fillDown();
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2020 Melin Software HB"));
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2021 Melin Software HB"));
gdi.dropLine(1);
gdi.popX();
@ -2412,7 +2412,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
gdi.dropLine(1.5);
gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2020 Melin Software HB"));
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2021 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,"
@ -2764,7 +2764,7 @@ void TabCompetition::textSizeControl(gdioutput &gdi) const
}
int TabCompetition::getOrganizer(bool updateEvent) {
wstring apikey = oe->getPropertyStringDecrypt("apikey", "");
wstring apikey = gdioutput::widen(oe->getPropertyStringDecrypt("apikey", ""));
if (apikey.empty())
return 0;
if (!isAscii(apikey))
@ -2837,7 +2837,7 @@ int TabCompetition::getOrganizer(bool updateEvent) {
}
void TabCompetition::getAPIKey(vector< pair<wstring, wstring> > &key) const {
wstring apikey = oe->getPropertyStringDecrypt("apikey", "");
wstring apikey = gdioutput::widen(oe->getPropertyStringDecrypt("apikey", ""));
if (apikey.empty() || organizorId == 0)
throw std::exception("Internal error");
@ -2989,7 +2989,7 @@ void TabCompetition::getEventorCmpData(gdioutput &gdi, int id,
pw.setProgress(1);
vector< pair<wstring, wstring> > key;
wstring apikey = oe->getPropertyStringDecrypt("apikey", "");
wstring apikey = gdioutput::widen(oe->getPropertyStringDecrypt("apikey", ""));
key.push_back(pair<wstring, wstring>(L"ApiKey", apikey));
gdi.fillRight();

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -108,10 +108,10 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
gdi.enableEditControls(true);
oControl::ControlStatus st = pc->getStatus();
if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming)
if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
gdi.disableInput("MinTime");
if (st == oControl::StatusNoTiming)
if (st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
gdi.disableInput("TimeAdjust");
if (gdi.hasWidget("Point") && st != oControl::StatusRogaining)
@ -164,7 +164,7 @@ void TabControl::save(gdioutput &gdi)
pc->setStatus(oControl::ControlStatus(gdi.getSelectedItem("Status").first));
pc->setTimeAdjust(gdi.getText("TimeAdjust"));
if (pc->getStatus() != oControl::StatusRogaining) {
if (pc->getStatus() != oControl::StatusNoTiming)
if (pc->getStatus() != oControl::StatusNoTiming && pc->getStatus() != oControl::StatusBadNoTiming)
pc->setMinTime(gdi.getText("MinTime"));
pc->setRogainingPoints(0);
}
@ -416,9 +416,9 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
selectControl(gdi, pc);
}
else if (bi.id == "Status" ) {
gdi.setInputStatus("MinTime", bi.data != oControl::StatusRogaining && bi.data != oControl::StatusNoTiming, true);
gdi.setInputStatus("MinTime", bi.data != oControl::StatusRogaining && bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
gdi.setInputStatus("Point", bi.data == oControl::StatusRogaining, true);
gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming, true);
gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
}
}
else if (type==GUI_CLEAR) {

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -543,7 +543,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
if (!htmlTarget.empty()) {
prm.setHTML(htmlTarget, currentList.getParam().timePerPage / 1000);
}
tabAutoAddMachinge(prm);
TabAuto::tabAutoAddMachinge(prm);
dynamic_cast<TabAuto *>(gdi.getTabs().get(TAutoTab))->loadPage(gdi, true);
}
else if (bi.id == "WideFormat") {

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -26,6 +26,8 @@
#include <commctrl.h>
#include <commdlg.h>
#include <MMSystem.h>
#include <algorithm>
#include "oEvent.h"
@ -134,7 +136,83 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
allowControl = gdi.isChecked(bi.id);
else if (bi.id == "AllowFinish")
allowFinish = gdi.isChecked(bi.id);
if (bi.id == "ClearMemory") {
else if (bi.id == "PlaySound") {
oe->setProperty("PlaySound", gdi.isChecked(bi.id) ? 1 : 0);
}
else if (bi.id == "SoundChoice") {
gdi.disableInput("SoundChoice");
gdi.setRestorePoint("Sound");
gdi.dropLine();
gdi.fillDown();
gdi.addString("", fontMediumPlus, "help:selectsound");
gdi.dropLine(0.5);
gdi.pushX();
gdi.fillRight();
auto addSoundWidget = [&gdi, this](const wchar_t *name, SND type, const wstring &label) {
string nname = gdioutput::narrow(name);
gdi.addInput(nname, oe->getPropertyString(nname.c_str(), L""), 32, nullptr, label);
gdi.dropLine(0.8);
gdi.addButton("BrowseSound", "Bläddra...", SportIdentCB).setExtra(name);
gdi.addButton("TestSound", "Testa", SportIdentCB).setExtra(int(type));
gdi.dropLine(3);
gdi.popX();
};
addSoundWidget(L"SoundOK", SND::OK, L"Status OK:");
addSoundWidget(L"SoundNotOK", SND::NotOK, L"Status inte OK (röd utgång):");
addSoundWidget(L"SoundLeader", SND::Leader, L"Ny ledare i klassen:");
addSoundWidget(L"SoundAction", SND::ActionNeeded, L"Åtgärd krävs:");
gdi.addButton("CloseSound", "OK", SportIdentCB);
gdi.popX();
gdi.dropLine(3);
gdi.scrollToBottom();
gdi.refresh();
/*
fn = oe->getPropertyString("SoundOK", L"");
res = 50;
break;
case SND::NotOK:
fn = oe->getPropertyString("SoundNotOK", L"");
res = 52;
break;
case SND::Leader:
fn = oe->getPropertyString("SoundLeader", L"");
res = 51;
break;
case SND::ActionNeeded:
fn = oe->getPropertyString("SoundAction", L"");
*/
}
else if (bi.id == "BrowseSound") {
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"Ljud (wav)", L"*.wav"));
wstring file = gdi.browseForOpen(ext, L"wav");
if (!file.empty()) {
wchar_t *type = bi.getExtra();
string name = gdioutput::narrow(type);
gdi.setText(name, file);
oe->setProperty(name.c_str(), file);
}
}
else if (bi.id == "SoundOK" || bi.id == "SoundNotOK" ||
bi.id == "SoundLeader" || bi.id == "SoundAction") {
oe->setProperty(bi.id.c_str(), bi.text);
}
else if (bi.id == "TestSound") {
oe->setProperty("PlaySound", 1);
gdi.check(bi.id, true);
playReadoutSound(SND(bi.getExtraInt()));
}
else if (bi.id == "CloseSound") {
gdi.restore("Sound", true);
gdi.enableInput("SoundChoice");
}
else if (bi.id == "ClearMemory") {
if (gdi.ask(L"Do you want to clear the card memory?")) {
savedCards.clear();
loadPage(gdi);
@ -1678,7 +1756,7 @@ void TabSI::showReadCards(gdioutput &gdi, vector<SICard> &cards)
SportIdent &TabSI::getSI(const gdioutput &gdi) {
if (!gSI) {
HWND hWnd=gdi.getHWNDMain();
gSI = new SportIdent(hWnd, 0, gEvent->getPropertyInt("ReadVoltageExp", 0) != 0);
gSI = new SportIdent(hWnd, 0, true);
}
return *gSI;
}
@ -1787,11 +1865,19 @@ bool TabSI::loadPage(gdioutput &gdi) {
gdi.selectItemByData("ReadType", mode);
gdi.dropLine(-0.1);
gdi.addButton("LockFunction", "Lås funktion...", SportIdentCB);
gdi.addButton("LockFunction", "Lås funktion", SportIdentCB);
readoutFunctionX = gdi.getCX();
readoutFunctionY = gdi.getCY();
gdi.dropLine(0.3);
gdi.addCheckbox("PlaySound", "Ljud", SportIdentCB, oe->getPropertyInt("PlaySound", 1) != 0,
"Spela upp ett ljud för att indikera resultatet av brickavläsningen.");
gdi.dropLine(-0.3);
gdi.addButton("SoundChoice", "Ljudval...", SportIdentCB);
gdi.dropLine(0.3);
gdi.addString("Allow", 0, "Tillåt:");
gdi.addCheckbox("AllowStart", "Start", SportIdentCB, allowStart);
gdi.addCheckbox("AllowControl", "Radio", SportIdentCB, allowControl);
@ -1883,6 +1969,8 @@ void TabSI::updateReadoutFunction(gdioutput &gdi) {
gdi.hideWidget("AllowStart", hide);
gdi.hideWidget("AllowControl", hide);
gdi.hideWidget("AllowFinish", hide);
gdi.hideWidget("SoundChoice", hide);
gdi.hideWidget("PlaySound", hide);
}
void InsertSICard(gdioutput &gdi, SICard &sic)
@ -2054,6 +2142,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
return;
}
gEvent->synchronizeList({ oListId::oLCardId, oListId::oLRunnerId });
if (sic.punchOnly) {
@ -2092,6 +2181,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
else {
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"info:readout_action#" + gEvent->getCurrentTimeS()+L"#"+itow(sic.CardNumber), 0, SportIdentCB);
playReadoutSound(SND::ActionNeeded);
return;
}
}
@ -2099,8 +2189,10 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
if (!readBefore) {
if (r && r->getClassId(false) && !sameCardNewRace)
processCard(gdi, r, sic, true);
else
else {
processUnmatched(gdi, sic, true);
playReadoutSound(SND::ActionNeeded);
}
}
else
gdi.addInfoBox("SIREAD", L"Brickan redan inläst.", 0, SportIdentCB);
@ -2126,6 +2218,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
name = itow(sic.CardNumber) + name;
CardQueue.push_back(sic);
gdi.addInfoBox("SIREAD", L"info:readout_queue#" + gEvent->getCurrentTimeS() + L"#" + name);
playReadoutSound(SND::ActionNeeded);
return;
}
@ -2166,6 +2259,7 @@ void TabSI::insertSICardAux(gdioutput &gdi, SICard &sic)
gdi.scrollToBottom();
gdi.refresh();
activeSIC.clear(0);
playReadoutSound(SND::ActionNeeded);
checkMoreCardsInQueue(gdi);
return;
}
@ -2422,7 +2516,7 @@ bool TabSI::processUnmatched(gdioutput &gdi, const SICard &csic, bool silent)
gdi.addInfoBox("SIINFO", L"#" + info, 10000);
}
gdi.makeEvent("DataUpdate", "sireadout", 0, 0, true);
playReadoutSound(SND::ActionNeeded);
checkMoreCardsInQueue(gdi);
return true;
}
@ -2619,6 +2713,11 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
runner->getTeam()->getLegPlaceS(runner->getLegNumber(), false) :
runner->getPlaceS();
if (placeS == L"1")
playReadoutSound(SND::Leader);
else
playReadoutSound(SND::OK);
if (!silent) {
gdi.fillDown();
//gdi.dropLine();
@ -2651,6 +2750,8 @@ bool TabSI::processCard(gdioutput &gdi, pRunner runner, const SICard &csic, bool
else {
wstring msg=lang.tl(L"Status: ") + runner->getStatusS(true, true);
playReadoutSound(SND::NotOK);
if (!MP.empty()) {
msg=msg + L", (";
vector<int>::iterator it;
@ -4258,7 +4359,49 @@ void TabSI::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
gdi.TabFocus(1);
}
bool TabSI::showDatabase() const {
return useDatabase && oe->useRunnerDb();
}
void TabSI::playReadoutSound(SND type) {
if (!oe->getPropertyInt("PlaySound", 0))
return;
int res = -1;
wstring fn;
switch (type) {
case SND::OK:
fn = oe->getPropertyString("SoundOK", L"");
res = 50;
break;
case SND::NotOK:
fn = oe->getPropertyString("SoundNotOK", L"");
res = 52;
break;
case SND::Leader:
fn = oe->getPropertyString("SoundLeader", L"");
res = 51;
break;
case SND::ActionNeeded:
fn = oe->getPropertyString("SoundAction", L"");
res = 53;
break;
}
if (checkedSound.count(fn) || (!fn.empty() && fileExists(fn))) {
playSoundFile(fn);
checkedSound.insert(fn);
}
else {
playSoundResource(res);
}
}
void TabSI::playSoundResource(int res) const {
PlaySound(MAKEINTRESOURCE(res), GetModuleHandle(nullptr), SND_RESOURCE| SND_ASYNC);
//OutputDebugString((L"Play: " + itow(res)).c_str());
}
void TabSI::playSoundFile(const wstring& file) const {
PlaySound(file.c_str(), nullptr, SND_FILENAME | SND_ASYNC);
//OutputDebugString(file.c_str());
}

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -68,6 +68,17 @@ private:
list< pair<unsigned, int> > printPunchRunnerIdQueue;
void addToPrintQueue(pRunner r);
enum class SND {
OK,
Leader,
NotOK,
ActionNeeded
};
set<wstring> checkedSound;
void playReadoutSound(SND type);
vector<PunchInfo> punches;
vector<SICard> cards;
vector<wstring> filterDate;
@ -206,6 +217,8 @@ private:
int readoutFunctionX = 0;
int readoutFunctionY = 0;
void playSoundResource(int res) const;
void playSoundFile(const wstring& file) const;
protected:
void clearCompetitionData();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -1102,7 +1102,7 @@ bool TabSpeaker::loadPage(gdioutput &gdi) {
if (getExtraWindows().size() == 1) {
wstring sf = getSpeakerSettingsFile();
if (fileExist(sf.c_str())) {
if (fileExists(sf)) {
if ((cx + db) > basex && (cx + db + bw) >= limitX) {
cx = basex; db = 0;
cy += gdi.getButtonHeight() + 4;

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -1908,13 +1908,17 @@ void TabTeam::processChangeRunner(gdioutput &gdi, pTeam t, int leg, pRunner r) {
void TabTeam::switchRunners(pTeam t, int leg, pRunner r, pRunner oldR) {
vector<int> mp;
bool removeAnnonumousTeamMember = false;
int crsIdR = r->getCourseId();
int crsIdROld = oldR ? oldR->getCourseId() : 0;
if (r->getTeam()) {
pTeam otherTeam = r->getTeam();
int otherLeg = r->getLegNumber();
otherTeam->setRunner(otherLeg, oldR, true);
if (oldR)
if (oldR) {
oldR->setCourseId(crsIdR);
oldR->evaluateCard(true, mp, 0, oBase::ChangeType::Update);
}
otherTeam->checkValdParSetup();
otherTeam->apply(oBase::ChangeType::Update, nullptr);
otherTeam->synchronize(true);
@ -1927,11 +1931,13 @@ void TabTeam::switchRunners(pTeam t, int leg, pRunner r, pRunner oldR) {
else
oldR->setClassId(r->getClassId(false), true);
removeAnnonumousTeamMember = oldR->isAnnonumousTeamMember();
oldR->setCourseId(crsIdR);
oldR->evaluateCard(true, mp, 0, oBase::ChangeType::Update);
oldR->synchronize(true);
}
t->setRunner(leg, r, true);
r->setCourseId(crsIdROld);
r->evaluateCard(true, mp, 0, oBase::ChangeType::Update);
t->checkValdParSetup();
t->apply(oBase::ChangeType::Update, nullptr);

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -90,10 +90,8 @@ Table::~Table(void)
}
void Table::clearCellSelection(gdioutput *gdi) {
upperRow = -1;
lowerRow = -1;
upperCol = -1;
lowerCol = -1;
sel.reset();
selScreen.reset();
if (gdi) {
HDC hDC = GetDC(gdi->getHWNDTarget());
clearSelectionBitmap(gdi, hDC);
@ -183,6 +181,7 @@ void Table::addRow(int rowId, oBase *object)
return;
}
dataRowToIndex.clear();
TableRow tr(nTitles, object);
tr.height=rowHeight;
tr.id = rowId;
@ -244,7 +243,9 @@ void Table::filter(int col, const wstring &filt, bool forceFilter)
if (filt==oldFilter && (!forceFilter || filt.empty()))
return;
else if (wcsncmp(oldFilter.c_str(), filt.c_str(), oldFilter.length())==0) {
dataRowToIndex.clear();
if (wcsncmp(oldFilter.c_str(), filt.c_str(), oldFilter.length())==0) {
if (sortIndex.empty())
return;
//Filter more...
@ -252,6 +253,7 @@ void Table::filter(int col, const wstring &filt, bool forceFilter)
baseIndex[0]=sortIndex[0];
baseIndex[1]=sortIndex[1];
swap(baseIndex, sortIndex);
sortIndex.reserve(baseIndex.size());
Titles[col].filter=filt;
}
else {
@ -293,16 +295,20 @@ bool Table::compareRow(int indexA, int indexB) const {
//return Data[indexA].key < Data[indexB].key;
}
void Table::sort(int col)
void Table::sort(int col, bool forceDirection)
{
int origCol = col;
bool reverse = col < 0;
if (col < 0)
col = -(10+col);
if (sortIndex.size()<2)
return;
dataRowToIndex.clear();
currentSortColumn=col;
if (PrevSort!=col && PrevSort!=-(10+col)) {
if (forceDirection || (PrevSort!=col && PrevSort!=-(10+col))) {
if (Titles[col].isnumeric) {
bool hasDeci = false;
for(size_t k=2; k<sortIndex.size(); k++){
@ -420,7 +426,7 @@ void Table::sort(int col)
//DWORD sEnd = GetTickCount();
//string st = itos(sEnd-sStart);
TableSortIndex::table = 0;
PrevSort=col;
PrevSort = origCol;
if (reverse)
std::reverse(sortIndex.begin()+2, sortIndex.end());
@ -434,7 +440,7 @@ void Table::sort(int col)
PrevSort=col;
}
}
/*
int TablesCB(gdioutput *gdi, int type, void *data) {
if (type!=GUI_LINK || gdi->Tables.empty())
return 0;
@ -451,7 +457,7 @@ int TablesCB(gdioutput *gdi, int type, void *data) {
gdi->refresh();
return 0;
}
}*/
void Table::getDimension(gdioutput &gdi, int &dx, int &dy, bool filteredResult) const
{
@ -507,7 +513,7 @@ void Table::restoreCell(HDC hDC, const TableCell &cell)
}
}
void Table::moveCell(HDC hDC, gdioutput &gdi, const TableCell &cell, int dx, int dy)
void Table::moveCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, int dx, int dy)
{
RECT rc=cell.absPos;
rc.left+=dx; rc.right+=dx;
@ -526,7 +532,7 @@ void Table::moveCell(HDC hDC, gdioutput &gdi, const TableCell &cell, int dx, int
dx=0;
dy=0;
}
highlightCell(hDC, gdi, cell, RGB(255, 0,0), dx, dy);
highlightCell(hDC, gdi, col, cell, RGB(255, 0,0), dx, dy);
}
void Table::stopMoveCell(HDC hDC, const TableCell &cell, int dx, int dy)
@ -554,94 +560,94 @@ void Table::stopMoveCell(HDC hDC, const TableCell &cell, int dx, int dy)
bool Table::mouseMove(gdioutput &gdi, int x, int y)
{
int row=getRow(y);
int col=-1;
int row = getRow(y);
int col = -1;
if (row!=-1)
col=getColumn(x);
if (row != -1)
col = getColumn(x);
HWND hWnd=gdi.getHWNDTarget();
HWND hWnd = gdi.getHWNDTarget();
if (colSelected!=-1) {
TableCell &cell=Data[0].cells[colSelected];
HDC hDC=GetDC(hWnd);
if (colSelected != -1) {
TableCell &cell = Data[0].cells[colSelected];
HDC hDC = GetDC(hWnd);
restoreCell(hDC, cell);
if (col!=highCol) {
if (unsigned(highRow)<Data.size() && unsigned(highCol)<nTitles)
if (col != highCol) {
if (unsigned(highRow) < Data.size() && unsigned(highCol) < nTitles)
redrawCell(gdi, hDC, highCol, highRow);
DWORD c=RGB(240, 200, 140);
if (unsigned(col)<nTitles)
highlightCell(hDC, gdi, Data[0].cells[col], c, 0,0);
DWORD c = RGB(240, 220, 180);
if (unsigned(col) < nTitles)
highlightCell(hDC, gdi, col, Data[0].cells[col], c, 0, 0);
}
//highlightCell(hDC, cell, RGB(255,0,0), x-startX, y-startY);
moveCell(hDC, gdi, cell, x-startX, y-startY);
moveCell(hDC, gdi, colSelected, cell, x - startX, y - startY);
ReleaseDC(hWnd, hDC);
highRow=0;
highCol=col;
highRow = 0;
highCol = col;
return false;
}
RECT rc;
GetClientRect(hWnd, &rc);
if (x<=rc.left || x>=rc.right || y<rc.top || y>rc.bottom)
row=-1;
if (x <= rc.left || x >= rc.right || y<rc.top || y>rc.bottom)
row = -1;
bool ret = false;
if (startSelect) {
int c = getColumn(x, true);
if (c != -1)
upperCol = c;
sel.upperCol = c, selScreen.upperCol = -1;
c = getRow(y, true);
if (c != -1 && c>=0) {
upperRow = max<int>(c, 2);
if (c != -1 && c >= 0) {
sel.upperRow = max<int>(c, 2), selScreen.upperRow = -1;
}
HDC hDC=GetDC(hWnd);
if (unsigned(highRow)<Data.size() && unsigned(highCol)<Titles.size())
HDC hDC = GetDC(hWnd);
if (unsigned(highRow) < Data.size() && unsigned(highCol) < Titles.size())
redrawCell(gdi, hDC, highCol, highRow);
highRow = -1;
drawSelection(gdi, hDC, false);
ReleaseDC(hWnd, hDC);
scrollToCell(gdi, upperRow, upperCol);
scrollToCell(gdi, sel.upperRow, sel.upperCol);
ret = true;
}
else if (row>=0 && col>=0) {
POINT pt = {x, y};
else if (row >= 0 && col >= 0) {
POINT pt = { x, y };
ClientToScreen(hWnd, &pt);
HWND hUnder = WindowFromPoint(pt);
if (hUnder == hWnd) {
//int index=sortIndex[row].index;
TableRow &trow=Data[row];
TableCell &cell=trow.cells[col];
TableRow &trow = Data[row];
TableCell &cell = trow.cells[col];
if (highRow!=row || highCol!=col) {
if (highRow != row || highCol != col) {
HDC hDC=GetDC(hWnd);
HDC hDC = GetDC(hWnd);
if (unsigned(highRow)<Data.size() && unsigned(highCol)<Titles.size())
if (unsigned(highRow) < Data.size() && unsigned(highCol) < Titles.size())
redrawCell(gdi, hDC, highCol, highRow);
if (row >= 2) {
DWORD c;
if (cell.canEdit)
c=RGB(240, 240, 150);
c = RGB(240, 240, 150);
else
c=RGB(240, 200, 140);
c = RGB(240, 200, 140);
highlightCell(hDC, gdi, cell, c, 0,0);
highlightCell(hDC, gdi, col, cell, c, 0, 0);
}
ReleaseDC(hWnd, hDC);
SetCapture(hWnd);
highCol=col;
highRow=row;
highCol = col;
highRow = row;
}
ret = true;
}
@ -650,33 +656,33 @@ bool Table::mouseMove(gdioutput &gdi, int x, int y)
if (ret)
return true;
if (unsigned(highRow)<Data.size() && unsigned(highCol)<Titles.size()) {
if (unsigned(highRow) < Data.size() && unsigned(highCol) < Titles.size()) {
ReleaseCapture();
HDC hDC=GetDC(hWnd);
HDC hDC = GetDC(hWnd);
redrawCell(gdi, hDC, highCol, highRow);
ReleaseDC(hWnd, hDC);
highRow=-1;
highRow = -1;
}
return false;
}
bool Table::mouseLeftUp(gdioutput &gdi, int x, int y)
{
if (colSelected!=-1) {
if (colSelected != -1) {
if (hdcCompatible) {
TableCell &cell=Data[0].cells[colSelected];
HWND hWnd=gdi.getHWNDTarget();
HDC hDC=GetDC(hWnd);
stopMoveCell(hDC, cell, x-startX, y-startY);
TableCell &cell = Data[0].cells[colSelected];
HWND hWnd = gdi.getHWNDTarget();
HDC hDC = GetDC(hWnd);
stopMoveCell(hDC, cell, x - startX, y - startY);
ReleaseDC(hWnd, hDC);
//return true;
}
if (highRow==0 && colSelected==highCol) {
colSelected=-1;
if (highRow == 0 && colSelected == highCol) {
colSelected = -1;
gdi.setWaitCursor(true);
sort(highCol);
sort(highCol, false);
gdi.setWaitCursor(false);
gdi.refresh();
mouseMove(gdi, x, y);
@ -685,22 +691,22 @@ bool Table::mouseLeftUp(gdioutput &gdi, int x, int y)
else {
moveColumn(colSelected, highCol);
InvalidateRect(gdi.getHWNDTarget(), 0, false);
colSelected=-1;
colSelected = -1;
return true;
}
}
else {
upperCol = getColumn(x);
upperRow = getRow(y);
sel.upperCol = getColumn(x), selScreen.upperCol = -1;
sel.upperRow = getRow(y), selScreen.upperRow = -1;
startSelect = false;
ReleaseCapture();
gdi.refreshFast();
}
colSelected=-1;
colSelected = -1;
return false;
}
int tblSelectionCB(gdioutput *gdi, int type, void *data)
{
int tblSelectionCB(gdioutput *gdi, int type, void *data) {
if (type == GUI_LISTBOX) {
ListBoxInfo lbi = *static_cast<ListBoxInfo *>(data);
Table &t = gdi->getTable();
@ -744,9 +750,18 @@ bool Table::keyCommand(gdioutput &gdi, KeyCommandCode code) {
exportClipboard(gdi);
else if (code == KC_PASTE && hEdit == 0) {
importClipboard(gdi);
}else if (code == KC_DELETE && hEdit == 0) {
}
else if (code == KC_DELETE && hEdit == 0) {
deleteSelection(gdi);
}
else if (code == KC_MARKALL && hEdit == 0) {
markAll(true);
gdi.refresh();
}
else if (code == KC_CLEARALL && hEdit == 0) {
markAll(false);
gdi.refresh();
}
else if (code == KC_REFRESH) {
gdi.setWaitCursor(true);
update();
@ -858,14 +873,11 @@ bool Table::mouseLeftDown(gdioutput &gdi, int x, int y) {
colSelected=highCol;
startX=x;
startY=y;
//sort(highCol);
//gdi.refresh();
//mouseMove(gdi, x, y);
}
else if (highRow==1) {
//filter(highCol, "lots");
showFilter(gdi);
/*
RECT rc=Data[1].cells[columns[0]].absPos;
//rc.right=rc.left+tableWidth;
editRow=highRow;
editCol=highCol;
@ -877,18 +889,158 @@ bool Table::mouseLeftDown(gdioutput &gdi, int x, int y) {
SendMessage(hEdit, EM_SETSEL, 0, -1);
SetFocus(hEdit);
SendMessage(hEdit, WM_SETFONT, (WPARAM) gdi.getGUIFont(), 0);
gdi.refresh();
gdi.refresh();*/
}
else {
SetFocus(gdi.getHWNDTarget());
SetCapture(gdi.getHWNDTarget());
lowerCol = getColumn(x);
lowerRow = getRow(y);
sel.lowerCol = getColumn(x), selScreen.lowerCol = -1;
sel.lowerRow = getRow(y), selScreen.lowerRow = -1;
startSelect = true;
}
return false;
}
void Table::showFilter(gdioutput &gdi) {
RECT rc = Data[1].cells[columns[0]].absPos;
editRow = 1;
editCol = highCol;
hEdit = CreateWindowEx(0, L"EDIT", Titles[highCol].filter.c_str(),
WS_TABSTOP | WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_BORDER,
rc.left + 105, rc.top, tableWidth - 105, (rc.bottom - rc.top - 1), gdi.getHWNDTarget(),
0, hInst, 0);
drawFilterLabel = true;
SendMessage(hEdit, EM_SETSEL, 0, -1);
SetFocus(hEdit);
SendMessage(hEdit, WM_SETFONT, (WPARAM)gdi.getGUIFont(), 0);
gdi.refresh();
}
bool Table::mouseRightDown(gdioutput &gdi, int x, int y) {
//partialCell = true;
//clearCellSelection(&gdi);
if (!destroyEditControl(gdi))
return false;
if (highRow == 0) {
colSelected = highCol;
}
// lowerCol = getColumn(x);
// lowerRow = getRow(y);
return false;
}
bool Table::mouseRightUp(gdioutput &gdi, int x, int y) {
if (highRow == 0 && colSelected == highCol) {
colSelected = -1;
vector<pair<wstring, int>> menu;
menu.emplace_back(L"Sortera stigande", 1);
menu.emplace_back(L"Sortera fallande", 2);
menu.emplace_back(L"", 0);
menu.emplace_back(L"Markera kolumn", 3);
menu.emplace_back(L"Filtrera", 5);
menu.emplace_back(L"Dölj", 4);
int res = gdi.popupMenu(x, y, menu);
switch (res) {
case 2: {
sort(-(highCol+10), true);
gdi.refresh();
break;
}
case 1: {
sort(highCol, true);
gdi.refresh();
break;
}
case 3: {
int col = highCol;
if (isFullColumnSelected()) {
sel.upperCol = max({ sel.upperCol, sel.lowerCol, col });
sel.lowerCol = min({ sel.upperCol, sel.lowerCol, col });
}
else {
sel.upperCol = sel.lowerCol = col;
}
if (sortIndex.size() > 2) {
sel.upperRow = sortIndex[2].index;
sel.lowerRow = sortIndex[sortIndex.size()-1].index;
}
selScreen.reset();
gdi.refresh();
break;
}
case 4:
columns.erase(find(columns.begin(), columns.end(), highCol));
doAutoSelectColumns = false;
gdi.refresh();
break;
case 5:
showFilter(gdi);
break;
default:
break;
}
/*POINT pt;
pt.x = x;
pt.y = y;
ClientToScreen(gdi.getHWNDTarget(), &pt);
HMENU hm = CreatePopupMenu();
AppendMenu(hm, MF_STRING, 1, lang.tl("Sortera stigande").c_str());
AppendMenu(hm, MF_STRING, 2, L"Select");
int res = TrackPopupMenuEx(hm, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, gdi.getHWNDTarget(), nullptr);
DestroyMenu(hm);*/
}
// lowerCol = getColumn(x);
// lowerRow = getRow(y);
return false;
}
bool Table::isFullColumnSelected() const {
if (sortIndex.size() < 2)
return false;
return (sel.upperRow == sortIndex[2].index &&
sel.lowerRow == sortIndex[sortIndex.size() - 1].index) ||
(sel.lowerRow == sortIndex[2].index &&
sel.upperRow == sortIndex[sortIndex.size() - 1].index);
}
void Table::markAll(bool doSelect) {
if (doSelect) {
sel.lowerCol = columns.front();
sel.upperCol = columns.back();
if (sortIndex.size() > 2) {
sel.upperRow = sortIndex[2].index;
sel.lowerRow = sortIndex.back().index;
}
selScreen.reset();
}
else {
sel.reset();
selScreen.reset();
}
}
bool Table::mouseMidDown(gdioutput &gdi, int x, int y) {
return false;
}
bool Table::mouseMidUp(gdioutput &gdi, int x, int y) {
return false;
}
bool Table::mouseLeftDblClick(gdioutput &gdi, int x, int y)
{
clearCellSelection(&gdi);
@ -1061,21 +1213,21 @@ void drawSymbol(gdioutput &gdi, HDC hDC, int height,
}
void Table::highlightCell(HDC hDC, gdioutput &gdi, const TableCell &cell, DWORD color, int dx, int dy)
void Table::highlightCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, DWORD color, int dx, int dy)
{
SelectObject(hDC, GetStockObject(DC_BRUSH));
SelectObject(hDC, GetStockObject(NULL_PEN));
SetDCBrushColor(hDC, color);
RECT rc=cell.absPos;
rc.left+=dx;
rc.right+=dx;
rc.top+=dy;
rc.bottom+=dy;
RECT rc = cell.absPos;
rc.left += dx;
rc.right += dx - 1;
rc.top += dy;
rc.bottom += dy;
Rectangle(hDC, rc.left+1, rc.top,
rc.right+2, rc.bottom);
Rectangle(hDC, rc.left + 2, rc.top+2,
rc.right + 1, rc.bottom-1);
TextInfo ti;
@ -1090,9 +1242,13 @@ void Table::highlightCell(HDC hDC, gdioutput &gdi, const TableCell &cell, DWORD
else {
gdi.formatString(ti, hDC);
SetBkMode(hDC, TRANSPARENT);
rc.left+=4;
rc.top+=2;
DrawText(hDC, cell.contents.c_str(), -1, &rc, DT_LEFT|DT_NOPREFIX);
rc.left += 4;
rc.top += 2;
rc.right -= 2;
if (Titles[col].formatRight)
DrawText(hDC, cell.contents.c_str(), -1, &rc, DT_RIGHT | DT_NOPREFIX);
else
DrawText(hDC, cell.contents.c_str(), -1, &rc, DT_LEFT | DT_NOPREFIX);
}
}
@ -1106,7 +1262,7 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
table_yp=dy-gdi.OffsetY;
if (currentSortColumn==-1)
sort(0);
sort(0, false);
int wi, he;
getDimension(gdi, wi, he, true);
@ -1129,7 +1285,7 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
xpos[0]=dx-gdi.OffsetX;
for (size_t i=1;i<=columns.size();i++)
xpos[i]=xpos[i-1]+Titles[columns[i-1]].width+1;
//xxx
//Find first and last visible column
while(firstCol<int(columns.size()) && xpos[firstCol+1]<=screen.left)
firstCol++;
@ -1219,21 +1375,29 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
rc.right=rc.left+Titles[index].width;
rc.top=yp+1-gdi.OffsetY;
rc.bottom=rc.top+rowHeight;
SetDCBrushColor(hDC, RGB(200,200,200));
bool sortOn = index == PrevSort || PrevSort == -(10 + index);
SetDCBrushColor(hDC, sortOn ? RGB(207, 218, 203) : RGB(200,200,200));
Rectangle(hDC, rc.left, rc.top-1, rc.right+2, rc.bottom);
if (index == PrevSort || PrevSort == -(10+index) ) {
SetDCBrushColor(hDC, RGB(100,250,100));
if (sortOn) {
auto pp = GetDCPenColor(hDC);
SetDCBrushColor(hDC, RGB(183,227,138));
SetDCPenColor(hDC, RGB(245, 250, 240));
POINT pt[3];
int r = gdi.scaleLength(4);
int r = gdi.scaleLength(6);
int s = rc.bottom - rc.top - r;
int px = (rc.right + rc.left + s)/2;
int s2 = s;
int px = rc.left + s2 + r;//(rc.right + rc.left + s2)/2;
int py = rc.top + r/2;
pt[0].x = px - s;
pt[1].x = px - s/2;
pt[0].x = px - s2;
pt[1].x = px - s2/2;
pt[2].x = px;
if (index == PrevSort) {
if (index != PrevSort) {
pt[0].y = py;
pt[1].y = py + s;
pt[2].y = py;
@ -1245,6 +1409,7 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
}
Polygon(hDC, pt, 3);
SetDCPenColor(hDC, pp);
}
Data[0].cells[index].absPos=rc;
@ -1300,19 +1465,62 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
}
}
int rLow = -1, rHigh = -1;
int cLow = -1, cHigh = -1;
if (!startSelect) {
getRowRange(rLow, rHigh);
getColRange(cLow, cHigh);
}
for (size_t k1=max(2, firstRow); int(k1)<lastRow; k1++){
int yp=dy+rowHeight*(k1+1);
TableRow &tr=Data[sortIndex[k1].index];
int xp=xpos[0];
if (k1&1)
SetDCBrushColor(hDC, RGB(230,230, 240));
else
SetDCBrushColor(hDC, RGB(230,230, 250));
SelectObject(hDC, GetStockObject(NULL_PEN));
Rectangle(hDC, max(xpos[firstCol], int(screen.left)), yp-gdi.OffsetY,
min(xpos[lastCol]+1, int(screen.right+2)), yp+rowHeight-gdi.OffsetY);
int ydraw = yp - gdi.OffsetY;
auto setBG = [k1, hDC](bool high) {
if (high) {
if (k1 & 1)
SetDCBrushColor(hDC, RGB(230, 240, 230));
else
SetDCBrushColor(hDC, RGB(230, 245, 230));
}
else {
if (k1 & 1)
SetDCBrushColor(hDC, RGB(230, 230, 240));
else
SetDCBrushColor(hDC, RGB(230, 230, 250));
}
};
setBG(false);
if (rLow != -1 && k1 >= rLow && k1 <= rHigh && cLow !=-1 && cHigh != -1) {
Rectangle(hDC, max(xpos[firstCol], int(screen.left)), ydraw,
min(xpos[lastCol] + 1, int(screen.right + 2)), ydraw + rowHeight);
//wstring w = L"cL" + itow(cLow) + L", cH" + itow(cHigh) + L"\n";
// OutputDebugString(w.c_str());
int lowHLC = max(cLow, firstCol);
int maxHLC = min(cHigh + 1, lastCol);
if (lowHLC < maxHLC) {
setBG(true);
Rectangle(hDC, max(xpos[lowHLC], int(screen.left)), ydraw,
min(xpos[maxHLC] + 1, int(screen.right + 2)), ydraw + rowHeight);
setBG(false);
}
}
else {
Rectangle(hDC, max(xpos[firstCol], int(screen.left)), ydraw,
min(xpos[lastCol] + 1, int(screen.right + 2)), ydraw + rowHeight);
}
SelectObject(hDC, GetStockObject(DC_PEN));
const int cy=yp+rowHeight-gdi.OffsetY-1;
MoveToEx(hDC, xp, cy, 0);
@ -1351,7 +1559,6 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
LineTo(hDC, xp, may);
}
SelectObject(hDC, GetStockObject(NULL_BRUSH));
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, RGB(64,64,64));
@ -1363,10 +1570,10 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
SetDCPenColor(hDC, RGB(64,64,64));
Rectangle(hDC, dx-gdi.OffsetX-2, dy-gdi.OffsetY-2,
dx+tableWidth-gdi.OffsetX+2, dy+tableHeight-gdi.OffsetY+2);
drawSelection(gdi, hDC, true);
if (!startSelect)
drawSelection(gdi, hDC, true);
}
TableCell &Table::getCell(int row, int col) const {
if (size_t(row) >= sortIndex.size())
throw std::exception("Index out of range");
@ -1417,22 +1624,31 @@ void Table::restoreSelection(gdioutput &gdi, HDC hDC) {
void Table::drawSelection(gdioutput &gdi, HDC hDC, bool forceDraw) {
bool modified = false;
if (lowerColOld != lowerCol || upperCol != upperColOld ||
lowerRow != lowerRowOld || upperRow != upperRowOld) {
if (forceDraw) {
partialCell = false;
}
else if (sel != oldSel) {
modified = true;
restoreSelection(gdi, hDC);
}
if (lowerCol != -1 && upperCol != -1 &&
lowerRow != -1 && upperRow != -1 &&
(forceDraw || modified)) {
TableCell &c1 = Data[lowerRow].cells[lowerCol];
TableCell &c2 = Data[upperRow].cells[upperCol];
if (!sel.empty() && (forceDraw || modified)) {
int rh, rl, ch, cl;
getRowRange(rl, rh);
getColRange(cl, ch);
rl = max(rl, 2);
rh = max(rh, 2);
if (isFullColumnSelected()) {
rl = 0;
}
RECT rc;
rc.top = min(c1.absPos.top, c2.absPos.top) + gdi.OffsetY;
rc.left = min(c1.absPos.left, c2.absPos.left) + gdi.OffsetX;
rc.right = max(c1.absPos.right, c2.absPos.right) + 1 + gdi.OffsetX;
rc.bottom = max(c1.absPos.bottom, c2.absPos.bottom) + gdi.OffsetY;
rc.left = xpos[cl] + gdi.OffsetX;
rc.right = xpos[ch + 1] + gdi.OffsetX;
rc.top = table_yp + rowHeight * (rl + 1) + gdi.OffsetY;
rc.bottom = table_yp + rowHeight * (rh + 2) + gdi.OffsetY;
if (modified) {
int cx=rc.right-rc.left + 1;
@ -1462,14 +1678,14 @@ void Table::drawSelection(gdioutput &gdi, HDC hDC, bool forceDraw) {
SelectObject(hDC, GetStockObject(NULL_BRUSH));
SelectObject(hDC, GetStockObject(DC_PEN));
SetDCPenColor(hDC, RGB(0,0, 128));
SetDCPenColor(hDC, RGB(50, 50, 128));
Rectangle(hDC, rc.left - gdi.OffsetX, rc.top - gdi.OffsetY,
rc.right - gdi.OffsetX, rc.bottom - gdi.OffsetY);
SetDCPenColor(hDC, RGB(80, 60, 170));
Rectangle(hDC, rc.left - gdi.OffsetX+1, rc.top - gdi.OffsetY+1,
rc.right - gdi.OffsetX-1, rc.bottom - gdi.OffsetY-1);
lowerColOld = lowerCol;
upperColOld = upperCol;
lowerRowOld = lowerRow;
upperRowOld = upperRow;
oldSel = sel;
}
}
@ -1830,7 +2046,7 @@ void Table::update()
PrevSort = -1;
if (oldSort != -1)
sort(oldSort);
sort(oldSort, false);
commandLock = false; // Reset lock
}
@ -1863,27 +2079,53 @@ void Table::getExportData(int col1, int col2, int row1, int row2, wstring &html,
}
void Table::getRowRange(int &rowLo, int &rowHi) const {
int row1 = -1, row2 = -1;
for (size_t k = 0; k < sortIndex.size(); k++) {
if (upperRow == sortIndex[k].index)
row1 = k;
if (lowerRow == sortIndex[k].index)
row2 = k;
if (sel.empty())
return;
if (selScreen.emptyRow()) {
if (dataRowToIndex.empty()) {
dataRowToIndex.resize(Data.size());
for (size_t k = 0; k < sortIndex.size(); k++) {
dataRowToIndex[sortIndex[k].index] = k;
}
}
int row1 = -1, row2 = -1;
row1 = dataRowToIndex[sel.upperRow];
row2 = dataRowToIndex[sel.lowerRow];
rowLo = min(row1, row2);
rowHi = max(row1, row2);
selScreen.lowerRow = rowLo;
selScreen.upperRow = rowHi;
}
else {
rowLo = selScreen.lowerRow;
rowHi = selScreen.upperRow;
}
rowLo = min(row1, row2);
rowHi = max(row1, row2);
}
void Table::getColRange(int &colLo, int &colHi) const {
int col1 = -1, col2 = -1;
for (size_t k = 0; k < columns.size(); k++) {
if (upperCol == columns[k])
col1 = k;
if (lowerCol == columns[k])
col2 = k;
if (sel.empty())
return;
if (selScreen.emptyCol()) {
int col1 = -1, col2 = -1;
for (size_t k = 0; k < columns.size(); k++) {
if (sel.upperCol == columns[k])
col1 = k;
if (sel.lowerCol == columns[k])
col2 = k;
}
colLo = min(col1, col2);
colHi = max(col1, col2);
selScreen.lowerCol = colLo;
selScreen.upperCol = colHi;
}
else {
colLo = selScreen.lowerCol;
colHi = selScreen.upperCol;
}
colLo = min(col1, col2);
colHi = max(col1, col2);
}
void Table::exportClipboard(gdioutput &gdi)
@ -2047,7 +2289,7 @@ void Table::importClipboard(gdioutput &gdi)
if (tw > columns.size())
throw meosException("Antalet kolumner i urklippet är större än antalet kolumner i tabellen.");
if (upperRow == -1) {
if (sel.emptyRow()) {
if (!gdi.ask(L"Vill du klistra in X nya rader i tabellen?#"+itow(table.size())))
return;
rowS = sortIndex.size(); // Add new rows

View File

@ -1,7 +1,7 @@
#pragma once
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -163,11 +163,13 @@ protected:
size_t dataPointer; // Insertation pointer
vector<TableSortIndex> sortIndex;
vector<int> columns;
mutable vector<int> dataRowToIndex;
inthashmap idToRow;
//highlight
int highRow;
int highCol;
bool isFullColumnSelected() const;
// Selected columns. For drag/drop and sort
int colSelected;
int startX;
@ -178,16 +180,37 @@ protected:
int editCol;
// Selected rectangle
int upperRow;
int lowerRow;
int upperCol;
int lowerCol;
struct Range {
int upperRow;
int lowerRow;
int upperCol;
int lowerCol;
void reset() {
upperRow = -1;
lowerRow = -1;
upperCol = -1;
lowerCol = -1;
}
bool emptyRow() const { return upperRow < 0 || lowerRow < 0; }
bool emptyCol() const { return upperCol < 0 || lowerCol < 0; }
bool empty() const { return emptyRow() || emptyCol(); }
int upperRowOld;
Range() { reset(); }
~Range() = default;
bool operator!=(const Range &other) const {
return upperRow != other.upperRow || lowerCol != other.lowerCol ||
lowerRow != other.lowerRow || upperCol != other.upperCol;
}
};
Range sel;
mutable Range selScreen;
Range oldSel;
/* int upperRowOld;
int lowerRowOld;
int upperColOld;
int lowerColOld;
*/
bool startSelect;
HWND hEdit;
@ -205,9 +228,9 @@ protected:
bool partialCell;
//static bool filterMatchString(const string &c, const char *filt);
void highlightCell(HDC hDC, gdioutput &gdi, const TableCell &cell, DWORD color, int dx, int dy);
void highlightCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, DWORD color, int dx, int dy);
void moveCell(HDC hDC, gdioutput &gdi, const TableCell &cell, int dx, int dy);
void moveCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, int dx, int dy);
void startMoveCell(HDC hDC, const TableCell &cell);
void stopMoveCell(HDC hDC, const TableCell &cell, int dx, int dy);
void restoreCell(HDC hDC, const TableCell &cell);
@ -337,12 +360,20 @@ public:
bool mouseLeftUp(gdioutput &gdi, int x, int y);
bool mouseLeftDblClick(gdioutput &gdi, int x, int y);
bool mouseRightDown(gdioutput &gdi, int x, int y);
bool mouseRightUp(gdioutput &gdi, int x, int y);
bool mouseMidDown(gdioutput &gdi, int x, int y);
bool mouseMidUp(gdioutput &gdi, int x, int y);
bool editCell(gdioutput &gdi, int row, int col);
bool keyCommand(gdioutput &gdi, KeyCommandCode code);
void sort(int col);
void sort(int col, bool forceDirection);
void filter(int col, const wstring &filt, bool forceFilter=false);
void showFilter(gdioutput &gdi);
int addColumn(const string &Title, int width, bool isnum, bool formatRight = false);
int addColumn(const wstring &translatedTitle, int width, bool isnum, bool formatRight = false);
@ -355,6 +386,8 @@ public:
void set(int column, oBase &owner, int id, const wstring &data,
bool canEdit=true, CellType type=cellEdit);
void markAll(bool doSelect);
//Reload a row from data
void reloadRow(int rowId);
@ -374,12 +407,9 @@ public:
};
struct TableSortIndex {
//TableSortIndex(const Table &t) : table(&t) {}
const static Table *table;
int index;
bool operator<(const TableSortIndex &t) const {return table->compareRow(index,t.index);}
//{return table->Data[index].key < table->Data[t.index].key;}
//bool operator<=(const TableSortIndex &t) const {return table->Data[index].key <= table->Data[t.index].key;}
};
enum {TID_CLASSNAME, TID_COURSE, TID_NUM, TID_ID, TID_MODIFIED,

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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

@ -1528,10 +1528,10 @@ Exportformat = Export format
Filnamnsprefix = Filename prefix
Mapp = Folder
Mappnamnet får inte vara tomt = Folder name cannot be empty
Onlineresultat = On-Line Results
Onlineresultat = Online Results
Packa stora filer (zip) = Compress large files (zip)
Publicera resultat direkt på nätet = Publish results directly on the web
Resultat online = Results On-Line
Resultat online = Results OnLine
Skicka till webben = Send to the web
Spara på disk = Save to disk
Till exempel X = For example X
@ -1541,13 +1541,13 @@ URL måste anges = URL missing
Tidsintervall (sekunder) = Time interval (seconds)
Antal skickade uppdateringar X (Y kb) = Number of updates X (Y kb)
Filen finns redan: X = Destination already exists: X
Misslyckades med att ladda upp onlineresultat = Failed to upload on-line results
Misslyckades med att ladda upp onlineresultat = Failed to upload online results
Onlineservern svarade felaktigt = Remote server gave unexpected reply (Incorrect configuration?)
Onlineservern svarade: ZIP stöds ej = Response from remote server: ZIP not supported.
Onlineservern svarade: Serverfel = Response from remote server: Server error
Onlineservern svarade: Felaktigt lösenord = Response from remote server: Wrong password
Onlineservern svarade: Felaktigt tävlings-id = Response from remote server: Wrong competition id
Online Results Error X = On-Line Results Error X
Online Results Error X = Online Results Error X
PDF = PDF
ClassTeamLeg = Class, team, leg
Okänd = Unknown
@ -2534,7 +2534,7 @@ RunnerStageTimeStatus = Competitor's time or status (on stage)
EFilterIncludeNotParticipating = Include not participating
RunnerStageNumber = Stage number earlier stage
Begränsa bredd (klipp text) = Limit width (crop text)
Håll ihop med = Keep together
Håll ihop med = Keep columns close
Justering i sidled = Line adjustment
Minsta blockbredd = Least width
Relation till föregående = Relation to previous
@ -2545,5 +2545,44 @@ prefsDatabaseEngine = Typ av databastabell för nya tävlingar (MySQL)
Startgrupperna X och Y överlappar = Start groups X and Y are overlapping
Batteristatus = Battery status
Low = Low
prefsReadVoltageExp = Read SIAC battery voltage
Replace[battery] = Replace
Spänning = Voltage
(kopia) = (copy)
Klassen använder banpool = The class has a course pool
Filen (X) innehåller IOF-XML tävlingsdata och kan importeras i en existerande tävling = The file (X) contains IOF-XML competition data. You can import it into an existing competition.
Filen (X) är en listdefinition = The file (X) is a list definition
Filen (X) är en resultatmodul = The file (X) is a result module
Filen (X) är inte en MeOS-tävling = The file (X) is not a MeOS competition
MeOS-data = MeOS-data
List definition = List definition
ask:importcopy = A competition (X) with the same origin already exist. You can import the competition as a version of that competition or as a new independent copy. If it is the same event with modifications, it is best to import it as a version.\n\nWould you like to import it as a version?
RunnerCardVoltage = Card voltage
Applicera för specifik etapp = Apply for specific stage
Ljud = Sound
Ljudval = Sound selection
Markera allt (X) = Select all (X)
Markera inget (X) = Select none (X)
Ny ledare i klassen = New class leader
Sparade automater = Saved machines
Spela upp ett ljud för att indikera resultatet av brickavläsningen = Play a sound to indicate the result of the card readout.
Status inte OK (röd utgång) = Status not OK (red exit)
help:selectsound = Select sounds to play. By default MeOS builtin sounds are played.
prefsPlaySound = Play sounds
prefsSoundAction = Sound file, action needed
prefsSoundLeader = Sound file, class leader
prefsSoundNotOK = Sound file, status not OK
prefsSoundOK = Sound file, status OK.
Åtgärd krävs = Action needed
Alla tidigare etapper = All previous stages
Dölj = Hide
Exempel = Example
Filtrera = Filter
Markera kolumn = Select column
Slå ihop text = Append text (share column)
Sortera fallande = Sort decreasing
Sortera stigande = Sort increasing
Sök symbol = Search for symbol
Testa = Test
Fel: Använd X i texten där värdet (Y) ska sättas in = Error: Use X in the text where the value (Y) should be used
info:teamcourseassignment = The imported file contains forking data for teams. To import this data you must prepare the competition to match the imported file: \n\n1. Ensure all classes are setup with the correct number of legs.\n2. Provide bib numbers in each class. Use Quick Settings on the page Classes and enter the first bib number in each class (meaning automatic bib setting). You can also import the teams first and assign bibs as usual.\n3. Import the courses. You can import this file several times if needed to update the forking.
Försvunnen = Missing

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -38,6 +38,8 @@ enum KeyCommandCode {
KC_SPEEDUP,
KC_SLOWDOWN,
KC_AUTOCOMPLETE,
KC_MARKALL,
KC_CLEARALL
};
/** Enum used to stack GUI command control, "command line wizard" */

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -2376,13 +2376,13 @@ void gdioutput::processListMessage(ListBoxInfo &bi, WPARAM wParam)
LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
{
if (iMessage==WM_COMMAND) {
if (iMessage == WM_COMMAND) {
WORD hwParam = HIWORD(wParam);
HWND hWnd=(HWND)lParam;
if (hwParam==EN_CHANGE) {
HWND hWnd = (HWND)lParam;
if (hwParam == EN_CHANGE) {
list<TableInfo>::iterator tit;
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
for (tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->inputChange(*this, hWnd))
return 0;
}
@ -2392,8 +2392,8 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
//for (it=BI.begin(); it != BI.end(); ++it) {
unordered_map<HWND, ButtonInfo*>::iterator it = biByHwnd.find(HWND(lParam));
// if (it->hWnd==hWnd) {
if ( it != biByHwnd.end() ) {
// if (it->hWnd==hWnd) {
if (it != biByHwnd.end()) {
ButtonInfo &bi = *it->second;
processButtonMessage(bi, wParam);
return 0;
@ -2431,62 +2431,62 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
}
}
}
else if (iMessage==WM_MOUSEMOVE) {
else if (iMessage == WM_MOUSEMOVE) {
POINT pt;
pt.x=(signed short)LOWORD(lParam);
pt.y=(signed short)HIWORD(lParam);
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
list<TableInfo>::iterator tit;
bool GotCapture=false;
bool GotCapture = false;
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
for (tit = Tables.begin(); tit != Tables.end(); ++tit)
GotCapture = tit->table->mouseMove(*this, pt.x, pt.y) || GotCapture;
if (GotCapture)
return 0;
list<InfoBox>::iterator it=IBox.begin();
list<InfoBox>::iterator it = IBox.begin();
while (it != IBox.end()) {
if (PtInRect(&it->TextRect, pt) && (it->callBack || it->hasEventHandler())) {
SetCursor(LoadCursor(NULL, IDC_HAND));
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawBoxText(hDC, it->TextRect, *it, true);
ReleaseDC(hWndTarget, hDC);
SetCapture(hWndTarget);
GotCapture=true;
it->HasTCapture=true;
GotCapture = true;
it->HasTCapture = true;
}
else {
if (it->HasTCapture) {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawBoxText(hDC, it->TextRect, *it, false);
ReleaseDC(hWndTarget, hDC);
if (!GotCapture)
ReleaseCapture();
it->HasTCapture=false;
it->HasTCapture = false;
}
}
if (it->HasCapture) {
if (GetCapture()!=hWndTarget) {
HDC hDC=GetDC(hWndTarget);
if (GetCapture() != hWndTarget) {
HDC hDC = GetDC(hWndTarget);
drawCloseBox(hDC, it->Close, false);
ReleaseDC(hWndTarget, hDC);
if (!GotCapture) ReleaseCapture();
it->HasCapture=false;
it->HasCapture = false;
}
else if (!PtInRect(&it->Close, pt)) {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawCloseBox(hDC, it->Close, false);
ReleaseDC(hWndTarget, hDC);
}
else {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawCloseBox(hDC, it->Close, true);
ReleaseDC(hWndTarget, hDC);
}
@ -2494,25 +2494,25 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
++it;
}
for (size_t k=0;k<shownStrings.size();k++) {
for (size_t k = 0; k < shownStrings.size(); k++) {
TextInfo &ti = *shownStrings[k];
if ((!ti.callBack && !ti.hasEventHandler()) || ti.hasTimer)
continue;
if (PtInRect(&ti.textRect, pt)) {
if (!ti.highlight){
ti.highlight=true;
if (!ti.highlight) {
ti.highlight = true;
InvalidateRect(hWndTarget, &ti.textRect, true);
}
SetCapture(hWndTarget);
GotCapture=true;
ti.hasCapture=true;
GotCapture = true;
ti.hasCapture = true;
SetCursor(LoadCursor(NULL, IDC_HAND));
}
else {
if (ti.highlight) {
ti.highlight=false;
ti.highlight = false;
InvalidateRect(hWndTarget, &ti.textRect, true);
}
@ -2520,79 +2520,80 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
if (!GotCapture)
ReleaseCapture();
ti.hasCapture=false;
ti.hasCapture = false;
}
}
}
}
else if (iMessage==WM_LBUTTONDOWN) {
else if (iMessage == WM_LBUTTONDOWN) {
if (autoCompleteInfo) {
autoCompleteInfo.reset();
return 0;
}
list<InfoBox>::iterator it=IBox.begin();
list<InfoBox>::iterator it = IBox.begin();
POINT pt;
pt.x=(signed short)LOWORD(lParam);
pt.y=(signed short)HIWORD(lParam);
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
list<TableInfo>::iterator tit;
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
if (useTables) {
for (tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseLeftDown(*this, pt.x, pt.y))
return 0;
}
while(it!=IBox.end()) {
while (it != IBox.end()) {
if (PtInRect(&it->Close, pt)) {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawCloseBox(hDC, it->Close, true);
ReleaseDC(hWndTarget, hDC);
SetCapture(hWndTarget);
it->HasCapture=true;
it->HasCapture = true;
}
++it;
}
//Handle links
for (size_t k=0;k<shownStrings.size();k++) {
for (size_t k = 0; k < shownStrings.size(); k++) {
TextInfo &ti = *shownStrings[k];
if (!ti.callBack && !ti.hasEventHandler())
continue;
if (ti.hasCapture) {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
if (PtInRect(&ti.textRect, pt)) {
ti.active=true;
ti.active = true;
RenderString(ti, hDC);
}
ReleaseDC(hWndTarget, hDC);
}
}
}
else if (iMessage==WM_LBUTTONUP) {
else if (iMessage == WM_LBUTTONUP) {
list<TableInfo>::iterator tit;
list<InfoBox>::iterator it=IBox.begin();
list<InfoBox>::iterator it = IBox.begin();
POINT pt;
pt.x=(signed short)LOWORD(lParam);
pt.y=(signed short)HIWORD(lParam);
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
if (useTables) {
for (tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseLeftUp(*this, pt.x, pt.y))
return 0;
while (it!=IBox.end()) {
}
while (it != IBox.end()) {
if (it->HasCapture) {
HDC hDC=GetDC(hWndTarget);
HDC hDC = GetDC(hWndTarget);
drawCloseBox(hDC, it->Close, false);
ReleaseDC(hWndTarget, hDC);
ReleaseCapture();
it->HasCapture=false;
it->HasCapture = false;
if (PtInRect(&it->Close, pt)) {
IBox.erase(it);
@ -2602,7 +2603,7 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
}
else if (it->HasTCapture) {
ReleaseCapture();
it->HasTCapture=false;
it->HasTCapture = false;
if (PtInRect(&it->TextRect, pt)) {
if (!it->handleEvent(*this, GUI_INFOBOX) && it->callBack)
@ -2614,12 +2615,12 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
}
//Handle links
for (size_t k=0;k<shownStrings.size();k++) {
for (size_t k = 0; k < shownStrings.size(); k++) {
TextInfo &ti = *shownStrings[k];
if (!ti.callBack && !ti.hasEventHandler())
continue;
if (ti.hasCapture){
if (ti.hasCapture) {
ReleaseCapture();
ti.hasCapture = false;
@ -2630,7 +2631,7 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
cmd = "click(\"" + ti.id + "\", " + itos(ti.getExtraInt()) + "); //" + toUTF8(ti.text);
else
cmd = "click(\"" + ti.id + "\"); //" + toUTF8(ti.text);
ti.active=false;
ti.active = false;
RenderString(ti);
if (!ti.handleEvent(*this, GUI_LINK))
ti.callBack(this, GUI_LINK, &ti);
@ -2639,24 +2640,68 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
}
}
}
else if (ti.active){
ti.active=false;
else if (ti.active) {
ti.active = false;
RenderString(ti);
}
}
}
else if (iMessage==WM_LBUTTONDBLCLK) {
else if (iMessage == WM_LBUTTONDBLCLK) {
list<TableInfo>::iterator tit;
POINT pt;
pt.x=(signed short)LOWORD(lParam);
pt.y=(signed short)HIWORD(lParam);
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables)
for (tit=Tables.begin(); tit!=Tables.end(); ++tit)
for (tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseLeftDblClick(*this, pt.x, pt.y))
return 0;
}
else if (iMessage == WM_RBUTTONDOWN) {
POINT pt;
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables) {
for (auto tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseRightDown(*this, pt.x, pt.y))
return 0;
}
}
else if (iMessage == WM_RBUTTONUP) {
POINT pt;
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables) {
for (auto tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseRightUp(*this, pt.x, pt.y))
return 0;
}
}
else if (iMessage == WM_MBUTTONDOWN) {
POINT pt;
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables) {
for (auto tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseMidDown(*this, pt.x, pt.y))
return 0;
}
}
else if (iMessage == WM_MBUTTONUP) {
POINT pt;
pt.x = (signed short)LOWORD(lParam);
pt.y = (signed short)HIWORD(lParam);
if (useTables) {
for (auto tit = Tables.begin(); tit != Tables.end(); ++tit)
if (tit->table->mouseMidUp(*this, pt.x, pt.y))
return 0;
}
}
else if (iMessage == WM_CHAR) {
/*list<TableInfo>::iterator tit;
if (useTables)
@ -3504,6 +3549,23 @@ void gdioutput::adjustDimension(int width, int height)
}
}
// Alert from main thread (via callback)
void gdioutput::delayAlert(const wstring& msg) {
if (!delayedAlert.empty())
delayedAlert += L", ";
if (delayedAlert.length() > 1000)
delayedAlert = L"";
delayedAlert += lang.tl(msg);
PostMessage(hWndAppMain, WM_USER + 6, 0, LPARAM(this));
}
wstring gdioutput::getDelayedAlert() {
wstring out = L"#" + delayedAlert;
delayedAlert.clear();
return out;
}
void gdioutput::alert(const string &msg) const
{
alert(widen(msg));
@ -4002,6 +4064,7 @@ void gdioutput::removeString(string id)
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
ReleaseDC(hWndTarget, hDC);
TL.erase(it);
itTL = TL.end();
shownStrings.clear();
return;
}
@ -4833,6 +4896,8 @@ bool gdioutput::removeWidget(const string &id)
}
++iit;
}
removeString(id);
return false;
}
@ -5757,6 +5822,12 @@ void gdioutput::tableCB(ButtonInfo &bu, Table *t)
t->updateDimension(*this);
refresh();
}
else if (bu.id == "tblMarkAll") {
t->keyCommand(*this, KC_MARKALL);
}
else if (bu.id == "tblClearAll") {
t->keyCommand(*this, KC_CLEARALL);
}
else if (bu.id=="tblUpdate") {
t->keyCommand(*this, KC_REFRESH);
}
@ -5799,6 +5870,8 @@ void gdioutput::enableTables()
toolbar->addButton("tblPrint", 0, STD_PRINT, "Skriv ut tabellen (X)#Ctrl+P");
toolbar->addButton("tblUpdate", 1, 0, "Uppdatera alla värden i tabellen (X)#F5");
toolbar->addButton("tblReset", 1, 4, "Återställ tabeldesignen och visa allt");
toolbar->addButton("tblMarkAll", 1, 5, "Markera allt (X)#Ctrl+A");
toolbar->addButton("tblClearAll", 1, 6, "Markera inget (X)#Ctrl+D");
toolbar->addButton("tblCopy", 0, STD_COPY, "Kopiera selektionen till urklipp (X)#Ctrl+C");
if (t->canPaste())
toolbar->addButton("tblPaste", 0, STD_PASTE, "Klistra in data från urklipp (X)#Ctrl+V");
@ -7040,7 +7113,18 @@ DWORD gdioutput::selectColor(wstring &def, DWORD input) {
}
cc.lpCustColors = staticColor;
if (ChooseColor(&cc)) {
int res = 0;
setCommandLock();
try {
res = ChooseColor(&cc);
liftCommandLock();
}
catch (...) {
liftCommandLock();
throw;
}
if (res) {
wstring co;
for (int ix = 0; ix < 16; ix++) {
wchar_t bf[16];
@ -7053,7 +7137,6 @@ DWORD gdioutput::selectColor(wstring &def, DWORD input) {
return -1;
}
void gdioutput::setAnimationMode(shared_ptr<AnimationData> &data) {
if (animationData && animationData->takeOver(data))
return;
@ -7118,3 +7201,22 @@ int gdioutput::getPageX() const {
else
return max(MaxX, xlimit) + scaleLength(60);
}
int gdioutput::popupMenu(int x, int y, const vector<pair<wstring, int>> &menuItems) const {
POINT pt;
pt.x = x;
pt.y = y;
ClientToScreen(getHWNDTarget(), &pt);
HMENU hm = CreatePopupMenu();
for (auto &me : menuItems) {
if (me.first.empty())
AppendMenu(hm, MF_SEPARATOR, me.second, L"");
else
AppendMenu(hm, MF_STRING, me.second, lang.tl(me.first).c_str());
}
int res = TrackPopupMenuEx(hm, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, getHWNDTarget(), nullptr);
DestroyMenu(hm);
return res;
}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -289,6 +289,8 @@ protected:
shared_ptr<AnimationData> animationData;
shared_ptr<AutoCompleteInfo> autoCompleteInfo;
wstring delayedAlert;
public:
AutoCompleteInfo &addAutoComplete(const string &key);
@ -571,6 +573,10 @@ public:
void alert(const string &msg) const;
void alert(const wstring &msg) const;
// Alert from main thread (via callback)
void delayAlert(const wstring& msg);
// Get and clear any delayed alert
wstring getDelayedAlert();
void fillDown(){Direction=1;}
void fillRight(){Direction=0;}
@ -762,8 +768,9 @@ public:
void closeWindow();
int popupMenu(int x, int y, const vector<pair<wstring, int>> &menuItems) const;
void setDBErrorState(bool state);
friend int TablesCB(gdioutput *gdi, int type, void *data);
friend class Table;
friend gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y, bool fixedSize);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -568,8 +568,19 @@ bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &
s = r.getTotalStatusInput();
}
else if (t && !isQF && r.getLegNumber() > 0) {
legInput = t->getLegRunningTime(r.getLegNumber() - 1, true, false) * 10;
s = t->getLegStatus(r.getLegNumber() - 1, true, false);
int ltu = r.getLegNumber();
pClass cls = t->getClassRef(true);
if (cls) {
LegTypes lt = cls->getLegType(ltu);
while (ltu > 0 && (lt == LTParallelOptional || lt == LTParallel|| lt == LTExtra || lt == LTIgnore) ) {
ltu--;
lt = cls->getLegType(ltu);
}
}
if (ltu > 0) {
legInput = t->getLegRunningTime(ltu - 1, true, false) * 10;
s = t->getLegStatus(ltu - 1, true, false);
}
}
if (totalStatus != s) {

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -509,6 +509,11 @@ pCourse IOF30Interface::findCourse(gdioutput &gdi,
void IOF30Interface::teamCourseAssignment(gdioutput &gdi, xmlList &xAssignment,
const map<wstring, pCourse> &courses) {
gdi.dropLine();
gdi.addString("", 10, "info:teamcourseassignment");
gdi.dropLine();
vector<pTeam> allT;
oe.getTeams(0, allT, false);
@ -1394,6 +1399,102 @@ void IOF30Interface::readStartList(gdioutput &gdi, xmlobject &xo, int &entRead,
}
}
void IOF30Interface::readResultList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail) {
string ver;
xo.getObjectString("iofVersion", ver);
if (!ver.empty() && ver > "3.0")
gdi.addString("", 0, "Varning, okänd XML-version X#" + ver);
map<int, vector<LegInfo> > teamClassConfig;
xmlobject xEvent = xo.getObject("Event");
if (xEvent) {
readEvent(gdi, xEvent, teamClassConfig);
}
xmlList cResults;
xo.getObjects("ClassResult", cResults);
struct RaceInfo {
int courseId;
int length;
int climb;
wstring startName;
};
for (xmlobject &xClassResult : cResults) {
pClass pc = readClass(xClassResult.getObject("Class"),
teamClassConfig);
int classId = pc ? pc->getId() : 0;
map<int, RaceInfo> raceToInfo;
xmlList courses;
xClassResult.getObjects("Course", courses);
for (size_t k = 0; k < courses.size(); k++) {
int raceNo = courses[k].getObjectInt("raceNumber");
if (raceNo > 0)
raceNo--;
RaceInfo &raceInfo = raceToInfo[raceNo];
raceInfo.courseId = courses[k].getObjectInt("Id");
raceInfo.length = courses[k].getObjectInt("Length");
raceInfo.climb = courses[k].getObjectInt("Climb");
}
if (raceToInfo.size() == 1) {
RaceInfo &raceInfo = raceToInfo.begin()->second;
if (raceInfo.courseId > 0) {
if (pc->getCourse() == 0) {
pCourse crs = oe.addCourse(pc->getName(), raceInfo.length, raceInfo.courseId);
crs->setStart(raceInfo.startName, false);
crs->getDI().setInt("Climb", raceInfo.climb);
pc->setCourse(crs);
crs->synchronize();
}
}
}
else if (raceToInfo.size() > 1) {
}
xmlList xPResults;
xClassResult.getObjects("PersonResult", xPResults);
//map<int, pair<wstring, int> > bibPatterns;
//oClass::extractBibPatterns(oe, bibPatterns);
for (size_t k = 0; k < xPResults.size(); k++) {
if (readPersonResult(gdi, pc, xPResults[k], 0, teamClassConfig))
entRead++;
else
entFail++;
}
xmlList tEntries;
xClassResult.getObjects("TeamResult", tEntries);
for (size_t k = 0; k < tEntries.size(); k++) {
//setupClassConfig(classId, tEntries[k], teamClassConfig);
entFail++; // Teams not supported
}
/*
//setupRelayClasses(teamClassConfig);
if (pc && teamClassConfig.count(pc->getId()) && !teamClassConfig[pc->getId()].empty()) {
setupRelayClass(pc, teamClassConfig[pc->getId()]);
}
for (size_t k = 0; k < tEntries.size(); k++) {
if (readTeamStart(gdi, pc, tEntries[k], bibPatterns, teamClassConfig))
entRead++;
else
entFail++;
}
*/
pc->synchronize();
}
}
void IOF30Interface::readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail) {
string ver;
xo.getObjectString("iofVersion", ver);
@ -2125,6 +2226,180 @@ pRunner IOF30Interface::readPersonStart(gdioutput &gdi, pClass pc, xmlobject &xo
return r;
}
wstring formatStatus(RunnerStatus st, bool hasTime) {
switch (st) {
case StatusNoTiming:
if (!hasTime)
break;
case StatusOK:
return L"OK";
case StatusDNS:
return L"DidNotStart";
case StatusCANCEL:
return L"Cancelled";
case StatusMP:
return L"MissingPunch";
case StatusDNF:
return L"DidNotFinish";
case StatusDQ:
return L"Disqualified";
case StatusMAX:
return L"OverTime";
case StatusOutOfCompetition:
if (!hasTime)
break;
case StatusNotCompetiting:
return L"NotCompeting";
}
return L"Inactive";
}
RunnerStatus parseStatus(const wstring &status) {
if (status == L"OK")
return StatusOK;
else if (status == L"DidNotStart")
return StatusDNS;
else if (status == L"MissingPunch")
return StatusMP;
else if (status == L"Cancelled")
return StatusCANCEL;
else if (status == L"DidNotFinish")
return StatusDNF;
else if (status == L"Disqualified")
return StatusDQ;
else if (status == L"OverTime")
return StatusMAX;
else if (status == L"NotCompeting")
return StatusOutOfCompetition;
return StatusUnknown;
}
pRunner IOF30Interface::readPersonResult(gdioutput &gdi, pClass pc, xmlobject &xo, pTeam team,
const map<int, vector<LegInfo> > &teamClassConfig) {
xmlobject xPers = xo.getObject("Person");
pRunner r = 0;
if (xPers)
r = readPerson(gdi, xPers);
if (r == 0)
return 0;
if (pc && (r->getClassId(false) == 0 || !r->hasFlag(oAbstractRunner::FlagUpdateClass)))
r->setClassId(pc->getId(), true);
// Club
pClub c = readOrganization(gdi, xo.getObject("Organisation"), false);
if (!c)
c = readOrganization(gdi, xo.getObject("Organization"), false);
if (c)
r->setClubId(c->getId());
xmlList results;
xo.getObjects("Result", results);
for (size_t k = 0; k < results.size(); k++) {
int race = results[k].getObjectInt("raceNumber");
pRunner rRace = r;
if (race > 1 && r->getNumMulti() > 0) {
pRunner rr = r->getMultiRunner(race - 1);
if (rr)
rRace = rr;
}
if (rRace) {
// Card
int cardNo = results[k].getObjectInt("ControlCard");
if (cardNo > 0)
rRace->setCardNo(cardNo, false);
wstring bib;
results[k].getObjectString("BibNumber", bib);
rRace->getDI().setString("Bib", bib);
xmlobject startTime = results[k].getObject("StartTime");
/*
if (team) {
int leg = starts[k].getObjectInt("Leg");
int legorder = starts[k].getObjectInt("LegOrder");
int legindex = max(0, leg - 1);
map<int, vector<LegInfo> >::const_iterator res = teamClassConfig.find(team->getClassId(false));
if (res != teamClassConfig.end()) {
legindex = getIndexFromLegPos(leg, legorder, res->second);
}
team->setRunner(legindex, rRace, false);
if (rRace->getClubId() == 0)
rRace->setClubId(team->getClubId());
if (startTime && pc) {
pc->setStartType(legindex, STDrawn, false);
}
}*/
int st = parseISO8601Time(startTime);
rRace->setStartTime(st, true, oBase::ChangeType::Update);
xmlobject finishTime = results[k].getObject("FinishTime");
int ft = parseISO8601Time(finishTime);
rRace->setFinishTime(ft);
wstring status;
results[k].getObjectString("Status", status);
rRace->setStatus(parseStatus(status), true, oBase::ChangeType::Update);
xmlList splits;
results[k].getObjects("SplitTime", splits);
if (!splits.empty()) {
pCard card = oe.allocateCard(rRace);
card->setCardNo(cardNo);
vector<int> controls;
wstring s;
for (auto &split : splits) {
int code = split.getObjectInt("ControlCode");
int time = split.getObjectInt("Time");
split.getObjectString("status", s);
if (s != L"missing")
card->addPunch(code, st + time, 0);
if (s != L"additional")
controls.push_back(code);
}
if (ft > 0)
card->addPunch(oPunch::PunchFinish, ft, 0);
//Update to SQL-source
card->synchronize();
if (!controls.empty()) {
pCourse c = r->getCourse(true);
if (!c)
c = oe.addCourse(oe.getAutoCourseName());
if (c->getNumControls() == 0) {
for (int ctrl : controls) {
c->addControl(ctrl);
}
c->synchronize();
}
if (pc)
pc->setCourse(c);
else
rRace->setCourseId(c->getId());
}
vector<int> mp;
rRace->addPunches(card, mp);
}
}
}
r->synchronize();
return r;
}
void IOF30Interface::readId(const xmlobject &person, int &pid, __int64 &extId) const {
wstring sid;
pid = 0;
@ -3052,34 +3327,6 @@ void IOF30Interface::writeCourseInfo(xmlparser &xml, const oCourse &c) {
xml.write("Climb", climb);
}
wstring formatStatus(RunnerStatus st, bool hasTime) {
switch (st) {
case StatusNoTiming:
if (!hasTime)
break;
case StatusOK:
return L"OK";
case StatusDNS:
return L"DidNotStart";
case StatusCANCEL:
return L"Cancelled";
case StatusMP:
return L"MissingPunch";
case StatusDNF:
return L"DidNotFinish";
case StatusDQ:
return L"Disqualified";
case StatusMAX:
return L"OverTime";
case StatusOutOfCompetition:
if (!hasTime)
break;
case StatusNotCompetiting:
return L"NotCompeting";
}
return L"Inactive";
}
void IOF30Interface::writePersonResult(xmlparser &xml, const oRunner &r,
bool includeCourse, bool teamMember, bool hasInputTime) {
if (!teamMember)
@ -4087,7 +4334,7 @@ pCourse IOF30Interface::readCourse(const xmlobject &xcrs) {
for (size_t k = 0; k < xControls.size(); k++) {
string type;
xControls[k].getObjectString("type", type);
if (type == "Start") {
if (type == "Start" && startName.empty()) {
wstring idStr;
xControls[k].getObjectString("Control", idStr);
pControl pStart = oe.getControl(getStartIndex(idStr), false);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -176,6 +176,10 @@ class IOF30Interface {
map<int, pair<wstring, int> > &bibPatterns,
const map<int, vector<LegInfo> > &teamClassConfig);
pRunner readPersonResult(gdioutput &gdi, pClass pc, xmlobject &xo, pTeam team,
const map<int, vector<LegInfo> > &teamClassConfig);
pTeam getCreateTeam(gdioutput &gdi, const xmlobject &xTeam, int expectedClassId, bool &newTeam);
static int getIndexFromLegPos(int leg, int legorder, const vector<LegInfo> &setup);
@ -310,6 +314,8 @@ public:
void readStartList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
void readResultList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
void readServiceRequestList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
void readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -328,20 +328,28 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
}
else if (type == GUI_INPUTCHANGE) {
InputInfo &ii = *(InputInfo *)(&data);
bool show = false;
if (ii.text.length() > 1) {
vector<AutoCompleteRecord> rec;
MetaList::getAutoComplete(ii.text, rec);
if (!rec.empty()) {
auto &ac = gdi.addAutoComplete(ii.id);
ac.setAutoCompleteHandler(this);
ac.setData(rec);
ac.show();
show = true;
if (ii.id == "SearchText") {
bool show = false;
if (ii.text.length() > 1) {
vector<AutoCompleteRecord> rec;
MetaList::getAutoComplete(ii.text, rec);
if (!rec.empty()) {
auto &ac = gdi.addAutoComplete(ii.id);
ac.setAutoCompleteHandler(this);
ac.setData(rec);
ac.show();
show = true;
}
}
if (!show) {
gdi.clearAutoComplete(ii.id);
}
}
if (!show) {
gdi.clearAutoComplete(ii.id);
}
else if (type == GUI_INPUT) {
InputInfo &ii = *(InputInfo *)(&data);
if (ii.id == "Text" && ii.text != lastShownExampleText) {
showExample(gdi);
}
}
else if (type == GUI_BUTTON) {
@ -423,7 +431,7 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
makeDirty(gdi, MakeDirty, MakeDirty);
show(gdi);
}
else if ( bi.id == "Remove" ) {
else if (bi.id == "Remove") {
DWORD id;
gdi.getData("CurrentId", id);
getPosFromId(id, groupIx, lineIx, ix);
@ -491,22 +499,8 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
mlp.setColor(GDICOLOR(gdi.getExtraInt("Color")));
if (gdi.isChecked("UseLeg")) {
int leg = gdi.getTextNo("Leg");
if (newType == lResultModuleNumber || newType == lResultModuleTime ||
newType == lResultModuleNumberTeam || newType == lResultModuleTimeTeam) {
if (leg < 0 || leg > 1000)
throw meosException("X är inget giltigt index#" + itos(leg));
mlp.setLeg(leg);
}
else {
if (leg < 1 || leg > 1000)
throw meosException("X är inget giltigt sträcknummer#" + itos(leg));
mlp.setLeg(leg - 1);
}
}
else
mlp.setLeg(-1);
int leg = readLeg(gdi, newType, true);
mlp.setLeg(leg);
if (gdi.hasWidget("UseResultModule") && gdi.isChecked("UseResultModule"))
mlp.setResultModule(currentList->getResultModule());
@ -625,8 +619,8 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
if (fileName.empty()) {
int ix = 0;
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"xml-data", L"*.xml"));
fileName = gdi.browseForSave(ext, L"xml", ix);
ext.push_back(make_pair(L"List definition", L"*.meoslist"));
fileName = gdi.browseForSave(ext, L"meoslist", ix);
if (fileName.empty())
return 0;
}
@ -643,8 +637,8 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
return 0;
vector< pair<wstring, wstring> > ext;
ext.push_back(make_pair(L"xml-data", L"*.xml"));
wstring fileName = gdi.browseForOpen(ext, L"xml");
ext.push_back(make_pair(L"List definition", L"*.meoslist;*.xml"));
wstring fileName = gdi.browseForOpen(ext, L"meoslist");
if (fileName.empty())
return 0;
@ -822,18 +816,55 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
else if (type==GUI_CLEAR) {
return checkSave(gdi);
}
return 0;
}
int ListEditor::readLeg(gdioutput &gdi, EPostType newType, bool checkError) const {
if (MetaList::isResultModuleOutput(newType)) {
int leg = gdi.getTextNo("Leg");
if (leg < 0 || leg > 1000) {
if (checkError)
throw meosException("X är inget giltigt index#" + itos(leg));
else
leg = -1;
}
return leg;
}
else if (MetaList::isAllStageType(newType)) {
int leg = gdi.getSelectedItem("LegSel").first;
if (leg >= 1)
return leg - 1;
else
return -1;
}
else {
if (gdi.isChecked("UseLeg")) {
int leg = gdi.getTextNo("Leg");
if (leg < 1 || leg > 1000) {
if (checkError)
throw meosException("X är inget giltigt sträcknummer#" + itos(leg));
else
leg = -1;
}
return leg - 1;
}
else
return -1;
}
}
void ListEditor::updateType(int iType, gdioutput & gdi) {
EPostType type = EPostType(iType);
gdi.setTextTranslate("TUseLeg", getIndexDescription(type), true);
if (type == lResultModuleNumber || type == lResultModuleTime ||
type == lResultModuleNumberTeam || type == lResultModuleTimeTeam) {
gdi.check("UseLeg", true);
gdi.disableInput("UseLeg");
int leg = -1;
if (gdi.hasWidget("leg"))
leg = gdi.getTextNo("Leg");
gdi.restore("Example", false);
if (legStageTypeIndex(gdi, type, leg)) {
gdi.setRestorePoint("Example");
}
if (MetaList::isResultModuleOutput(type)) {
if (gdi.hasWidget("UseResultModule")) {
gdi.check("UseResultModule", true);
gdi.disableInput("UseResultModule");
@ -841,10 +872,12 @@ void ListEditor::updateType(int iType, gdioutput & gdi) {
gdi.enableInput("Leg");
if (gdi.getText("Leg").empty())
gdi.setText("Leg", L"0");
}
else if (MetaList::isAllStageType(type)) {
}
else {
gdi.enableInput("UseLeg");
if (gdi.getTextNo("Leg") == 0) {
if (leg == 0) {
gdi.setText("Leg", L"");
gdi.enableInput("UseLeg");
gdi.enableInput("UseResultModule", true);
@ -853,10 +886,7 @@ void ListEditor::updateType(int iType, gdioutput & gdi) {
}
}
gdi.restore("Example", false);
int margin = gdi.scaleLength(10);
showExample(gdi, margin, type);
gdi.refreshFast();
showExample(gdi, type);
}
void ListEditor::checkUnsaved(gdioutput &gdi) {
@ -886,10 +916,8 @@ void ListEditor::updateAlign(gdioutput &gdi, int val) {
gdi.setInputStatus("Color", val != 1);
gdi.setInputStatus("Fonts", val != 1);
}
void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
checkUnsaved(gdi);
gdi.restore("EditList", false);
@ -918,7 +946,10 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
if (ix + 1 == currentList->getNumPostsOnLine(groupIx, lineIx))
gdi.setInputStatus("MoveRight", false);
gdi.dropLine(3);
gdi.dropLine(1);
int boxY = gdi.getCY();
gdi.dropLine(2);
gdi.popX();
vector< pair<wstring, size_t> > types;
int currentType;
@ -940,7 +971,6 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
sort(types.begin(), types.end());
gdi.pushX();
int boxY = gdi.getCY();
gdi.fillRight();
gdi.addString("", 0, L"Typ:");
gdi.fillDown();
@ -958,7 +988,8 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
gdi.dropLine(-1);
gdi.addItem("Type", types);
gdi.selectItemByData("Type", currentType);
gdi.addInput("Text", mlp.getText(), 16, 0, L"Egen text:", L"Använd symbolen X där MeOS ska fylla i typens data.");
gdi.addInput("Text", mlp.getText(), 16, editListCB,
L"Egen text:", L"Använd symbolen X där MeOS ska fylla i typens data.");
gdi.setInputFocus("Text", true);
((InputInfo *)gdi.setText("SearchText", getSearchString()))->setFgColor(colorGreyBlue);
int boxX = gdi.getCX();
@ -972,21 +1003,28 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
gdi.popX();
}
xpUseLeg = gdi.getCX();
ypUseLeg = gdi.getCY();
int leg = mlp.getLeg();
gdi.addCheckbox("UseLeg", getIndexDescription(storedType), editListCB, leg != -1);
gdi.dropLine(-0.2);
gdi.setCX(gdi.getCX() + gdi.getLineHeight() * 5);
if (storedType == lResultModuleNumber || storedType == lResultModuleTime || storedType == lResultModuleTimeTeam || storedType == lResultModuleNumberTeam)
gdi.addInput("Leg", leg >= 0 ? itow(leg) : L"0", 4);
legStageTypeIndex(gdi, storedType, leg);
/*gdi.addCheckbox(xpUseLeg, ypUseLeg, "UseLeg", getIndexDescription(storedType), editListCB, leg != -1);
//gdi.dropLine(-0.2);
int dx = gdi.scaleLength(250);
int dy = -gdi.getLineHeight() / 5;
//gdi.setCX(gdi.getCX() + gdi.scaleLength(100));
if (MetaList::isResultModuleOutput(storedType))
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", leg >= 0 ? itow(leg) : L"0", 4);
else
gdi.addInput("Leg", leg >= 0 ? itow(leg + 1) : L"", 4);
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", leg >= 0 ? itow(leg + 1) : L"", 4);
gdi.enableInput("Leg", leg != -1);
if (storedType == lResultModuleNumber || storedType == lResultModuleTime ||
storedType == lResultModuleTimeTeam || storedType == lResultModuleNumberTeam) {
gdi.check("UseLeg", true);
gdi.disableInput("UseLeg");
gdi.setInputStatus("Leg", leg != -1);
*/
if (MetaList::isResultModuleOutput(storedType)) {
//gdi.check("UseLeg", true);
//gdi.disableInput("UseLeg");
if (gdi.hasWidget("UseResultModule")) {
gdi.check("UseResultModule", true);
gdi.disableInput("UseResultModule");
@ -1023,10 +1061,13 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
int maxY = gdi.getCY();
gdi.popX();
gdi.fillDown();
int innerBoxUpperCX = boxX + gdi.scaleLength(18);
int innerBoxUpperCY = boxY;
gdi.setCX(boxX + gdi.scaleLength(24));
gdi.setCY(boxY);
gdi.setCY(boxY + gdi.scaleLength(6));
gdi.pushX();
gdi.addString("", 1, "Formateringsregler");
gdi.addString("", fontMediumPlus, "Formateringsregler");
gdi.dropLine(0.5);
gdi.fillRight();
int val = 0;
@ -1069,10 +1110,15 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
gdi.dropLine();
gdi.addButton("Color", "Färg...", editListCB).setExtra(mlp.getColorValue());
maxX = max(maxX, gdi.getCX());
gdi.popX();
int innerBoxLowerCX = maxX + gdi.scaleLength(6);
maxX += gdi.scaleLength(12);
gdi.setCX(boxX - gdi.scaleLength(6));
gdi.dropLine(3);
int innerBoxLowerCY = gdi.getCY();
gdi.dropLine();
gdi.setData("CurrentId", id);
gdi.addButton("Remove", "Radera", editListCB, "Ta bort listposten");
@ -1086,29 +1132,63 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
maxX = max(gdi.getCX(), maxX);
RECT rc;
rc.top = y1;
rc.left = x1;
rc.right = maxX + gdi.scaleLength(6);
rc.bottom = maxY + gdi.scaleLength(6) + gdi.getLineHeight()*4;
gdi.addRectangle(rc, colorLightBlue, true);
gdi.addRectangle(rc, colorLightBlue, true, false);
rc.top = innerBoxUpperCY;
rc.left = innerBoxUpperCX;
rc.right = innerBoxLowerCX;
rc.bottom = innerBoxLowerCY;
gdi.addRectangle(rc, colorLightYellow, true, false);
gdi.setData("IsEditing", 1);
gdi.setCX(x1);
gdi.setCY(maxY);
showExample(gdi, margin, mlp);
gdi.scrollToBottom();
showExample(gdi, mlp);
updateAlign(gdi, val);
gdi.scrollToBottom();
gdi.refresh();
}
void ListEditor::showExample(gdioutput &gdi, int margin, const MetaListPost &mlp) {
void ListEditor::showExample(gdioutput &gdi, EPostType type) {
if (type == EPostType::lLastItem) {
type = EPostType(gdi.getSelectedItem("Type").first);
}
gdi.restore("Example", false);
MetaListPost mlp(type);
// Has not effect
//mlp.setLeg(readLeg(gdi, type, false));
mlp.setText(gdi.getText("Text", false));
showExample(gdi, mlp);
gdi.refreshFast();
}
void ListEditor::showExample(gdioutput &gdi, const MetaListPost &mlp) {
int x1 = gdi.getCX();
int margin = gdi.scaleLength(10);
RECT rrInner;
rrInner.left = x1 + margin;
rrInner.top = gdi.getCY();
bool hasSymbol;
lastShownExampleText = mlp.getText();
GDICOLOR color = GDICOLOR::colorLightGreen;
wstring text = MetaList::encode(mlp.getTypeRaw(), lastShownExampleText, hasSymbol);
if (!hasSymbol) {
text = lang.tl("Fel: Använd X i texten där värdet (Y) ska sättas in.#X#%s");
color = GDICOLOR::colorLightRed;
}
gdi.setRestorePoint("Example");
gdi.fillDown();
@ -1127,6 +1207,12 @@ void ListEditor::showExample(gdioutput &gdi, int margin, const MetaListPost &mlp
wstring s = oe->formatListString(mlp.getTypeRaw(), rr[i]);
if (used.insert(s).second) {
int xb = gdi.getCX();
if (!text.empty()) {
wchar_t st[300];
swprintf_s(st, text.c_str(), s.c_str());
s = st;
}
gdi.addStringUT(italicText, s + L" ");
int xa = gdi.getCX();
int delta = xa - xb;
@ -1142,7 +1228,7 @@ void ListEditor::showExample(gdioutput &gdi, int margin, const MetaListPost &mlp
gdi.fillDown();
gdi.popX();
gdi.addRectangle(rrInner, colorLightGreen, true);
gdi.addRectangle(rrInner, color, true);
}
const wchar_t *ListEditor::getIndexDescription(EPostType type) {
@ -1150,10 +1236,88 @@ const wchar_t *ListEditor::getIndexDescription(EPostType type) {
return L"Index in X[index]#OutputTimes";
else if (type == lResultModuleNumber || type == lResultModuleNumberTeam)
return L"Index in X[index]#OutputNumbers";
else if (MetaList::isAllStageType(type))
return L"Applicera för specifik etapp:";
else
return L"Applicera för specifik sträcka:";
}
bool ListEditor::legStageTypeIndex(gdioutput &gdi, EPostType type, int leg) {
int dx = gdi.scaleLength(250);
int dy = -gdi.getLineHeight() / 5;
if (MetaList::isResultModuleOutput(type)) {
if (gdi.hasWidget("UseLeg"))
gdi.removeWidget("UseLeg");
if (gdi.hasWidget("LegSel"))
gdi.removeWidget("LegSel");
if (gdi.hasWidget("TUseLeg"))
gdi.setTextTranslate("TUseLeg", getIndexDescription(type), true);
else
gdi.addString("TUseLeg", ypUseLeg, xpUseLeg, 0, getIndexDescription(type));
wstring legW = leg >= 0 ? itow(leg) : L"0";
if (!gdi.hasWidget("Leg"))
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", legW, 4, editListCB);
else {
if (gdi.getText("Leg").empty())
gdi.setText("Leg", legW);
}
}
else if (MetaList::isAllStageType(type)) {
if (gdi.hasWidget("UseLeg"))
gdi.removeWidget("UseLeg");
if (gdi.hasWidget("Leg"))
gdi.removeWidget("Leg");
if (gdi.hasWidget("TUseLeg"))
gdi.setTextTranslate("TUseLeg", getIndexDescription(type), true);
else
gdi.addString("TUseLeg", ypUseLeg, xpUseLeg, 0, getIndexDescription(type));
if (!gdi.hasWidget("LegSel")) {
gdi.addSelection(xpUseLeg + dx, ypUseLeg + dy, "LegSel", 160, gdi.scaleLength(300), editListCB);
vector<pair<wstring, size_t>> items;
items.emplace_back(lang.tl("Alla tidigare etapper"), -2);
for (int j = 1; j < 20; j++) {
items.emplace_back(lang.tl("Etapp X#" + itos(j)), j);
}
gdi.addItem("LegSel", items);
gdi.selectItemByData("LegSel", leg >= 0 ? leg + 1 : -2);
}
}
else {
if (gdi.hasWidget("LegSel"))
gdi.removeWidget("LegSel");
if (!gdi.hasWidget("UseLeg")) {
if (gdi.hasWidget("TUseLeg"))
gdi.removeWidget("TUseLeg");
gdi.addCheckbox(xpUseLeg, ypUseLeg, "UseLeg", getIndexDescription(type), editListCB, leg != -1);
wstring ix = leg >= 0 ? itow(leg + 1) : L"";
if (!gdi.hasWidget("Leg"))
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", ix, 4, editListCB);
else {
int leg = gdi.getTextNo("Leg");
gdi.setText("Leg", ix);
}
gdi.setInputStatus("Leg", leg != -1);
}
}
/*
if (MetaList::isResultModuleOutput(type)) {
gdi.check("UseLeg", true);
gdi.disableInput("UseLeg");
}*/
return true;
}
void ListEditor::editListProp(gdioutput &gdi, bool newList) {
checkUnsaved(gdi);

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -34,6 +34,7 @@ class TabBase;
#include <vector>
#include "autocompletehandler.h"
#include "oListInfo.h"
class ListEditor : public AutoCompleteHandler {
private:
@ -47,7 +48,7 @@ private:
bool dirtyInt;
SaveType lastSaved;
const wchar_t *getIndexDescription(EPostType type);
wstring lastShownExampleText;
void showLine(gdioutput &gdi, const vector<MetaListPost> &line, int ix) const;
int editList(gdioutput &gdi, int type, BaseInfo &data);
void updateType(int iType, gdioutput &gdi);
@ -56,7 +57,12 @@ private:
int lineIx, int ix) const;
void editListPost(gdioutput &gdi, const MetaListPost &mlp, int id);
void showExample(gdioutput &gdi, int margin, const MetaListPost &mlp);
void showExample(gdioutput &gdi, EPostType type = EPostType::lLastItem);
void showExample(gdioutput &gdi, const MetaListPost &mlp);
int readLeg(gdioutput &gdi, EPostType newType, bool checkError) const;
void editListProp(gdioutput &gdi, bool newList);
@ -78,6 +84,12 @@ private:
TabBase *origin = nullptr;
void show(gdioutput &gdi);
int xpUseLeg;
int ypUseLeg;
bool legStageTypeIndex(gdioutput &gdi, EPostType type, int leg);
public:
ListEditor(oEvent *oe);
virtual ~ListEditor();

View File

@ -1,6 +1,6 @@
/********************i****************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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

202
code/machinecontainer.cpp Normal file
View File

@ -0,0 +1,202 @@
#include "StdAfx.h"
#include "machinecontainer.h"
#include "meos_util.h"
#include "xmlparser.h"
#include "gdioutput.h"
int MachineContainer::AbstractMachine::getInt(const string &v) const {
return _wtoi(getString(v).c_str());
}
const wstring &MachineContainer::AbstractMachine::getString(const string &v) const {
auto res = props.find(v);
if (res != props.end())
return res->second;
return _EmptyWString;
}
vector<int> MachineContainer::AbstractMachine::getVectorInt(const string &v) const {
auto &s = getString(v);
vector<wstring> sp;
split(s, L",", sp);
vector<int> res(sp.size());
for (int j = 0; j < sp.size(); j++)
res[j] = _wtoi(sp[j].c_str());
return res;
}
set<int> MachineContainer::AbstractMachine::getSetInt(const string &v) const {
std::set<int> res;
for (int i : getVectorInt(v)) {
res.insert(i);
}
return res;
}
void MachineContainer::AbstractMachine::set(const string &name, int v) {
if (v != 0)
props[name] = itow(v);
}
void MachineContainer::AbstractMachine::set(const string &name, const vector<int> &v) {
wstring &r = props[name];
for (int j = 0; j < v.size(); j++) {
if (j == 0)
r = itow(v[j]);
else
r += L"," + itow(v[j]);
}
}
void MachineContainer::AbstractMachine::load(const xmlobject &data) {
xmlList out;
data.getObjects(out);
for (auto &x : out) {
props[x.getName()] = x.getw();
}
}
void MachineContainer::AbstractMachine::save(xmlparser &data) const {
for (auto &p : props) {
data.write(p.first.c_str(), p.second);
}
}
namespace {
string encode(const string &in) {
string out;
out.reserve(in.length());
for (int j = 0; j < in.length(); j++) {
if (in[j] == '|' || in[j] == '$' || in[j] == '%') {
out.push_back('%');
if (in[j] == '|')
out.push_back('1');
else if (in[j] == '$')
out.push_back('2');
else if (in[j] == '%')
out.push_back('3');
}
else
out.push_back(in[j]);
}
return out;
}
string decode(const string &in) {
string out;
out.reserve(in.length());
for (int j = 0; j < in.length(); j++) {
if (in[j] == '%') {
j++;
if (j < in.length()) {
if (in[j] == '1')
out.push_back('|');
else if (in[j] == '2')
out.push_back('§');
else if (in[j] == '3')
out.push_back('%');
}
}
else
out.push_back(in[j]);
}
return out;
}
}
void MachineContainer::AbstractMachine::load(const string &data) {
vector<string> parts;
split(data, "|", parts);
for (int j = 0; j < parts.size(); j+=2) {
const wstring &w = gdioutput::fromUTF8(decode(parts[j + 1]));
props[parts[j]] = w;
}
}
string MachineContainer::AbstractMachine::save() const {
string out;
for (auto &p : props) {
if (!out.empty())
out += "|";
out.append(p.first);
out += "|";
out.append(encode(gdioutput::toUTF8(p.second)));
}
return out;
}
void MachineContainer::AbstractMachine::set(const string &name, const wstring &v) {
if (!v.empty())
props[name] = v;
}
vector<pair<string, wstring>> MachineContainer::enumerate() const {
vector<pair<string, wstring>> res;
for (auto v : machines)
res.push_back(v.first);
return res;
}
void MachineContainer::load(const xmlobject &data) {
xmlList out;
data.getObjects("Machine", out);
for (auto &m : out) {
string type;
wstring tag;
m.getObjectString("type", type);
m.getObjectString("name", tag);
if (!type.empty() && !tag.empty()) {
auto res = machines.emplace(make_pair(type, tag), MachineContainer::AbstractMachine());
if (res.second)
res.first->second.load(m);
}
}
}
void MachineContainer::save(xmlparser &data) {
for (auto &m : machines) {
vector<wstring> p({ wstring(L"type"), gdioutput::widen(m.first.first),
wstring(L"name"), m.first.second });
data.startTag("Machine", p);
m.second.save(data);
data.endTag();
}
}
void MachineContainer::load(const string &data) {
vector<string> parts;
split(data, "$", parts);
for (int j = 0; j + 2 < parts.size(); j++) {
const string &type = parts[j];
wstring tag = gdioutput::fromUTF8(decode(parts[j + 1]));
auto res = machines.emplace(make_pair(type, tag), MachineContainer::AbstractMachine());
if (res.second)
res.first->second.load(parts[j+2]);
}
}
string MachineContainer::save() {
vector<string> ml;
ml.reserve(machines.size() * 3);
size_t tSize = 0;
for (auto &m : machines) {
ml.push_back(m.first.first);
tSize += ml.back().length() + 2;
ml.push_back(encode(gdioutput::toUTF8(m.first.second)));
tSize += ml.back().length() + 2;
ml.push_back(m.second.save());
tSize += ml.back().length() + 2;
}
string out;
out.reserve(tSize);
for (const string & m : ml) {
if (!out.empty())
out.append("$");
out.append(m);
}
return out;
}

79
code/machinecontainer.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include <string>
#include <map>
#include <set>
#include <vector>
class xmlparser;
class xmlobject;
using namespace std;
class MachineContainer {
public:
class AbstractMachine {
map<string, wstring> props;
public:
void clear() {
props.clear();
}
int getInt(const string &v) const;
const wstring &getString(const string &v) const;
vector<int> getVectorInt(const string &v) const;
set<int> getSetInt(const string &v) const;
void set(const string &name, int v);
void set(const string &name, const vector<int> &v);
void set(const string &name, const wstring &v);
void set(const string &name, bool v) {
set(name, int(v));
}
template<typename T>
void set(const string &name, const T &v) {
vector<int> vv;
for (auto x : v)
vv.push_back(x);
set(name, vv);
}
protected:
void load(const xmlobject &data);
void load(const string &data);
void save(xmlparser &data) const;
string save() const;
friend class MachineContainer;
};
private:
map<pair<string, wstring>, AbstractMachine> machines;
public:
const AbstractMachine *get(const string &type, const wstring &name) const {
auto res = machines.find(make_pair(type, name));
if (res != machines.end())
return &res->second;
return nullptr;
}
void erase(const string &type, const wstring &name) {
machines.erase(make_pair(type, name));
}
AbstractMachine &set(const string &type, const wstring &name) {
auto &m = machines[make_pair(type, name)];
m.clear();
return m;
}
vector<pair<string, wstring>> enumerate() const;
void load(const xmlobject &data);
void save(xmlparser &data);
void load(const string &data);
string save();
};

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -294,7 +294,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
return 0;
}
if (fileExist(settings)) {
if (fileExists(settings)) {
gEvent->loadProperties(settings);
}
else {
@ -314,13 +314,13 @@ int APIENTRY WinMain(HINSTANCE hInstance,
lang.get().addLangResource(L"Español", L"111");
lang.get().addLangResource(L"Russian", L"107");
if (fileExist(L"extra.lng")) {
if (fileExists(L"extra.lng")) {
lang.get().addLangResource(L"Extraspråk", L"extra.lng");
}
else {
wchar_t lpath[260];
getUserFile(lpath, L"extra.lng");
if (fileExist(lpath))
if (fileExists(lpath))
lang.get().addLangResource(L"Extraspråk", lpath);
}
@ -479,7 +479,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
// Main message loop:
mainMessageLoop(hAccelTable, 0);
tabAutoRegister(0);
TabAuto::tabAutoRegister(nullptr);
tabList->clear();
delete tabList;
tabList = nullptr;
@ -730,6 +730,14 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
gdi->keyCommand(KC_FINDBACK);
}
}
else if (wParam == 'A' && ctrlPressed) {
if (gdi)
gdi->keyCommand(KC_MARKALL);
}
else if (wParam == 'D' && ctrlPressed) {
if (gdi)
gdi->keyCommand(KC_CLEARALL);
}
else if (wParam == VK_DELETE) {
if (gdi)
gdi->keyCommand(KC_DELETE);
@ -1072,6 +1080,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static bool connectionAlert = false;
switch (message)
{
@ -1084,7 +1093,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TabAuto *ta = (TabAuto *)gdi_main->getTabs().get(TAutoTab);
tabList->push_back(TabObject(ta, "Automater"));
tabAutoRegister(ta);
TabAuto::tabAutoRegister(ta);
}
tabList->push_back(TabObject(gdi_main->getTabs().get(TSpeakerTab), "Speaker"));
tabList->push_back(TabObject(gdi_main->getTabs().get(TClassTab), "Klasser"));
@ -1248,7 +1257,18 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_USER + 5:
if (gdi_main)
gdi_main->addInfoBox("ainfo", L"info:advanceinfo", 10000);
break;
case WM_USER + 6:
if (gdi_main && lParam) {
gdioutput* g = (gdioutput*)lParam;
wstring msg = g->getDelayedAlert();
if (!connectionAlert) {
connectionAlert = true;
gdi_main->alert(msg);
connectionAlert = false;
}
}
break;
case WM_COMMAND:

View File

@ -149,8 +149,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,1,0,1
PRODUCTVERSION 3,1,0,1
FILEVERSION 3,8,0,1
PRODUCTVERSION 3,8,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -167,12 +167,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Melin Software HB"
VALUE "FileDescription", "meos"
VALUE "FileVersion", "3.7.0.1"
VALUE "FileVersion", "3.8.0.1"
VALUE "InternalName", "meos"
VALUE "LegalCopyright", "Copyright © 2007-2020"
VALUE "LegalCopyright", "Copyright © 2007-2021"
VALUE "OriginalFilename", "meos.exe"
VALUE "ProductName", " meos"
VALUE "ProductVersion", "3.7.0.1"
VALUE "ProductVersion", "3.8.0.1"
END
END
BLOCK "VarFileInfo"

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -882,9 +882,9 @@ wstring trim(const wstring &s) {
else return L"";
}
bool fileExist(const wchar_t *file)
bool fileExists(const wstring &file)
{
return GetFileAttributes(file) != INVALID_FILE_ATTRIBUTES;
return GetFileAttributes(file.c_str()) != INVALID_FILE_ATTRIBUTES;
}
bool stringMatch(const wstring &a, const wstring &b) {

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -158,7 +158,7 @@ int countWords(const wchar_t *p);
wstring trim(const wstring &s);
string trim(const string &s);
bool fileExist(const wchar_t *file);
bool fileExists(const wstring &file);
bool stringMatch(const wstring &a, const wstring &b);

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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,6 +7,10 @@
#define IDR_3007 109
#define IDR_3008 110
#define IDR_3011 111
#define SND_OK 50
#define SND_LEADER 51
#define SND_NOTOK 52
#define SND_NEEDACTION 53
IDR_3001 300 DISCARDABLE "swedish.lng"
IDR_3002 300 DISCARDABLE "english.lng"
@ -18,3 +22,7 @@ IDR_3008 300 DISCARDABLE "french.lng"
IDR_3011 300 DISCARDABLE "spanish.lng"
/////////////////////////////////////////////////////////////////////////////
SND_OK WAVE DISCARDABLE "./sound/ok.wav"
SND_LEADER WAVE DISCARDABLE "./sound/leader.wav"
SND_NOTOK WAVE DISCARDABLE "./sound/notok.wav"
SND_NEEDACTION WAVE DISCARDABLE "./sound/needaction.wav"

View File

@ -489,6 +489,7 @@
<ClCompile Include="listeditor.cpp" />
<ClCompile Include="liveresult.cpp" />
<ClCompile Include="localizer.cpp" />
<ClCompile Include="machinecontainer.cpp" />
<ClCompile Include="meos.cpp">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -683,6 +684,7 @@
<ClInclude Include="iof30interface.h" />
<ClInclude Include="listeditor.h" />
<ClInclude Include="liveresult.h" />
<ClInclude Include="machinecontainer.h" />
<ClInclude Include="meosdb\sqltypes.h" />
<ClInclude Include="meosdb\targetver.h" />
<ClInclude Include="meosexception.h" />

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -25,17 +25,17 @@
//ABCDEFGHIJKLMNO
int getMeosBuild() {
string revision("$Rev: 1081 $");
string revision("$Rev: 1103 $");
return 174 + atoi(revision.substr(5, string::npos).c_str());
}
wstring getMeosDate() {
wstring date(L"$Date: 2021-07-12 17:51:51 +0200 (mån, 12 jul 2021) $");
wstring date(L"$Date: 2021-12-11 15:54:57 +0100 (lör, 11 dec 2021) $");
return date.substr(7,10);
}
wstring getBuildType() {
return L"Beta"; // No parantheses (...)
return L"Beta II"; // No parantheses (...)
}
wstring getMajorVersion() {
@ -90,7 +90,6 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
supp.emplace_back(L"OK Tjärnen");
supp.emplace_back(L"Leksands OK");
supp.emplace_back(L"O-Travel");
supp.emplace_back(L"Kamil Pipek, OK Lokomotiva Pardubice");
developSupp.emplace_back(L"KOB Kysak");
supp.emplace_back(L"Ingemar Carlsson");
supp.emplace_back(L"Tolereds AIK");
@ -149,6 +148,20 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
supp.emplace_back(L"IFK Kiruna");
supp.emplace_back(L"Smedjebackens OK");
supp.emplace_back(L"Gunnar Persson, Svanesunds GIF");
supp.emplace_back(L"Kamil Pipek, OK Lokomotiva Pardubice");
supp.emplace_back(L"Køge Orienteringsklub");
supp.emplace_back(L"Simrishamns OK");
supp.emplace_back(L"OK Fryksdalen");
supp.emplace_back(L"Magnus Asplund, Sundbybergs IK");
supp.emplace_back(L"Frölunda OL");
supp.emplace_back(L"Hjobygdens OK");
supp.emplace_back(L"OK Malmia");
supp.emplace_back(L"Säterbygdens OK");
supp.emplace_back(L"OK Orinto");
supp.emplace_back(L"Trosabygdens OK");
supp.emplace_back(L"Järla Orientering");
supp.emplace_back(L"Hans Wilhelmsson, Säffle OK");
supp.emplace_back(L"Cent Vallées Orientation 12 (C.V.O. 12)");
reverse(supp.begin(), supp.end());
}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -485,16 +485,24 @@ void MetaList::initUniqueIndex() const {
uniqueIndex = "A" + itos(ix) + "B" + itos(yx);
}
bool MetaList::isBreak(int x) const {
bool MetaList::isBreak(int x) {
return isspace(x) || x == '.' || x == ',' ||
x == '-' || x == ':' || x == ';' || x == '('
|| x == ')' || x=='/' || (x>30 && x < 127 && !isalnum(x));
}
wstring MetaList::encode(const wstring &input_) const {
wstring MetaList::encode(EPostType type, const wstring &inputS, bool &foundSymbol) {
if (inputS.empty()) {
foundSymbol = true; // No symbol needed
return inputS;
}
wstring out;
wstring input = lang.tl(input_);
wstring input = lang.tl(inputS);
out.reserve(input.length() + 5);
int sCount = 0;
if (type == EPostType::lString)
sCount = 1; // No symbols expected in string
for (size_t k = 0; k<input.length(); k++) {
int c = input[k];
@ -505,20 +513,22 @@ wstring MetaList::encode(const wstring &input_) const {
out.push_back('%');
out.push_back('%');
}
else if (c == 'X' && isBreak(n) && isBreak(p) ) {
else if (c == 'X' && isBreak(n) && isBreak(p) && sCount == 0) {
out.push_back('%');
out.push_back('s');
sCount++;
}
else
out.push_back(c);
}
foundSymbol = sCount > 0;
return out;
}
MetaListPost &MetaList::add(ListIndex ix, const MetaListPost &post) {
if (data[ix].empty())
addRow(ix);
// data[ix].resize(1);
vector<MetaListPost> &d = data[ix].back();
d.push_back(post);
@ -636,9 +646,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
}
auto isAllStageType = [](const MetaListPost &mp) {
return ((mp.type == lRunnerStagePlace || mp.type == lRunnerStageStatus
|| mp.type == lRunnerStageTime || mp.type == lRunnerStageTimeStatus ||
mp.type == lRunnerStagePoints || mp.type == lRunnerStageNumber) && mp.leg == -1);
return MetaList::isAllStageType(mp.type) && mp.leg == -1;
};
for (size_t j = 0; j<lines.size(); j++) {
@ -729,12 +737,13 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
if (mp.font != formatIgnore)
font = mp.font;
vector< pair<EPostType, wstring> > typeFormats;
typeFormats.push_back(make_pair(mp.type, encode(mp.text)));
bool dmy;
vector<pair<EPostType, wstring>> typeFormats;
typeFormats.push_back(make_pair(mp.type, encode(mp.type, mp.text, dmy)));
size_t kk = k+1;
//Add merged entities
while (kk < cline.size() && cline[kk].mergeWithPrevious) {
typeFormats.push_back(make_pair(cline[kk].type, encode(cline[kk].text)));
typeFormats.push_back(make_pair(cline[kk].type, encode(cline[kk].type, cline[kk].text, dmy)));
kk++;
}
@ -838,7 +847,8 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
continue;
string label = "P" + itos(0*1000 + j*100 + k);
wstring text = makeDash(encode(cline[k].text));
bool dmy;
wstring text = makeDash(encode(cline[k].type, cline[k].text, dmy));
if (capitalizeTitle)
capitalizeWords(text);
@ -899,8 +909,8 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
gdiFonts font = header;
if (mp.font != formatIgnore)
font = mp.font;
wstring text = encode(mp.text);
bool dmy;
wstring text = encode(mp.type, mp.text, dmy);
if (capitalizeTitle)
capitalizeWords(text);
@ -949,7 +959,8 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
font = mp.font;
next_dy = max(next_dy, fontHeight[make_pair(font, MLList)]);
oPrintPost &added = li.addListPost(oPrintPost(mp.type, encode(mp.text), font|mp.textAdjust,
bool dmy;
oPrintPost &added = li.addListPost(oPrintPost(mp.type, encode(mp.type, mp.text, dmy), font|mp.textAdjust,
pos.get(label, s_factor),
dy + list_dy, cline[k].leg == -1 ? parLegNumber : make_pair(cline[k].leg, true))).
setFontFace(fontFaces[MLList].font,
@ -1000,7 +1011,8 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
xp = pos.get(label, s_factor);
next_dy = max(next_dy, fontHeight[make_pair(font, MLSubList)]);
oPrintPost &added = li.addSubListPost(oPrintPost(mp.type, encode(mp.text), font|mp.textAdjust,
bool dmy;
oPrintPost &added = li.addSubListPost(oPrintPost(mp.type, encode(mp.type, mp.text, dmy), font|mp.textAdjust,
xp, dy+sublist_dy, mp.leg == -1 ? parLegNumber : make_pair(mp.leg, true))).
setFontFace(fontFaces[MLSubList].font,
fontFaces[MLSubList].scale);
@ -1979,6 +1991,7 @@ void MetaList::initSymbols() {
typeToSymbol[lRunnerTimeAdjustment] = L"RunnerTimeAdjustment";
typeToSymbol[lRunnerPointAdjustment] = L"RunnerPointAdjustment";
typeToSymbol[lRunnerRogainingPointGross] = L"RunnerRogainingPointGross";
typeToSymbol[lRunnerCardVoltage] = L"RunnerCardVoltage";
typeToSymbol[lRunnerStageTime] = L"RunnerStageTime";
typeToSymbol[lRunnerStageStatus] = L"RunnerStageStatus";

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -50,7 +50,6 @@ class Position
void update(int ix, const string &newname, int width, bool alignBlock, bool alignLock);
public:
int getWidth() const;
bool postAdjust();
@ -207,8 +206,6 @@ private:
enum ListIndex {MLHead = 0, MLSubHead = 1, MLList = 2, MLSubList=3};
MetaListPost &add(ListIndex ix, const MetaListPost &post);
void addRow(int ix);
wstring encode(const wstring &input) const;
bool isBreak(int x) const;
static map<EPostType, wstring> typeToSymbol;
static map<wstring, EPostType> symbolToType;
@ -237,15 +234,28 @@ private:
int getResultModuleIndex(oEvent *oe, oListInfo &li, const MetaListPost &lp) const;
mutable map<string, int> resultToIndex;
static bool isBreak(int x);
public:
static wstring encode(EPostType type, const wstring &input, bool &foundSymbol);
static void getAutoComplete(const wstring &w, vector<AutoCompleteRecord> &records);
MetaList();
virtual ~MetaList() {}
bool supportClasses() const;
static constexpr bool isAllStageType(EPostType type) {
return type == lRunnerStagePlace || type == lRunnerStageStatus ||
type == lRunnerStageTime || type == lRunnerStageTimeStatus ||
type == lRunnerStagePoints || type == lRunnerStageNumber;
}
static constexpr bool isResultModuleOutput(EPostType type) {
return type == lResultModuleNumber || type == lResultModuleTime ||
type == lResultModuleTimeTeam || type == lResultModuleNumberTeam;
}
bool supportClasses() const;
const wstring &getListInfo(const oEvent &oe) const;
void clearTag() {tag.clear();}

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -971,7 +971,7 @@ bool MethodEditor::resultIsInstalled() const {
return false; // Used in a list in this competition
//string path = getInternalPath(currentResult->getTag());
return fileExist(fileNameSource.c_str());
return fileExists(fileNameSource);
}
void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {

View File

@ -2,7 +2,7 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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-2020 Melin Software HB
Copyright (C) 2009-2021 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
@ -86,7 +86,7 @@ unsigned __stdcall reconnectThread(void *v) {
return 0;
}
void MySQLReconnect::settings(gdioutput &gdi, oEvent &oe, bool created) {
void MySQLReconnect::settings(gdioutput &gdi, oEvent &oe, State state) {
}
void MySQLReconnect::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
@ -111,6 +111,7 @@ void MySQLReconnect::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
gdi.setDBErrorState(false);
gdi.setWindowTitle(oe->getTitleName());
interval=0;
toRemove = true;
}
}
else if (mysqlStatus==-1) {
@ -138,9 +139,7 @@ void MySQLReconnect::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
int AutomaticCB(gdioutput *gdi, int type, void *data);
void MySQLReconnect::status(gdioutput &gdi) {
gdi.dropLine(0.5);
gdi.addString("", 1, name);
gdi.pushX();
AutoMachine::status(gdi);
if (interval>0){
gdi.addStringUT(1, timeError + L": " + lang.tl("DATABASE ERROR")).setColor(colorDarkRed);
gdi.fillRight();

View File

@ -1,6 +1,6 @@
/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2020 Melin Software HB
Copyright (C) 2009-2021 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

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