diff --git a/code/HTMLWriter.cpp b/code/HTMLWriter.cpp
index 9d0732a..2038cc1 100644
--- a/code/HTMLWriter.cpp
+++ b/code/HTMLWriter.cpp
@@ -189,6 +189,7 @@ static void getStyle(const map< pair, pair > &
bool gdioutput::writeHTML(const wstring &file, const wstring &title, int refreshTimeOut) const
{
+ checkWriteAccess(file);
ofstream fout(file.c_str());
if (fout.bad())
@@ -294,6 +295,7 @@ bool sortTL_X(const TextInfo *a, const TextInfo *b)
bool gdioutput::writeTableHTML(const wstring &file,
const wstring &title, int refreshTimeOut) const
{
+ checkWriteAccess(file);
ofstream fout(file.c_str());
if (fout.bad())
diff --git a/code/RestService.cpp b/code/RestService.cpp
new file mode 100644
index 0000000..53893cb
--- /dev/null
+++ b/code/RestService.cpp
@@ -0,0 +1,92 @@
+#include "stdafx.h"
+#include "RestService.h"
+#include "meos_util.h"
+#include "restserver.h"
+
+int AutomaticCB(gdioutput *gdi, int type, void *data);
+
+RestService::RestService() : AutoMachine("RestService"), port(-1) {
+}
+
+
+RestService::~RestService() {
+ if (server) {
+ server->stop();
+ RestServer::remove(server);
+ }
+}
+
+void RestService::save(oEvent &oe, gdioutput &gdi) {
+ if (!server)
+ server = RestServer::construct();
+
+ int port = gdi.getTextNo("Port");
+ if (port > 0 && port < 65536)
+ server->startService(port);
+ else
+ throw std::exception("Invalid port number");
+}
+
+void RestService::settings(gdioutput &gdi, oEvent &oe, bool created) {
+ if (port == -1)
+ port = oe.getPropertyInt("ServicePort", 2009);
+
+ settingsTitle(gdi, "MeOS Informationsserver REST-API");
+ startCancelInterval(gdi, "Save", created, IntervalNone, L"");
+
+ if (!server)
+ gdi.addInput("Port", itow(port), 10, 0, L"Port:", L"Testa genom http://localhost:[PORT]/meos");
+ else
+ gdi.addString("", 0, "Server startad på X#" + itos(port));
+
+ gdi.popX();
+ gdi.addString("", 10, "help:rest");
+}
+
+void RestService::status(gdioutput &gdi) {
+ gdi.pushX();
+ gdi.addString("", 1, name);
+ /*if (!baseFile.empty()) {
+ gdi.fillRight();
+ gdi.pushX();
+ gdi.addString("", 0, L"Destination: X#" + baseFile);
+
+ if (interval>0) {
+ gdi.popX();
+ gdi.dropLine(1);
+ gdi.addString("", 0, "Säkerhetskopierar om: ");
+ gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount() - timeout) / 1000);
+ }
+
+ gdi.popX();
+ }*/
+
+ if (server) {
+ gdi.addString("", 0, "Server startad på port X#" + itos(port));
+
+ RestServer::Statistics rs;
+ server->getStatistics(rs);
+ gdi.addString("", 0, "Antal förfrågningar: X#" + itos(rs.numRequests));
+ gdi.addString("", 0, "Genomsnittlig svarstid: X ms#" + itos(rs.averageResponseTime));
+ gdi.addString("", 0, "Längsta svarstid: X ms#" + itos(rs.maxResponseTime));
+ }
+
+ gdi.dropLine(2);
+ gdi.fillRight();
+ gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId());
+ gdi.fillDown();
+ gdi.addButton("InfoService", "Inställningar...", AutomaticCB).setExtra(getId());
+ gdi.popX();
+}
+
+void RestService::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
+
+}
+
+
+void RestService::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+ if (type == GUI_BUTTON) {
+ ButtonInfo &bi = static_cast(info);
+
+ }
+}
\ No newline at end of file
diff --git a/code/RestService.h b/code/RestService.h
new file mode 100644
index 0000000..92dfdcb
--- /dev/null
+++ b/code/RestService.h
@@ -0,0 +1,48 @@
+/************************************************************************
+MeOS - Orienteering Software
+Copyright (C) 2009-2017 Melin Software HB
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+Melin Software HB - software@melin.nu - www.melin.nu
+Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
+
+************************************************************************/
+
+#pragma once
+#include "TabAuto.h"
+#include
+
+class RestServer;
+
+class RestService :
+ public AutoMachine, GuiHandler
+{
+ int port;
+ shared_ptr server;
+
+public:
+
+ void save(oEvent &oe, gdioutput &gdi) override;
+ void settings(gdioutput &gdi, oEvent &oe, bool created) override;
+ RestService *clone() const override { return new RestService(*this); }
+ void status(gdioutput &gdi) override;
+ void process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) override;
+
+ void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) override;
+
+ RestService();
+ ~RestService();
+};
+
diff --git a/code/SportIdent.cpp b/code/SportIdent.cpp
index a864fb8..054c611 100644
--- a/code/SportIdent.cpp
+++ b/code/SportIdent.cpp
@@ -2140,13 +2140,19 @@ void SportIdent::getInfoString(const wstring &com, vector &infov)
}
}
+static string formatTimeN(int t) {
+ const wstring &wt = formatTime(t);
+ string nt(wt.begin(), wt.end());
+ return nt;
+}
+
vector SICard::codeLogData(int row) const
{
vector log;
log.push_back(itos(row));
if (readOutTime[0] == 0)
- log.push_back(getLocalTime());
+ log.push_back(getLocalTimeN());
else
log.push_back(readOutTime);
log.push_back(itos(CardNumber));
diff --git a/code/TabAuto.cpp b/code/TabAuto.cpp
index 4ba343d..3e91537 100644
--- a/code/TabAuto.cpp
+++ b/code/TabAuto.cpp
@@ -35,6 +35,7 @@
#include "classconfiginfo.h"
#include "onlineresults.h"
#include "onlineinput.h"
+#include "RestService.h"
#include "TabAuto.h"
#include "TabSI.h"
@@ -78,6 +79,8 @@ AutoMachine* AutoMachine::construct(Machines ms) {
return new OnlineResults();
case mSaveBackup:
return new SaveMachine();
+ case mInfoService:
+ return new RestService();
}
throw meosException("Invalid machine");
}
@@ -316,6 +319,9 @@ int TabAuto::processButton(gdioutput &gdi, const ButtonInfo &bu)
SaveMachine *sm=dynamic_cast(getMachine(bu.getExtraInt()));
settings(gdi, sm, mSaveBackup);
}
+ else if (bu.id == "InfoService") {
+ settings(gdi, getMachine(bu.getExtraInt()), mInfoService);
+ }
else if (bu.id=="StartResult") {
#ifndef MEOSDB
wstring minute=gdi.getText("Interval");
@@ -602,12 +608,14 @@ bool TabAuto::loadPage(gdioutput &gdi)
gdi.addButton("OnlineInput", "Inmatning online", AutomaticCB, "Hämta stämplingar m.m. från nätet");
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("SaveBackup", "Säkerhetskopiering", AutomaticCB);
+ gdi.addButton("InfoService", "Informationsserver", AutomaticCB);
gdi.addButton("Punches", "Stämplingstest", AutomaticCB, "Simulera inläsning av stämplar");
gdi.popX();
gdi.dropLine(2.5);
- gdi.addButton("SaveBackup", "Säkerhetskopiering", AutomaticCB);
+ 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.fillDown();
gdi.dropLine(3);
@@ -682,7 +690,7 @@ void AutoMachine::startCancelInterval(gdioutput &gdi, char *startCommand, bool c
void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
settingsTitle(gdi, "Resultatutskrift / export");
- wstring time=created ? L"10:00" : getTimeMSW(interval);
+ wstring time=created ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "StartResult", created, IntervalMinute, time);
if (created) {
@@ -1097,7 +1105,7 @@ void SaveMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
void SaveMachine::settings(gdioutput &gdi, oEvent &oe, bool created) {
settingsTitle(gdi, "Säkerhetskopiering");
- wstring time=created ? L"10:00" : getTimeMSW(interval);
+ wstring time=created ? L"10:00" : getTimeMS(interval);
startCancelInterval(gdi, "StartBackup", created, IntervalMinute, time);
int cx = gdi.getCX();
diff --git a/code/TabAuto.h b/code/TabAuto.h
index ea5a051..cd39160 100644
--- a/code/TabAuto.h
+++ b/code/TabAuto.h
@@ -43,6 +43,7 @@ enum Machines {
mOnlineResults,
mOnlineInput,
mSaveBackup,
+ mInfoService,
};
class AutoMachine
diff --git a/code/TabClass.cpp b/code/TabClass.cpp
index 7110706..dc55ead 100644
--- a/code/TabClass.cpp
+++ b/code/TabClass.cpp
@@ -69,6 +69,7 @@ void TabClass::clearCompetitionData() {
storedPredefined = oEvent::PredefinedTypes(-1);
cInfoCache.clear();
hasWarnedDirect = false;
+ hasWarnedStartTime = false;
lastSeedMethod = -1;
lastSeedPreventClubNb = true;
@@ -159,8 +160,12 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
gdi.setInputStatus("CommonStartTime", gdi.isChecked(bi.id));
}
else if (bi.id == "CoursePool") {
- string strId = "StageCourses_expl";
+ string strId = "StageCourses_label";
gdi.setTextTranslate(strId, getCourseLabel(gdi.isChecked(bi.id)), true);
+ setLockForkingState(gdi, gdi.isChecked("CoursePool"), gdi.isChecked("LockForking"));
+ }
+ else if (bi.id == "LockForking") {
+ setLockForkingState(gdi, gdi.isChecked("CoursePool"), gdi.isChecked(bi.id));
}
else if (bi.id == "DefineForking") {
if (!checkClassSelected(gdi))
@@ -390,7 +395,13 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
if (nstages>0 && nstages<41) {
wstring st=gdi.getText("StartTime");
- if (oe->convertAbsoluteTime(st)>0)
+
+ int nst = oe->convertAbsoluteTime(st);
+ if (warnDrawStartTime(gdi, nst)) {
+ nst = 3600;
+ st = oe->getAbsTime(nst);
+ }
+ if (nst>0)
storedStart = st;
save(gdi, false); //Clears and reloads
@@ -568,7 +579,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
bool checked = gdi.isChecked("UseAdvanced");
oe->setProperty("AdvancedClassSettings", checked);
save(gdi, true);
- PostMessage(gdi.getTarget(), WM_USER + 2, TClassTab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TClassTab, 0);
}
else if (bi.id=="SwitchMode") {
if (!tableMode)
@@ -578,7 +589,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id=="Restart") {
save(gdi, true);
- gdi.clearPage(true);
+ clearPage(gdi, true);
gdi.addString("", 2, "Omstart i stafettklasser");
gdi.addString("", 10, "help:31661");
gdi.addListBox("RestartClasses", 200, 250, 0, L"Stafettklasser", L"", true);
@@ -662,13 +673,16 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
bool drawCoursebased = drawInfo.coursesTogether;
+ int maxST = 0;
map > specs;
for(size_t k=0; ksynchronize(false);
- ci.pc->setDrawFirstStart(drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart);
+ int stloc = drawInfo.firstStart + drawInfo.baseInterval * ci.firstStart;
+ maxST = max(maxST, stloc);
+ ci.pc->setDrawFirstStart(stloc);
ci.pc->setDrawInterval(ci.interval * drawInfo.baseInterval);
ci.pc->setDrawVacant(ci.nVacant);
ci.pc->setDrawNumReserved(ci.nExtra);
@@ -685,6 +699,9 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
specs[ci.classId].push_back(cds);
}
+ if (warnDrawStartTime(gdi, maxST))
+ return 0;
+
for (map >::iterator it = specs.begin();
it != specs.end(); ++it) {
oe->drawList(it->second, soft, pairSize, oEvent::drawAll);
@@ -692,7 +709,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
oe->addAutoBib();
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addButton("Cancel", "Återgå", ClassesCB);
oListParam par;
@@ -750,8 +767,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
ClassId = 0;
EditChanged=false;
- gdi.clearPage(true);
-
+ clearPage(gdi, true);
+
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.dropLine();
@@ -877,6 +894,9 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "AutomaticDraw") {
wstring firstStart = gdi.getText("FirstStart");
+
+ if (warnDrawStartTime(gdi, firstStart))
+ return 0;
wstring minInterval = gdi.getText("MinInterval");
wstring vacances = gdi.getText("Vacances");
bool lateBefore = false;
@@ -888,7 +908,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
int method = gdi.getSelectedItem("Method").first;
bool useSoft = method == DMSOFT;
- gdi.clearPage(true);
+ clearPage(gdi, true);
oe->automaticDrawAll(gdi, firstStart, minInterval, vacances,
lateBefore, useSoft, pairSize);
oe->addAutoBib();
@@ -909,7 +929,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
wstring firstStart;
firstStart = gdi.getText("FirstStart");
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addString("", boldLarge, "Gemensam start");
gdi.dropLine();
int by = 0;
@@ -938,6 +958,9 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
wstring time = gdi.getText("FirstStart");
+ if (warnDrawStartTime(gdi, time))
+ return 0;
+
for (set::iterator it = classes.begin(); it!=classes.end();++it) {
simultaneous(*it, time);
}
@@ -973,8 +996,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
}
}
- gdi.clearPage(false);
-
+ clearPage(gdi, false);
gdi.addString("", boldLarge, "Lotta flera klasser");
gdi.dropLine(0.5);
@@ -1331,13 +1353,17 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (t<=0)
throw std::exception("Ogiltig första starttid. Måste vara efter nolltid.");
-
+
+
oEvent::DrawType dtype(oEvent::drawAll);
if (bi.id=="DoDrawAfter")
dtype = oEvent::remainingAfter;
else if (bi.id=="DoDrawBefore")
dtype = oEvent::remainingBefore;
-
+ else {
+ if (warnDrawStartTime(gdi, t))
+ return 0;
+ }
//bool pairwise = false;
// if (gdi.hasField("Pairwise"))
@@ -1427,6 +1453,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
oe->generateList(gdi, false, info, true);
gdi.refresh();
+ gdi.setData("ClassPageLoaded", 1);
+
return 0;
}
else if (bi.id=="HandleBibs") {
@@ -1469,7 +1497,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (EditChanged)
gdi.sendCtrlMessage("Save");
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addString("", boldLarge, L"Lotta klassen X#"+pc->getName());
gdi.dropLine();
@@ -1519,7 +1547,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (!pc)
throw std::exception("Class not found");
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addString("", boldLarge, L"Nummerlappar i X#" + pc->getName());
gdi.dropLine();
gdi.setRestorePoint("bib");
@@ -1632,7 +1660,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (!pc)
throw std::exception("Class not found");
- gdi.clearPage(true);
+ clearPage(gdi, true);
gdi.addString("", boldLarge, L"Dela klass: X#" + pc->getName());
gdi.dropLine();
int tot, fin, dns;
@@ -1682,7 +1710,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
pc->splitClass(ClassSplitMethod(lbi.data), parts, outClass);
- gdi.clearPage(true);
+ clearPage(gdi, true);
gdi.addButton("Cancel", "Återgå", ClassesCB);
oListParam par;
@@ -1692,6 +1720,21 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
oe->generateListInfo(par, gdi.getLineHeight(), info);
oe->generateList(gdi, false, info, true);
}
+ else if (bi.id == "LockAllForks" || bi.id == "UnLockAllForks") {
+ bool lock = bi.id == "LockAllForks";
+ vector allCls;
+ oe->getClasses(allCls, true);
+ for (pClass c : allCls) {
+ if (c->isRemoved())
+ continue;
+ if (!c->hasCoursePool() && c->hasMultiCourse()) {
+ c->lockedForking(lock);
+ c->synchronize(true);
+ }
+ }
+ loadPage(gdi);
+ return 0;
+ }
else if (bi.id=="Merge") {
save(gdi, true);
if (!checkClassSelected(gdi))
@@ -1720,7 +1763,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
if (cls.empty())
throw std::exception("En klass kan inte slås ihop med sig själv.");
- gdi.clearPage(true);
+
+ clearPage(gdi, true);
gdi.addString("", boldLarge, L"Slå ihop klass: X (denna klass behålls)#" + pc->getName());
gdi.dropLine();
gdi.addString("", 10, "help:12138");
@@ -1781,7 +1825,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
throw std::exception("En klass kan inte slås ihop med sig själv.");
pc->mergeClass(lbi.data);
- gdi.clearPage(true);
+
+ clearPage(gdi, true);
gdi.addButton("Cancel", "Återgå", ClassesCB);
oListParam par;
@@ -2078,7 +2123,7 @@ void TabClass::showClassSettings(gdioutput &gdi)
gdi.addString("C" + itos(id), 0, L"X platser. Startar Y#" + wstring(bf1) + L"#" + bf2);
y = gdi.getCY();
gdi.addInput(xp+300, y, "S"+itos(id), first, 7, DrawClassesCB);
- gdi.addInput(xp+300+width, y, "I"+itos(id), formatTimeW(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
+ gdi.addInput(xp+300+width, y, "I"+itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
gdi.addInput(xp+300+width*2, y, "V"+itos(id), itow(ci.nVacant), 7, DrawClassesCB);
gdi.addInput(xp+300+width*3, y, "R"+itos(id), itow(ci.nExtra), 7, DrawClassesCB);
@@ -2245,9 +2290,14 @@ void TabClass::selectClass(gdioutput &gdi, int cid)
if (gdi.hasField("Unordered"))
gdi.check("Unordered", pc->hasUnorderedLegs());
+ if (gdi.hasField("LockForking")) {
+ gdi.check("LockForking", pc->lockedForking());
+ setLockForkingState(gdi, pc->hasCoursePool(), pc->lockedForking());
+ }
+
if (gdi.hasField("MCourses")) {
oe->fillCourses(gdi, "MCourses", true);
- string strId = "StageCourses_expl";
+ string strId = "StageCourses_label";
gdi.setTextTranslate(strId, getCourseLabel(pc->hasCoursePool()), true);
}
@@ -2510,6 +2560,9 @@ void TabClass::multiCourse(gdioutput &gdi, int nLeg) {
"Knyt löparna till banor från en pool vid målgång.");
gdi.addCheckbox("Unordered", "Oordnade parallella sträckor", MultiCB, false,
"Tillåt löpare inom en parallell grupp att springa gruppens banor i godtycklig ordning.");
+ gdi.addCheckbox("LockForking", "Lås gafflingar", MultiCB, false,
+ "Markera för att förhindra oavsiktlig ändring av gafflingsnycklar.");
+
gdi.popX();
gdi.fillRight();
gdi.dropLine(1.7);
@@ -2594,6 +2647,9 @@ void TabClass::save(gdioutput &gdi, bool skipReload)
if (gdi.hasField("Unordered"))
pc->setUnorderedLegs(gdi.isChecked("Unordered"));
+ if (gdi.hasField("LockForking"))
+ pc->lockedForking(gdi.isChecked("LockForking"));
+
pc->setAllowQuickEntry(gdi.isChecked("AllowQuickEntry"));
pc->setNoTiming(gdi.isChecked("NoTiming"));
@@ -2636,7 +2692,8 @@ void TabClass::save(gdioutput &gdi, bool skipReload)
bool sim = gdi.isChecked("CommonStart");
if (sim) {
pc->setStartType(0, STTime, true);
- pc->setStartData(0, gdi.getText("CommonStartTime"));
+ if (!warnDrawStartTime(gdi, gdi.getText("CommonStartTime")))
+ pc->setStartData(0, gdi.getText("CommonStartTime"));
}
else {
pc->setStartType(0, STDrawn, true);
@@ -2728,12 +2785,14 @@ struct ButtonData {
bool TabClass::loadPage(gdioutput &gdi)
{
+ if (!gdi.hasData("ClassPageLoaded"))
+ hasWarnedStartTime = false;
oe->checkDB();
oe->checkNecessaryFeatures();
gdi.selectTab(tabId);
- gdi.clearPage(false);
+ clearPage(gdi, false);
int xp=gdi.getCX();
-
+
const int button_w=gdi.scaleLength(90);
string switchMode;
switchMode=tableMode ? "Formulärläge" : "Tabelläge";
@@ -2839,24 +2898,51 @@ bool TabClass::loadPage(gdioutput &gdi)
gdi.dropLine(2);
gdi.popX();
- gdi.fillDown();
- gdi.addString("", 1, "Funktioner");
-
vector func;
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList))
func.push_back(ButtonData("Draw", "Lotta / starttider...", false));
+
if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Bib))
func.push_back(ButtonData("Bibs", "Nummerlappar...", false));
- if (cnf.hasTeamClass())
+
+ if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList))
+ func.push_back(ButtonData("DrawMode", "Lotta flera klasser", true));
+
+ if (cnf.hasTeamClass()) {
func.push_back(ButtonData("Restart", "Omstart...", true));
+
+ vector allCls;
+ oe->getClasses(allCls, false);
+ bool unlockedClass = false;
+ bool lockedClass = false;
+
+ if (showAdvanced) {
+ for (pClass c : allCls) {
+ if (c->isRemoved())
+ continue;
+
+ if (!c->hasCoursePool() && c->hasMultiCourse()) {
+ if (c->lockedForking())
+ lockedClass = true;
+ else
+ unlockedClass = true;
+ }
+ }
+
+ if (unlockedClass) {
+ func.push_back(ButtonData("LockAllForks", "Lås gafflingar", true));
+ }
+ if (lockedClass) {
+ func.push_back(ButtonData("UnLockAllForks", "Tillåt gafflingsändringar", true));
+ }
+ }
+ }
+
if (showAdvanced) {
func.push_back(ButtonData("Merge", "Slå ihop klasser...", false));
func.push_back(ButtonData("Split", "Dela klassen...", false));
}
- if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::DrawStartList))
- func.push_back(ButtonData("DrawMode", "Lotta flera klasser", true));
- func.push_back(ButtonData("QuickSettings", "Snabbinställningar", true));
if (showAdvanced && oe->getMeOSFeatures().hasFeature(MeOSFeatures::Vacancy)) {
vector rr;
@@ -2872,22 +2958,40 @@ bool TabClass::loadPage(gdioutput &gdi)
func.push_back(ButtonData("RemoveVacant", "Radera vakanser", true));
}
+ func.push_back(ButtonData("QuickSettings", "Snabbinställningar", true));
+
+ RECT funRect;
+ funRect.right = gdi.getCX() - 7;
+ funRect.top = gdi.getCY() - 2;
+ funRect.left = 0;
+
+ gdi.dropLine(0.5);
+ gdi.fillDown();
+ gdi.addString("", fontMediumPlus, "Funktioner");
+
gdi.dropLine(0.3);
gdi.pushX();
gdi.fillRight();
+ int xlimit = gdi.getWidth() - button_w/2;
+
for (size_t k = 0; k < func.size(); k++) {
ButtonInfo &bi = gdi.addButton(func[k].id, func[k].label, ClassesCB);
if (!func[k].global)
bi.isEdit(true);
- if ( k % 2 == 1) {
+ funRect.left = max(funRect.left, gdi.getCX() + 7);
+ if ( gdi.getCX() > xlimit && k+1 < func.size()) {
gdi.popX();
gdi.dropLine(2.5);
}
}
+ gdi.dropLine(2.5);
+
+ funRect.bottom = gdi.getCY();
+ gdi.addRectangle(funRect, colorLightGreen);
gdi.popX();
- gdi.dropLine(3);
+ gdi.dropLine(0.5);
gdi.fillRight();
gdi.addButton("Save", "Spara", ClassesCB).setDefault();
gdi.disableInput("Save");
@@ -2988,7 +3092,7 @@ void TabClass::saveClassSettingsTable(gdioutput &gdi) {
}
void TabClass::prepareForDrawing(gdioutput &gdi) {
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addString("", 2, "Klassinställningar");
int baseLine = gdi.getCY();
gdi.addString("", 10, "help:59395");
@@ -3110,7 +3214,7 @@ void TabClass::drawDialog(gdioutput &gdi, DrawMethod method, const oClass &pc) {
}
if (method != DMSimultaneous)
- gdi.addInput("Interval", formatTimeW(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
+ gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
if (method == DMRandom || method == DMSOFT || method == DMClumped)
gdi.addInput("Vacanses", itow(vac), 10, 0, L"Antal vakanser:").setSynchData(&lastNumVac);
@@ -3204,7 +3308,7 @@ void TabClass::setMultiDayClass(gdioutput &gdi, bool hasMulti, DrawMethod defaul
}
void TabClass::pursuitDialog(gdioutput &gdi) {
- gdi.clearPage(false);
+ clearPage(gdi, false);
gdi.addString("", boldLarge, "Jaktstart");
gdi.dropLine();
vector cls;
@@ -3216,9 +3320,9 @@ void TabClass::pursuitDialog(gdioutput &gdi) {
gdi.fillRight();
- gdi.addInput("MaxAfter", formatTimeW(pSavedDepth), 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart");
- gdi.addInput("TimeRestart", L"+" + formatTimeW(pFirstRestart), 8, 0, L"Första omstartstid:", L"Ange tiden relativt klassens första start");
- gdi.addInput("Interval", formatTimeW(pInterval), 8, 0, L"Startintervall:", L"Ange startintervall för minutstart");
+ gdi.addInput("MaxAfter", formatTime(pSavedDepth), 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart");
+ gdi.addInput("TimeRestart", L"+" + formatTime(pFirstRestart), 8, 0, L"Första omstartstid:", L"Ange tiden relativt klassens första start");
+ gdi.addInput("Interval", formatTime(pInterval), 8, 0, L"Startintervall:", L"Ange startintervall för minutstart");
wchar_t bf[32];
swprintf_s(bf, L"%f", pTimeScaling);
gdi.addInput("ScaleFactor", bf, 8, 0, L"Tidsskalning:");
@@ -3917,12 +4021,45 @@ void TabClass::writeDrawInfo(gdioutput &gdi, const DrawInfo &drawInfoIn) {
gdi.setText("Vacances", itow(int(drawInfoIn.vacancyFactor *100.0)) + L"%");
gdi.setText("Extra", itow(int(drawInfoIn.extraFactor * 100.0) ) + L"%");
- gdi.setText("BaseInterval", formatTimeW(drawInfoIn.baseInterval));
+ gdi.setText("BaseInterval", formatTime(drawInfoIn.baseInterval));
gdi.check("AllowNeighbours", drawInfoIn.allowNeighbourSameCourse);
gdi.check("CoursesTogether", drawInfoIn.coursesTogether);
- gdi.setText("MinInterval", formatTimeW(drawInfoIn.minClassInterval));
- gdi.setText("MaxInterval", formatTimeW(drawInfoIn.maxClassInterval));
+ gdi.setText("MinInterval", formatTime(drawInfoIn.minClassInterval));
+ gdi.setText("MaxInterval", formatTime(drawInfoIn.maxClassInterval));
gdi.setText("nFields", drawInfoIn.nFields);
gdi.setText("FirstStart", oe->getAbsTime(drawInfoIn.firstStart));
}
+
+void TabClass::setLockForkingState(gdioutput &gdi, bool poolState, bool lockState) {
+ if (gdi.hasField("DefineForking"))
+ gdi.setInputStatus("DefineForking", !lockState && !poolState);
+
+ if (gdi.hasField("LockForking"))
+ gdi.setInputStatus("LockForking", !poolState);
+
+ int legno = 0;
+ while (gdi.hasField("@Course" + itos(legno))) {
+ gdi.setInputStatus("@Course" + itos(legno++), !lockState || poolState);
+ }
+}
+
+bool TabClass::warnDrawStartTime(gdioutput &gdi, const wstring &firstStart) {
+ int st = oe->getRelativeTime(firstStart);
+ return warnDrawStartTime(gdi, st);
+}
+
+bool TabClass::warnDrawStartTime(gdioutput &gdi, int time) {
+ if (!hasWarnedStartTime && time > 3600 * 8 && !oe->useLongTimes()) {
+ bool res = gdi.ask(L"warn:latestarttime#" + itow(time/3600));
+ if (res)
+ hasWarnedStartTime = true;
+ return !res;
+ }
+ return false;
+}
+
+void TabClass::clearPage(gdioutput &gdi, bool autoRefresh) {
+ gdi.clearPage(autoRefresh);
+ gdi.setData("ClassPageLoaded", 1);
+}
diff --git a/code/TabClass.h b/code/TabClass.h
index 9b627ae..fcca150 100644
--- a/code/TabClass.h
+++ b/code/TabClass.h
@@ -79,6 +79,12 @@ class TabClass :
void pursuitDialog(gdioutput &gdi);
+ bool warnDrawStartTime(gdioutput &gdi, int time);
+ bool warnDrawStartTime(gdioutput &gdi, const wstring &firstStart);
+
+ void static clearPage(gdioutput &gdi, bool autoRefresh);
+
+ bool hasWarnedStartTime;
bool hasWarnedDirect;
bool tableMode;
DrawMethod lastDrawMethod;
@@ -137,6 +143,9 @@ class TabClass :
void writeDrawInfo(gdioutput &gdi, const DrawInfo &drawInfo);
static vector< pair > getPairOptions();
+
+ void setLockForkingState(gdioutput &gdi, bool poolState, bool lockState);
+
public:
void clearCompetitionData();
diff --git a/code/TabCompetition.cpp b/code/TabCompetition.cpp
index 06d76ee..a98d155 100644
--- a/code/TabCompetition.cpp
+++ b/code/TabCompetition.cpp
@@ -119,6 +119,12 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
gdi.setText("Date", oe->getDate());
return 0;
}
+ bool updateTimes = newZT != oldZT && oe->getNumRunners() > 0 && gdi.ask(L"ask:updatetimes");
+
+ if (updateTimes) {
+ int delta = oldZT - newZT;
+ oe->updateStartTimes(delta);
+ }
}
oe->setDate(date);
oe->useLongTimes(longTimes);
@@ -380,7 +386,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
if (bi.id == "CopyLink") {
string url = gdi.narrow(gdi.getText("link"));
- if (OpenClipboard(gdi.getHWND())) {
+ if (OpenClipboard(gdi.getHWNDMain())) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE,
@@ -603,7 +609,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
loadPage(gdi);
}
else if (bi.id == "Exit") {
- PostMessage(gdi.getMain(), WM_CLOSE, 0, 0);
+ PostMessage(gdi.getHWNDMain(), WM_CLOSE, 0, 0);
}
else if (bi.id == "Help") {
wchar_t fn[MAX_PATH];
@@ -757,7 +763,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.setWindowTitle(oe->getTitleName());
if (oe->isClient() && oe->getPropertyInt("UseDirectSocket", true) != 0) {
- oe->getDirectSocket().startUDPSocketThread(gdi.getMain());
+ oe->getDirectSocket().startUDPSocketThread(gdi.getHWNDMain());
}
loadConnectionPage(gdi);
@@ -986,7 +992,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
oe->setProperty("UseEventor", 1);
else
oe->setProperty("UseEventor", 2);
- PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TCmpTab, 0);
}
else if (bi.id == "EventorAPI") {
assert(!eventorOrigin.empty());
@@ -1124,7 +1130,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
wstring zipped = getTempFile();
zip(zipped.c_str(), 0, fileList);
- ProgressWindow pw(gdi.getTarget());
+ ProgressWindow pw(gdi.getHWNDTarget());
pw.init();
vector > key;
getAPIKey(key);
@@ -1192,6 +1198,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
return loadPage(gdi);
}
+ checkReadyForResultExport(gdi, set());
+
gdi.clearPage(true);
gdi.fillDown();
gdi.dropLine();
@@ -1216,7 +1224,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
wstring zipped = getTempFile();
zip(zipped.c_str(), 0, fileList);
- ProgressWindow pw(gdi.getTarget());
+ ProgressWindow pw(gdi.getHWNDTarget());
pw.init();
vector > key;
getAPIKey(key);
@@ -1282,7 +1290,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
SYSTEMTIME st;
GetLocalTime(&st);
st.wYear--; // Include last years competitions
- getEventorCompetitions(gdi, convertSystemDateW(st), events);
+ getEventorCompetitions(gdi, convertSystemDate(st), events);
gdi.clearPage(true);
gdi.addString("", boldLarge, "Hämta data från Eventor");
@@ -1296,7 +1304,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.addSelection("EventorSel", 300, 200);
sort(events.begin(), events.end());
st.wYear++; // Restore current time
- wstring now = convertSystemDateW(st);
+ wstring now = convertSystemDate(st);
int selected = 0; // Select next event by default
for (int k = events.size()-1; k>=0; k--) {
@@ -1500,7 +1508,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
gdi.addString("", 1, "Skapar ny tävling");
oe->newCompetition(L"New");
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter);
- oe->setZeroTime(formatTimeHMSW(zeroTime));
+ oe->setZeroTime(formatTimeHMS(zeroTime));
oe->getDI().setDate("OrdinaryEntry", lastEntry);
if (ci) {
if (!ci->account.empty())
@@ -1540,7 +1548,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
switch (startType) {
case SMCommon:
- oe->automaticDrawAll(gdi, formatTimeHMSW(firstStart), L"0", L"0", false, false, 1);
+ oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0", L"0", false, false, 1);
drawn = true;
break;
@@ -1565,7 +1573,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
}
if (!skip)
- oe->automaticDrawAll(gdi, formatTimeHMSW(firstStart), L"2:00", L"2", true, true, 1);
+ oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00", L"2", true, true, 1);
drawn = true;
break;
}
@@ -1712,23 +1720,14 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
int filterIndex = gdi.getSelectedItem("Type").first;
vector< pair > ext;
ImportFormats::getExportFilters(bi.id!="BrowseExport", ext);
- /*if (bi.id=="BrowseExport") {
- ext.push_back(make_pair("IOF Startlista (xml)", "*.xml"));
- ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv"));
- ext.push_back(make_pair("Webbdokument (html)", "*.html;*.htm"));
- }
- else {
- ext.push_back(make_pair("IOF Resultat (xml)", "*.xml"));
- ext.push_back(make_pair("OE Semikolonseparerad (csv)", "*.csv"));
- ext.push_back(make_pair("Webbdokument (html)", "*.html"));
- }*/
wstring save = gdi.browseForSave(ext, L"xml", filterIndex);
if (save.length() > 0) {
gdi.setText("Filename", save);
gdi.selectItemByData("Type", filterIndex);
- if (gdi.getExtra("Filename")) {
- gdi.enableInput((char *)gdi.getExtra("Filename"));
+ wchar_t *fn = gdi.getExtra("Filename");
+ if (fn) {
+ gdi.enableInput(gdi.narrow(fn).c_str());
}
}
}
@@ -1784,6 +1783,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
//bool individual = !gdi.hasField("ExportTeam") || gdi.isChecked("ExportTeam");
gdi.getSelection("ClassNewEntries", allTransfer);
+ checkReadyForResultExport(gdi, allTransfer);
+
ImportFormats::ExportFormats filterIndex = ImportFormats::setExportFormat(*oe, gdi.getSelectedItem("Type").first);
int cSVLanguageHeaderIndex = gdi.getSelectedItem("LanguageType").first;
bool includeSplits = gdi.isChecked("ExportSplitTimes");
@@ -1954,7 +1955,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
}
if (oe->isClient() && oe->getPropertyInt("UseDirectSocket", true) != 0) {
- oe->getDirectSocket().startUDPSocketThread(gdi.getMain());
+ oe->getDirectSocket().startUDPSocketThread(gdi.getHWNDMain());
}
return 0;
}
@@ -2152,7 +2153,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
int textSize = lbi.data;
oe->setProperty("TextSize", textSize);
gdi.setFont(textSize, oe->getPropertyString("TextFont", L"Arial"));
- PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TCmpTab, 0);
}
else if (lbi.id == "Language") {
lang.get().loadLangResource(lbi.text);
@@ -2160,7 +2161,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
oe->setProperty("Language", lbi.text);
//gdi.setEncoding(interpetEncoding(lang.tl("encoding")));
gdi.setFont(oe->getPropertyInt("TextSize", 0), oe->getPropertyString("TextFont", L"Arial"));
- PostMessage(gdi.getTarget(), WM_USER + 2, TCmpTab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TCmpTab, 0);
}
else if (lbi.id == "PreEvent") {
gdi.setInputStatus("OpenPre", int(lbi.data)>0);
@@ -2183,8 +2184,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
else if (type== GUI_INPUT) {
InputInfo ii=*(InputInfo *)data;
if (ii.id == "Filename") {
- if (ii.getExtra()) {
- gdi.setInputStatus((char *)ii.getExtra(), !ii.text.empty());
+ const wchar_t *fn = ii.getExtra();
+ if (fn) {
+ gdi.setInputStatus(gdi.narrow(fn).c_str(), !ii.text.empty());
}
}
else if (ii.id == "NumStages") {
@@ -2196,8 +2198,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
else if (type == GUI_INPUTCHANGE) {
InputInfo ii=*(InputInfo *)data;
if (ii.id == "Filename") {
- if (ii.getExtra()) {
- gdi.setInputStatus((char *)ii.getExtra(), !ii.text.empty());
+ const wchar_t *fn = ii.getExtra();
+ if (fn) {
+ gdi.setInputStatus(gdi.narrow(fn).c_str(), !ii.text.empty());
}
}
}
@@ -2537,7 +2540,6 @@ bool TabCompetition::loadPage(gdioutput &gdi)
}
gdi.addButton("Settings", "Tävlingsinställningar", CompetitionCB);
- gdi.addButton("Report", "Tävlingsrapport", CompetitionCB);
gdi.addButton("Features", "MeOS Funktioner", CompetitionCB);
#ifdef _DEBUG
@@ -2849,7 +2851,7 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
nt -= 24*3600;
dayOffset = 1;
}
- ci.firstStart = formatTimeHMSW(nt);
+ ci.firstStart = formatTimeHMS(nt);
//TODO: Take dayoffset into account
}
@@ -2890,7 +2892,7 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
SYSTEMTIME st;
convertDateYMS(breakDate, st, false);
__int64 time = SystemTimeToInt64Second(st) - 1;
- breakDate = convertSystemDateW(Int64SecondToSystemTime(time));
+ breakDate = convertSystemDate(Int64SecondToSystemTime(time));
if (ci.lastNormalEntryDate.empty() || ci.lastNormalEntryDate >= breakDate)
ci.lastNormalEntryDate = breakDate;
@@ -2917,7 +2919,7 @@ void TabCompetition::getEventorCmpData(gdioutput &gdi, int id,
const wstring &entryFile,
const wstring &dbFile) const
{
- ProgressWindow pw(gdi.getHWND());
+ ProgressWindow pw(gdi.getHWNDTarget());
pw.init();
gdi.fillDown();
gdi.addString("", 1, "Ansluter till Internet").setColor(colorGreen);
@@ -3981,3 +3983,38 @@ void TabCompetition::saveSettings(gdioutput &gdi) {
else if (changedCardFee)
oe->applyEventFees(false, false, true, dummy);
}
+
+void TabCompetition::checkReadyForResultExport(gdioutput &gdi, const set &classFilter) {
+ vector runners;
+ oe->getRunners(0, 0, runners, true);
+ int numNoResult = 0;
+ int numVacant = 0;
+
+ for (pRunner r : runners) {
+ if (!classFilter.empty() && !classFilter.count(r->getClassId()))
+ continue;
+
+ if (r->isVacant())
+ numVacant++;
+ else if (r->getStatus() == StatusUnknown && !r->needNoCard())
+ numNoResult++;
+ }
+
+ if (numVacant > 0) {
+ if (gdi.ask(L"ask:hasVacant")) {
+ if (gdi.ask(L"Vill du radera alla vakanser från tävlingen?")) {
+ if (classFilter.empty())
+ oe->removeVacanies(0);
+ else {
+ for (int c : classFilter)
+ oe->removeVacanies(c);
+ }
+ }
+ }
+ }
+
+ if (numNoResult > 0) {
+ gdi.alert(L"warn:missingResult#" + itow(numNoResult));
+ }
+}
+
diff --git a/code/TabCompetition.h b/code/TabCompetition.h
index f1f2299..1823762 100644
--- a/code/TabCompetition.h
+++ b/code/TabCompetition.h
@@ -116,6 +116,9 @@ class TabCompetition :
set allTransfer;
+
+ void checkReadyForResultExport(gdioutput &gdi, const set &classFilter);
+
void displayRunners(gdioutput &gdi, const vector &changedClass) const;
void meosFeatures(gdioutput &gdi, bool newGuide);
diff --git a/code/TabControl.cpp b/code/TabControl.cpp
index 62ee074..d44a69e 100644
--- a/code/TabControl.cpp
+++ b/code/TabControl.cpp
@@ -79,18 +79,19 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
const int numVisit = pc->getNumVisitors(true);
const int numVisitExp = pc->getNumVisitors(false);
- string info;
+ wstring info;
if (numVisit > 0) {
- info = "Antal besökare X, genomsnittlig bomtid Y, största bomtid Z#" +
- itos(numVisit) + " (" + itos(numVisitExp) + ")#" + getTimeMS(pc->getMissedTimeTotal() / numVisit) +
- "#" + getTimeMS(pc->getMissedTimeMax());
+ info = L"Antal besökare X, genomsnittlig bomtid Y, största bomtid Z#" +
+ itow(numVisit) + L" (" + itow(numVisitExp) + L")#" + getTimeMS(pc->getMissedTimeTotal() / numVisit) +
+ L"#" + getTimeMS(pc->getMissedTimeMax());
}
else if (numVisitExp > 0) {
- info = "Förväntat antal besökare: X#" + itos(numVisitExp);
+ info = L"Förväntat antal besökare: X#" + itow(numVisitExp);
}
gdi.setText("ControlID", itow(pc->getId()), true);
- gdi.setText("Info", lang.tl(info), true);
+ wstring winfo = lang.tl(info);
+ gdi.setText("Info", winfo, true);
gdi.setText("Code", pc->codeNumbers());
gdi.setText("Name", pc->getName());
gdi.setText("TimeAdjust", pc->getTimeAdjustS());
diff --git a/code/TabCourse.cpp b/code/TabCourse.cpp
index 46b621e..488b532 100644
--- a/code/TabCourse.cpp
+++ b/code/TabCourse.cpp
@@ -95,7 +95,7 @@ void TabCourse::selectCourse(gdioutput &gdi, pCourse pc)
if ( rt > 0 ) {
gdi.selectItemByData("Rogaining", 1);
gdi.enableInput("TimeLimit");
- gdi.setText("TimeLimit", formatTimeHMSW(rt));
+ gdi.setText("TimeLimit", formatTimeHMS(rt));
gdi.enableInput("PointReduction");
gdi.setText("PointReduction", itow(pc->getRogainingPointsPerMinute()));
gdi.enableInput("ReductionPerMinute");
@@ -506,7 +506,7 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
int interval = 2*60;
int vac = 1;
gdi.addInput("FirstStart", oe->getAbsTime(firstStart), 10, 0, L"Första start:");
- gdi.addInput("Interval", formatTimeW(interval), 10, 0, L"Startintervall (min):");
+ gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):");
gdi.addInput("Vacances", itow(vac), 10, 0, L"Antal vakanser:");
gdi.fillDown();
gdi.popX();
diff --git a/code/TabList.cpp b/code/TabList.cpp
index 14022ae..3e6e86c 100644
--- a/code/TabList.cpp
+++ b/code/TabList.cpp
@@ -49,9 +49,11 @@
#include "methodeditor.h"
#include "MeOSFeatures.h"
#include "liveresult.h"
+#include "animationdata.h"
#include
const static int CUSTOM_OFFSET = 10;
+const static int NUMTEXTSAMPLE = 13;
TabList::TabList(oEvent *poe):TabBase(poe)
{
@@ -90,7 +92,7 @@ int ListsEventCB(gdioutput *gdi, int type, void *data)
void TabList::rebuildList(gdioutput &gdi)
{
- if (!SelectedList.empty()) {
+ if (!SelectedList.empty()) {
ButtonInfo bi;
bi.id=SelectedList;
noReEvaluate = true;
@@ -127,7 +129,7 @@ int NoStartRunnerCB(gdioutput *gdi, int type, void *data)
TabList &tc = dynamic_cast(*gdi->getTabs().get(TListTab));
pRunner p = tc.getEvent()->getRunner(id, 0);
- if (p){
+ if (p) {
p->setStatus(StatusDNS, true, false);
p->synchronize();
ti->callBack=0;
@@ -172,34 +174,33 @@ int TabList::baseButtons(gdioutput &gdi, int extraButtons) {
return ypos;
}
-void TabList::generateList(gdioutput &gdi)
+void TabList::generateList(gdioutput &gdi, bool forceUpdate)
{
if (currentList.getListCode() == EFixedLiveResult) {
liveResult(gdi, currentList);
-
+
int baseY = 15;
- if (!gdi.isFullScreen()) {
- gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120),
- "Cancel", ownWindow ? "Stäng" : "Återgå", ListsCB, "", true, false);
+ if (!gdi.isFullScreen()) {
+ gdi.addButton(gdi.getWidth() + 20, baseY, gdi.scaleLength(120),
+ "Cancel", ownWindow ? "Stäng" : "Återgå", ListsCB, "", true, false);
baseY += 3 + gdi.getButtonHeight();
- gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120),
- "FullScreenLive", "Fullskärm", ListsCB, "Visa listan i fullskärm", true, false);
+ gdi.addButton(gdi.getWidth() + 20, baseY, gdi.scaleLength(120),
+ "FullScreenLive", "Fullskärm", ListsCB, "Visa listan i fullskärm", true, false);
}
- SelectedList="GeneralList";
-
+ SelectedList = "GeneralList";
return;
}
-
+
DWORD storedWidth = 0;
int oX = 0;
int oY = 0;
if (gdi.hasData("GeneralList")) {
- if (!currentList.needRegenerate(*oe))
+ if (!forceUpdate && !currentList.needRegenerate(*oe))
return;
gdi.takeShownStringsSnapshot();
- oX=gdi.GetOffsetX();
- oY=gdi.GetOffsetY();
+ oX = gdi.GetOffsetX();
+ oY = gdi.GetOffsetY();
gdi.getData("GeneralList", storedWidth);
gdi.restoreNoUpdate("GeneralList");
}
@@ -209,6 +210,17 @@ void TabList::generateList(gdioutput &gdi)
gdi.setRestorePoint("GeneralList");
currentList.setCallback(ownWindow ? 0 : openRunnerTeamCB);
+ const auto &par = currentList.getParam();
+ int bgColor = par.bgColor;
+
+ if (bgColor == -1 && par.screenMode == 1) {
+ bgColor = RGB(255, 255, 255);
+ }
+
+ gdi.setColorMode(bgColor,
+ -1,
+ par.fgColor,
+ par.bgImage);
try {
oe->generateList(gdi, !noReEvaluate, currentList, false);
}
@@ -216,8 +228,15 @@ void TabList::generateList(gdioutput &gdi)
wstring err = lang.tl(ex.wwhat());
gdi.addString("", 1, L"List Error: X#" + err).setColor(colorRed);
}
+ bool wasAnimation = false;
+ if (par.screenMode == 1 && !par.lockUpdate) {
+ setAnimationMode(gdi);
+ wasAnimation = true;
+ }
+ else {
+ gdi.setOffset(oX, oY, false);
+ }
- gdi.setOffset(oX, oY, false);
int currentWidth = gdi.getWidth();
gdi.setData("GeneralList", currentWidth);
@@ -237,13 +256,17 @@ void TabList::generateList(gdioutput &gdi)
baseY += 2*(3+gdi.getButtonHeight());
}
- baseY += 3 + gdi.getButtonHeight();
+ /*baseY += 3 + gdi.getButtonHeight();
gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120),
"AutoScroll", "Automatisk skroll", ListsCB, "Rulla upp och ner automatiskt", true, false);
baseY += 3 + gdi.getButtonHeight();
gdi.addButton(gdi.getWidth()+20, baseY, gdi.scaleLength(120),
"FullScreen", "Fullskärm", ListsCB, "Visa listan i fullskärm", true, false);
+ */
+ baseY += 3 + gdi.getButtonHeight();
+ gdi.addButton(gdi.getWidth() + 20, baseY, gdi.scaleLength(120),
+ "ListDesign", "Utseende...", ListsCB, "Justera visningsinställningar", true, false);
if (!currentList.getParam().saved && !oe->isReadOnly()) {
baseY += 3 + gdi.getButtonHeight();
@@ -260,11 +283,13 @@ void TabList::generateList(gdioutput &gdi)
gdi.setOnClearCb(ListsCB);
SelectedList="GeneralList";
- if (abs(int(currentWidth - storedWidth)) < 5) {
- gdi.refreshSmartFromSnapshot(true);
+ if (!wasAnimation) {
+ if (abs(int(currentWidth - storedWidth)) < 5) {
+ gdi.refreshSmartFromSnapshot(true);
+ }
+ else
+ gdi.refresh();
}
- else
- gdi.refresh();
}
int TabList::listCB(gdioutput &gdi, int type, void *data)
@@ -335,22 +360,24 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
gdi.openDoc(file.c_str());
}
}
+ else if (bi.id == "ListDesign") {
+ gdioutput *gdi_settings = getExtraWindow("list_settings", true);
+ if (!gdi_settings) {
+ gdi_settings = createExtraWindow("list_settings", lang.tl("Inställningar"), gdi.scaleLength(600), gdi.scaleLength(400));
+ }
+ if (gdi_settings) {
+ loadSettings(*gdi_settings, gdi.getTag());
+ }
+ }
else if (bi.id == "Window" || bi.id == "AutoScroll" ||
bi.id == "FullScreen" || bi.id == "FullScreenLive") {
gdioutput *gdi_new;
TabList *tl_new = this;
if (!ownWindow) {
- gdi_new = createExtraWindow(uniqueTag("list"), makeDash(L"MeOS - ") + currentList.getName(), gdi.getWidth() + 64 + gdi.scaleLength(120));
- if (gdi_new) {
- TabList &tl = dynamic_cast(*gdi_new->getTabs().get(TListTab));
- tl.currentList = currentList;
- tl.SelectedList = SelectedList;
- tl.ownWindow = true;
- tl.loadPage(*gdi_new);
- tl_new = &tl;
- SelectedList = "";
- currentList = oListInfo();
- loadPage(gdi);
+ auto nw = makeOwnWindow(gdi);
+ if (nw.first) {
+ tl_new = nw.second;
+ gdi_new = nw.first;
}
}
else
@@ -1129,6 +1156,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
else if (type==GUI_CLEAR) {
offsetY=gdi.GetOffsetY();
offsetX=gdi.GetOffsetX();
+ leavingList(gdi.getTag());
return true;
}
else if (type == GUI_LINK) {
@@ -1192,6 +1220,24 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
return 0;
}
+pair TabList::makeOwnWindow(gdioutput &gdi) {
+ gdioutput *gdi_new = createExtraWindow(uniqueTag("list"), makeDash(L"MeOS - ") + currentList.getName(), gdi.getWidth() + 64 + gdi.scaleLength(120));
+ TabList *tl_new = 0;
+ if (gdi_new) {
+ TabList &tl = dynamic_cast(*gdi_new->getTabs().get(TListTab));
+ tl.currentList = currentList;
+ tl.SelectedList = SelectedList;
+ tl.ownWindow = true;
+ tl.loadPage(*gdi_new);
+ tl_new = &tl;
+ changeListSettingsTarget(gdi, *gdi_new);
+ SelectedList = "";
+ currentList = oListInfo();
+ loadPage(gdi);
+ }
+ return make_pair(gdi_new, tl_new);
+}
+
void TabList::enableFromTo(oEvent &oe, gdioutput &gdi, bool from, bool to) {
vector< pair > d;
oe.fillControls(d, oEvent::CTCourseControl);
@@ -1376,6 +1422,272 @@ void TabList::makeFromTo(gdioutput &gdi) {
gdi.dropLine(3);
}
+class ListSettings : public GuiHandler {
+ void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+ string target;
+ if (!gdi.getData("target", target))
+ return;
+ gdioutput *dest_gdi = getExtraWindow(target, false);
+ if (!dest_gdi)
+ return;
+
+ TabBase *tb = dest_gdi->getTabs().get(TabType::TListTab);
+ if (tb) {
+ TabList *list = dynamic_cast(tb);
+ list->handleListSettings(gdi, info, type, *dest_gdi);
+ }
+ }
+};
+
+ListSettings settingsClass;
+
+void TabList::changeListSettingsTarget(gdioutput &oldWindow, gdioutput &newWindow) {
+ gdioutput *gdi_settings = getExtraWindow("list_settings", true);
+ if (gdi_settings) {
+ string oldTag;
+ gdi_settings->getData("target", oldTag);
+ if (oldWindow.getTag() == oldTag)
+ gdi_settings->setData("target", newWindow.getTag());
+ }
+}
+
+void TabList::leavingList(const string &wnd) {
+ gdioutput *gdi_settings = getExtraWindow("list_settings", true);
+ if (gdi_settings) {
+ string oldTag;
+ gdi_settings->getData("target", oldTag);
+ if (wnd == oldTag)
+ gdi_settings->closeWindow();
+ }
+}
+
+static void addAnimationSettings(gdioutput &gdi, oListParam &dst) {
+ DWORD cx, cy;
+ gdi.getData("xmode", cx);
+ gdi.getData("ymode", cy);
+
+ gdi.setCX(cx);
+ gdi.setCY(cy);
+ gdi.pushX();
+ gdi.fillRight();
+ gdi.addInput("Time", itow(dst.timePerPage), 5, 0, L"Visningstid:");
+ gdi.addSelection("NPage", 70, 200, 0, L"Sidor per skärm:");
+ for (int i = 1; i <= 8; i++)
+ gdi.addItem("NPage", itow(i), i);
+ if (dst.nColumns == 0)
+ dst.nColumns = 1;
+ gdi.selectItemByData("NPage", dst.nColumns);
+ gdi.addInput("Margin", itow(dst.margin) + L" %", 5, 0, L"Marginal:");
+ gdi.dropLine(1);
+ gdi.addCheckbox("Animate", "Animation", 0, dst.animate);
+}
+
+static void saveAnimationSettings(gdioutput &gdi, oListParam &dst) {
+ dst.timePerPage = gdi.getTextNo("Time");
+ dst.nColumns = gdi.getSelectedItem("NPage").first;
+ dst.animate = gdi.isChecked("Animate");
+ dst.margin = gdi.getTextNo("Margin");
+}
+
+void TabList::loadSettings(gdioutput &gdi, string targetTag) {
+ gdi.clearPage(false);
+ gdi.setCX(10);
+ gdi.setCY(15);
+ gdi.setColorMode(RGB(242, 240, 250));
+ gdi.setData("target", targetTag);
+ settingsTarget = targetTag;
+ gdi.addString("", fontMediumPlus, L"Visningsinställningar för 'X'#" + currentList.getName());
+
+ gdi.dropLine(0.5);
+ gdi.addSelection("Background", 200, 100, 0, L"Bakgrund:").setHandler(&settingsClass);
+ gdi.addItem("Background", lang.tl("Standard"), 0);
+ gdi.addItem("Background", lang.tl("Färg"), 1);
+ //gdi.addItem("Background", lang.tl("Bild"), 2);
+ tmpSettingsParam = currentList.getParam();
+ int bgColor = currentList.getParam().bgColor;
+ int fgColor = currentList.getParam().fgColor;
+ bool useColor = bgColor != -1;
+ gdi.selectItemByData("Background", useColor ? 1 : 0);
+ gdi.pushX();
+ gdi.fillRight();
+ gdi.addButton("BGColor", "Bakgrundsfärg...").setHandler(&settingsClass).setExtra(bgColor);
+ gdi.setInputStatus("BGColor", useColor);
+ gdi.addButton("FGColor", "Textfärg...").setHandler(&settingsClass).setExtra(fgColor);
+
+ gdi.popX();
+
+ gdi.dropLine(3);
+ gdi.addSelection("Mode", 200, 100, 0, L"Visning:").setHandler(&settingsClass);
+ gdi.addItem("Mode", lang.tl("Fönster"), 0);
+ gdi.addItem("Mode", lang.tl("Fönster (rullande)"), 3);
+ gdi.addItem("Mode", lang.tl("Fullskärm (sidvis)"), 1);
+ gdi.addItem("Mode", lang.tl("Fullskärm (rullande)"), 2);
+ gdi.selectItemByData("Mode", tmpSettingsParam.screenMode);
+ gdi.popX();
+ gdi.dropLine(3);
+
+ gdi.setData("xmode", gdi.getCX());
+ gdi.setData("ymode", gdi.getCY());
+ gdi.dropLine(3);
+
+ gdi.addButton("ApplyList", "Verkställ").setHandler(&settingsClass);
+
+ if (tmpSettingsParam.screenMode == 1)
+ addAnimationSettings(gdi, tmpSettingsParam);
+
+ RECT rc;
+ rc.left = gdi.getWidth() + gdi.scaleLength(80);
+ rc.right = rc.left + gdi.scaleLength(150);
+ rc.top = 20;
+
+ gdi.addString("", rc.top, rc.left, 1, "Exempel");
+ rc.top += (gdi.getLineHeight() * 3) / 2;
+
+ rc.bottom = rc.top + gdi.scaleLength(200);
+ gdi.addRectangle(rc, bgColor != -1 ? GDICOLOR(bgColor) : GDICOLOR(colorTransparent)).id = "Background";
+ string val = "123. Abc MeOS";
+ int key = rand()%12;
+ for (int i = 0; i < NUMTEXTSAMPLE; i++) {
+ gdi.addString("Sample" + itos(i), rc.top + 3 + gdi.getLineHeight()*i,
+ rc.left + 3 + 5*i, i == 0 ? boldText : normalText, "#" + val).setColor(GDICOLOR(fgColor));
+ string val2 = val;
+ for (int j = 0; j < 13; j++) {
+ val2[j] = val[((j+1)*(key+1)) % 13];
+ }
+ val = val2;
+ }
+ gdi.refresh();
+}
+
+void TabList::handleListSettings(gdioutput &gdi, BaseInfo &info, GuiEventType type, gdioutput &dest_gdi) {
+ if (type == GUI_BUTTON) {
+ ButtonInfo bi = static_cast(info);
+ if (bi.id == "BGColor") {
+ wstring c = oe->getPropertyString("Colors", L"");
+ int res = gdi.selectColor(c, bi.getExtraInt());
+ if (res > -1) {
+ info.setExtra(res);
+ oe->setProperty("Colors", c);
+ RectangleInfo &rc = gdi.getRectangle("Background");
+ rc.setColor(GDICOLOR(res));
+ gdi.refreshFast();
+ }
+ }
+ else if (bi.id == "FGColor") {
+ wstring c = oe->getPropertyString("Colors", L"");
+ int inC = bi.getExtraInt();
+ if (inC == -1)
+ inC = RGB(255,255,255);
+ int res = gdi.selectColor(c, inC);
+ if (res > -1) {
+ info.setExtra(res);
+ oe->setProperty("Colors", c);
+ for (int i = 0; i < NUMTEXTSAMPLE; i++) {
+ BaseInfo &bi = gdi.getBaseInfo(("Sample" + itos(i)).c_str());
+ dynamic_cast(bi).setColor(GDICOLOR(res));
+ }
+ gdi.refreshFast();
+ }
+ }
+ else if (bi.id == "ApplyList") {
+ oListParam ¶m = currentList.getParam();
+ param.lockUpdate = true;
+ int type = gdi.getSelectedItem("Background").first;
+ if (type == 1)
+ param.bgColor = gdi.getExtraInt("BGColor");
+ else
+ param.bgColor = -1;
+
+ param.fgColor = gdi.getExtraInt("FGColor");
+ param.screenMode = gdi.getSelectedItem("Mode").first;
+ if (param.screenMode == 1) {
+ saveAnimationSettings(gdi, param);
+ }
+ TabList *dest = this;
+ gdioutput *dgdi = &dest_gdi;
+ int mode = param.screenMode;
+ if (param.screenMode == 2 || param.screenMode == 3) {
+ dgdi->alert("help:fullscreen");
+ }
+
+ if ((mode==1 || mode==2) && !dest_gdi.isFullScreen()) {
+ // Require fullscreen
+ if (!ownWindow) {
+ auto nw = makeOwnWindow(dest_gdi);
+ dest = nw.second;
+ dgdi = nw.first;
+ }
+ dgdi->setFullScreen(true);
+ dest->hideButtons = true;
+ }
+ else if ((mode == 0 || mode == 3) && dest_gdi.isFullScreen()) {
+ dest_gdi.setFullScreen(false);
+ hideButtons = false;
+ }
+
+ if (mode == 2 || mode == 3) {
+ if (!dest->ownWindow) {
+ auto nw = makeOwnWindow(dest_gdi);
+ dest = nw.second;
+ dgdi = nw.first;
+ }
+ dest->hideButtons = true;
+ int h = dgdi->setHighContrastMaxWidth();
+ dest->loadPage(*dgdi);
+ double sec = 6.0;
+ double delta = h * 20. / (1000. * sec);
+ dgdi->setAutoScroll(delta);
+ }
+ else {
+ dest->loadPage(*dgdi);
+ }
+ dest->currentList.getParam().lockUpdate = false;
+ param.lockUpdate = false;
+
+ SetForegroundWindow(dgdi->getHWNDMain());
+ SetWindowPos(dgdi->getHWNDMain(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+
+ if (mode == 1) {
+ dest->setAnimationMode(*dgdi);
+ dgdi->refresh();
+ dest->generateList(*dgdi, true);
+ }
+
+ if (param.screenMode == 2 || param.screenMode == 3) {
+ gdi.closeWindow();
+ }
+ }
+ }
+ else if (type == GUI_LISTBOX) {
+ ListBoxInfo lbi = static_cast(info);
+ if (lbi.id == "Background") {
+ gdi.setInputStatus("BGColor", lbi.data == 1);
+ BaseInfo &bi = gdi.getBaseInfo("BGColor");
+ if (lbi.data == 1 && bi.getExtraInt() == -1)
+ bi.setExtra(int(RGB(255,255,255)));
+
+ RectangleInfo &rc = gdi.getRectangle("Background");
+ rc.setColor(GDICOLOR(lbi.data == 1 ? bi.getExtraInt() : colorTransparent));
+ gdi.refreshFast();
+ }
+ else if (lbi.id == "Mode") {
+ if (lbi.data == 1) {
+ addAnimationSettings(gdi, tmpSettingsParam);
+ }
+ else {
+ if (gdi.hasField("Time"))
+ saveAnimationSettings(gdi, tmpSettingsParam);
+
+ gdi.removeControl("Time");
+ gdi.removeControl("NPage");
+ gdi.removeControl("Margin");
+ gdi.removeControl("Animate");
+ }
+ gdi.refresh();
+ }
+ }
+}
+
void TabList::settingsResultList(gdioutput &gdi)
{
lastFilledResultClassType = -1;
@@ -1569,7 +1881,8 @@ bool TabList::loadPage(gdioutput &gdi)
if (cnf.hasIndividual()) {
gdi.addButton("StartIndividual", "Individuell", ListsCB);
checkWidth(gdi);
- gdi.addButton("StartClub", "Klubbstartlista", ListsCB);
+ if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Clubs))
+ gdi.addButton("StartClub", "Klubbstartlista", ListsCB);
}
for (size_t k = 0; kgetMeOSFeatures().hasFeature(MeOSFeatures::Clubs)) {
+ gdi.addButton("ResultClub", "Klubbresultat", ListsCB);
+ checkWidth(gdi);
+ }
+
gdi.addButton("ResultIndSplit", "Sträcktider", ListsCB);
checkWidth(gdi);
@@ -2098,3 +2414,9 @@ void TabList::clearCompetitionData() {
listEditor = 0;
methodEditor = 0;
}
+
+void TabList::setAnimationMode(gdioutput &gdi) {
+ auto par = currentList.getParam();
+ gdi.setAnimationMode(make_shared(gdi, par.timePerPage, par.nColumns,
+ par.margin, par.animate));
+}
diff --git a/code/TabList.h b/code/TabList.h
index 4c1b9ec..5542724 100644
--- a/code/TabList.h
+++ b/code/TabList.h
@@ -48,7 +48,7 @@ protected:
static void createListButtons(gdioutput &gdi);
- void generateList(gdioutput &gdi);
+ void generateList(gdioutput &gdi, bool forceUpdate = false);
void selectGeneralList(gdioutput &gdi, EStdListType type);
int offsetY;
@@ -78,6 +78,15 @@ private:
TabList(const TabList &);
const TabList &operator = (const TabList &);
+ string settingsTarget;
+ oListParam tmpSettingsParam;
+ void changeListSettingsTarget(gdioutput &oldWindow, gdioutput &newWindow);
+ void leavingList(const string &wnd);
+
+ pair makeOwnWindow(gdioutput &gdi);
+
+ /** Set animation mode*/
+ void setAnimationMode(gdioutput &gdi);
public:
bool loadPage(gdioutput &gdi);
bool loadPage(gdioutput &gdi, const string &command);
@@ -94,6 +103,8 @@ public:
void rebuildList(gdioutput &gdi);
void settingsResultList(gdioutput &gdi);
+ void loadSettings(gdioutput &gdi, string targetTag);
+ void handleListSettings(gdioutput &gdi, BaseInfo &info, GuiEventType type, gdioutput &dest_gdi);
enum PrintSettingsSelection {
Splits = 0,
StartInfo = 1,
diff --git a/code/TabRunner.cpp b/code/TabRunner.cpp
index f434553..5655253 100644
--- a/code/TabRunner.cpp
+++ b/code/TabRunner.cpp
@@ -199,7 +199,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
gdi.setText("Team", L"");
}
- gdi.setText("TimeAdjust", getTimeMSW(r->getTimeAdjustment()));
+ gdi.setText("TimeAdjust", getTimeMS(r->getTimeAdjustment()));
gdi.setText("PointAdjust", -r->getPointAdjustment());
#ifdef _DEBUG
@@ -216,22 +216,22 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
r->getLegTimeAfterAcc(afterAcc);
r->getLegPlacesAcc(placeAcc);
- string out;
+ wstring out;
for (size_t k = 0; k0)
- out+= " +" + getTimeMS(after[k]);
+ out+= L" +" + getTimeMS(after[k]);
if (k0)
- out+= " (+" + getTimeMS(afterAcc[k]) + ")";
+ out+= L" (+" + getTimeMS(afterAcc[k]) + L")";
if (delta[k]>0)
- out+= " B: " + getTimeMS(delta[k]);
+ out+= L" B: " + getTimeMS(delta[k]);
- out += " | ";
+ out += L" | ";
}
gdi.restore("fantom", false);
@@ -805,6 +805,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
for (size_t k=0; kgetStatus()==StatusUnknown) {
unknown[k]->setStatus(StatusDNS, true, false);
+ unknown[k]->setFlag(oAbstractRunner::FlagAutoDNS, true);
unknown[k]->synchronize(true);
}
}
@@ -813,6 +814,21 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
clearInForestData();
showInForestList(gdi);
}
+ else if (bi.id == "UndoSetDNS") {
+ vector runners;
+ oe->getRunners(0, 0, runners, true);
+ for (pRunner r : runners) {
+ if (r->getStatus() == StatusDNS && r->hasFlag(oAbstractRunner::FlagAutoDNS)) {
+ r->setStatus(StatusUnknown, true, false);
+ r->setFlag(oAbstractRunner::FlagAutoDNS, false);
+ r->synchronize(true);
+ }
+ }
+ //Reevaluate and synchronize all
+ oe->reEvaluateAll(set(), true);
+ clearInForestData();
+ showInForestList(gdi);
+ }
else if (bi.id=="SetUnknown") {
for (size_t k=0; kgetStatus()==StatusDNS) {
@@ -842,7 +858,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
pRunner r=oe->getRunner(runnerId, 0);
if (!r) return 0;
- gdioutput gdiprint(2.0, gdi.getHWND(), splitPrinter, gdi.getCP());
+ gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP());
if (bi.getExtraInt() == 0)
r->printSplits(gdiprint);
else
@@ -917,6 +933,14 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
selectRunner(gdi, 0);
}
}
+ }
+ else if (bi.id == "Economy") {
+ if (!runnerId)
+ return 0;
+ pRunner r = oe->getRunner(runnerId, 0);
+ gdioutput *settings = createExtraWindow("ecosettings", L"Economy for X#" + r->getName(), 400, 200);
+
+
}
else if (bi.id=="NoStart") {
if (!runnerId)
@@ -938,8 +962,8 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
pRunner rr = r->getMultiRunner(k);
if (rr) {
rr->setStartTime(0, true, false);
- rr->setStartNo(0, false);
- rr->setStatus(StatusDNS, true, false);
+ //rr->setStartNo(0, false);
+ rr->setStatus(StatusCANCEL, true, false);
rr->setCardNo(0, false);
}
}
@@ -1051,7 +1075,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
}
runnerId = bi.data;
//loadPage(gdi);
- PostMessage(gdi.getTarget(), WM_USER + 2, TRunnerTab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TRunnerTab, 0);
}
else if (bi.id=="RClass") {
gdi.selectItemByData("RCourse", 0);
@@ -1318,7 +1342,8 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
}
}
- r->getDI().setDate("EntryDate", getLocalDateW());
+ r->getDI().setDate("EntryDate", getLocalDate());
+ r->getDI().setInt("EntryTime", getLocalAbsTime());
r->addClassDefaultFee(false);
int cardFee = 0;
@@ -1328,8 +1353,6 @@ int TabRunner::vacancyCB(gdioutput &gdi, int type, void *data)
}
else
r->getDI().setInt("CardFee", 0);
-
-
if (cardFee < 0)
cardFee = 0;
@@ -1482,7 +1505,7 @@ void TabRunner::showRunnerReport(gdioutput &gdi)
if (t->statusOK()) {
tInfo += L", " + t->getRunningTimeS() + lang.tl(".S Placering: ") + t->getPlaceS();
if (t->getTimeAfter(-1) > 0)
- tInfo += L", +" + formatTimeW(t->getTimeAfter(-1));
+ tInfo += L", +" + formatTime(t->getTimeAfter(-1));
}
else if (t->getStatus() != StatusUnknown) {
tInfo += L" " + t->getStatusS();
@@ -1640,7 +1663,7 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
GDICOLOR color = colorDefault;
if (k < int(after.size()) ) {
if (after[k] > 0)
- split += L" (" + itow(place[k]) + L", +" + getTimeMSW(after[k]) + L")";
+ split += L" (" + itow(place[k]) + L", +" + getTimeMS(after[k]) + L")";
else if (place[k] == 1)
split += lang.tl(" (sträckseger)");
else if (place[k] > 0)
@@ -1656,7 +1679,7 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
wstring pl = placeAcc[k] > 0 ? itow(placeAcc[k]) : L"-";
if (k < int(afterAcc.size()) ) {
if (afterAcc[k] > 0)
- split += L" (" + pl + L", +" + getTimeMSW(afterAcc[k]) + L")";
+ split += L" (" + pl + L", +" + getTimeMS(afterAcc[k]) + L")";
else if (placeAcc[k] == 1)
split += lang.tl(" (ledare)");
else if (placeAcc[k] > 0)
@@ -1666,7 +1689,7 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
}
if (k < int(delta.size()) && delta[k] > 0 ) {
- gdi.addString("", yp + 3*lh, cx, fontMedium, "Bomtid: X#" + getTimeMS(delta[k]));
+ gdi.addString("", yp + 3*lh, cx, fontMedium, L"Bomtid: X#" + getTimeMS(delta[k]));
color = (delta[k] > bestTime * 0.5 && delta[k]>60 ) ?
colorMediumDarkRed : colorMediumRed;
@@ -1724,9 +1747,9 @@ void TabRunner::runnerReport(gdioutput &gdi, int id, bool compact) {
int st = r->getStartTime();
gdi.addString("", yp + lh, cx, normalText, L"Klocktid: X#" + oe->getAbsTime(t), limit);
if (st > 0 && t > st) {
- string split = formatTimeHMS(t-st);
+ wstring split = formatTimeHMS(t-st);
if (lastT>0 && st != lastT && lastT < t)
- split += " (" + getTimeMS(t-lastT) + ")";
+ split += L" (" + getTimeMS(t-lastT) + L")";
gdi.addStringUT(yp + 2*lh, cx, normalText, split, limit);
}
}
@@ -1925,7 +1948,8 @@ void TabRunner::showInForestList(gdioutput &gdi)
gdi.popX();
clearInForestData();
- oe->analyseDNS(unknown_dns, known_dns, known, unknown);
+ bool hasDNS;
+ oe->analyseDNS(unknown_dns, known_dns, known, unknown, hasDNS);
oe->setupCardHash(false);
if (!unknown.empty()) {
gdi.dropLine();
@@ -1934,7 +1958,14 @@ void TabRunner::showInForestList(gdioutput &gdi)
listRunners(gdi, unknown, true);
}
else {
- gdi.disableInput("SetDNS");
+ if (hasDNS) {
+ BaseInfo &bi = gdi.getBaseInfo("SetDNS");
+ bi.id = "UndoSetDNS";
+ gdi.setTextTranslate(bi.id, L"Återställ till ");
+ }
+ else {
+ gdi.disableInput("SetDNS");
+ }
}
if (!known.empty()) {
@@ -2262,10 +2293,10 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.selectTab(tabId);
}
gdi.clearPage(false);
- int basex=gdi.getCX();
+ int basex = gdi.getCX();
if (currentMode == 1) {
- Table *tbl=oe->getRunnersTB();
+ Table *tbl = oe->getRunnersTB();
addToolbar(gdi);
gdi.dropLine(1);
gdi.addTable(tbl, basex, gdi.getCY());
@@ -2298,8 +2329,8 @@ bool TabRunner::loadPage(gdioutput &gdi)
gdi.registerEvent("SearchRunnerBack", runnerSearchCB).setKeyCommand(KC_FINDBACK);
gdi.addInput("SearchText", getSearchString(), 13, runnerSearchCB, L"",
- L"Sök på namn, bricka eller startnummer.").isEdit(false)
- .setBgColor(colorLightCyan).ignore(true);
+ L"Sök på namn, bricka eller startnummer.").isEdit(false)
+ .setBgColor(colorLightCyan).ignore(true);
gdi.dropLine(-0.2);
//gdi.addButton("Search", "Sök", RunnerCB, "Sök på namn, bricka eller startnummer.");
gdi.addButton("ShowAll", "Visa alla", RunnerCB).isEdit(false);
@@ -2349,16 +2380,19 @@ bool TabRunner::loadPage(gdioutput &gdi)
}
gdi.fillRight();
- gdi.addSelection("RClass", 150, 300, RunnerCB, L"Klass:");
+ gdi.addSelection("RClass", 130, 300, RunnerCB, L"Klass:");
oe->fillClasses(gdi, "RClass", oEvent::extraNone, oEvent::filterNone);
gdi.addItem("RClass", lang.tl("Ingen klass"), 0);
- gdi.fillDown();
-
- if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy))
- gdi.addInput("Fee", L"", 6, 0, L"Avgift:");
- else
+ if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Economy)) {
+ gdi.fillDown();
+ gdi.addInput("Fee", L"", 4, 0, L"Avgift:");
+ //gdi.addButton("Economy", "@" + itos(131), RunnerCB, "Ekonomi...");
+ }
+ else {
+ gdi.fillDown();
gdi.dropLine(3);
+ }
gdi.dropLine(0.4);
diff --git a/code/TabSI.cpp b/code/TabSI.cpp
index 6b9b487..c0c8ced 100644
--- a/code/TabSI.cpp
+++ b/code/TabSI.cpp
@@ -948,7 +948,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
throw meosException("Löparen hittades inte");
bool useNow = gdi.getExtraInt("FinishTime") == 1;
- wstring time = useNow ? getLocalTimeOnlyW() : gdi.getText("FinishTime");
+ wstring time = useNow ? getLocalTimeOnly() : gdi.getText("FinishTime");
int relTime = oe->getRelativeTime(time);
if (relTime <= 0) {
@@ -1097,7 +1097,7 @@ int TabSI::siCB(gdioutput &gdi, int type, void *data)
}
else if (bi.id == "NC") {
NC = bi.data;
- PostMessage(gdi.getTarget(), WM_USER + 2, TSITab, 0);
+ PostMessage(gdi.getHWNDTarget(), WM_USER + 2, TSITab, 0);
}
}
else if (type == GUI_LINK) {
@@ -1473,7 +1473,7 @@ void TabSI::showReadCards(gdioutput &gdi, vector &cards)
SportIdent &TabSI::getSI(const gdioutput &gdi) {
if (!gSI) {
- HWND hWnd=gdi.getMain();
+ HWND hWnd=gdi.getHWNDMain();
gSI = new SportIdent(hWnd, 0);
gSI->setZeroTime(gEvent->getZeroTimeNum());
}
@@ -2681,7 +2681,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
while(checkpPrintQueue(gdi));
}
else {
- gdioutput gdiprint(2.0, gdi.getHWND(), splitPrinter, gdi.getCP());
+ gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP());
vector mp;
r->evaluateCard(true, mp);
r->printSplits(gdiprint);
@@ -2692,7 +2692,7 @@ void TabSI::generateSplits(const pRunner r, gdioutput &gdi)
void TabSI::generateStartInfo(gdioutput &gdi, const oRunner &r) {
if (printStartInfo) {
- gdioutput gdiprint(2.0, gdi.getHWND(), splitPrinter, gdi.getCP());
+ gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP());
r.printStartInfo(gdiprint);
printProtected(gdi, gdiprint);
//gdiprint.print(splitPrinter, oe, false, true);
@@ -3023,7 +3023,7 @@ void TabSI::EditCardData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType ty
void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
SICard &c = getCard(cardId);
if (c.readOutTime[0] == 0)
- strcpy_s(c.readOutTime, getLocalTime().c_str());
+ strcpy_s(c.readOutTime, getLocalTimeN().c_str());
gdi.pushX();
gdi.fillRight();
@@ -3066,10 +3066,10 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
int start = NOTIME;
if (c.CheckPunch.Code != -1)
- gdi.addString("", 0, "Check: X#" + formatTimeHMS(c.CheckPunch.Time));
+ gdi.addString("", 0, L"Check: X#" + formatTimeHMS(c.CheckPunch.Time));
if (c.StartPunch.Code != -1) {
- gdi.addString("", 0, "Start: X#" + formatTimeHMS(c.StartPunch.Time));
+ gdi.addString("", 0, L"Start: X#" + formatTimeHMS(c.StartPunch.Time));
start = c.StartPunch.Time;
}
int xp = gdi.getCX();
@@ -3088,9 +3088,9 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
if (start != NOTIME) {
int legTime = analyzePunch(c.Punch[k], start, accTime, days);
if (legTime > 0)
- gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTimeW(legTime));
+ gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime));
- gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTimeW(days*3600*24 + accTime));
+ gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime));
}
else {
start = c.Punch[k].Time;
@@ -3104,11 +3104,11 @@ void TabSI::printCard(gdioutput &gdi, int cardId, bool forPrinter) const {
if (start != NOTIME) {
int legTime = analyzePunch(c.FinishPunch, start, accTime, days);
if (legTime > 0)
- gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTimeW(legTime));
+ gdi.addStringUT(cy, xp5-gdi.scaleLength(10), textRight, formatTime(legTime));
- gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTimeW(days*3600*24 + accTime));
+ gdi.addStringUT(cy, xp5 + gdi.scaleLength(40), textRight, formatTime(days*3600*24 + accTime));
}
- gdi.addString("", 1, L"Time: X#" + formatTimeW(days*3600*24 + accTime));
+ gdi.addString("", 1, L"Time: X#" + formatTime(days*3600*24 + accTime));
}
if (forPrinter) {
@@ -3143,7 +3143,7 @@ int TabSI::analyzePunch(SIPunch &p, int &start, int &accTime, int &days) {
}
void TabSI::generateSplits(int cardId, gdioutput &gdi) {
- gdioutput gdiprint(2.0, gdi.getHWND(), splitPrinter, gdi.getCP());
+ gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP());
printCard(gdiprint, cardId, true);
printProtected(gdi, gdiprint);
}
@@ -3196,7 +3196,7 @@ void TabSI::createCompetitionFromCards(gdioutput &gdi) {
if (zeroTime < 0)
zeroTime += 3600 * 24;
zeroTime -= zeroTime % 1800;
- oe->setZeroTime(formatTimeW(zeroTime));
+ oe->setZeroTime(formatTime(zeroTime));
int course = 0;
for (size_t k = 0; k < cards.size(); k++) {
@@ -3570,7 +3570,7 @@ bool TabSI::checkpPrintQueue(gdioutput &gdi) {
return false; // Wait a little longer
}
- gdioutput gdiprint(2.0, gdi.getHWND(), splitPrinter, gdi.getCP());
+ gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter, gdi.getCP());
vector mp;
for (size_t m = 0; m < printLen && !printPunchRunnerIdQueue.empty(); m++) {
int rid = printPunchRunnerIdQueue.front().second;
diff --git a/code/TabSpeaker.cpp b/code/TabSpeaker.cpp
index 4e5d678..33e39f0 100644
--- a/code/TabSpeaker.cpp
+++ b/code/TabSpeaker.cpp
@@ -662,7 +662,7 @@ void TabSpeaker::splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r)
else
first = false;
- timeloss += pc->getControlOrdinal(j) + L". " + formatTimeW(delta[j]);
+ timeloss += pc->getControlOrdinal(j) + L". " + formatTime(delta[j]);
}
if (timeloss.length() > charlimit || (!timeloss.empty() && !first && j+1 == delta.size())) {
gdi.addStringUT(yp, xp, 0, timeloss).setColor(colorDarkRed);
@@ -876,7 +876,7 @@ int TabSpeaker::processListBox(gdioutput &gdi, const ListBoxInfo &bu)
}
}
else if (bu.id == "MultiStage") {
- getSpeakerMonitor()->useTotalResults(gdi.isChecked(bu.id));
+ getSpeakerMonitor()->useTotalResults(bu.data != 0);
updateTimeLine(gdi);
}
else if (bu.id == "DetailLevel") {
@@ -1087,7 +1087,7 @@ void TabSpeaker::storeManualTime(gdioutput &gdi)
wstring time=gdi.getText("Time");
if (time.empty())
- time=getLocalTimeOnlyW();
+ time=getLocalTimeOnly();
int itime=oe->getRelativeTime(time);
@@ -1240,7 +1240,7 @@ void TabSpeaker::importSettings(gdioutput &gdi, multimap &setti
selectedControl.clear();
int ctrl = 0, leg = 0, total = 0;
- for (auto s : settings) {
+ for (auto &s : settings) {
if (s.first == "currentClass") {
if (s.second == L"@Events") {
classId = -1;
@@ -1312,11 +1312,11 @@ void TabSpeaker::loadSettings(vector< multimap > &settings) {
xmlList xmlsettings;
sp.getObjects(xmlsettings);
- for (auto s : xmlsettings) {
+ for (auto &s : xmlsettings) {
settings.push_back(multimap());
xmlList allS;
s.getObjects(allS);
- for (auto prop : allS) {
+ for (auto &prop : allS) {
settings.back().insert(make_pair(prop.getName(), prop.getw()));
}
}
@@ -1326,9 +1326,9 @@ void TabSpeaker::saveSettings(const vector< multimap > &setting
xmlparser d;
d.openOutput(getSpeakerSettingsFile().c_str(), false);
d.startTag("Speaker");
- for (auto s : settings) {
+ for (auto &s : settings) {
d.startTag("SpeakerWindow");
- for (auto prop : s) {
+ for (auto &prop : s) {
d.write(prop.first.c_str(), prop.second);
}
d.endTag();
diff --git a/code/TabTeam.cpp b/code/TabTeam.cpp
index 5f1e26b..dfc8aa7 100644
--- a/code/TabTeam.cpp
+++ b/code/TabTeam.cpp
@@ -270,7 +270,7 @@ void TabTeam::updateTeamStatus(gdioutput &gdi, pTeam t)
gdi.setText("Start", t->getStartTimeS());
gdi.setText("Finish",t->getFinishTimeS());
gdi.setText("Time", t->getRunningTimeS());
- gdi.setText("TimeAdjust", getTimeMSW(t->getTimeAdjustment()));
+ gdi.setText("TimeAdjust", getTimeMS(t->getTimeAdjustment()));
gdi.setText("PointAdjust", -t->getPointAdjustment());
gdi.selectItemByData("Status", t->getStatus());
}
@@ -342,11 +342,11 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
RunnerStatus sIn = (RunnerStatus)lbi.data;
// Must be done AFTER all runners are set. But setting runner can modify status, so decide here.
- bool setDNS = (sIn == StatusDNS) && (t->getStatus()!=StatusDNS);
+ bool setDNS = (sIn == StatusDNS || sIn == StatusCANCEL) && (t->getStatus() != sIn);
bool checkStatus = (sIn != t->getStatus());
- if (sIn == StatusUnknown && t->getStatus() == StatusDNS)
- t->setTeamNoStart(false);
+ if (sIn == StatusUnknown && (t->getStatus() == StatusDNS || t->getStatus() == StatusCANCEL))
+ t->setTeamNoStart(false, StatusDNS);
else if ((RunnerStatus)lbi.data != t->getStatus())
t->setStatus((RunnerStatus)lbi.data, true, false);
@@ -464,7 +464,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
}
if (setDNS)
- t->setTeamNoStart(true);
+ t->setTeamNoStart(true, sIn);
if (t->checkValdParSetup()) {
gdi.alert("Laguppställningen hade fel, som har rättats");
@@ -662,7 +662,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
selectTeam(gdi, t);
}
else if (bi.id == "Browse") {
- const char *target = (const char *)bi.getExtra();
+ const wchar_t *target = bi.getExtra();
vector< pair > ext;
ext.push_back(make_pair(L"Laguppställning", L"*.csv;*.txt"));
wstring fileName = gdi.browseForOpen(ext, L"csv");
diff --git a/code/Table.cpp b/code/Table.cpp
index b6234f7..5fef724 100644
--- a/code/Table.cpp
+++ b/code/Table.cpp
@@ -33,6 +33,7 @@
#include "gdiconstants.h"
#include "meosexception.h"
#include "recorder.h"
+#include "oDataContainer.h"
extern HINSTANCE hInst;
const char *tId="_TABLE_SEL";
@@ -103,9 +104,9 @@ void Table::clearCellSelection(gdioutput *gdi) {
upperCol = -1;
lowerCol = -1;
if (gdi) {
- HDC hDC = GetDC(gdi->getTarget());
+ HDC hDC = GetDC(gdi->getHWNDTarget());
clearSelectionBitmap(gdi, hDC);
- ReleaseDC(gdi->getTarget(), hDC);
+ ReleaseDC(gdi->getHWNDTarget(), hDC);
}
}
@@ -567,7 +568,7 @@ bool Table::mouseMove(gdioutput &gdi, int x, int y)
if (row!=-1)
col=getColumn(x);
- HWND hWnd=gdi.getTarget();
+ HWND hWnd=gdi.getHWNDTarget();
if (colSelected!=-1) {
TableCell &cell=Data[0].cells[colSelected];
@@ -673,7 +674,7 @@ bool Table::mouseLeftUp(gdioutput &gdi, int x, int y)
if (hdcCompatible) {
TableCell &cell=Data[0].cells[colSelected];
- HWND hWnd=gdi.getTarget();
+ HWND hWnd=gdi.getHWNDTarget();
HDC hDC=GetDC(hWnd);
stopMoveCell(hDC, cell, x-startX, y-startY);
ReleaseDC(hWnd, hDC);
@@ -691,7 +692,7 @@ bool Table::mouseLeftUp(gdioutput &gdi, int x, int y)
}
else {
moveColumn(colSelected, highCol);
- InvalidateRect(gdi.getTarget(), 0, false);
+ InvalidateRect(gdi.getHWNDTarget(), 0, false);
colSelected=-1;
return true;
}
@@ -726,7 +727,7 @@ void Table::selection(gdioutput &gdi, const wstring &text, int data) {
reloadRow(id);
RECT rc;
getRowRect(selectionRow, rc);
- InvalidateRect(gdi.getTarget(), &rc, false);
+ InvalidateRect(gdi.getHWNDTarget(), &rc, false);
}
#ifndef MEOSDB
@@ -868,7 +869,7 @@ bool Table::mouseLeftDown(gdioutput &gdi, int x, int y) {
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.getTarget(),
+ 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);
@@ -877,8 +878,8 @@ bool Table::mouseLeftDown(gdioutput &gdi, int x, int y) {
gdi.refresh();
}
else {
- SetFocus(gdi.getHWND());
- SetCapture(gdi.getTarget());
+ SetFocus(gdi.getHWNDTarget());
+ SetCapture(gdi.getHWNDTarget());
lowerCol = getColumn(x);
lowerRow = getRow(y);
startSelect = true;
@@ -954,7 +955,7 @@ bool Table::editCell(gdioutput &gdi, int row, int col) {
else if (cell.type==cellEdit) {
hEdit=CreateWindowEx(0, L"EDIT", cell.contents.c_str(),
WS_TABSTOP|WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL|WS_BORDER,
- rc.left, rc.top, rc.right-rc.left+1, (rc.bottom-rc.top), gdi.getTarget(),
+ rc.left, rc.top, rc.right-rc.left+1, (rc.bottom-rc.top), gdi.getHWNDTarget(),
0, hInst, 0);
SendMessage(hEdit, EM_SETSEL, 0, -1);
SetFocus(hEdit);
@@ -1276,7 +1277,7 @@ void Table::draw(gdioutput &gdi, HDC hDC, int dx, int dy, const RECT &screen)
RECT desktop, target;
GetClientRect(GetDesktopWindow(), &desktop);
- GetClientRect(gdi.getTarget(), &target);
+ GetClientRect(gdi.getHWNDTarget(), &target);
int marginPixel = (desktop.bottom - desktop.top) - (target.bottom - target.top);
int margin = max(5, (marginPixel + rowHeight) / rowHeight);
@@ -1398,7 +1399,7 @@ void Table::restoreSelection(gdioutput &gdi, HDC hDC) {
rc.right -= gdi.OffsetX;
rc.top -= gdi.OffsetY;
rc.bottom -= gdi.OffsetY;
- InvalidateRect(gdi.getTarget(), &rc, false);
+ InvalidateRect(gdi.getHWNDTarget(), &rc, false);
partialCell = false;
}
else if (hdcCompatibleCell) {
@@ -1598,7 +1599,7 @@ void Table::setTableText(gdioutput &gdi, int editRow, int editCol, const wstring
reloadRow(Data[editRow].id);
RECT rc;
getRowRect(editRow, rc);
- InvalidateRect(gdi.getTarget(), &rc, false);
+ InvalidateRect(gdi.getHWNDTarget(), &rc, false);
}
const wstring &Table::getTableText(gdioutput &gdi, int editRow, int editCol) {
@@ -1802,6 +1803,8 @@ void Table::resetColumns()
void Table::update()
{
+ for (auto &dd : dataDefiners)
+ dd.second->prepare(oe);
int oldSort = PrevSort;
Data.clear();
sortIndex.clear();
@@ -1821,7 +1824,6 @@ void Table::update()
for (size_t k=0;k dataDefiners;
public:
+ void addDataDefiner(const string &key, const oDataDefiner *definer);
void setTableText(gdioutput &gdi, int editRow, int editCol, const wstring &bf);
const wstring &getTableText(gdioutput &gdi, int editRow, int editCol);
diff --git a/code/animationdata.cpp b/code/animationdata.cpp
new file mode 100644
index 0000000..8404129
--- /dev/null
+++ b/code/animationdata.cpp
@@ -0,0 +1,228 @@
+/************************************************************************
+MeOS - Orienteering Software
+Copyright (C) 2009-2017 Melin Software HB
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+Melin Software HB - software@melin.nu - www.melin.nu
+Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
+
+************************************************************************/
+
+#include "StdAfx.h"
+#include "animationdata.h"
+#include "meos_util.h"
+#include "Printer.h"
+
+AnimationData::AnimationData(gdioutput &gdi, int timePerPage, int nCol,
+ int marginPercent, bool animate) :
+ nCol(nCol), animate(animate), page(-1), gdiRef(0) {
+
+ lastTime = 0;
+ nextTime = 0;
+ timeOut = timePerPage;
+ doAnimation = true;
+ PageInfo pageInfo;
+ errorState = false;
+
+ gdi.getTargetDimension(width, height);
+
+ margin = (width * marginPercent) / 100;
+ double w = (gdi.getWidth() + 20) *nCol + margin;
+ double s = width / w;
+ if ((fabs(s - 1.0) > 1e-3)) {
+ gdi.scaleSize(s, true, false);
+ }
+ pageInfo.topMargin = 20;
+ pageInfo.scaleX = 1.0f;
+ pageInfo.scaleY = 1.0f;
+ pageInfo.leftMargin = 20;
+ pageInfo.bottomMargin = 30;
+ pageInfo.pageY = float(height-margin);
+ pageInfo.printHeader = false;
+ pageInfo.yMM2PrintC = pageInfo.xMM2PrintC = 1;
+ pageInfo.xMM2PrintK = 0;
+ pageInfo.yMM2PrintK = 0;
+
+ list rectangles;
+ pageInfo.renderPages(gdi.getTL(), rectangles, false, pages);
+}
+
+AnimationData::~AnimationData() {
+ if (animationThread && animationThread->joinable()) {
+ animationThread->join();
+ animationThread.reset();
+ }
+
+ if (gdiRef) {
+ gdiRef->removeHandler(this);
+ }
+}
+
+bool AnimationData::takeOver(shared_ptr &other) {
+ delayedTakeOver = other;
+ return true;
+}
+
+void AnimationData::takeOverInternal(shared_ptr &other) {
+ pages.swap(other->pages);
+ width = other->width;
+ height = other->height;
+ nCol = other->nCol;
+ margin = other->margin;
+ animate = other->animate;
+}
+
+void AnimationData::renderPage(HDC hDC, gdioutput &gdi, DWORD time) {
+
+ bool addTextAnimation = false;
+ if (doAnimation) {
+ if (page == -1)
+ page = 0;
+ else
+ page++;
+
+ addTextAnimation = true;
+ nextTime = time + timeOut;
+ lastTime = time;
+ gdiRef = &gdi;
+ gdi.addTimeoutMilli(timeOut, "AnimationData", 0).setHandler(this);
+ doAnimation = false;
+ }
+
+ if (animationThread && animationThread->joinable()) {
+ if (!addTextAnimation)
+ return; // Ignore repaint
+
+ if (animationThread) {
+ animationThread->join();
+ animationThread.reset();
+ }
+ }
+
+ if (delayedTakeOver && addTextAnimation) {
+ takeOverInternal(delayedTakeOver);
+ delayedTakeOver.reset();
+ }
+
+ size_t sp = nCol * page;
+ if (sp >= pages.size()) {
+ sp = 0;
+ page = 0;
+ }
+
+ int count = 1;
+ for (size_t i = sp; i < sp + nCol && i < pages.size(); i++) {
+ int currentRow = 0;
+ for (auto &text : pages[i].text) {
+ if (text.ti.yp != currentRow) {
+ currentRow = text.ti.yp;
+ count++;
+ }
+ }
+ }
+
+ int atime = 400;
+ if (count < 30)
+ atime = 800;
+ else if (count < 50)
+ atime = 500;
+
+ int delay = addTextAnimation && animate ? atime / count : 0;
+ if (delay == 0 || errorState == true) {
+ doRender(hDC, gdi, sp, delay);
+ errorState = false;
+ }
+ else {
+ animationThread = make_shared(&AnimationData::threadRender, this, &gdi, sp, delay);
+ }
+}
+
+void AnimationData::threadRender(gdioutput *gdi, size_t sp, int delay) {
+ HWND hWnd = gdi->getHWNDTarget();
+ HDC hDC = GetDC(hWnd);
+ int x, y;
+ gdi->getTargetDimension(x, y);
+ RECT rc;
+ rc.left = 0;
+ rc.right = x;
+ rc.top = 0;
+ rc.bottom = y;
+ gdi->drawBackground(hDC, rc);
+ try {
+ doRender(hDC, *gdi, sp, delay);
+ }
+ catch (...) {
+ errorState = true;
+ }
+ ReleaseDC(hWnd, hDC);
+ // End thread and notify that it has ended
+}
+
+ void AnimationData::doRender(HDC hDC, gdioutput &gdi, size_t sp, int delay) {
+ for (size_t i = sp; i < sp + nCol && i < pages.size(); i++) {
+ renderSubPage(hDC, gdi, pages[i], margin / 2 + ((i - sp) * width) / nCol, 0, delay);
+
+ if (i + 1 < sp + nCol) {
+ int x = margin / 2 + ((i + 1 - sp) * width) / nCol - 10;
+
+ SelectObject(hDC, GetStockObject(DC_BRUSH));
+ HLS fg, bg;
+ fg.RGBtoHLS(gdi.getFGColor());
+ bg.RGBtoHLS(gdi.getBGColor());
+
+ if (bg.lightness > fg.lightness)
+ fg.lighten(1.3);
+ else
+ fg.lighten(1.0 / 1.3);
+
+ SetDCBrushColor(hDC, fg.HLStoRGB());
+ Rectangle(hDC, x - 1, 20, x + 1, height - 20);
+ }
+ }
+}
+
+void AnimationData::renderSubPage(HDC hDC, gdioutput &gdi, RenderedPage &page, int x, int y, int animateDelay) {
+ int ox = gdi.GetOffsetX();
+ int oy = gdi.GetOffsetY();
+
+ int top = 10000;
+ for (const auto &text : page.text) {
+ if (!text.ti.isFormatInfo()) {
+ top = min(top, text.ti.yp);
+ }
+ }
+ gdi.SetOffsetY(-y+top-margin/2);
+ gdi.SetOffsetX(-x);
+
+ int currentRow = 0;
+ for (auto &text : page.text) {
+ if (animateDelay>0 && text.ti.yp != currentRow) {
+ Sleep(animateDelay);
+ currentRow = text.ti.yp;
+ }
+ gdi.RenderString(text.ti, hDC);
+ }
+ gdi.SetOffsetY(ox);
+ gdi.SetOffsetX(oy);
+}
+
+void AnimationData::handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) {
+ if (pages.size() > size_t(nCol) || delayedTakeOver) {
+ doAnimation = true;
+ gdi.refreshFast();
+ }
+ gdiRef = &gdi;
+ gdi.addTimeoutMilli(timeOut, "AnimationData", 0).setHandler(this);
+}
diff --git a/code/animationdata.h b/code/animationdata.h
new file mode 100644
index 0000000..cc3bfd7
--- /dev/null
+++ b/code/animationdata.h
@@ -0,0 +1,64 @@
+#pragma once
+
+/************************************************************************
+MeOS - Orienteering Software
+Copyright (C) 2009-2017 Melin Software HB
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+Melin Software HB - software@melin.nu - www.melin.nu
+Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
+
+************************************************************************/
+
+#include "gdioutput.h"
+#include
+#include
+
+class AnimationData : public GuiHandler {
+ vector pages;
+ int width;
+ int height;
+ int nCol;
+ int margin;
+ bool animate;
+
+ int page;
+ DWORD lastTime;
+ DWORD nextTime;
+ DWORD timeOut;
+ bool doAnimation;
+ atomic_bool errorState;
+ gdioutput *gdiRef;
+
+ void renderSubPage(HDC hDC, gdioutput &gdi, RenderedPage &page, int x, int y, int animationDelay);
+
+ void doRender(HDC hDC, gdioutput &gdi, size_t sp, int delay);
+
+ shared_ptr animationThread;
+ shared_ptr delayedTakeOver;
+ void takeOverInternal(shared_ptr &other);
+
+ void threadRender(gdioutput *gdi, size_t sp, int delay);
+public:
+
+ AnimationData(gdioutput &gdi, int timePerPage, int nCol,
+ int marginPercent, bool animate);
+ ~AnimationData();
+
+ void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type);
+ bool takeOver(shared_ptr &other);
+
+ void renderPage(HDC hDC, gdioutput &gdi, DWORD time);
+};
diff --git a/code/csvparser.cpp b/code/csvparser.cpp
index f5c9238..4522e6c 100644
--- a/code/csvparser.cpp
+++ b/code/csvparser.cpp
@@ -416,7 +416,7 @@ bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
bool csvparser::openOutput(const wstring &filename)
{
- //Startnr;Bricka;Databas nr.;Efternamn;Förnamn;År;K;Block;ut;Start;Mål;Tid;Status;Klubb nr.;Namn;Ort;Land;Klass nr.;Kort;Lång;Num1;Num2;Num3;Text1;Text2;Text3;Adr. namn;Gata;Rad 2;Post nr.;Ort;Tel;Fax;E-post;Id/Club;Hyrd;Startavgift;Betalt;Bana nr.;Bana;km;Hm;Bana kontroller
+ checkWriteAccess(filename);
fout.open(filename);
if (fout.bad())
diff --git a/code/english.lng b/code/english.lng
index da0baaf..ce2e830 100644
--- a/code/english.lng
+++ b/code/english.lng
@@ -65,7 +65,7 @@ Antal: %d = Number: %d
Antal: X = Number: X
Antalet rader i urklipp får inte plats i selektionen = The number of rows on the clipboard does not fit the selection
Använd Eventor = Use Eventor
-Använd banpool = Use course pooli
+Använd banpool = Use course pool
Använd funktioner för fleretappsklass = Use functions for multi stage class
Använd första kontrollen som start = Use first control as start
Använd löpardatabasen = Use runner database
@@ -350,8 +350,8 @@ Hantera brickor = Manage Cards
Hantera flera etapper = Manage Several Stages
Hantera jaktstart = Handle Pursuit
Hantera klubbar och ekonomi = Manage clubs and economy
-Hantera kvar-i-skogen = Handle Remaining Runners
-Hantera löparbrickor = Handle Runner Cards
+Hantera kvar-i-skogen = Manage Remaining Runners
+Hantera löparbrickor = Manage Runner Cards
Hemsida = Homepage
Hjälp = Help
Hoppar över stafettklass: X = Skipping relay class: X
@@ -1172,7 +1172,7 @@ Varning: Inget kontonummer angivet (Se tävlingsinställningar) = Warning: No ac
Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar) = Warning: payment due not given (See Competition Settings)
Varning: deltagare med blankt namn påträffad. MeOS kräver att alla deltagare har ett namn, och tilldelar namnet 'N.N.' = Warning: A competitor without name was found. MeOS requires a name, and has assigned the name 'N.N.'
Varning: lag utan namn påträffat. MeOS kräver att alla lag har ett namn, och tilldelar namnet 'N.N.' = Warning: A team without name was found. MeOS requires a name and has assigned the name 'N.N.'
-Verkställ = Confirm
+Verkställ = Apply
Version X = Version X
Vi stöder MeOS = We support MeOS
Viktiga händelser = Important events
@@ -1870,7 +1870,7 @@ Byt till rätt klass (behåll eventuell starttid) = Switch to the right class (k
Byt till vakansplats i rätt klass (om möjligt) = Switch to a vacant position in the right class (if possible)
Tillåt ny klass, behåll resultat från annan klass = Allow new class and keep results from other class
Tillåt ny klass, inget totalresultat = Allow new class but without total result
-tooltip_explain_status = - = Unknown Status (No result yet)\nOK = Valid result\nDNS = Did Not Start\nMP = Missing Punch\nDNF = Did Not Finish\nDISQ = Disqualified\nOMT = Over Maximum Time\nNTP = Not Taking Part
+tooltip_explain_status = - = Unknown Status (No result yet)\nOK = Valid result\nDNS = Did Not Start\nCancelled = Cancelled entry (shown in start list)\nMP = Missing Punch\nDNF = Did Not Finish\nDISQ = Disqualified\nOMT = Over Maximum Time\nNTP = Not Taking Part
Placering = Place
Resultat från tidigare etapper = Results from Earlier Stages
Input Results = Input Results
@@ -2252,3 +2252,35 @@ Spara fönster- och speakerinställningar på datorn = Save windows and settings
ask:loadspeaker = Do you wish to re-create previously saved windows on this computer?
Ã…terskapa = Re-create
Återskapa tidigare sparade fönster- och speakerinställningar = Re-create previously saved windows and settings
+Inkludera resultat från tidigare etapper = Include results from all stages
+Animation = Animation
+Bakgrund = Background
+Bakgrundsfärg = Background color
+Fullskärm (rullande) = Full screen (rolling)
+Fullskärm (sidvis) = Full screen (page by page)
+Fönster = Window
+Fönster (rullande) = Window (rolling)
+Justera visningsinställningar = Adjust view settings
+Marginal = Margin
+Sidor per skärm = Pages per screen
+Textfärg = Text color
+Utseende = Appearance
+Visningsinställningar för 'X' = View settings for 'X'
+Visningstid = Show time
+Visning = Display mode
+ask:hasVacant = There are still vacancies.\n\nDo you wish to remove all vacancies before exporting results?
+warn:missingResult = X competitors are still missing results and are therefore excluded.\n\nYou should manage competitors in forest to assign status to remaining runners.
+Återställ till = Reset to
+Ã…terbud[status] = Cancelled
+LÃ¥s gafflingar = Lock forkings
+Markera för att förhindra oavsiktlig ändring av gafflingsnycklar = Check to prevent unintentional altering of forking keys
+Tillåt gafflingsändringar = Allow forking modification
+ask:updatetimes = Do you wish to keep all currently assigned start times, if possible? Answer no to move the competition in time.
+X har en tid (Y) som inte är kompatibel med förändringen = X has a time (Y) that is incompatible with this change
+warn:latestarttime = Using start times more than X hours after the zero time is not recommended, since older SI cards only has a 12 hour clock.\n\nDo you wish to proceed anyway?
+Anm. tid = Entry time
+RunnerEntryDate = Competitor's entry date
+RunnerEntryTime = Competitor's entry time
+RunnerPaid = Paid amount
+RunnerPayMethod = Payment method
+EntryTime = Entry Time
diff --git a/code/gdifonts.h b/code/gdifonts.h
index a5557de..c86ae05 100644
--- a/code/gdifonts.h
+++ b/code/gdifonts.h
@@ -74,5 +74,6 @@ enum GDICOLOR {colorBlack = RGB(0,0,0),
colorMediumRed = RGB(255,200,200),
colorMediumDarkRed = RGB(240,120,120),
colorWindowBar = -2,
- colorDefault = -1};
+ colorDefault = -1,
+ colorTransparent = -3};
diff --git a/code/gdioutput.cpp b/code/gdioutput.cpp
index 956f579..6888459 100644
--- a/code/gdioutput.cpp
+++ b/code/gdioutput.cpp
@@ -55,6 +55,7 @@
#include "gdiimpl.h"
#include "Printer.h"
#include "recorder.h"
+#include "animationdata.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
@@ -133,6 +134,10 @@ void gdioutput::constructor(double _scale)
lockUpDown = false;
Background = 0;
+ backgroundColor1 = -1;
+ backgroundColor2 = -1;
+ foregroundColor = -1;
+ backgroundImage = -1;
toolbar = 0;
initCommon(_scale, L"Arial");
@@ -190,12 +195,12 @@ int transformX(int x, double scale) {
return int((x-40) * scale + 0.5) + 40;
}
-void gdioutput::scaleSize(double scale_) {
+void gdioutput::scaleSize(double scale_, bool allowSmallScale, bool doRefresh) {
if (fabs(scale_ - 1.0) < 1e-4)
return; // No scaling
double ns = scale*scale_;
- if (ns + 1e-6 < 1.0 ) {
+ if (!allowSmallScale && ns + 1e-6 < 1.0 ) {
ns = 1.0;
scale_ = 1.0;
}
@@ -273,7 +278,16 @@ void gdioutput::scaleSize(double scale_) {
r.sOY = int (r.sOY * scale_ + 0.5);
}
- refresh();
+ if (doRefresh) {
+ refresh();
+ }
+ else {
+ HDC hDC = GetDC(hWndTarget);
+ for (auto &ti : TL) {
+ calcStringSize(ti, hDC);
+ }
+ ReleaseDC(hWndTarget, hDC);
+ }
}
void gdioutput::initCommon(double _scale, const wstring &font)
@@ -317,16 +331,7 @@ const GDIImplFontSet & gdioutput::loadFont(const wstring &font) {
relScale = enumeratedFonts[fontIx[k].second].getRelScale();
}
}
- /*vector res;
- split(font, ";", res);
- double locScale = 1.0;
- if (res.empty() || res.size() > 2)
- throw meosException("Cannot load font: " + font);
- if (res.size() == 2) {
- locScale = atof(res[1].c_str());
- if (!(locScale>0.001 && locScale < 100))
- throw meosException("Cannot scale font with factor: " + res[1]);
- }*/
+
wstring faceName;
double locScale = getLocalScale(font, faceName);
@@ -351,9 +356,11 @@ gdioutput::~gdioutput()
{
while(!timers.empty()) {
KillTimer(hWndTarget, (UINT_PTR)&timers.back());
+ timers.back().setWnd = 0;
timers.back().parent = 0;
timers.pop_back();
}
+ animationData.reset();
deleteFonts();
@@ -397,6 +404,18 @@ void gdioutput::fetchPrinterSettings(PrinterObject &po) const {
void gdioutput::drawBackground(HDC hDC, RECT &rc)
{
+ if (backgroundColor1 != -1) {
+ SelectObject(hDC, GetStockObject(NULL_PEN));
+ SelectObject(hDC, GetStockObject(DC_BRUSH));
+ SetDCBrushColor(hDC, backgroundColor1);
+ Rectangle(hDC, -1, -1, rc.right + 1, rc.bottom + 1);
+ return;
+ }
+ else if (!backgroundImage.empty()) {
+ // TODO
+
+ }
+
GRADIENT_RECT gr[1];
SelectObject(hDC, GetStockObject(NULL_PEN));
@@ -575,21 +594,17 @@ void gdioutput::draw(HDC hDC, RECT &rc, RECT &drawArea)
return;
}
- list::iterator rit;
- SelectObject(hDC,GetStockObject(DC_BRUSH));
-
- for(rit=Rectangles.begin();rit!=Rectangles.end(); ++rit){
- if (rit->drawBorder)
- SelectObject(hDC, GetStockObject(BLACK_PEN));
- else
- SelectObject(hDC, GetStockObject(NULL_PEN));
- SetDCBrushColor(hDC, rit->color);
-
- RECT rect_rc=rit->rc;
- OffsetRect(&rect_rc, -OffsetX, -OffsetY);
- Rectangle(hDC, rect_rc.left, rect_rc.top, rect_rc.right, rect_rc.bottom);
+ if (animationData) {
+ int page = 0;
+ animationData->renderPage(hDC, *this, GetTickCount());
+ return;
}
+ SelectObject(hDC,GetStockObject(DC_BRUSH));
+
+ for (auto &rit : Rectangles)
+ renderRectangle(hDC, 0, rit);
+
if (useTables)
for(list::iterator tit=Tables.begin();tit!=Tables.end(); ++tit){
tit->table->draw(*this, hDC, tit->xp, tit->yp, rc);
@@ -641,11 +656,17 @@ void gdioutput::renderRectangle(HDC hDC, RECT *clipRegion, const RectangleInfo &
SelectObject(hDC, GetStockObject(BLACK_PEN));
else
SelectObject(hDC, GetStockObject(NULL_PEN));
- SetDCBrushColor(hDC, ri.color);
-
+
+ if (ri.color == colorTransparent)
+ SelectObject(hDC, GetStockObject(NULL_BRUSH));
+ else {
+ SetDCBrushColor(hDC, ri.color);
+ }
RECT rect_rc=ri.rc;
OffsetRect(&rect_rc, -OffsetX, -OffsetY);
Rectangle(hDC, rect_rc.left, rect_rc.top, rect_rc.right, rect_rc.bottom);
+ if (ri.color == colorTransparent)
+ SelectObject(hDC, GetStockObject(DC_BRUSH));
}
void gdioutput::updateStringPosCache() {
@@ -723,6 +744,7 @@ void CALLBACK gdiTimerProc(HWND hWnd, UINT a, UINT_PTR ptr, DWORD b) {
wstring msg;
KillTimer(hWnd, ptr);
TimerInfo *it = (TimerInfo *)ptr;
+ it->setWnd = 0;
try {
if (it->parent) {
it->parent->timerProc(*it, b);
@@ -745,25 +767,49 @@ void CALLBACK gdiTimerProc(HWND hWnd, UINT a, UINT_PTR ptr, DWORD b) {
}
}
+int TimerInfo::globalTimerId = 0;
+
void gdioutput::timerProc(TimerInfo &timer, DWORD timeout) {
+ int timerId = timer.timerId;
if (timer.handler)
timer.handler->handle(*this, timer, GUI_TIMER);
else if (timer.callBack)
timer.callBack(this, GUI_TIMER, &timer);
- for (list::iterator it = timers.begin(); it != timers.end(); ++it) {
- if (&*it == &timer) {
- timers.erase(it);
- return;
- }
+ remove_if(timers.begin(), timers.end(), [timerId](TimerInfo &x) {return x.getId() == timerId; });
+}
+
+void gdioutput::removeHandler(GuiHandler *h) {
+ for (auto &it : timers) {
+ if (it.handler == h)
+ it.handler = 0;
+ }
+
+ for (auto &it : BI) {
+ if (it.handler == h)
+ it.handler = 0;
+ }
+
+
+ for (auto &it : II) {
+ if (it.handler == h)
+ it.handler = 0;
+ }
+
+ for (auto &it : TL) {
+ if (it.handler == h)
+ it.handler = 0;
+ }
+
+ for (auto &it : LBI) {
+ if (it.handler == h)
+ it.handler = 0;
}
}
void gdioutput::removeTimeoutMilli(const string &id) {
for (list::iterator it = timers.begin(); it != timers.end(); ++it) {
if (it->id == id) {
- UINT_PTR ptr = (UINT_PTR)&*it;
- KillTimer(hWndTarget, ptr);
timers.erase(it);
return;
}
@@ -775,12 +821,17 @@ TimerInfo &gdioutput::addTimeoutMilli(int timeOut, const string &id, GUICALLBACK
removeTimeoutMilli(id);
timers.push_back(TimerInfo(this, cb));
timers.back().id = id;
- //timers.back().data = 0;
SetTimer(hWndTarget, (UINT_PTR)&timers.back(), timeOut, gdiTimerProc);
+ timers.back().setWnd = hWndTarget;
return timers.back();
}
-
+TimerInfo:: ~TimerInfo() {
+ handler = 0;
+ callBack = 0;
+ if (setWnd)
+ KillTimer(setWnd, (UINT_PTR)this);
+}
TextInfo &gdioutput::addStringUT(int yp, int xp, int format, const string &text,
int xlimit, GUICALLBACK cb, const wchar_t *fontFace) {
return addStringUT(yp, xp, format, widen(text), xlimit, cb, fontFace);
@@ -951,22 +1002,41 @@ ButtonInfo &gdioutput::addButton(int x, int y, const string &id, const string &t
}
ButtonInfo &gdioutput::addButton(int x, int y, const string &id, const wstring &text, GUICALLBACK cb,
- const wstring &tooltip)
+ const wstring &tooltip)
{
- SIZE size;
+ HANDLE bm = 0;
+ int width = 0;
+ if (text[0] == '@') {
+ HINSTANCE hInst = GetModuleHandle(0);//(HINSTANCE)GetWindowLong(hWndTarget, GWL_HINSTANCE);
+ int ir = _wtoi(text.c_str() + 1);
+ // bm = LoadImage(hInst, MAKEINTRESOURCE(ir), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+ bm = LoadBitmap(hInst, MAKEINTRESOURCE(ir));// , IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+
+ SIZE size;
+ size.cx = 24;
+ //GetBitmapDimensionEx(bm, &size);
+ width = size.cx+4;
+ }
+ else {
+ SIZE size;
+ HDC hDC = GetDC(hWndTarget);
+ SelectObject(hDC, getGUIFont());
+ wstring ttext = lang.tl(text);
+ if (lang.capitalizeWords())
+ capitalizeWords(ttext);
+ GetTextExtentPoint32(hDC, ttext.c_str(), ttext.length(), &size);
+ ReleaseDC(hWndTarget, hDC);
+ width = size.cx + scaleLength(30);
+ if (text != L"...")
+ width = max(width, scaleLength(75));
+ }
- HDC hDC=GetDC(hWndTarget);
- SelectObject(hDC, getGUIFont());
- wstring ttext = lang.tl(text);
- if (lang.capitalizeWords())
- capitalizeWords(ttext);
- GetTextExtentPoint32(hDC, ttext.c_str(), ttext.length(), &size);
- ReleaseDC(hWndTarget, hDC);
- int width = size.cx+scaleLength(30);
- if (text != L"...")
- width = max(width, scaleLength(75));
ButtonInfo &bi=addButton(x, y, width, id, text, cb, tooltip, false, false);
+ if (bm != 0) {
+ SendMessage(bi.hWnd, BM_SETIMAGE, IMAGE_BITMAP, LPARAM(bm));
+ }
+
return bi;
}
@@ -1015,6 +1085,10 @@ ButtonInfo &gdioutput::addButton(int x, int y, int w, const string &id,
bool AbsPos, bool hasState)
{
int style = hasState ? BS_CHECKBOX|BS_PUSHLIKE : BS_PUSHBUTTON;
+
+ if (text[0] == '@')
+ style |= BS_BITMAP;
+
ButtonInfo bi;
wstring ttext = lang.tl(text);
if (lang.capitalizeWords())
@@ -1369,7 +1443,7 @@ void gdioutput::synchronizeListScroll(const string &id1, const string &id2)
ListBoxInfo &gdioutput::addListBox(int x, int y, const string &id, int width, int height, GUICALLBACK cb,
const wstring &explanation, const wstring &tooltip, bool multiple) {
if (explanation.length()>0) {
- addString(id+"_expl", y, x, 0, explanation);
+ addString(id+"_label", y, x, 0, explanation);
y+=lineHeight;
}
ListBoxInfo lbi;
@@ -1461,7 +1535,7 @@ ListBoxInfo &gdioutput::addSelection(int x, int y, const string &id, int width,
GUICALLBACK cb, const wstring &explanation, const wstring &tooltip)
{
if (explanation.length()>0) {
- addString("", y, x, 0, explanation);
+ addString(id + "_label", y, x, 0, explanation);
y+=lineHeight;
}
@@ -1504,7 +1578,7 @@ ListBoxInfo &gdioutput::addCombo(const string &id, int width, int height, GUICAL
ListBoxInfo &gdioutput::addCombo(int x, int y, const string &id, int width, int height, GUICALLBACK cb,
const wstring &explanation, const wstring &tooltip) {
if (explanation.length()>0) {
- addString("", y, x, 0, explanation);
+ addString(id + "_label", y, x, 0, explanation);
y+=lineHeight;
}
@@ -1697,18 +1771,19 @@ bool gdioutput::getSelectedItem(ListBoxInfo &lbi) {
}
int gdioutput::getItemDataByName(const char *id, const char *name) const{
+ wstring wname = recodeToWide(name);
list::const_iterator it;
for(it = LBI.begin(); it != LBI.end(); ++it){
if (it->id==id) {
if (it->IsCombo) {
- int ix = SendMessage(it->hWnd, CB_FINDSTRING, -1, LPARAM(name));
+ int ix = SendMessage(it->hWnd, CB_FINDSTRING, -1, LPARAM(wname.c_str()));
if (ix >= 0) {
return SendMessage(it->hWnd, CB_GETITEMDATA, ix, 0);
}
return -1;
}
else {
- int ix = SendMessage(it->hWnd, LB_FINDSTRING, -1, LPARAM(name));
+ int ix = SendMessage(it->hWnd, LB_FINDSTRING, -1, LPARAM(wname.c_str()));
if (ix >= 0) {
return SendMessage(it->hWnd, LB_GETITEMDATA, ix, 0);
}
@@ -2441,8 +2516,6 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
return 0;*/
}
else if (iMessage == WM_CTLCOLOREDIT) {
- //for (list::const_iterator it = II.begin(); it != II.end(); ++it) {
- // if (it->hWnd == HWND(lParam)) {
unordered_map::iterator it = iiByHwnd.find(HWND(lParam));
if (it != iiByHwnd.end()) {
InputInfo &ii = *it->second;
@@ -2460,9 +2533,11 @@ LRESULT gdioutput::ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam)
return LRESULT(GetStockObject(DC_BRUSH));
}
}
-
return 0;
}
+ else if (iMessage == WM_DESTROY) {
+ canClear();// Ignore return value
+ }
return 0;
}
@@ -2747,6 +2822,7 @@ void gdioutput::doEscape()
}
void gdioutput::clearPage(bool autoRefresh, bool keepToolbar) {
+ animationData.reset();
lockUpDown = false;
hasAnyTimer = false;
enableTables();
@@ -2757,6 +2833,7 @@ void gdioutput::clearPage(bool autoRefresh, bool keepToolbar) {
while(!timers.empty()) {
KillTimer(hWndTarget, (UINT_PTR)&timers.back());
+ timers.back().setWnd = 0;
timers.back().parent = 0;
timers.pop_back();
}
@@ -2845,6 +2922,12 @@ void gdioutput::clearPage(bool autoRefresh, bool keepToolbar) {
renderOptimize=true;
+ backgroundColor1 = -1;
+ backgroundColor2 = -1;
+ foregroundColor = -1;
+ backgroundImage = -1;
+
+
setRestorePoint();
if (autoRefresh)
@@ -3152,6 +3235,32 @@ bool gdioutput::getData(const string &id, DWORD &data) const
return false;
}
+void gdioutput::setData(const string &id, const string &data) {
+ for (auto &it : DataInfo) {
+ if (it.id == id) {
+ it.sdata = data;
+ return;
+ }
+ }
+
+ DataStore ds;
+ ds.id = id;
+ ds.sdata = data;
+ DataInfo.push_front(ds);
+ return;
+}
+
+bool gdioutput::getData(const string &id, string &out) const {
+ for (auto &it : DataInfo) {
+ if (it.id == id) {
+ out = it.sdata;
+ return true;
+ }
+ }
+ out.clear();
+ return false;
+}
+
void *gdioutput::getData(const string &id) const {
list::const_iterator it;
for (it = DataInfo.begin(); it != DataInfo.end(); ++it){
@@ -4095,6 +4204,8 @@ void gdioutput::formatString(const TextInfo &ti, HDC hDC) const
SetTextColor(hDC, RGB(255,0,0));
else if (ti.highlight)
SetTextColor(hDC, RGB(64,64,128));
+ else if (ti.color == 0 && foregroundColor != -1)
+ SetTextColor(hDC, foregroundColor);
else
SetTextColor(hDC, ti.color);
}
@@ -4488,6 +4599,9 @@ bool gdioutput::removeControl(const string &id)
if (it->id==id) {
DestroyWindow(it->hWnd);
biByHwnd.erase(it->hWnd);
+
+ if (it->isCheckbox)
+ removeString("T" + id);
BI.erase(it);
return true;
}
@@ -4500,6 +4614,7 @@ bool gdioutput::removeControl(const string &id)
if (lit->id==id) {
DestroyWindow(lit->hWnd);
lbiByHwnd.erase(lit->hWnd);
+ removeString(id + "_label");
if (lit->writeLock)
hasCleared = true;
LBI.erase(lit);
@@ -4515,6 +4630,7 @@ bool gdioutput::removeControl(const string &id)
DestroyWindow(iit->hWnd);
iiByHwnd.erase(iit->hWnd);
II.erase(iit);
+ removeString(id + "_label");
return true;
}
++iit;
@@ -4843,7 +4959,11 @@ RectangleInfo &RectangleInfo::changeDimension(gdioutput &gdi, int dx, int dy) {
RectangleInfo &gdioutput::addRectangle(RECT &rc, GDICOLOR color, bool drawBorder, bool addFirst) {
RectangleInfo ri;
- ri.rc = rc;
+ ri.rc.left = min(rc.left, rc.right);
+ ri.rc.right = max(rc.left, rc.right);
+ ri.rc.top = min(rc.top, rc.bottom);
+ ri.rc.bottom = max(rc.top, rc.bottom);
+
if (color==colorDefault)
ri.color = GetSysColor(COLOR_INFOBK);
else if (color == colorWindowBar) {
@@ -4861,7 +4981,7 @@ RectangleInfo &gdioutput::addRectangle(RECT &rc, GDICOLOR color, bool drawBorder
}
int ex = scaleLength(5);
- updatePos(rc.left, rc.top, rc.right-rc.left+ex, rc.bottom-rc.top+ex);
+ updatePos(ri.rc.left, ri.rc.top, ri.rc.right-ri.rc.left+ex, ri.rc.bottom-ri.rc.top+ex);
if (addFirst) {
Rectangles.push_front(ri);
return Rectangles.front();
@@ -5022,6 +5142,12 @@ void gdioutput::scrollToBottom()
bool gdioutput::clipOffset(int PageX, int PageY, int &MaxOffsetX, int &MaxOffsetY)
{
+ if (animationData) {
+ MaxOffsetX = 0;
+ MaxOffsetY = 0;
+ return false;
+ }
+
if (highContrast)
setHighContrastMaxWidth();
@@ -5732,10 +5858,38 @@ void gdioutput::storeAutoPos(double pos) {
}
void gdioutput::setFullScreen(bool useFullScreen) {
- SetWindowLong(hWndTarget, GWL_STYLE, WS_POPUP|WS_BORDER);
- ShowWindow(hWndTarget, SW_MAXIMIZE);
- UpdateWindow(hWndTarget);
- fullScreen = true;
+ if (useFullScreen && !fullScreen) {
+ SetWindowLong(hWndTarget, GWL_STYLE, WS_POPUP | WS_BORDER);
+ ShowWindow(hWndTarget, SW_MAXIMIZE);
+ UpdateWindow(hWndTarget);
+ }
+ else if (fullScreen) {
+ SetWindowLong(hWndTarget, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ ShowWindow(hWndTarget, SW_NORMAL);
+ UpdateWindow(hWndTarget);
+ }
+ fullScreen = useFullScreen;
+}
+
+void gdioutput::setColorMode(DWORD bgColor1, DWORD bgColor2,
+ DWORD fgColor, const wstring &bgImage) {
+ backgroundColor1 = bgColor1;
+ backgroundColor2 = bgColor2;
+ foregroundColor = fgColor;
+ backgroundImage = bgImage;
+}
+
+DWORD gdioutput::getFGColor() const {
+ return foregroundColor != -1 ? foregroundColor : 0;
+}
+DWORD gdioutput::getBGColor() const {
+ return backgroundColor1 != -1 ? backgroundColor1 : RGB(255,255,255);
+}
+DWORD gdioutput::getBGColor2() const {
+ return backgroundColor2;
+}
+const wstring &gdioutput::getBGImage() const {
+ return backgroundImage;
}
bool gdioutput::hasCommandLock() const {
@@ -6249,7 +6403,7 @@ InputInfo &InputInfo::setFont(gdioutput &gdi, gdiFonts font) {
void gdioutput::copyToClipboard(const string &html, const wstring &txt) const {
- if (OpenClipboard(getHWND()) != false) {
+ if (OpenClipboard(getHWNDMain()) != false) {
EmptyClipboard();
size_t len = html.length() + 1;
@@ -6658,4 +6812,43 @@ void gdioutput::getVirtualScreenSize(RECT &rc) {
rc.right = px;
rc.top = 0;
rc.bottom = py;
-}
\ No newline at end of file
+}
+
+DWORD gdioutput::selectColor(wstring &def, DWORD input) {
+ CHOOSECOLOR cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.lStructSize = sizeof(cc);
+ cc.hwndOwner = getHWNDMain();
+ cc.rgbResult = COLORREF(input);
+ if (GDICOLOR(input) != colorDefault)
+ cc.Flags |= CC_RGBINIT;
+
+ COLORREF staticColor[16];
+ memset(staticColor, 0, 16 * sizeof(COLORREF));
+
+ const wchar_t *end = def.c_str() + def.length();
+ const wchar_t * pEnd = def.c_str();
+ int pix = 0;
+ while (pEnd < end && pix < 16) {
+ staticColor[pix++] = wcstol(pEnd, (wchar_t **)&pEnd, 16);
+ }
+
+ cc.lpCustColors = staticColor;
+ if (ChooseColor(&cc)) {
+ wstring co;
+ for (int ix = 0; ix < 16; ix++) {
+ wchar_t bf[16];
+ swprintf_s(bf, L"%x ", staticColor[ix]);
+ co += bf;
+ }
+ swap(def,co);
+ return cc.rgbResult;
+ }
+ return -1;
+}
+
+void gdioutput::setAnimationMode(shared_ptr &data) {
+ if (animationData && animationData->takeOver(data))
+ return;
+ animationData = data;
+}
diff --git a/code/gdioutput.h b/code/gdioutput.h
index 4775009..3f7b9d1 100644
--- a/code/gdioutput.h
+++ b/code/gdioutput.h
@@ -63,6 +63,7 @@ class FixedTabs;
struct PageInfo;
struct RenderedPage;
+class AnimationData;
typedef int (*GUICALLBACK)(gdioutput *gdi, int type, void *data);
@@ -70,7 +71,7 @@ enum GDICOLOR;
enum KeyCommandCode;
enum gdiFonts;
#include "gdistructures.h"
-
+#include
#define START_YP 30
#define NOTIMEOUT 0x0AAAAAAA
@@ -238,6 +239,12 @@ protected:
bool lockRefresh;
bool fullScreen;
bool hideBG;
+
+ DWORD backgroundColor1;
+ DWORD backgroundColor2;
+ wstring backgroundImage;
+ DWORD foregroundColor;
+
mutable bool commandLock;
mutable DWORD commandUnlockTime;
@@ -271,6 +278,8 @@ protected:
pair recorder;
list< pair > subCommands;
+ shared_ptr animationData;
+
int defaultCodePage;
public:
// Return the bounding dimension of the desktop
@@ -279,6 +288,7 @@ public:
void getWindowsPosition(RECT &rc) const;
void setWindowsPosition(const RECT &rc);
+
void initRecorder(Recorder *rec);
Recorder &getRecorder();
string dbPress(const string &id, int extra);
@@ -332,6 +342,16 @@ public:
bool isFullScreen() const {return fullScreen;}
void setFullScreen(bool useFullScreen);
+ void setColorMode(DWORD bgColor1, DWORD bgColor2 = -1,
+ DWORD fgColor = -1, const wstring &bgImage = L"");
+
+ DWORD getFGColor() const;
+ DWORD getBGColor() const;
+ DWORD getBGColor2() const;
+ const wstring &getBGImage() const;
+
+ void setAnimationMode(shared_ptr &mode);
+
void setAutoScroll(double speed);
void getAutoScroll(double &speed, double &pos) const;
void storeAutoPos(double pos);
@@ -394,8 +414,8 @@ public:
void getSelection(const string &id, set &selection);
- HWND getTarget() const {return hWndTarget;}
- HWND getMain() const {return hWndAppMain;}
+ HWND getHWNDTarget() const {return hWndTarget;}
+ HWND getHWNDMain() const {return hWndAppMain;}
void scrollToBottom();
void scrollTo(int x, int y);
@@ -456,7 +476,6 @@ public:
void drawBoxes(HDC hDC, RECT &rc);
void drawBox(HDC hDC, InfoBox &Box, RECT &pos);
void addInfoBox(string id, wstring text, int TimeOut=0, GUICALLBACK cb=0);
- HWND getHWND() const {return hWndTarget;}
void updateObjectPositions();
void drawBackground(HDC hDC, RECT &rc);
void renderRectangle(HDC hDC, RECT *clipRegion, const RectangleInfo &ri);
@@ -516,7 +535,13 @@ public:
void setTabStops(const string &Name, int t1, int t2=-1);
void setData(const string &id, DWORD data);
void setData(const string &id, void *data);
+ void setData(const string &id, const string &data);
+
void *getData(const string &id) const;
+ bool getData(const string &id, string &out) const;
+
+
+ DWORD selectColor(wstring &def, DWORD input);
void autoRefresh(bool flag) {manualUpdate = !flag;}
@@ -618,7 +643,7 @@ public:
LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam);
void setWindow(HWND hWnd){hWndTarget=hWnd;}
- void scaleSize(double scale);
+ void scaleSize(double scale, bool allowSmallScale = false, bool doRefresh = true);
ButtonInfo &addButton(const string &id, const wstring &text, GUICALLBACK cb = 0,
const wstring &tooltip = L"");
@@ -713,6 +738,8 @@ public:
TimerInfo &addTimeoutMilli(int timeOut, const string &id, GUICALLBACK cb);
void timerProc(TimerInfo &timer, DWORD timeout);
+ void removeHandler(GuiHandler *h);
+
void draw(HDC hDC, RECT &windowArea, RECT &drawArea);
void closeWindow();
diff --git a/code/gdistructures.h b/code/gdistructures.h
index fd182cf..18aa5b7 100644
--- a/code/gdistructures.h
+++ b/code/gdistructures.h
@@ -25,6 +25,7 @@
#include
#include "guihandler.h"
+#include "gdifonts.h"
class BaseInfo
{
@@ -151,6 +152,8 @@ public:
TextInfo &setColor(GDICOLOR c) {color = c; return *this;}
TextInfo &changeFont(const wstring &fnt) {font = fnt; return *this;} //Note: size not updated
+ bool isFormatInfo() const { return format == pageNewPage || format == pagePageInfo; }
+
int getHeight() {return int(textRect.bottom-textRect.top);}
gdiFonts getGdiFont() const {return gdiFonts(format & 0xFF);}
// Sets absolute print coordinates in [mm]
@@ -183,6 +186,8 @@ public:
HWND getControlWindow() const {throw std::exception("Unsupported");}
+
+ friend class gdioutput;
};
class ButtonInfo : public BaseInfo
@@ -330,8 +335,12 @@ private:
class DataStore
{
public:
+ DataStore() {
+ data = 0;
+ }
string id;
void *data;
+ string sdata;
};
class EventInfo : public BaseInfo
@@ -355,12 +364,17 @@ public:
class TimerInfo : public BaseInfo
{
private:
+ static int globalTimerId;
+ int timerId;
DWORD dataInt;
wstring dataString;
gdioutput *parent;
- TimerInfo(gdioutput *gdi, GUICALLBACK cb) : parent(gdi), callBack(cb) {}
-
+ TimerInfo(gdioutput *gdi, GUICALLBACK cb) : parent(gdi), callBack(cb), setWnd(0), timerId(++globalTimerId) {}
+ HWND setWnd;
public:
+ ~TimerInfo();
+
+ int getId() const { return timerId; }
BaseInfo &setExtra(const wchar_t *e) {return BaseInfo::setExtra(e);}
BaseInfo &setExtra(int e) {return BaseInfo::setExtra(e);}
diff --git a/code/generalresult.cpp b/code/generalresult.cpp
index d4d3412..2cf22b2 100644
--- a/code/generalresult.cpp
+++ b/code/generalresult.cpp
@@ -699,6 +699,8 @@ RunnerStatus DynamicResult::toStatus(int status) const {
return StatusDNF;
case StatusDNS:
return StatusDNS;
+ case StatusCANCEL:
+ return StatusCANCEL;
case StatusNotCompetiting:
return StatusNotCompetiting;
case StatusDQ:
@@ -798,9 +800,9 @@ void DynamicResult::save(xmlparser &xml) const {
xml.write("Tag", gdioutput::widen(tag));
xml.write("Description", description);
if (origin.empty())
- origin = gEvent->getName() + L" (" + getLocalDateW() + L")";
+ origin = gEvent->getName() + L" (" + getLocalDate() + L")";
xml.write("Origin", origin);
- xml.write("Date", getLocalTimeW());
+ xml.write("Date", getLocalTime());
// xml.write("Tag", tag);
// xml.write("UID", getUniqueId());
@@ -975,6 +977,7 @@ void DynamicResult::declareSymbols(DynamicMethods m, bool clear) const {
parser.declareSymbol("StatusMP", "Status code for a missing punch", false);
parser.declareSymbol("StatusDNF", "Status code for not finishing", false);
parser.declareSymbol("StatusDNS", "Status code for not starting", false);
+ parser.declareSymbol("StatusCANCEL", "Status code for cancelled entry", false);
parser.declareSymbol("StatusMAX", "Status code for a time over the maximum", false);
parser.declareSymbol("StatusDQ", "Status code for disqualification", false);
parser.declareSymbol("StatusNotCompetiting", "Status code for not competing", false);
@@ -1016,6 +1019,7 @@ void DynamicResult::prepareCalculations(oEvent &oe, bool prepareForTeam, int inp
parser.addSymbol("StatusOK", StatusOK);
parser.addSymbol("StatusMP", StatusMP);
parser.addSymbol("StatusDNF", StatusDNF);
+ parser.addSymbol("StatusCANCEL", StatusCANCEL);
parser.addSymbol("StatusDNS", StatusDNS);
parser.addSymbol("StatusMAX", StatusMAX);
parser.addSymbol("StatusDQ", StatusDQ);
diff --git a/code/infoserver.cpp b/code/infoserver.cpp
index a6f604a..a449dd1 100644
--- a/code/infoserver.cpp
+++ b/code/infoserver.cpp
@@ -65,6 +65,7 @@ int InfoBase::convertRelativeTime(const oBase &elem, int t) {
InfoCompetition::InfoCompetition(int id) : InfoBase(id) {
forceComplete = true;
+ includeTotal = false;
}
InfoRadioControl::InfoRadioControl(int id) : InfoBase(id) {
@@ -93,7 +94,7 @@ InfoTeam::InfoTeam(int id) : InfoBaseCompetitor(id) {
}
-bool InfoCompetition::synchronize(oEvent &oe, const set &includeCls, const set &ctrls) {
+bool InfoCompetition::synchronize(oEvent &oe, bool onlyCmp, const set &includeCls, const set &ctrls) {
bool changed = false;
if (oe.getName() != name) {
name = oe.getName();
@@ -117,6 +118,9 @@ bool InfoCompetition::synchronize(oEvent &oe, const set &includeCls, const
if (changed)
needCommit(*this);
+
+ if (onlyCmp)
+ return changed;
vector ctrl;
oe.getControls(ctrl, true);
@@ -422,23 +426,41 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
return ch;
}
-bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
+bool InfoCompetitor::synchronize(bool useTotalResults, oRunner &r) {
bool ch = synchronizeBase(r);
-
changeTotalSt = r.getEvent()->hasPrevStage() || r.getLegNumber()>0; // Always write full attributes
- int s = r.getTotalStatusInput();
+
+ int s = StatusOK;
+ int legInput = 0;
+
+ pTeam t = r.getTeam();
+ if (useTotalResults) {
+ legInput = r.getTotalTimeInput() * 10;
+ s = r.getTotalStatusInput();
+ }
+ else if (t && r.getLegNumber() > 0) {
+ legInput = t->getLegRunningTime(r.getLegNumber() - 1, false);
+ s = t->getLegStatus(r.getLegNumber() - 1, false);
+ }
+
if (totalStatus != s) {
totalStatus = s;
ch = true;
changeTotalSt = true;
}
- int legInput = r.getTotalTimeInput() * 10;
if (legInput != inputTime) {
inputTime = legInput;
ch = true;
changeTotalSt = true;
}
+
+ return ch;
+}
+
+bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
+ bool useTotalResults = cmp.includeTotalResults();
+ bool ch = synchronize(useTotalResults, r);
vector newRT;
if (r.getClassId() > 0) {
diff --git a/code/infoserver.h b/code/infoserver.h
index 3b1f290..6084e63 100644
--- a/code/infoserver.h
+++ b/code/infoserver.h
@@ -114,9 +114,10 @@ class InfoClass : public InfoBase {
int sortOrder;
vector< vector > radioControls;
vector linearLegNumberToActual;
+ public:
bool synchronize(oClass &c, const set &ctrls);
void serialize(xmlbuffer &xml, bool diffOnly) const;
- public:
+
InfoClass(int id);
virtual ~InfoClass() {}
@@ -166,10 +167,12 @@ class InfoCompetitor : public InfoBaseCompetitor {
int inputTime;
int totalStatus;
bool synchronize(const InfoCompetition &cmp, oRunner &c);
- void serialize(xmlbuffer &xml, bool diffOnly) const;
bool changeTotalSt;
bool changeRadio;
public:
+ bool synchronize(bool useTotalResults, oRunner &c);
+ void serialize(xmlbuffer &xml, bool diffOnly) const;
+
InfoCompetitor(int id);
virtual ~InfoCompetitor() {}
@@ -197,6 +200,8 @@ private:
protected:
bool forceComplete;
+ bool includeTotal;
+
list toCommit;
map controls;
@@ -206,13 +211,20 @@ protected:
map teams;
void needCommit(InfoBase &obj);
+
+ public:
void serialize(xmlbuffer &xml, bool diffOnly) const;
- public:
- const vector &getControls(int classId, int legNumber) const;
- bool synchronize(oEvent &oe, const set &classes, const set &ctrls);
+ bool includeTotalResults() const {return includeTotal;}
+ void includeTotalResults(bool inc) {includeTotal = inc;}
+ const vector &getControls(int classId, int legNumber) const;
+ bool synchronize(oEvent &oe, bool onlyCmp, const set &classes, const set &ctrls);
+ bool synchronize(oEvent &oe) {
+ set dmy;
+ return synchronize(oe, true, dmy, dmy);
+ }
void getCompleteXML(xmlbuffer &xml);
void getDiffXML(xmlbuffer &xml);
diff --git a/code/iof30interface.cpp b/code/iof30interface.cpp
index 10f2718..6441b28 100644
--- a/code/iof30interface.cpp
+++ b/code/iof30interface.cpp
@@ -1150,7 +1150,7 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo,
wstring dateStr;
date.getObjectString("Date", dateStr);
oe.setDate(dateStr);
- string timeStr;
+ wstring timeStr;
date.getObjectString("Time", timeStr);
if (!timeStr.empty()) {
int t = convertAbsoluteTimeISO(timeStr);
@@ -1158,7 +1158,7 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo,
int zt = t - 3600;
if (zt < 0)
zt += 3600*24;
- oe.setZeroTime(formatTimeHMSW(zt));
+ oe.setZeroTime(formatTimeHMS(zt));
}
}
//oe.setZeroTime(...);
@@ -1347,6 +1347,14 @@ pTeam IOF30Interface::readTeamEntry(gdioutput &gdi, xmlobject &xTeam,
wstring entryTime;
xTeam.getObjectString("EntryTime", entryTime);
di.setDate("EntryDate", entryTime);
+
+ size_t tpos = entryTime.find_first_of(L"T");
+ if (tpos != -1) {
+ wstring timeString = entryTime.substr(tpos+1);
+ int t = convertAbsoluteTimeISO(timeString);
+ if (t >= 0)
+ di.setInt("EntryTime", t);
+ }
}
double fee = 0, paid = 0, taxable = 0, percentage = 0;
@@ -1485,7 +1493,7 @@ void IOF30Interface::prescanEntry(xmlobject &xo, set &stages) {
if (races.empty())
stages.insert(-1);// All
else {
- for (auto race : races) {
+ for (auto &race : races) {
int r = race.getInt();
if (r > 0)
stages.insert(r);
@@ -1497,7 +1505,7 @@ bool IOF30Interface::matchStageFilter(const set &stageFilter, const xmlList
if (stageFilter.empty() || races.empty())
return true;
- for (auto r : races) {
+ for (auto &r : races) {
if (stageFilter.count(r.getInt()))
return true;
}
@@ -1580,6 +1588,14 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
wstring entryTime;
xo.getObjectString("EntryTime", entryTime);
di.setDate("EntryDate", entryTime);
+ size_t tpos = entryTime.find_first_of(L"T");
+ if (tpos != -1) {
+ wstring timeString = entryTime.substr(tpos+1);
+ int t = convertAbsoluteTimeISO(timeString);
+ if (t >= 0)
+ di.setInt("EntryTime", t);
+ }
+
double fee = 0, paid = 0, taxable = 0, percentage = 0;
wstring currency;
@@ -2064,7 +2080,7 @@ void IOF30Interface::FeeInfo::add(IOF30Interface::FeeInfo &fi) {
convertDateYMS(fi.toTime, st, false);
__int64 sec = SystemTimeToInt64Second(st);
sec -= 3600;
- fi.toTime = convertSystemDateW(Int64SecondToSystemTime(sec));
+ fi.toTime = convertSystemDate(Int64SecondToSystemTime(sec));
}
}
//if (fi.fromTime.empty() || (fi.fromTime < toTime && !toTime.empty()))
@@ -2270,7 +2286,7 @@ void IOF30Interface::setupRelayClass(pClass pc, const vector &legs) {
wstring IOF30Interface::getCurrentTime() const {
// Don't call this method at midnight!
- return getLocalDateW() + L"T" + getLocalTimeOnlyW();
+ return getLocalDate() + L"T" + getLocalTimeOnly();
}
int IOF30Interface::parseISO8601Time(const xmlobject &xo) {
@@ -2488,6 +2504,8 @@ wstring formatStatus(RunnerStatus st) {
return L"OK";
case StatusDNS:
return L"DidNotStart";
+ case StatusCANCEL:
+ return L"Cancelled";
case StatusMP:
return L"MissingPunch";
case StatusDNF:
@@ -2647,7 +2665,9 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
writeCourse(xml, *crs);
const vector &sp = r.getSplitTimes(unrollLoops);
- if (r.getStatus()>0 && r.getStatus() != StatusDNS && r.getStatus() != StatusNotCompetiting) {
+ if (r.getStatus()>0 && r.getStatus() != StatusDNS &&
+ r.getStatus() != StatusCANCEL &&
+ r.getStatus() != StatusNotCompetiting) {
int nc = crs->getNumControls();
bool hasRogaining = crs->hasRogaining();
int firstControl = crs->useFirstAsStart() ? 1 : 0;
diff --git a/code/listeditor.cpp b/code/listeditor.cpp
index 80d21e4..90390ac 100644
--- a/code/listeditor.cpp
+++ b/code/listeditor.cpp
@@ -298,7 +298,13 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
ButtonInfo &biSrc = dynamic_cast(data);
if (bi.id == "Color") {
- CHOOSECOLOR cc;
+ wstring c = oe->getPropertyString("Colors", L"");
+ int res = gdi.selectColor(c, bi.getExtraInt());
+ if (res >= -1) {
+ biSrc.setExtra(res);
+ oe->setProperty("Colors", c);
+ }
+ /*CHOOSECOLOR cc;
memset(&cc, 0, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = gdi.getHWND();
@@ -317,8 +323,6 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
staticColor[pix++] = strtol(pEnd,(char **)&pEnd,16);
}
- //vector splitvector;
- //split(c, ";", splitvector);
cc.lpCustColors = staticColor;
if (ChooseColor(&cc)) {
data.setExtra((int)cc.rgbResult);
@@ -330,7 +334,7 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
co += bf;
}
oe->setProperty("Colors", co);
- }
+ }*/
}
if ( bi.id.substr(0, 8) == "EditPost" ) {
int id = atoi(bi.id.substr(8).c_str());
diff --git a/code/liveresult.cpp b/code/liveresult.cpp
index 64d29a5..9753067 100644
--- a/code/liveresult.cpp
+++ b/code/liveresult.cpp
@@ -313,12 +313,12 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
if (screenSize == 1) {
gdi.restore("LiveResult", false);
wstring font = getFont(gdi, timerScale);
- gdi.addString("", h/2, w/2, boldHuge|textCenter, formatTimeW(rt), 0, 0, font.c_str()).setColor(colorGreen);
+ gdi.addString("", h/2, w/2, boldHuge|textCenter, formatTime(rt), 0, 0, font.c_str()).setColor(colorGreen);
gdi.addTimeout(5, 0).setHandler(this);
}
else if (screenSize == 2) {
string id = "timer" + itos(runner2ScreenPos[rToFinish->getId()]);
- BaseInfo *bi = gdi.setText(id, formatTimeW(rt), false);
+ BaseInfo *bi = gdi.setText(id, formatTime(rt), false);
wstring font = getFont(gdi, timerScale * 0.6);
if (bi) {
@@ -388,7 +388,7 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
int ht = ti.textRect.bottom - ti.textRect.top;
gdi.addStringUT(y, 30 + ht * 2 , fontLarge, r->getName(), 0, 0, font.c_str());
//int w = gdi.getWidth();
- gdi.addStringUT(y, w - 4 * ht, fontLarge, formatTimeW(res.time), 0, 0, font.c_str());
+ gdi.addStringUT(y, w - 4 * ht, fontLarge, formatTime(res.time), 0, 0, font.c_str());
gdi.refreshSmartFromSnapshot(false);
resYPos += int (ht * 1.1);
showResultList++;
diff --git a/code/meos.cpp b/code/meos.cpp
index 1e39f04..0a57138 100644
--- a/code/meos.cpp
+++ b/code/meos.cpp
@@ -63,8 +63,7 @@
#include "autotask.h"
#include "meosexception.h"
#include "parser.h"
-
-#include "restbed/restbed"
+#include "restserver.h"
gdioutput *gdi_main=0;
oEvent *gEvent=0;
@@ -162,6 +161,8 @@ void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
while ( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 ) {
if (bRet == -1)
return;
+ if (gEvent != 0)
+ RestServer::computeRequested(*gEvent);
if (hAccelTable == 0 || !TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
@@ -174,19 +175,6 @@ void mainMessageLoop(HACCEL hAccelTable, DWORD time) {
}
}
-void post_method_handler(const shared_ptr< restbed::Session > session)
-{
- using namespace restbed;
- const auto request = session->get_request();
-
- size_t content_length = request->get_header("Content-Length", 0);
-
- session->fetch(content_length, [request](const shared_ptr< Session > session, const Bytes & body)
- {
- fprintf(stdout, "%.*s\n", (int)body.size(), body.data());
- session->close(restbed::OK, "Hello, World!", { { "Content-Length", "13" },{ "Connection", "close" } });
- });
-}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
@@ -195,20 +183,6 @@ int APIENTRY WinMain(HINSTANCE hInstance,
{
atexit(dumpLeaks); //
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- /*{
- using namespace restbed;
- auto resource = make_shared< Resource >();
- resource->set_path("/resource");
- resource->set_method_handler("GET", post_method_handler);
-
- Service service;
-
- auto settings = make_shared< Settings >();
- settings->set_port(1984);
-
- service.publish(resource);
- service.start(settings);
- }*/
if (strstr(lpCmdLine, "-s") != 0) {
Setup(true, false);
@@ -226,9 +200,10 @@ int APIENTRY WinMain(HINSTANCE hInstance,
RunnerStatusOrderMap[StatusMP] = 2;
RunnerStatusOrderMap[StatusDNF] = 3;
RunnerStatusOrderMap[StatusDQ] = 4;
- RunnerStatusOrderMap[StatusDNS] = 5;
- RunnerStatusOrderMap[StatusUnknown] = 6;
- RunnerStatusOrderMap[StatusNotCompetiting] = 7;
+ RunnerStatusOrderMap[StatusCANCEL] = 5;
+ RunnerStatusOrderMap[StatusDNS] = 6;
+ RunnerStatusOrderMap[StatusUnknown] = 7;
+ RunnerStatusOrderMap[StatusNotCompetiting] = 8;
lang.init();
StringCache::getInstance().init();
@@ -413,7 +388,7 @@ int APIENTRY WinMain(HINSTANCE hInstance,
for (size_t k = 0; kgetHWND());
+ DestroyWindow(gdi_extra[k]->getHWNDMain());
if (k < gdi_extra.size()) {
delete gdi_extra[k];
gdi_extra[k] = 0;
@@ -555,7 +530,7 @@ LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
gdi = gdi_main;
- HWND hWnd = gdi ? gdi->getHWND() : 0;
+ HWND hWnd = gdi ? gdi->getHWNDTarget() : 0;
bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
bool shiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
@@ -740,7 +715,7 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
void destroyExtraWindows() {
for (size_t k = 1; kgetHWND());
+ DestroyWindow(gdi_extra[k]->getHWNDMain());
}
}
}
@@ -768,7 +743,7 @@ gdioutput *getExtraWindow(const string &tag, bool toForeGround) {
for (size_t k = 0; khasTag(tag)) {
if (toForeGround)
- SetForegroundWindow(gdi_extra[k]->getHWND());
+ SetForegroundWindow(gdi_extra[k]->getHWNDMain());
return gdi_extra[k];
}
}
@@ -791,7 +766,7 @@ gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x,
for (size_t k = 0; kgetHWND();
+ HWND hWnd = gdi_extra[k]->getHWNDTarget();
RECT rc;
if (GetWindowRect(hWnd, &rc)) {
xp = max(rc.left + 16, xp);
@@ -829,6 +804,9 @@ gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x,
gdi_main->cmdAnswers.pop_front();
}
}
+ else {
+ gdi->initRecorder(&gdi_main->getRecorder());
+ }
SetWindowLong(hWnd, GWL_USERDATA, gdi_extra.size());
currentFocusIx = gdi_extra.size();
gdi_extra.push_back(gdi);
diff --git a/code/meos_util.cpp b/code/meos_util.cpp
index 746a9ba..d14ecff 100644
--- a/code/meos_util.cpp
+++ b/code/meos_util.cpp
@@ -35,6 +35,11 @@ namespace MeOSUtil {
int useHourFormat = true;
}
+string convertSystemTimeN(const SYSTEMTIME &st);
+string convertSystemDateN(const SYSTEMTIME &st);
+string convertSystemTimeOnlyN(const SYSTEMTIME &st);
+
+
DWORD mainThreadId = -1;
StringCache &StringCache::getInstance() {
DWORD id = GetCurrentThreadId();
@@ -45,29 +50,33 @@ StringCache &StringCache::getInstance() {
return globalStringCache;
}
-string getLocalTime() {
+string getLocalTimeN() {
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ return convertSystemTimeN(st);
+}
+
+string getLocalDateN()
+{
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ return convertSystemDateN(st);
+}
+
+wstring getLocalTime() {
SYSTEMTIME st;
GetLocalTime(&st);
return convertSystemTime(st);
}
-string getLocalDate()
-{
+wstring getLocalDate() {
SYSTEMTIME st;
GetLocalTime(&st);
return convertSystemDate(st);
}
-wstring getLocalTimeW() {
- SYSTEMTIME st;
- GetLocalTime(&st);
- return convertSystemTimeW(st);
-}
-
-wstring getLocalDateW() {
- SYSTEMTIME st;
- GetLocalTime(&st);
- return convertSystemDateW(st);
+int getLocalAbsTime() {
+ return convertAbsoluteTimeHMS(getLocalTimeOnly(), -1);
}
int getThisYear() {
@@ -114,20 +123,20 @@ wstring getLocalTimeFileName()
return bf;
}
-string getLocalTimeOnly()
+string getLocalTimeOnlyN()
+{
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ return convertSystemTimeOnlyN(st);
+}
+
+wstring getLocalTimeOnly()
{
SYSTEMTIME st;
GetLocalTime(&st);
return convertSystemTimeOnly(st);
}
-wstring getLocalTimeOnlyW()
-{
- SYSTEMTIME st;
- GetLocalTime(&st);
- return convertSystemTimeOnlyW(st);
-}
-
int getRelativeDay() {
SYSTEMTIME st;
GetLocalTime(&st);
@@ -169,7 +178,7 @@ SYSTEMTIME Int64SecondToSystemTime(__int64 time) {
return st;
}
//2014-11-03 07:02:00
-string convertSystemTime(const SYSTEMTIME &st)
+string convertSystemTimeN(const SYSTEMTIME &st)
{
char bf[32];
sprintf_s(bf, "%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
@@ -179,7 +188,7 @@ string convertSystemTime(const SYSTEMTIME &st)
}
//2014-11-03 07:02:00
-wstring convertSystemTimeW(const SYSTEMTIME &st)
+wstring convertSystemTime(const SYSTEMTIME &st)
{
wchar_t bf[32];
swprintf_s(bf, L"%d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
@@ -188,7 +197,7 @@ wstring convertSystemTimeW(const SYSTEMTIME &st)
return bf;
}
-string convertSystemTimeOnly(const SYSTEMTIME &st)
+string convertSystemTimeOnlyN(const SYSTEMTIME &st)
{
char bf[32];
sprintf_s(bf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
@@ -196,14 +205,14 @@ string convertSystemTimeOnly(const SYSTEMTIME &st)
return bf;
}
-wstring convertSystemTimeOnlyW(const SYSTEMTIME &st) {
+wstring convertSystemTimeOnly(const SYSTEMTIME &st) {
wchar_t bf[32];
swprintf_s(bf, L"%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
return bf;
}
-string convertSystemDate(const SYSTEMTIME &st)
+string convertSystemDateN(const SYSTEMTIME &st)
{
char bf[32];
sprintf_s(bf, "%d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
@@ -211,7 +220,7 @@ string convertSystemDate(const SYSTEMTIME &st)
return bf;
}
-wstring convertSystemDateW(const SYSTEMTIME &st)
+wstring convertSystemDate(const SYSTEMTIME &st)
{
wchar_t bf[32];
swprintf_s(bf, L"%d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
@@ -219,7 +228,7 @@ wstring convertSystemDateW(const SYSTEMTIME &st)
return bf;
}
-string formatDate(int m, bool useIsoFormat) {
+string formatDateN(int m, bool useIsoFormat) {
char bf[24];
if (m > 0 && m < 30000101) {
sprintf_s(bf, 24, "%d-%02d-%02d", m/(100*100), (m/100)%100, m%100);
@@ -231,7 +240,7 @@ string formatDate(int m, bool useIsoFormat) {
return bf;
}
-wstring formatDateW(int m, bool useIsoFormat) {
+wstring formatDate(int m, bool useIsoFormat) {
wchar_t bf[24];
if (m > 0 && m < 30000101) {
swprintf_s(bf, 24, L"%d-%02d-%02d", m/(100*100), (m/100)%100, m%100);
@@ -320,11 +329,6 @@ bool myIsSpace(wchar_t b) {
return iswspace(b) != 0 || b == 0x00A0 || b == 0x2007 || b == 0x202F;
}
-//Absolute time string to absolute time int
-int convertAbsoluteTimeHMS(const wstring &m, int daysZeroTime) {
- string sm(m.begin(), m.end());
- return convertAbsoluteTimeHMS(sm, daysZeroTime);
-}
//Absolute time string to absolute time int
int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
@@ -408,10 +412,10 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
return t;
}
-
-int convertAbsoluteTimeISO(const wstring &m) {
- string mn(m.begin(), m.end());
- return convertAbsoluteTimeISO(mn);
+//Absolute time string to absolute time int
+int convertAbsoluteTimeHMS(const wstring &m, int daysZeroTime) {
+ string sm(m.begin(), m.end());
+ return convertAbsoluteTimeHMS(sm, daysZeroTime);
}
//Absolute time string to absolute time int
@@ -450,6 +454,15 @@ int convertAbsoluteTimeISO(const string &m)
sStr = tmp.substr(0, 2);
+ for (int i = 0; i < 2; i++) {
+ if (hStr[i] < '0' || hStr[i] > '9')
+ return -1;
+ if (mStr[i] < '0' || mStr[i] > '9')
+ return -1;
+ if (sStr[i] < '0' || sStr[i] > '9')
+ return -1;
+ }
+
int hour = atoi(hStr.c_str());
if (hour<0 || hour>23)
return -1;
@@ -469,9 +482,9 @@ int convertAbsoluteTimeISO(const string &m)
return t;
}
-int convertAbsoluteTimeMS(const wstring &m) {
+int convertAbsoluteTimeISO(const wstring &m) {
string mn(m.begin(), m.end());
- return convertAbsoluteTimeMS(mn);
+ return convertAbsoluteTimeISO(mn);
}
// Parse +-MM:SS or +-HH:MM:SS
@@ -524,29 +537,25 @@ int convertAbsoluteTimeMS(const string &m)
return sign*t;
}
-//Generate +-MM:SS or +-HH:MM:SS
-const wstring &getTimeMSW(int m) {
- wstring &res = StringCache::getInstance().wget();
- const string tr = getTimeMS(m);
- res.clear();
- res.insert(res.begin(), tr.begin(), tr.end());
- return res;
+int convertAbsoluteTimeMS(const wstring &m) {
+ string mn(m.begin(), m.end());
+ return convertAbsoluteTimeMS(mn);
}
//Generate +-MM:SS or +-HH:MM:SS
-const string &getTimeMS(int m) {
- char bf[32];
+const wstring &getTimeMS(int m) {
+ wchar_t bf[32];
int am = abs(m);
if (am < 3600 || !MeOSUtil::useHourFormat)
- sprintf_s(bf, "-%02d:%02d", am/60, am%60);
+ swprintf_s(bf, L"-%02d:%02d", am/60, am%60);
else if (am < 3600*48)
- sprintf_s(bf, "-%02d:%02d:%02d", am/3600, (am/60)%60, am%60);
+ swprintf_s(bf, L"-%02d:%02d:%02d", am/3600, (am/60)%60, am%60);
else {
m = 0;
- bf[0] = BYTE(0x96);
+ bf[0] = 0x2013;
bf[1] = 0;
}
- string &res = StringCache::getInstance().get();
+ wstring &res = StringCache::getInstance().wget();
if (m<0)
res = bf; // with minus
else
@@ -555,7 +564,7 @@ const string &getTimeMS(int m) {
return res;
}
-const wstring &formatTimeW(int rt) {
+const wstring &formatTime(int rt) {
wstring &res = StringCache::getInstance().wget();
if (rt>0 && rt<3600*999) {
wchar_t bf[16];
@@ -588,25 +597,15 @@ const string &formatTimeN(int rt) {
return res;
}
-const wstring &formatTimeHMSW(int m) {
+const wstring &formatTimeHMS(int rt) {
wstring &res = StringCache::getInstance().wget();
- const string tr = formatTimeHMS(m);
- res.clear();
- res.insert(res.begin(), tr.begin(), tr.end());
- return res;
-}
-
-const string &formatTimeHMS(int rt) {
-
- string &res = StringCache::getInstance().get();
if (rt>=0) {
- char bf[32];
- sprintf_s(bf, 16, "%02d:%02d:%02d", rt/3600,(rt/60)%60, rt%60);
-
+ wchar_t bf[32];
+ swprintf_s(bf, 16, L"%02d:%02d:%02d", rt/3600,(rt/60)%60, rt%60);
res = bf;
return res;
}
- char ret[2] = {char(0x96), 0};
+ wchar_t ret[2] = {0x2013, 0};
res = ret;
return res;
}
@@ -2170,3 +2169,17 @@ void wide2String(const wstring &in, string &out) {
out.clear();
out.insert(out.begin(), in.begin(), in.end());// XXX Simple extend
}
+
+void checkWriteAccess(const wstring &file) {
+ if (_waccess(file.c_str(), 4) == 0)
+ return;
+
+ auto h = CreateFile(file.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
+ if (h == INVALID_HANDLE_VALUE) {
+ wchar_t absPath[260];
+ _wfullpath(absPath, file.c_str(), 260);
+
+ throw meosException(wstring(L"Du saknar behörighet att skriva till 'X'.#") + absPath);
+ }
+ CloseHandle(h);
+}
diff --git a/code/meos_util.h b/code/meos_util.h
index 7d4eb98..d5a4660 100644
--- a/code/meos_util.h
+++ b/code/meos_util.h
@@ -52,20 +52,26 @@ public:
}
};
+string convertSystemTimeN(const SYSTEMTIME &st);
+
+/*
string convertSystemTime(const SYSTEMTIME &st);
string convertSystemTimeOnly(const SYSTEMTIME &st);
string convertSystemDate(const SYSTEMTIME &st);
string getLocalTime();
string getLocalDate();
string getLocalTimeOnly();
+*/
+string getLocalTimeN();
-wstring convertSystemTimeW(const SYSTEMTIME &st);
-wstring convertSystemTimeOnlyW(const SYSTEMTIME &st);
-wstring convertSystemDateW(const SYSTEMTIME &st);
-wstring getLocalTimeW();
-wstring getLocalDateW();
-wstring getLocalTimeOnlyW();
-
+wstring convertSystemTime(const SYSTEMTIME &st);
+wstring convertSystemTimeOnly(const SYSTEMTIME &st);
+wstring convertSystemDate(const SYSTEMTIME &st);
+wstring getLocalTime();
+wstring getLocalDate();
+wstring getLocalTimeOnly();
+// Returns time in seconds after midnight
+int getLocalAbsTime();
// Get a day number after a fixed day some time ago...
int getRelativeDay();
@@ -73,13 +79,11 @@ int getRelativeDay();
/// Get time and date in a format that forms a part of a filename
wstring getLocalTimeFileName();
-const wstring &getTimeMSW(int m);
-const wstring &formatTimeW(int rt);
-const wstring &formatTimeHMSW(int rt);
+const wstring &getTimeMS(int m);
+const wstring &formatTime(int rt);
+const wstring &formatTimeHMS(int rt);
-const string &getTimeMS(int m);
-const string &formatTimeN(int rt);
-const string &formatTimeHMS(int rt);
+//const string &formatTimeN(int rt);
wstring formatTimeIOF(int rt, int zeroTime);
int convertDateYMS(const string &m, bool checkValid);
@@ -93,8 +97,8 @@ int convertDateYMS(const wstring &m, SYSTEMTIME &st, bool checkValid);
void processGeneralTime(const wstring &generalTime, wstring &meosTime, wstring &meosDate);
// Format number date 20160421 -> 2016-04-21 (if iso) or according to a custom format otherwise
-string formatDate(int m, bool useIsoFormat);
-wstring formatDateW(int m, bool useIsoFormat);
+//string formatDate(int m, bool useIsoFormat);
+wstring formatDate(int m, bool useIsoFormat);
__int64 SystemTimeToInt64Second(const SYSTEMTIME &st);
SYSTEMTIME Int64SecondToSystemTime(__int64 time);
@@ -107,15 +111,16 @@ int convertAbsoluteTimeMS(const wstring &m);
int convertAbsoluteTimeISO(const wstring &m);
//Returns a time converted from +/-MM:SS or NOTIME, in seconds
-int convertAbsoluteTimeMS(const string &m);
+//int convertAbsoluteTimeMS(const string &m);
// Parses a time on format HH:MM:SS+01:00Z or HHMMSS+0100Z (but ignores time zone)
-int convertAbsoluteTimeISO(const string &m);
+//int convertAbsoluteTimeISO(const string &m);
/** Returns a time converted from HH:MM:SS or -1, in seconds
@param m time to convert
@param daysZeroTime -1 do not support days syntax, positive interpret days w.r.t the specified zero time.
*/
int convertAbsoluteTimeHMS(const string &m, int daysZeroTime);
+
/** Returns a time converted from HH:MM:SS or -1, in seconds
@param m time to convert
@param daysZeroTime -1 do not support days syntax, positive interpret days w.r.t the specified zero time.
@@ -123,7 +128,7 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime);
int convertAbsoluteTimeHMS(const wstring &m, int daysZeroTime);
const vector &split(const string &line, const string &separators, vector &split_vector);
-const string &unsplit(const vector &split_vector, const string &separators, string &line);
+//const string &unsplit(const vector &split_vector, const string &separators, string &line);
const vector &split(const wstring &line, const wstring &separators, vector &split_vector);
const wstring &unsplit(const vector &split_vector, const wstring &separators, wstring &line);
@@ -289,3 +294,5 @@ namespace MeOSUtil {
void string2Wide(const string &in, wstring &out);
void wide2String(const wstring &in, string &out);
+
+void checkWriteAccess(const wstring &file);
diff --git a/code/meosdb/MeosSQL.cpp b/code/meosdb/MeosSQL.cpp
index 3d4377f..dc2c51c 100644
--- a/code/meosdb/MeosSQL.cpp
+++ b/code/meosdb/MeosSQL.cpp
@@ -840,7 +840,7 @@ OpFailStatus MeosSQL::uploadRunnerDB(oEvent *oe)
return opStatusFail;
int errorCount = 0;
int totErrorCount = 0;
- ProgressWindow pw(oe->hWnd());
+ ProgressWindow pw(oe->gdiBase().getHWNDTarget());
try {
const vector &cdb = oe->runnerDB->getClubDB(true);
size_t size = cdb.size();
@@ -1000,7 +1000,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
if (!oe->Id) return SyncUpdate(oe);
- ProgressWindow pw(oe->hWnd());
+ ProgressWindow pw(oe->gdiBase().getHWNDTarget());
try {
con.select_db("MeOSMain");
diff --git a/code/meosvc15.vcxproj b/code/meosvc15.vcxproj
index 0c5e9ee..0b0fd7f 100644
--- a/code/meosvc15.vcxproj
+++ b/code/meosvc15.vcxproj
@@ -239,6 +239,7 @@
+
@@ -340,6 +341,8 @@
%(PreprocessorDefinitions)
+
+
@@ -386,6 +389,7 @@
+
@@ -417,6 +421,8 @@
+
+
@@ -479,6 +485,9 @@
+
+
+
diff --git a/code/meosversion.cpp b/code/meosversion.cpp
index 6d71fef..a91ac30 100644
--- a/code/meosversion.cpp
+++ b/code/meosversion.cpp
@@ -29,7 +29,7 @@
//V33: abcde
//V35: abc
int getMeosBuild() {
- string revision("$Rev: 611 $");
+ string revision("$Rev: 621 $");
return 174 + atoi(revision.substr(5, string::npos).c_str());
}
@@ -41,7 +41,7 @@ int getMeosBuild() {
//V33: abcdefghij
//V34: abcdfg
wstring getMeosDate() {
- wstring date(L"$Date: 2017-08-28 20:32:01 +0200 (må, 28 aug 2017) $");
+ wstring date(L"$Date: 2017-10-21 22:43:38 +0200 (lö, 21 okt 2017) $");
return date.substr(7,10);
}
@@ -176,4 +176,5 @@ void getSupporters(vector &supp)
supp.push_back("Timrå SOK");
supp.push_back("Åke Larsson, OK Hedströmmen");
supp.push_back("Avesta OK");
+ supp.push_back("Motionsorientering Göteborg");
}
diff --git a/code/metalist.cpp b/code/metalist.cpp
index 515533a..81c97a5 100644
--- a/code/metalist.cpp
+++ b/code/metalist.cpp
@@ -43,6 +43,7 @@ const int MAXLISTPARAMID = 10000000;
using namespace tr1;
oListParam::oListParam() {
+ lockUpdate = false;
listCode = EStdResultList; //Just need a default
cb = 0;
legNumber = 0;
@@ -59,6 +60,15 @@ oListParam::oListParam() {
nextList = 0; // No linked list
previousList = 0;
relayLegIndex = -1;
+ bgColor = -1;
+ fgColor = -1;
+ bgColor2 = -1;
+
+ nColumns = 0;
+ animate = true;
+ timePerPage = 8000;
+ margin = 5;
+ screenMode = 0;
}
void oListParam::serialize(xmlparser &xml,
@@ -90,6 +100,24 @@ void oListParam::serialize(xmlparser &xml,
if (res != idToIndex.end())
xml.write("NextList", res->second);
}
+ if (bgColor != -1)
+ xml.write("BGColor", itos(bgColor));
+ if (bgColor2 != -1)
+ xml.write("BGColor2", itos(bgColor2));
+
+ if (fgColor != -1)
+ xml.write("FGColor", itos(fgColor));
+ xml.write("Image", bgImage);
+
+ xml.write("ScreenMode", screenMode);
+
+ if (nColumns != 0) {
+ xml.write("NumColumns", itos(nColumns));
+ xml.writeBool("Animate", animate);
+ xml.write("TimePerPage", timePerPage);
+ xml.write("Margin", margin);
+ }
+
xml.endTag();
}
@@ -120,6 +148,32 @@ void oListParam::deserialize(const xmlobject &xml, const MetaListContainer &cont
showInterTitle = xml.getObjectBool("ShowInterTitle");
inputNumber = xml.getObjectInt("InputNumber");
nextList = xml.getObjectInt("NextList");
+
+ xmlobject bg = xml.getObject("BGColor");
+ if (bg)
+ bgColor = bg.getInt();
+
+ xmlobject bg2 = xml.getObject("BGColor2");
+ if (bg2)
+ bgColor2 = bg2.getInt();
+
+ xmlobject fg = xml.getObject("FGColor");
+ if (fg)
+ fgColor = fg.getInt();
+
+ xml.getObjectString("Image", bgImage);
+
+ int nColumns = xml.getObjectInt("NumColumns");
+
+ screenMode = xml.getObjectInt("ScreenMode");
+ animate = xml.getObjectBool("Animate");
+
+ if (xml.got("TimePerPage"))
+ timePerPage = xml.getObjectInt("TimePerPage");
+
+ if (xml.got("Margin"))
+ timePerPage = xml.getObjectInt("Margin");
+
saved = true;
}
@@ -961,7 +1015,7 @@ void MetaList::save(xmlparser &xml, const oEvent *oe) const {
// xml.write("Title", defaultTitle);
xml.write("ListName", listName);
if (listOrigin.empty())
- listOrigin = gEvent->getName() + L" (" + getLocalDateW() + L")";
+ listOrigin = gEvent->getName() + L" (" + getLocalDate() + L")";
xml.write("ListOrigin", listOrigin);
xml.write("Tag", tag);
xml.write("UID", getUniqueId());
@@ -1604,6 +1658,10 @@ void MetaList::initSymbols() {
typeToSymbol[lRunnerNationality] = L"RunnerNationality";
typeToSymbol[lRunnerPhone] = L"RunnerPhone";
typeToSymbol[lRunnerFee] = L"RunnerFee";
+ typeToSymbol[lRunnerPaid] = L"RunnerPaid";
+ typeToSymbol[lRunnerPayMethod] = L"RunnerPayMethod";
+ typeToSymbol[lRunnerEntryDate] = L"RunnerEntryDate";
+ typeToSymbol[lRunnerEntryTime] = L"RunnerEntryTime";
typeToSymbol[lTeamName] = L"TeamName";
typeToSymbol[lTeamStart] = L"TeamStart";
@@ -1719,6 +1777,7 @@ void MetaList::initSymbols() {
orderToSymbol[SortByFinishTimeReverse] = "FinishTimeReverse";
orderToSymbol[ClassFinishTime] = "ClassFinishTime";
orderToSymbol[SortByStartTime] = "StartTime";
+ orderToSymbol[SortByEntryTime] = "EntryTime";
orderToSymbol[ClassPoints] = "ClassPoints";
orderToSymbol[ClassTotalResult] = "ClassTotalResult";
orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult";
diff --git a/code/methodeditor.cpp b/code/methodeditor.cpp
index 4f1de71..bbcd13f 100644
--- a/code/methodeditor.cpp
+++ b/code/methodeditor.cpp
@@ -556,7 +556,7 @@ int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) {
wstring str;
try {
rt = currentResult->deduceTime(*rr[k], rr[k]->getStartTime());
- str = formatTimeW(rt);
+ str = formatTime(rt);
}
catch (meosException &ex) {
err = ex.wwhat();
@@ -657,7 +657,7 @@ int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) {
wstring str;
try {
rt = currentResult->deduceTime(*tr[k]);
- str = formatTimeW(rt);
+ str = formatTime(rt);
}
catch (meosException &ex) {
err = ex.wwhat();
@@ -976,7 +976,7 @@ void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {
try {
rt = currentResult->deduceTime(r, r.getStartTime());
- gdi.addStringUT(1, L"ComputedTime: " + formatTimeW(rt)).setColor(colorGreen);
+ gdi.addStringUT(1, L"ComputedTime: " + formatTime(rt)).setColor(colorGreen);
}
catch (meosException &ex) {
wstring err = lang.tl(ex.wwhat());
@@ -1030,7 +1030,7 @@ void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {
try {
rt = currentResult->deduceTime(t);
- gdi.addStringUT(1, L"ComputedTime: " + formatTimeW(rt)).setColor(colorGreen);
+ gdi.addStringUT(1, L"ComputedTime: " + formatTime(rt)).setColor(colorGreen);
}
catch (meosException &ex) {
wstring err = lang.tl(ex.wwhat());
diff --git a/code/mysqldaemon.cpp b/code/mysqldaemon.cpp
index 8d4745f..2a9c5e8 100644
--- a/code/mysqldaemon.cpp
+++ b/code/mysqldaemon.cpp
@@ -31,7 +31,7 @@
MySQLReconnect::MySQLReconnect(const wstring &errorIn) : AutoMachine("MySQL-daemon"), error(errorIn)
{
- timeError = getLocalTimeW();
+ timeError = getLocalTime();
hThread=0;
}
@@ -110,7 +110,7 @@ void MySQLReconnect::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
}
else {
gdi.addInfoBox("", L"Återansluten mot databasen, tävlingen synkroniserad.", 10000);
- timeReconnect = getLocalTimeW();
+ timeReconnect = getLocalTime();
gdi.setDBErrorState(false);
gdi.setWindowTitle(oe->getTitleName());
interval=0;
diff --git a/code/newcompetition.cpp b/code/newcompetition.cpp
index 73b78bb..801eda6 100644
--- a/code/newcompetition.cpp
+++ b/code/newcompetition.cpp
@@ -229,7 +229,7 @@ int TabCompetition::newGuideCB(gdioutput &gdi, int type, void *data)
long long stopT = absT + 23 * 3600;
SYSTEMTIME start = Int64SecondToSystemTime(absT);
SYSTEMTIME end = Int64SecondToSystemTime(stopT);
- wstring s = L"Tävlingen måste avgöras mellan X och Y.#" + convertSystemTimeW(start) + L"#" + convertSystemTimeW(end);
+ wstring s = L"Tävlingen måste avgöras mellan X och Y.#" + convertSystemTime(start) + L"#" + convertSystemTime(end);
gdi.setTextTranslate("AllowedInterval", s, true);
}
}
@@ -261,7 +261,7 @@ void TabCompetition::newCompetitionGuide(gdioutput &gdi, int step) {
gdi.pushX();
gdi.fillRight();
- InputInfo &date = gdi.addInput("Date", getLocalDateW(), 16, NewGuideCB, L"Datum (för första start):");
+ InputInfo &date = gdi.addInput("Date", getLocalDate(), 16, NewGuideCB, L"Datum (för första start):");
gdi.addInput("FirstStart", L"07:00:00", 12, NewGuideCB, L"Första tillåtna starttid:");
@@ -301,6 +301,7 @@ void TabCompetition::newCompetitionGuide(gdioutput &gdi, int step) {
}
else if (step == 2) {
rc.top = gdi.getCY();
+ oe->updateTabs(true, true);
gdi.fillDown();
gdi.dropLine();
gdi.addString("", fontMediumPlus, "Funktioner i MeOS");
@@ -391,7 +392,7 @@ void TabCompetition::createCompetition(gdioutput &gdi) {
int t = convertAbsoluteTimeHMS(start, -1);
if (t > 0 && t < 3600*24) {
t = max(0, t-3600);
- oe->setZeroTime(formatTimeHMSW(t));
+ oe->setZeroTime(formatTimeHMS(t));
}
else
throw meosException("Ogiltig tid");
diff --git a/code/oBase.h b/code/oBase.h
index 19bda4e..e86e0c8 100644
--- a/code/oBase.h
+++ b/code/oBase.h
@@ -43,7 +43,7 @@ class oDataContainer;
typedef void * pvoid;
typedef vector< vector > * pvectorstr;
-enum RunnerStatus {StatusOK=1, StatusDNS=20, StatusMP=3,
+enum RunnerStatus {StatusOK=1, StatusDNS=20, StatusCANCEL = 21, StatusMP=3,
StatusDNF=4, StatusDQ=5, StatusMAX=6,
StatusUnknown=0, StatusNotCompetiting=99};
@@ -64,6 +64,7 @@ enum SortOrder {ClassStartTime,
SortByFinishTimeReverse,
SortByStartTime,
CourseResult,
+ SortByEntryTime,
Custom,
SortEnumLastItem};
diff --git a/code/oCard.cpp b/code/oCard.cpp
index 3a2c24a..951bb29 100644
--- a/code/oCard.cpp
+++ b/code/oCard.cpp
@@ -668,7 +668,7 @@ wstring oCard::getRogainingSplit(int ix, int startTime) const
int t = it->getAdjustedTime();
if (0 == ix--) {
if (t > 0 && t > startTime)
- return formatTimeW(t - startTime);
+ return formatTime(t - startTime);
}
if (it->isUsed)
startTime = t;
diff --git a/code/oClass.cpp b/code/oClass.cpp
index c36b8de..26905da 100644
--- a/code/oClass.cpp
+++ b/code/oClass.cpp
@@ -1522,7 +1522,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
if (it->tStatus != StatusUnknown)
finished++;
- else if (it->tStatus==StatusDNS)
+ else if (it->tStatus==StatusDNS || it->tStatus == StatusCANCEL)
dns++;
}
else {
@@ -1532,7 +1532,7 @@ void oEvent::getNumClassRunners(int id, int leg, int &total, int &finished, int
total++;
if (r->tStatus!=StatusUnknown)
finished++;
- else if (it->tStatus==StatusDNS)
+ else if (it->tStatus==StatusDNS || it->tStatus == StatusCANCEL)
dns++;
}
}
@@ -2698,7 +2698,7 @@ void oClass::getStatistics(const set &feeLock, int &entries, int &started)
if (it->getClassId()==Id) {
if (feeLock.empty() || feeLock.count(it->getDCI().getInt("Fee"))) {
entries++;
- if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS)
+ if (it->getStatus()!= StatusUnknown && it->getStatus()!= StatusDNS && it->tStatus != StatusCANCEL)
started++;
}
}
@@ -4145,3 +4145,11 @@ int oClass::getPreceedingLeg(int leg) const {
}
return -1;
}
+
+bool oClass::lockedForking() const {
+ return getDCI().getInt("Locked") != 0;
+}
+
+void oClass::lockedForking(bool locked) {
+ getDI().setInt("Locked", locked);
+}
diff --git a/code/oClass.h b/code/oClass.h
index a842221..4c176e9 100644
--- a/code/oClass.h
+++ b/code/oClass.h
@@ -262,6 +262,10 @@ public:
static void initClassId(oEvent &oe);
+ // Return true if forking in the class is locked
+ bool lockedForking() const;
+ void lockedForking(bool locked);
+
// Draw data
int getDrawFirstStart() const;
void setDrawFirstStart(int st);
diff --git a/code/oControl.cpp b/code/oControl.cpp
index 1a2c585..0562e82 100644
--- a/code/oControl.cpp
+++ b/code/oControl.cpp
@@ -488,13 +488,13 @@ int oControl::getTimeAdjust() const
wstring oControl::getTimeAdjustS() const
{
- return getTimeMSW(getTimeAdjust());
+ return getTimeMS(getTimeAdjust());
}
wstring oControl::getMinTimeS() const
{
if (getMinTime()>0)
- return getTimeMSW(getMinTime());
+ return getTimeMS(getMinTime());
else
return makeDash(L"-");
}
@@ -706,8 +706,8 @@ void oEvent::setupControlStatistics() const {
}
}
- if (!it->isVacant() && it->getStatus() != StatusDNS
- && it->getStatus() != StatusNotCompetiting) {
+ if (!it->isVacant() && it->getStatus() != StatusDNS && it->getStatus() != StatusCANCEL
+ && it->getStatus() != StatusNotCompetiting) {
for (int i = 0; i < nc; i++) {
pControl ctrl = pc->getControl(i);
@@ -855,9 +855,9 @@ void oControl::addTableRow(Table &table) const {
int nv = getNumVisitors(true);
table.set(row++, it, 50, itow(nv), false);
- table.set(row++, it, 51, nv > 0 ? formatTimeW(getMissedTimeMax()) : L"-", false);
- table.set(row++, it, 52, nv > 0 ? formatTimeW(getMissedTimeTotal()/nv) : L"-", false);
- table.set(row++, it, 53, nv > 0 ? formatTimeW(getMissedTimeMedian()) : L"-", false);
+ table.set(row++, it, 51, nv > 0 ? formatTime(getMissedTimeMax()) : L"-", false);
+ table.set(row++, it, 52, nv > 0 ? formatTime(getMissedTimeTotal()/nv) : L"-", false);
+ table.set(row++, it, 53, nv > 0 ? formatTime(getMissedTimeMedian()) : L"-", false);
oe->oControlData->fillTableCol(it, table, true);
}
diff --git a/code/oCourse.cpp b/code/oCourse.cpp
index ed940e5..b2e8251 100644
--- a/code/oCourse.cpp
+++ b/code/oCourse.cpp
@@ -693,7 +693,7 @@ void oEvent::calculateNumRemainingMaps()
for (oRunnerList::const_iterator it=Runners.begin(); it != Runners.end(); ++it) {
- if (!it->isRemoved() && it->getStatus() != StatusDNS) {
+ if (!it->isRemoved() && it->getStatus() != StatusDNS && it->getStatus() != StatusCANCEL) {
pCourse pc = it->getCourse(false);
if (pc) {
if (pc->tMapsRemaining != numeric_limits::min())
diff --git a/code/oDataContainer.cpp b/code/oDataContainer.cpp
index 4f3b6d8..ef0526b 100644
--- a/code/oDataContainer.cpp
+++ b/code/oDataContainer.cpp
@@ -322,6 +322,20 @@ bool oDataContainer::setString(oBase *ob, const char *name, const wstring &v)
}
+const wstring &oDataContainer::formatString(const oBase *ob, const char *Name) const {
+ const oDataInfo *odi = findVariable(Name);
+ if (odi->dataDefiner) {
+ return odi->dataDefiner->formatData(ob);
+ }
+ else if (odi->Type == oDTString) {
+ return getString(ob, Name);
+ }
+ else if (odi->Type == oDTInt) {
+ return itow(getInt(ob, Name));
+ }
+ throw std::exception("oDataContainer: Formatting failed.");
+}
+
const wstring &oDataContainer::getString(const oBase *ob, const char *Name) const {
const oDataInfo *odi=findVariable(Name);
@@ -982,6 +996,7 @@ void oDataContainer::buildTableCol(Table *table)
oDataInfo &di=ordered[kk];
if (di.dataDefiner) {
+ table->addDataDefiner(di.Name, di.dataDefiner);
int w = strlen(di.Description)*6;
di.tableIndex = di.dataDefiner->addTableColumn(table, di.Description, w);
}
diff --git a/code/oDataContainer.h b/code/oDataContainer.h
index 304845d..b61a420 100644
--- a/code/oDataContainer.h
+++ b/code/oDataContainer.h
@@ -34,10 +34,11 @@ class Table;
class oDataDefiner {
public:
virtual ~oDataDefiner() {}
- virtual const wstring &formatData(oBase *obj) const = 0;
+ virtual const wstring &formatData(const oBase *obj) const = 0;
virtual wstring setData(oBase *obj, const wstring &input) const = 0;
/** Used to define/add the table column in the table*/
virtual int addTableColumn(Table *table, const string &description, int minWidth) const = 0;
+ virtual void prepare(oEvent *oe) const {}
};
struct oDataInfo {
@@ -160,6 +161,7 @@ public:
bool setString(oBase *ob, const char *name, const wstring &v);
const wstring &getString(const oBase *ob, const char *name) const;
+ const wstring &formatString(const oBase *ob, const char *name) const;
bool setDate(void *data, const char *Name, const wstring &V);
const wstring &getDate(const void *data, const char *Name) const;
@@ -236,9 +238,13 @@ public:
else return false;
}
- inline wstring getString(const char *Name) const
+ inline const wstring &getString(const char *Name) const
{return oDC->getString(oB, Name);}
+ inline const wstring &formatString(const oBase *oB, const char *name) const {
+ return oDC->formatString(oB, name);
+ }
+
inline bool setDate(const char *Name, const wstring &Value)
{
if (oDC->setDate(Data, Name, Value)){
@@ -327,6 +333,10 @@ public:
inline const wstring &getString(const char *Name) const
{return oDC->getString(oB, Name);}
+ inline const wstring &formatString(const oBase *oB, const char *name) const {
+ return oDC->formatString(oB, name);
+ }
+
inline const wstring &getDate(const char *Name) const
{return oDC->getDate(Data, Name);}
diff --git a/code/oEvent.cpp b/code/oEvent.cpp
index 0dd3d95..b698897 100644
--- a/code/oEvent.cpp
+++ b/code/oEvent.cpp
@@ -71,7 +71,7 @@ class RelativeTimeFormatter : public oDataDefiner {
public:
RelativeTimeFormatter(const char *n) : name(n) {}
- const wstring &formatData(oBase *obj) const {
+ const wstring &formatData(const oBase *obj) const {
int t = obj->getDCI().getInt(name);
if (t <= 0)
return makeDash(L"-");
@@ -92,9 +92,9 @@ class AbsoluteTimeFormatter : public oDataDefiner {
public:
AbsoluteTimeFormatter(const char *n) : name(n) {}
- const wstring &formatData(oBase *obj) const {
+ const wstring &formatData(const oBase *obj) const {
int t = obj->getDCI().getInt(name);
- return formatTimeW(t);
+ return formatTime(t);
}
wstring setData(oBase *obj, const wstring &input) const {
int t = convertAbsoluteTimeMS(input);
@@ -108,6 +108,49 @@ class AbsoluteTimeFormatter : public oDataDefiner {
}
};
+class PayMethodFormatter : public oDataDefiner {
+ mutable vector< pair > modes;
+ mutable map setCodes;
+ mutable long rev;
+public:
+ PayMethodFormatter() : rev(-1) {}
+
+ void prepare(oEvent *oe) const override {
+ oe->getPayModes(modes);
+ for (size_t i = 0; i < modes.size(); i++) {
+ setCodes[canonizeName(modes[i].first.c_str())] = modes[i].second;
+ }
+ }
+
+ const wstring &formatData(const oBase *ob) const {
+ if (ob->getEvent()->getRevision() != rev)
+ prepare(ob->getEvent());
+ int p = ob->getDCI().getInt("Paid");
+ if (p == 0)
+ return lang.tl("Faktura");
+ else {
+ int pm = ob->getDCI().getInt("PayMode");
+ for (size_t i = 0; i < modes.size(); i++) {
+ if (modes[i].second == pm)
+ return modes[i].first;
+ }
+ return _EmptyWString;
+ }
+ }
+
+ wstring setData(oBase *ob, const wstring &input) const {
+ auto res = setCodes.find(canonizeName(input.c_str()));
+ if (res != setCodes.end()) {
+ ob->getDI().setInt("PayMode", res->second);
+ }
+ return formatData(ob);
+ }
+
+ int addTableColumn(Table *table, const string &description, int minWidth) const {
+ return table->addColumn(description, max(minWidth, 90), true, true);
+ }
+};
+
oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
{
readOnly = false;
@@ -275,11 +318,13 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
oClubData->addVariableEnum("Invoice", 1, "Faktura", eInvoice);
oClubData->addVariableInt("InvoiceNo", oDataContainer::oIS16U, "Fakturanummer");
+ static PayMethodFormatter paymentMethod;
+
oRunnerData=new oDataContainer(oRunner::dataSize);
oRunnerData->addVariableCurrency("Fee", "Anm. avgift");
oRunnerData->addVariableCurrency("CardFee", "Brickhyra");
oRunnerData->addVariableCurrency("Paid", "Betalat");
- oRunnerData->addVariableInt("PayMode", oDataContainer::oIS8U, "Betalsätt");
+ oRunnerData->addVariableInt("PayMode", oDataContainer::oIS8U, "Betalsätt", &paymentMethod);
oRunnerData->addVariableCurrency("Taxable", "Skattad avgift");
oRunnerData->addVariableInt("BirthYear", oDataContainer::oIS32, "Födelseår");
oRunnerData->addVariableString("Bib", 8, "Nummerlapp").zeroSortPadding = 5;
@@ -287,6 +332,8 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
//oRunnerData->addVariableInt("VacRank", oDataContainer::oIS16U, "Vak. ranking");
oRunnerData->addVariableDate("EntryDate", "Anm. datum");
+ static AbsoluteTimeFormatter atf("EntryTime");
+ oRunnerData->addVariableInt("EntryTime", oDataContainer::oIS32, "Anm. tid", &atf);
vector< pair > sex;
sex.push_back(make_pair(L"M", L"Man"));
@@ -393,6 +440,7 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
oClassData->addVariableEnum("BibMode", 1, "Nummerlappshantering", bibMode);
oClassData->addVariableInt("Unordered", oDataContainer::oIS8U, "Oordnade parallella");
oClassData->addVariableInt("Heat", oDataContainer::oIS8U, "Heat");
+ oClassData->addVariableInt("Locked", oDataContainer::oIS8U, "Låst gaffling");
oTeamData = new oDataContainer(oTeam::dataSize);
oTeamData->addVariableCurrency("Fee", "Anm. avgift");
@@ -400,6 +448,7 @@ oEvent::oEvent(gdioutput &gdi):oBase(0), gdibase(gdi)
oTeamData->addVariableInt("PayMode", oDataContainer::oIS8U, "Betalsätt");
oTeamData->addVariableCurrency("Taxable", "Skattad avgift");
oTeamData->addVariableDate("EntryDate", "Anm. datum");
+ oTeamData->addVariableInt("EntryTime", oDataContainer::oIS32, "Anm. tid", &atf);
oTeamData->addVariableString("Nationality", 3, "Nationalitet");
oTeamData->addVariableString("Country", 23, "Land");
oTeamData->addVariableString("Bib", 8, "Nummerlapp").zeroSortPadding = 5;
@@ -863,7 +912,7 @@ bool oEvent::save(const wstring &fileIn) {
const wchar_t *file = fileIn.c_str();
xmlparser xml;
- ProgressWindow pw(gdibase.getHWND());
+ ProgressWindow pw(gdibase.getHWNDTarget());
if (Runners.size()>200)
pw.init();
@@ -1019,7 +1068,7 @@ bool oEvent::open(const wstring &file, bool Import)
openFileLock->lockFile(file);
xmlparser xml;
- xml.setProgress(gdibase.getHWND());
+ xml.setProgress(gdibase.getHWNDTarget());
tic();
string log;
xml.read(file);
@@ -1596,8 +1645,10 @@ pRunner oEvent::addRunner(const wstring &name, int clubId, int classId,
r.setBirthYear(birthYear);
pRunner pr = addRunner(r, true);
- if (pr->getDI().getInt("EntryDate") == 0)
- pr->getDI().setDate("EntryDate", getLocalDateW());
+ if (pr->getDI().getInt("EntryDate") == 0 && !pr->isVacant()) {
+ pr->getDI().setDate("EntryDate", getLocalDate());
+ pr->getDI().setInt("EntryTime", getLocalAbsTime());
+ }
if (pr->Class) {
int heat = pr->Class->getDCI().getInt("Heat");
if (heat != 0)
@@ -1640,9 +1691,10 @@ pRunner oEvent::addRunnerFromDB(const pRunner db_r,
memcpy(r.oData, db_r->oData, sizeof(r.oData));
pRunner pr = addRunner(r, true);
- if (pr->getDI().getInt("EntryDate") == 0)
- pr->getDI().setDate("EntryDate", getLocalDateW());
-
+ if (pr->getDI().getInt("EntryDate") == 0 && !pr->isVacant()) {
+ pr->getDI().setDate("EntryDate", getLocalDate());
+ pr->getDI().setInt("EntryTime", getLocalAbsTime());
+ }
if (r.Class) {
int heat = r.Class->getDCI().getInt("Heat");
if (heat != 0)
@@ -2105,7 +2157,7 @@ void oEvent::setDate(const wstring &m)
int d = convertDateYMS(m, true);
if (d <= 0)
throw meosException(L"Felaktigt datumformat 'X' (Använd ÅÅÅÅ-MM-DD).#" + m);
- Date = formatDateW(d, true);
+ Date = formatDate(d, true);
updateChanged();
}
}
@@ -2116,10 +2168,10 @@ const wstring &oEvent::getAbsTime(DWORD time) const {
t = 0;
int days = time/(3600*24);
if (days <= 0)
- return formatTimeHMSW(t % (24*3600));
+ return formatTimeHMS(t % (24*3600));
else {
wstring &res = StringCache::getInstance().wget();
- res = itow(days) + L"D " + formatTimeHMSW(t % (24*3600));
+ res = itow(days) + L"D " + formatTimeHMS(t % (24*3600));
return res;
}
}
@@ -2175,7 +2227,7 @@ wstring oEvent::getAbsDateTimeISO(DWORD time, bool includeDate, bool useGMT) con
__int64 sec = SystemTimeToInt64Second(st);
sec = sec + (extraDay * 3600 * 24);
st = Int64SecondToSystemTime(sec);
- dateS = convertSystemDateW(st);
+ dateS = convertSystemDate(st);
}
}
@@ -2986,7 +3038,7 @@ void oEvent::generateMinuteStartlist(gdioutput &gdi) {
continue;
if (!it->Class && blocks[k]!=0)
continue;
- if (it->getStatus() == StatusNotCompetiting)
+ if (it->getStatus() == StatusNotCompetiting || it->getStatus() == StatusCANCEL)
continue;
if (LastStartTime!=it->tStartTime) {
@@ -3141,7 +3193,7 @@ bool oEvent::enumerateCompetitions(const wchar_t *file, const wchar_t *filetype)
SYSTEMTIME st;
FileTimeToSystemTime(&fd.ftLastWriteTime, &st);
- ci.Modified=convertSystemTime(st);
+ ci.Modified=convertSystemTimeN(st);
xmlparser xp;
try {
@@ -3345,7 +3397,7 @@ bool oEvent::enumerateBackups(const wstring &file, const wstring &filetype, int
FileTimeToLocalFileTime(&fd.ftLastWriteTime, &localTime);
FileTimeToSystemTime(&localTime, &st);
- ci.Modified=convertSystemTime(st);
+ ci.Modified=convertSystemTimeN(st);
xmlparser xp;
try {
@@ -3500,6 +3552,7 @@ void oEvent::clear()
punchIndex.clear();
punches.clear();
+ cachedFirstStart.clear();
updateFreeId();
@@ -3571,7 +3624,7 @@ void oEvent::newCompetition(const wstring &name)
SYSTEMTIME st;
GetLocalTime(&st);
- Date = convertSystemDateW(st);
+ Date = convertSystemDate(st);
ZeroTime = st.wHour*3600;
Name = name;
@@ -4035,23 +4088,28 @@ void oEvent::convertTimes(SICard &sic) const
}
}
-int oEvent::getFirstStart(int ClassId)
-{
- oRunnerList::iterator it=Runners.begin();
- int MinTime=3600*24;
+int oEvent::getFirstStart(int classId) const {
+ auto &cf = cachedFirstStart[classId];
+ if (dataRevision == cf.first)
+ return cf.second;
+
+ oRunnerList::const_iterator it=Runners.begin();
+ int minTime=3600*24;
while(it!=Runners.end()){
- if (ClassId==0 || it->getClassId()==ClassId)
- if (it->tStartTimetStatus==StatusOK && it->tStartTime!=0)
- MinTime=it->tStartTime;
-
+ if (!it->isRemoved() && classId==0 || it->getClassId()==classId)
+ if (it->tStartTime < minTime && it->tStatus!=StatusNotCompetiting && it->tStartTime>0)
+ minTime = it->tStartTime;
++it;
}
- if (MinTime==3600*24)
- MinTime=0;
+ if (minTime==3600*24)
+ minTime=0;
- return MinTime;
+ cf.first = dataRevision;
+ cf.second = minTime;
+
+ return minTime;
}
bool oEvent::hasRank() const
@@ -4077,7 +4135,7 @@ int oEvent::getMaximalTime() const
wstring oEvent::getMaximalTimeS() const
{
- return formatTimeW(getMaximalTime());
+ return formatTime(getMaximalTime());
}
@@ -4141,19 +4199,24 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
oTeamList::iterator it;
for (it=Teams.begin(); it != Teams.end(); ++it)
it->apply(false, 0, false);
-
+ map teamStartNo;
+
if (!firstNumber.empty()) {
// Clear out start number temporarily, to not use it for sorting
for (it=Teams.begin(); it != Teams.end(); ++it) {
+ if (it->isRemoved())
+ continue;
if (ClassId==0 || it->getClassId()==ClassId) {
if (it->getClassRef() && it->getClassRef()->getBibMode() != BibFree) {
for (size_t i = 0; i < it->Runners.size(); i++) {
if (it->Runners[i]) {
+ //runnerStartNo[it->Runners[i]->getId()] = it->Runners[i]->getStartNo();
it->Runners[i]->setStartNo(0, false);
it->Runners[i]->setBib(L"", 0, false, false);
}
}
}
+ teamStartNo[it->getId()] = it->getStartNo();
it->setStartNo(0, false);
}
}
@@ -4166,10 +4229,20 @@ void oEvent::addBib(int ClassId, int leg, const wstring &firstNumber) {
int num = oClass::extractBibPattern(firstNumber, pattern);
for (it=Teams.begin(); it != Teams.end(); ++it) {
- if (ClassId==0 || it->getClassId()==ClassId) {
+ if (it->isRemoved())
+ continue;
+
+ if (ClassId == 0 || it->getClassId() == ClassId) {
wchar_t bib[32];
swprintf_s(bib, pattern, num);
- it->setBib(bib, num, true, false);
+ bool lockedStartNo = it->Class && it->Class->lockedForking();
+ if (lockedStartNo) {
+ it->setBib(bib, num, false, false);
+ it->setStartNo(teamStartNo[it->getId()], false);
+ }
+ else {
+ it->setBib(bib, num, true, false);
+ }
num++;
it->apply(true, 0, false);
}
@@ -4205,6 +4278,7 @@ void oEvent::addAutoBib() {
tit->apply(false, 0, false);
}
+ map teamStartNo;
// Clear out start number temporarily, to not use it for sorting
for (oTeamList::iterator tit = Teams.begin(); tit != Teams.end(); ++tit) {
if (tit->skip())
@@ -4212,6 +4286,8 @@ void oEvent::addAutoBib() {
pClass cls = tit->getClassRef();
if (cls == 0)
continue;
+ teamStartNo[tit->getId()] = tit->getStartNo();
+
wstring bibInfo = cls->getDCI().getString("Bib");
bool teamAssign = !bibInfo.empty();
@@ -4313,10 +4389,18 @@ void oEvent::addAutoBib() {
}
}
else {
+ bool lockedForking = cls->lockedForking();
for (size_t k = 0; k < tl.size(); k++) {
wchar_t buff[32];
swprintf_s(buff, pattern, number);
- tl[k]->setBib(buff, number, true, false);
+
+ if (lockedForking) {
+ tl[k]->setBib(buff, number, false, false);
+ tl[k]->setStartNo(teamStartNo[tl[k]->getId()], false);
+ }
+ else {
+ tl[k]->setBib(buff, number, true, false);
+ }
number += interval;
tl[k]->apply(true, 0, false);
}
@@ -4382,6 +4466,7 @@ const vector< pair > &oEvent::fillStatus(vector< pairskip() || it->getCardNo() || it->isVacant() || it->needNoCard())
continue;
- if (it->getStatus() == StatusDNS || it->getStatus() == StatusNotCompetiting)
+ if (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL || it->getStatus() == StatusNotCompetiting)
continue;
if (it->Club!=lastClub) {
@@ -4610,12 +4695,15 @@ void oEvent::calcUseStartSeconds()
const wstring &oEvent::formatStatus(RunnerStatus status)
{
- const static wstring stats[8]={L"?", L"Godkänd", L"Ej start", L"Felst.", L"Utg.", L"Disk.", L"Maxtid", L"Deltar ej"};
+ const static wstring stats[9]={L"?", L"Godkänd", L"Ej start", L"Felst.", L"Utg.", L"Disk.",
+ L"Maxtid", L"Deltar ej", L"Återbud[status]"};
switch(status) {
case StatusOK:
return lang.tl(stats[1]);
case StatusDNS:
return lang.tl(stats[2]);
+ case StatusCANCEL:
+ return lang.tl(stats[8]);
case StatusMP:
return lang.tl(stats[3]);
case StatusDNF:
@@ -5501,11 +5589,6 @@ void oEvent::sanityCheck(gdioutput &gdi, bool expectResult, int onlyThisClass) {
}
}
-HWND oEvent::hWnd() const
-{
- return gdibase.getHWND();
-}
-
oTimeLine::~oTimeLine() {
}
@@ -5640,7 +5723,7 @@ wstring oEvent::cloneCompetition(bool cloneRunners, bool cloneTimes,
convertDateYMS(Date, st, false);
__int64 absD = SystemTimeToInt64Second(st);
absD += 3600*24;
- ce.Date = convertSystemDateW(Int64SecondToSystemTime(absD));
+ ce.Date = convertSystemDate(Int64SecondToSystemTime(absD));
}
int len = Name.length();
if (len > 2 && isdigit(Name[len-1]) && !isdigit(Name[len-2])) {
@@ -6361,7 +6444,7 @@ bool oEvent::hasNextStage() const {
}
bool oEvent::hasPrevStage() const {
- return !getDCI().getString("PreEvent").empty();
+ return !getDCI().getString("PreEvent").empty() || getStageNumber() > 1;
}
int oEvent::getNumStages() const {
@@ -6396,7 +6479,7 @@ void oEvent::changedObject() {
}
void oEvent::pushDirectChange() {
- PostMessage(gdibase.getMain(), WM_USER + 4, 0, 0);
+ PostMessage(gdibase.getHWNDMain(), WM_USER + 4, 0, 0);
}
int oEvent::getBibClassGap() const {
@@ -6555,4 +6638,121 @@ void oEvent::useDefaultProperties(bool useDefault) {
savedProperties.clear();
}
}
-}
\ No newline at end of file
+}
+
+static void checkValid(oEvent &oe, int &time, int delta, const wstring &name) {
+ int srcTime = time;
+ time += delta;
+ if (time <= 0)
+ time += 24 * 3600;
+ if (time > 24 * 3600)
+ time -= 24 * 3600;
+ if (time < 0 || time > 22 * 3600) {
+ throw meosException(L"X har en tid (Y) som inte är kompatibel med förändringen.#" + name + L"#" + oe.getAbsTime(srcTime));
+ }
+}
+
+
+void oEvent::updateStartTimes(int delta) {
+ for (int pass = 0; pass <= 1; pass++) {
+ for (oClass &c : Classes) {
+ if (c.isRemoved())
+ continue;
+ for (unsigned i = 0; i < c.getNumStages(); i++) {
+ int st = c.getStartData(i);
+ if (st > 0) {
+ checkValid(*oe, st, delta, c.getName());
+ if (pass == 1) {
+ c.setStartData(i, st);
+ c.synchronize(true);
+ }
+ }
+ }
+ }
+
+ if (pass == 1)
+ reEvaluateAll(set(), false);
+
+ for (oRunner &r : Runners) {
+ if (r.isRemoved())
+ continue;
+ if (r.Class && r.Class->getStartType(r.getLegNumber()) == STDrawn) {
+ int st = r.getStartTime();
+ if (st > 0) {
+ checkValid(*oe, st, delta, r.getName());
+ if (pass == 1) {
+ r.setStartTime(st, true, false, false);
+ r.synchronize(true);
+ }
+ }
+ }
+ int ft = r.getFinishTime();
+ if (ft > 0) {
+ checkValid(*oe, ft, delta, r.getName());
+ if (pass == 1) {
+ r.setFinishTime(ft);
+ r.synchronize(true);
+ }
+ }
+ }
+
+ for (oCard &c : Cards) {
+ if (c.isRemoved())
+ continue;
+ wstring desc = L"Bricka X#" + c.getCardNoString();
+ for (oPunch &p : c.punches) {
+ int t = p.Time;
+ if (t > 0) {
+ if (c.getOwner() != 0)
+ checkValid(*oe, t, delta, desc);
+ else {
+ // Skip check
+ t += delta;
+ if (t <= 0)
+ t += 24 * 3600;
+ }
+
+ if (pass == 1) {
+ p.setTimeInt(t, false);
+ }
+ }
+ }
+ }
+
+ for (oTeam &t : Teams) {
+ if (t.isRemoved())
+ continue;
+ if (t.Class && t.Class->getStartType(0) == STDrawn) {
+ int st = t.getStartTime();
+ if (st > 0) {
+ checkValid(*oe, st, delta, t.getName());
+ if (pass == 1) {
+ t.setStartTime(st, true, false, false);
+ t.synchronize(true);
+ }
+ }
+ }
+ int ft = t.getFinishTime();
+ if (ft > 0) {
+ checkValid(*oe, ft, delta, t.getName());
+ if (pass == 1) {
+ t.setFinishTime(ft);
+ t.synchronize(true);
+ }
+ }
+ }
+
+ for (oFreePunch &p : punches) {
+ int t = p.Time;
+ if (t > 0) {
+ if (pass == 1) {
+ t += delta;
+ if (t <= 0)
+ t += 24 * 3600;
+
+ p.setTimeInt(t, false); // Skip check
+ }
+ }
+ }
+ }
+}
diff --git a/code/oEvent.h b/code/oEvent.h
index fc346ad..98a0ac2 100644
--- a/code/oEvent.h
+++ b/code/oEvent.h
@@ -560,9 +560,6 @@ public:
void saveProperties(const wchar_t *file);
void loadProperties(const wchar_t *file);
- // Get window handle
- HWND hWnd() const;
-
/** Get number of classes*/
int getNumClasses() const {return Classes.size();}
@@ -799,10 +796,11 @@ protected:
int tClubDataRevision;
bool readOnly;
mutable int tLongTimesCached;
-
+ mutable map > cachedFirstStart; //First start per classid.
map, oFreePunch> advanceInformationPunches;
public:
+ void updateStartTimes(int delta);
void useDefaultProperties(bool useDefault);
@@ -864,7 +862,8 @@ public:
void updateRunnerDatabase();
void updateRunnerDatabase(pRunner r, map &clubIdMap);
- int getFirstStart(int ClassId=0);
+ /** Returns the first start in a class */
+ int getFirstStart(int classId = 0) const;
void convertTimes(SICard &sic) const;
pCard getCard(int Id) const;
@@ -1273,7 +1272,7 @@ public:
bool checkCardUsed(gdioutput &gdi, oRunner &runnerToAssignCard, int CardNo);
void analyseDNS(vector &unknown_dns, vector &known_dns,
- vector &known, vector &unknown);
+ vector &known, vector &unknown, bool &hasSetDNS);
void importOECSV_Data(const wstring &oecsvfile, bool clear);
void importXML_IOF_Data(const wstring &clubfile, const wstring &competitorfile, bool clear);
diff --git a/code/oEventSpeaker.cpp b/code/oEventSpeaker.cpp
index e3b1e3e..a530560 100644
--- a/code/oEventSpeaker.cpp
+++ b/code/oEventSpeaker.cpp
@@ -349,10 +349,10 @@ void renderRowSpeakerList(const oSpeakerObject &r, const oSpeakerObject *next_r,
row.push_back(SpeakerString(normalText, r.club));
if (r.status == StatusOK) {
- row.push_back(SpeakerString(textRight, formatTimeW(r.runningTime.preliminary)));
+ row.push_back(SpeakerString(textRight, formatTime(r.runningTime.preliminary)));
if (r.runningTime.time != r.runningTimeLeg.time)
- row.push_back(SpeakerString(textRight, formatTimeW(r.runningTimeLeg.time)));
+ row.push_back(SpeakerString(textRight, formatTime(r.runningTimeLeg.time)));
else
row.push_back(SpeakerString());
@@ -1053,7 +1053,7 @@ int oEvent::setupTimeLineEvents(int classId, int currentTime)
continue;
if (!r.Class ||r.Class->Id != classId)
continue;
- if (r.tStatus == StatusDNS || r.tStatus == StatusNotCompetiting)
+ if (r.tStatus == StatusDNS || r.tStatus == StatusCANCEL || r.tStatus == StatusNotCompetiting)
continue;
// if (r.CardNo == 0)
// continue;
@@ -1377,7 +1377,7 @@ int oEvent::setupTimeLineEvents(vector &started, const vector< pair 0);
r.tTimeAfter = timeAfter;
@@ -1461,7 +1461,7 @@ int oEvent::setupTimeLineEvents(vector &started, const vector< pair 0);
diff --git a/code/oImportExport.cpp b/code/oImportExport.cpp
index 9f5afb3..a72cc88 100644
--- a/code/oImportExport.cpp
+++ b/code/oImportExport.cpp
@@ -73,6 +73,8 @@ int ConvertStatusToOE(int i)
case StatusOK:
return 0;
case StatusDNS: // Ej start
+ case StatusCANCEL:
+ case StatusNotCompetiting:
return 1;
case StatusDNF: // Utg.
return 2;
@@ -206,7 +208,7 @@ bool oEvent::exportOECSV(const wchar_t *file, int languageTypeIndex, bool includ
// Excel format HH:MM:SS
if (it->getRunningTime() > 0)
- row[OEtime] = formatTimeHMS(it->getRunningTime());
+ row[OEtime] = gdibase.recodeToNarrow(formatTimeHMS(it->getRunningTime()));
row[OEstatus] = conv_is(ConvertStatusToOE(it->getStatus()));
row[OEclubno] = conv_is(it->getClubId());
@@ -259,7 +261,7 @@ bool oEvent::exportOECSV(const wchar_t *file, int languageTypeIndex, bool includ
continue;
row.push_back(gdibase.recodeToNarrow(pc->getControl(k)->getIdS()));
if (unsigned(k) < sp.size() && sp[k].time > 0)
- row.push_back(formatTimeHMS(sp[k].time - it->tStartTime));
+ row.push_back(gdibase.recodeToNarrow(formatTimeHMS(sp[k].time - it->tStartTime)));
else
row.push_back("-----");
}
@@ -276,7 +278,7 @@ bool oEvent::exportOECSV(const wchar_t *file, int languageTypeIndex, bool includ
int t = punch->getAdjustedTime();
if (it->tStartTime > 0 && t > 0 && t > it->tStartTime)
- row.push_back(formatTimeHMS(t - it->tStartTime));
+ row.push_back(gdibase.recodeToNarrow(formatTimeHMS(t - it->tStartTime)));
else
return "-----";
}
@@ -1178,7 +1180,7 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
{
if (!clubfile.empty()) {
xmlparser xml_club;
- xml_club.setProgress(gdibase.getHWND());
+ xml_club.setProgress(gdibase.getHWNDTarget());
if (clear)
runnerDB->clearClubs();
@@ -1218,7 +1220,7 @@ void oEvent::importXML_IOF_Data(const wstring &clubfile,
if (!competitorfile.empty()) {
xmlparser xml_cmp;
- xml_cmp.setProgress(gdibase.getHWND());
+ xml_cmp.setProgress(gdibase.getHWNDTarget());
gdibase.dropLine();
gdibase.addString("",0,"Läser löpare...");
gdibase.refresh();
@@ -2270,7 +2272,8 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set
if (pc) xml.write("CourseLength", "unit", L"m", pc->getLengthS());
pCourse pcourse=pc;
- if (pcourse && it->getLegStatus(-1, false)>0 && it->getLegStatus(-1, false)!=StatusDNS) {
+ auto legStatus = it->getLegStatus(-1, false);
+ if (pcourse && legStatus>0 && legStatus!=StatusDNS && legStatus!=StatusCANCEL) {
int no = 1;
bool hasRogaining = pcourse->hasRogaining();
int startIx = pcourse->useFirstAsStart() ? 1 : 0;
@@ -2375,7 +2378,7 @@ void oEvent::exportIOFResults(xmlparser &xml, bool selfContained, const set
pCourse pcourse=it->getCourse(true);
if (pcourse && it->getStatus()>0 && it->getStatus()!=StatusDNS
- && it->getStatus()!=StatusNotCompetiting) {
+ && it->getStatus()!=StatusNotCompetiting && it->getStatus() != StatusCANCEL) {
bool hasRogaining = pcourse->hasRogaining();
int no = 1;
int startIx = pcourse->useFirstAsStart() ? 1 : 0;
@@ -2527,7 +2530,7 @@ void oEvent::exportTeamSplits(xmlparser &xml, const set &classes, bool oldS
}
pCourse pcourse=pc;
if (pcourse && r->getStatus()>0 && r->getStatus()!=StatusDNS
- && r->getStatus()!=StatusNotCompetiting) {
+ && r->getStatus()!=StatusNotCompetiting && r->getStatus() != StatusCANCEL) {
int no = 1;
bool hasRogaining = pcourse->hasRogaining();
int startIx = pcourse->useFirstAsStart() ? 1 : 0;
diff --git a/code/oListInfo.cpp b/code/oListInfo.cpp
index e36a875..2b437b3 100644
--- a/code/oListInfo.cpp
+++ b/code/oListInfo.cpp
@@ -232,7 +232,7 @@ public:
int w = 0;
TextInfo ti;
- HDC hDC = GetDC(gdi.getHWND());
+ HDC hDC = GetDC(gdi.getHWNDTarget());
for (multimap::iterator it = words.begin(); it != words.end(); ++it) {
ti.xp = 0;
@@ -247,7 +247,7 @@ public:
}
}
- ReleaseDC(gdi.getHWND(), hDC);
+ ReleaseDC(gdi.getHWNDTarget(), hDC);
return w;
}
@@ -687,12 +687,12 @@ const wstring &oEvent::formatSpecialStringAux(const oPrintPost &pp, const oListP
case lControlMedianLostTime:
if (ctrl)
- wsptr = &formatTimeW(ctrl->getMissedTimeMedian());
+ wsptr = &formatTime(ctrl->getMissedTimeMedian());
break;
case lControlMaxLostTime:
if (ctrl)
- wsptr = &formatTimeW(ctrl->getMissedTimeMax());
+ wsptr = &formatTime(ctrl->getMissedTimeMax());
break;
case lControlMistakeQuotient:
@@ -896,12 +896,15 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
break; // Common start time, skip
}
}
- if (r->startTimeAvailable()) {
+ if (r->getStatus() == StatusCANCEL) {
+ wsptr = &oEvent::formatStatus(StatusCANCEL);
+ }
+ else if (r->startTimeAvailable()) {
if (pp.type != lRunnerStartZero)
wsptr = &r->getStartTimeCompact();
else {
int st = r->getStartTime();
- wsptr = &getTimeMSW(st-3600);
+ wsptr = &getTimeMS(st-oe->getFirstStart());
}
}
else
@@ -1021,7 +1024,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
RunnerStatus ts = r->getTotalStatus();
int rt = r->getTotalRunningTime();
if (ts == StatusOK || (ts == StatusUnknown && rt > 0)) {
- wstring vts = formatTimeW(rt) + L" (" + timeStatus + L")";
+ wstring vts = formatTime(rt) + L" (" + timeStatus + L")";
swap(vts, timeStatus);
}
else {
@@ -1105,7 +1108,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
int len = pc->getLength();
if (len > 0 && t > 0) {
int sperkm = (1000 * t) / len;
- wsptr = &formatTimeW(sperkm);
+ wsptr = &formatTime(sperkm);
}
}
}
@@ -1154,7 +1157,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
wsptr = &lang.tl("Struken");
else if (r) {
if (r->tempStatus==StatusOK && pc && !pc->getNoTiming())
- wcscpy_s(wbf, formatTimeW(r->tempRT).c_str());
+ wcscpy_s(wbf, formatTime(r->tempRT).c_str());
else
wcscpy_s(wbf, formatStatus(r->tempStatus).c_str() );
}
@@ -1278,14 +1281,14 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
if (r && !invalidClass) {
int a = r->getTimeAdjustment();
if (a != 0)
- wsptr = &getTimeMSW(a);
+ wsptr = &getTimeMS(a);
}
break;
case lRunnerRogainingPointOvertime:
if (r && !invalidClass) {
int over = r->getRogainingOvertime();
if (over > 0)
- wsptr = &formatTimeW(over);
+ wsptr = &formatTime(over);
}
break;
@@ -1434,6 +1437,27 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
wcscpy_s(wbf, s.c_str());
}
break;
+ case lRunnerPaid:
+ if (r) {
+ wstring s = formatCurrency(r->getDCI().getInt("Paid"));
+ wcscpy_s(wbf, s.c_str());
+ }
+ break;
+ case lRunnerPayMethod:
+ if (r) {
+ wsptr = &r->getDCI().formatString(r, "PayMode");
+ }
+ break;
+ case lRunnerEntryDate:
+ if (r && r->getDCI().getInt("EntryDate") > 0) {
+ wsptr = &r->getDCI().getDate("EntryDate");
+ }
+ break;
+ case lRunnerEntryTime:
+ if (r) {
+ wsptr = &formatTime(r->getDCI().getInt("EntryTime"));
+ }
+ break;
case lTeamFee:
if (t) {
wstring s = formatCurrency(t->getTeamFee());
@@ -1469,7 +1493,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
wsptr = &t->Runners[legIndex]->getStartTimeCompact();
else {
int st = t->Runners[legIndex]->getStartTime();
- wsptr = &getTimeMSW(st-3600);
+ wsptr = &getTimeMS(st-3600);
}
}
}
@@ -1544,7 +1568,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
if (t && !invalidClass) {
int over = t->getRogainingOvertime();
if (over > 0)
- wsptr = &formatTimeW(over);
+ wsptr = &formatTime(over);
}
break;
@@ -1562,7 +1586,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
if (t && !invalidClass) {
int a = t->getTimeAdjustment();
if (a != 0)
- wsptr = &getTimeMSW(a);
+ wsptr = &getTimeMS(a);
}
break;
@@ -1863,7 +1887,7 @@ const wstring &oEvent::formatListStringAux(const oPrintPost &pp, const oListPara
res.swap(out[ix]);
if (res.find_first_of('%') != res.npos) {
wchar_t bf2[256];
- swprintf_s(bf2, res.c_str(), itos(nr).c_str());
+ swprintf_s(bf2, res.c_str(), itow(nr).c_str());
res = bf2;
}
}
@@ -2274,12 +2298,11 @@ void oEvent::generateListInternal(gdioutput &gdi, const oListInfo &li, bool form
GeneralResult *gResult = 0;
if (!li.resultModule.empty()) {
wstring src;
- gResult = &getGeneralResult(li.resultModule, src);
oListInfo::ResultType resType = li.getResultType();
+ gResult = &getGeneralResult(li.resultModule, src);
gResult->calculateIndividualResults(rlist, resType, li.sortOrder == Custom, li.getParam().getInputNumber());
- if (li.sortOrder == SortByFinishTime || li.sortOrder == SortByFinishTimeReverse
- || li.sortOrder == SortByStartTime)
+ if (li.sortOrder == SortByFinishTime || li.sortOrder == SortByFinishTimeReverse || li.sortOrder == SortByStartTime)
gResult->sort(rlist, li.sortOrder);
}
diff --git a/code/oListInfo.h b/code/oListInfo.h
index 5aaf96b..514928b 100644
--- a/code/oListInfo.h
+++ b/code/oListInfo.h
@@ -112,6 +112,10 @@ enum EPostType
lRunnerNationality,
lRunnerPhone,
lRunnerFee,
+ lRunnerPaid,
+ lRunnerPayMethod,
+ lRunnerEntryDate,
+ lRunnerEntryTime,
lTeamName,
lTeamStart,
@@ -294,6 +298,8 @@ struct oListParam {
GUICALLBACK cb;
set selection;
+ bool lockUpdate; // Temporary prevent animation update
+
int useControlIdResultTo;
int useControlIdResultFrom;
int filterMaxPer;
@@ -314,6 +320,18 @@ struct oListParam {
bool useLargeSize;
bool saved;
+ int bgColor;
+ int bgColor2;
+
+ int fgColor;
+ wstring bgImage;
+
+ int nColumns;
+ bool animate;
+ int timePerPage;
+ int margin;
+ int screenMode;// 0 normal window, 1 = page by page, 2 = scroll
+
void updateDefaultName(const wstring &pname) const {defaultName = pname;}
void setCustomTitle(const wstring &t) {title = t;}
void getCustomTitle(wchar_t *t) const; // 256 size buffer required. Get title if set
@@ -347,8 +365,6 @@ struct oListParam {
return legNumber >= 0 ? legNumber : 1000;
}
-
-
private:
int legNumber;
};
diff --git a/code/oPunch.cpp b/code/oPunch.cpp
index d4523a9..2e84237 100644
--- a/code/oPunch.cpp
+++ b/code/oPunch.cpp
@@ -146,7 +146,7 @@ wstring oPunch::getRunningTime(int startTime) const
{
int t = getAdjustedTime();
if (startTime>0 && t>0 && t>startTime)
- return formatTimeW(t-startTime);
+ return formatTime(t-startTime);
else
return makeDash(L"-");
}
diff --git a/code/oRunner.cpp b/code/oRunner.cpp
index f24ec36..e740300 100644
--- a/code/oRunner.cpp
+++ b/code/oRunner.cpp
@@ -47,8 +47,8 @@
oRunner::RaceIdFormatter oRunner::raceIdFormatter;
-const wstring &oRunner::RaceIdFormatter::formatData(oBase *ob) const {
- return itow(dynamic_cast(ob)->getRaceIdentifier());
+const wstring &oRunner::RaceIdFormatter::formatData(const oBase *ob) const {
+ return itow(dynamic_cast(*ob).getRaceIdentifier());
}
wstring oRunner::RaceIdFormatter::setData(oBase *ob, const wstring &input) const {
@@ -322,6 +322,7 @@ void oAbstractRunner::addClassDefaultFee(bool resetFees) {
if (isVacant()) {
di.setInt("Fee", 0);
di.setInt("EntryDate", 0);
+ di.setInt("EntryTime", 0);
di.setInt("Paid", 0);
if (typeid(*this)==typeid(oRunner))
di.setInt("CardFee", 0);
@@ -357,7 +358,10 @@ wstring oRunner::getEntryDate(bool useTeamEntryDate) const {
oDataConstInterface dci = getDCI();
int date = dci.getInt("EntryDate");
if (date == 0) {
- (const_cast(this)->getDI()).setDate("EntryDate", getLocalDateW());
+ auto di = (const_cast(this)->getDI());
+ di.setDate("EntryDate", getLocalDate());
+ di.setInt("EntryTime", convertAbsoluteTimeHMS(getLocalTimeOnly(), -1));
+
}
return dci.getDate("EntryDate");
}
@@ -607,12 +611,12 @@ int oAbstractRunner::getRunningTime() const {
const wstring &oAbstractRunner::getRunningTimeS() const
{
- return formatTimeW(getRunningTime());
+ return formatTime(getRunningTime());
}
const wstring &oAbstractRunner::getTotalRunningTimeS() const
{
- return formatTimeW(getTotalRunningTime());
+ return formatTime(getTotalRunningTime());
}
int oAbstractRunner::getTotalRunningTime() const {
@@ -661,6 +665,8 @@ const wchar_t *formatIOFStatus(RunnerStatus s) {
return L"OK";
case StatusDNS:
return L"DidNotStart";
+ case StatusCANCEL:
+ return L"Cancelled";
case StatusMP:
return L"MisPunch";
case StatusDNF:
@@ -1279,7 +1285,7 @@ bool oRunner::evaluateCard(bool doApply, vector & MissingPunches,
if (*refStatus == StatusMAX && maxTimeStatus == 2)
*refStatus = StatusUnknown;
- if (OK && (*refStatus==0 || *refStatus==StatusDNS || *refStatus==StatusMP || *refStatus==StatusOK || *refStatus==StatusDNF))
+ if (OK && (*refStatus==0 || *refStatus==StatusDNS || *refStatus == StatusCANCEL || *refStatus==StatusMP || *refStatus==StatusOK || *refStatus==StatusDNF))
*refStatus = StatusOK;
else *refStatus = RunnerStatus(max(int(StatusMP), int(*refStatus)));
@@ -1816,6 +1822,17 @@ bool oRunner::operator <(const oRunner &c) {
else if (tStartTime > c.tStartTime)
return false;
}
+ else if (oe->CurrentSortOrder == SortByEntryTime) {
+ auto dci = getDCI(), cdci = c.getDCI();
+ int ed = dci.getInt("EntryDate");
+ int ced = cdci.getInt("EntryDate");
+ if (ed != ced)
+ return ed > ced;
+ int et = dci.getInt("EntryTime");
+ int cet = cdci.getInt("EntryTime");
+ if (et != cet)
+ return et > cet;
+ }
else if (oe->CurrentSortOrder == ClassPoints) {
if (Class != c.Class)
return Class->tSortIndex < c.Class->tSortIndex;
@@ -1944,6 +1961,10 @@ void oAbstractRunner::setClub(const wstring &clubName)
// Vacant clubs have special logic
Class->tResultInfo.clear();
}
+ if (Club && Club->isVacant()) { // Clear entry date/time for vacant
+ getDI().setInt("EntryDate", 0);
+ getDI().setInt("EntryTime", 0);
+ }
}
}
@@ -1957,6 +1978,10 @@ pClub oAbstractRunner::setClubId(int clubId)
// Vacant clubs have special logic
Class->tResultInfo.clear();
}
+ if (Club && Club->isVacant()) { // Clear entry date/time for vacant
+ getDI().setInt("EntryDate", 0);
+ getDI().setInt("EntryTime", 0);
+ }
}
return Club;
}
@@ -2263,7 +2288,7 @@ bool oAbstractRunner::setStatus(RunnerStatus st, bool updateSource, bool tmpOnly
int oAbstractRunner::getPrelRunningTime() const
{
- if (FinishTime>0 && tStatus!=StatusDNS && tStatus!=StatusDNF && tStatus!=StatusNotCompetiting)
+ if (FinishTime>0 && tStatus!=StatusDNS && tStatus != StatusCANCEL && tStatus!=StatusDNF && tStatus!=StatusNotCompetiting)
return getRunningTime();
else if (tStatus==StatusUnknown)
return oe->getComputerTime()-tStartTime;
@@ -2273,7 +2298,7 @@ int oAbstractRunner::getPrelRunningTime() const
wstring oAbstractRunner::getPrelRunningTimeS() const
{
int rt=getPrelRunningTime();
- return formatTimeW(rt);
+ return formatTime(rt);
}
oDataContainer &oRunner::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const {
@@ -2386,7 +2411,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
if (t == range.second) {
pRunner r = range.first->second;
assert(r->getCardNo() == cardNo);
- if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
return 0;
if (r->getStatus() == StatusNotCompetiting)
return 0;
@@ -2397,7 +2422,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
for (hashConstIter it = range.first; it != range.second; ++it) {
pRunner r = it->second;
assert(r->getCardNo() == cardNo);
- if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
continue;
if (r->getStatus() == StatusNotCompetiting)
continue;
@@ -2411,7 +2436,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
for (it=Runners.begin(); it != Runners.end(); ++it) {
if (it->skip())
continue;
- if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL))
continue;
if (it->getStatus() == StatusNotCompetiting)
continue;
@@ -2426,7 +2451,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
pRunner r = pRunner(&*it);
if (r->CardNo != cardNo || r->isRemoved())
continue;
- if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
continue;
if (r->getStatus() == StatusNotCompetiting)
continue;
@@ -2487,7 +2512,7 @@ pRunner oEvent::getRunnerByCardNo(int cardNo, int time, bool onlyWithNoCard, boo
if (!onlyWithNoCard) {
//Then try all runners.
for (it=Runners.begin(); it != Runners.end(); ++it){
- if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL))
continue;
if (it->getStatus() == StatusNotCompetiting)
continue;
@@ -2509,7 +2534,7 @@ void oEvent::getRunnersByCardNo(int cardNo, bool ignoreRunnersWithNoStart, bool
for (hashConstIter it = range.first; it != range.second; ++it) {
pRunner r = it->second;
assert(r->getCardNo() == cardNo);
- if (ignoreRunnersWithNoStart && r->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (r->getStatus() == StatusDNS || r->getStatus() == StatusCANCEL))
continue;
if (skipDuplicates && r->getRaceNo() != 0)
continue;
@@ -2523,7 +2548,7 @@ void oEvent::getRunnersByCardNo(int cardNo, bool ignoreRunnersWithNoStart, bool
for (oRunnerList::const_iterator it=Runners.begin(); it != Runners.end(); ++it) {
if (it->CardNo != cardNo)
continue;
- if (ignoreRunnersWithNoStart && it->getStatus() == StatusDNS)
+ if (ignoreRunnersWithNoStart && (it->getStatus() == StatusDNS || it->getStatus() == StatusCANCEL))
continue;
if (it->getStatus() == StatusNotCompetiting)
continue;
@@ -3310,12 +3335,12 @@ int oRunner::getNamedSplit(int controlNumber) const
wstring oRunner::getSplitTimeS(int controlNumber, bool normalized) const
{
- return formatTimeW(getSplitTime(controlNumber, normalized));
+ return formatTime(getSplitTime(controlNumber, normalized));
}
wstring oRunner::getNamedSplitS(int controlNumber) const
{
- return formatTimeW(getNamedSplit(controlNumber));
+ return formatTime(getNamedSplit(controlNumber));
}
int oRunner::getPunchTime(int controlNumber, bool normalized) const
@@ -3335,7 +3360,7 @@ int oRunner::getPunchTime(int controlNumber, bool normalized) const
wstring oRunner::getPunchTimeS(int controlNumber, bool normalized) const
{
- return formatTimeW(getPunchTime(controlNumber, normalized));
+ return formatTime(getPunchTime(controlNumber, normalized));
}
bool oAbstractRunner::isVacant() const
@@ -3643,7 +3668,7 @@ void oRunner::setBib(const wstring &bib, int bibNumerical, bool updateStartNo, b
void oEvent::analyseDNS(vector &unknown_dns, vector &known_dns,
- vector &known, vector &unknown)
+ vector &known, vector &unknown, bool &hasSetDNS)
{
autoSynchronizeLists(true);
@@ -3654,8 +3679,11 @@ void oEvent::analyseDNS(vector &unknown_dns, vector &known_dns
if (!it->isRemoved() && !it->needNoCard()) {
if (it->getStatus() == StatusUnknown)
stUnknown.push_back(&*it);
- else if (it->getStatus() == StatusDNS)
+ else if (it->getStatus() == StatusDNS) {
stDNS.push_back(&*it);
+ if (it->hasFlag(oAbstractRunner::FlagAutoDNS))
+ hasSetDNS = true;
+ }
}
}
@@ -3827,7 +3855,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
wstring statInfo = lang.tl("Status: ") + getStatusS() + lang.tl(", Tid: ") + getRunningTimeS();
if (withSpeed && pc && pc->getLength() > 0) {
int kmt = (getRunningTime() * 1000) / pc->getLength();
- statInfo += L" (" + formatTimeW(kmt) + lang.tl(" min/km") + L")";
+ statInfo += L" (" + formatTime(kmt) + lang.tl(" min/km") + L")";
}
if (pc && withSpeed) {
if (pc->legLengths.empty() || *max_element(pc->legLengths.begin(), pc->legLengths.end()) <= 0)
@@ -3910,14 +3938,14 @@ void oRunner::printSplits(gdioutput &gdi) const {
int st = Card->getSplitTime(getStartTime(), &*it);
if (st>0)
- gdi.addStringUT(cy, cx + c2, fontSmall|textRight, formatTimeW(st));
+ gdi.addStringUT(cy, cx + c2, fontSmall|textRight, formatTime(st));
gdi.addStringUT(cy, cx+c3, fontSmall, it->getTime());
int pt = it->getAdjustedTime();
st = getStartTime();
if (st>0 && pt>0 && pt>st) {
- wstring punchTime = formatTimeW(pt-st);
+ wstring punchTime = formatTime(pt-st);
gdi.addStringUT(cy, cx+c4, fontSmall|textRight, punchTime);
}
@@ -3944,8 +3972,8 @@ void oRunner::printSplits(gdioutput &gdi) const {
gdi.addString("", cy, cx, fontSmall, "Mål");
sp = getSplitTime(splitTimes.size(), false);
if (sp>0) {
- gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTimeW(sp));
- punchTime = formatTimeW(getRunningTime());
+ gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTime(sp));
+ punchTime = formatTime(getRunningTime());
}
gdi.addStringUT(cy, cx+c3, fontSmall, oe->getAbsTime(it->Time + adjust));
any = true;
@@ -3995,7 +4023,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
sp = getSplitTime(controlLegIndex, false);
if (sp>0) {
punchTime = getPunchTimeS(controlLegIndex, false);
- gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTimeW(sp));
+ gdi.addStringUT(cy, cx+c2, fontSmall|textRight, formatTime(sp));
}
}
else {
@@ -4022,7 +4050,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
int length = pc->legLengths[controlLegIndex];
if (length > 0) {
int tempo=(sp*1000)/length;
- gdi.addStringUT(cy, cx+c5, fontSmall|textRight, formatTimeW(tempo));
+ gdi.addStringUT(cy, cx+c5, fontSmall|textRight, formatTime(tempo));
}
}
@@ -4056,7 +4084,7 @@ void oRunner::printSplits(gdioutput &gdi) const {
for (int k = pc->useFirstAsStart() ? 1 : 0; k < last; k++) {
int missed = getMissedTime(k);
if (missed>0) {
- misses.push_back(pc->getControlOrdinal(k) + L"/" + formatTimeW(missed));
+ misses.push_back(pc->getControlOrdinal(k) + L"/" + formatTime(missed));
}
}
if (misses.size()==0) {
@@ -4728,14 +4756,14 @@ wstring oRunner::getMissedTimeS() const
if (tMissedTime[k]>0)
t += tMissedTime[k];
- return getTimeMSW(t);
+ return getTimeMS(t);
}
wstring oRunner::getMissedTimeS(int ctrlNo) const
{
int t = getMissedTime(ctrlNo);
if (t>0)
- return getTimeMSW(t);
+ return getTimeMS(t);
else
return L"";
}
@@ -4981,7 +5009,7 @@ void oAbstractRunner::setInputTime(const wstring &time) {
wstring oAbstractRunner::getInputTimeS() const {
if (inputTime > 0)
- return formatTimeW(inputTime);
+ return formatTime(inputTime);
else
return makeDash(L"-");
}
@@ -5352,7 +5380,7 @@ const wstring &oAbstractRunner::TempResult::getPrintPlaceS(bool withDot) const {
}
const wstring &oAbstractRunner::TempResult::getRunningTimeS(int inputTime) const {
- return formatTimeW(getRunningTime() + inputTime);
+ return formatTime(getRunningTime() + inputTime);
}
const wstring &oAbstractRunner::TempResult::getFinishTimeS(const oEvent *oe) const {
@@ -5368,7 +5396,7 @@ const wstring &oAbstractRunner::TempResult::getStartTimeS(const oEvent *oe) cons
const wstring &oAbstractRunner::TempResult::getOutputTime(int ix) const {
int t = size_t(ix) < outputTimes.size() ? outputTimes[ix] : 0;
- return formatTimeW(t);
+ return formatTime(t);
}
int oAbstractRunner::TempResult::getOutputNumber(int ix) const {
diff --git a/code/oRunner.h b/code/oRunner.h
index 5b9d5a0..83df501 100644
--- a/code/oRunner.h
+++ b/code/oRunner.h
@@ -174,6 +174,7 @@ public:
FlagFeeSpecified = 8,
FlagUpdateClass = 16,
FlagUpdateName = 32,
+ FlagAutoDNS = 64,
};
bool hasFlag(TransferFlags flag) const;
@@ -480,7 +481,7 @@ protected:
class RaceIdFormatter : public oDataDefiner {
public:
- const wstring &formatData(oBase *obj) const;
+ const wstring &formatData(const oBase *obj) const;
wstring setData(oBase *obj, const wstring &input) const;
int addTableColumn(Table *table, const string &description, int minWidth) const;
};
diff --git a/code/oTeam.cpp b/code/oTeam.cpp
index 92eed23..33920b6 100644
--- a/code/oTeam.cpp
+++ b/code/oTeam.cpp
@@ -574,7 +574,7 @@ wstring oTeam::getLegRunningTimeS(int leg, bool multidayTotal) const
leg = Runners.size()-1;
int rt=getLegRunningTime(leg, multidayTotal);
- const wstring &bf = formatTimeW(rt);
+ const wstring &bf = formatTime(rt);
if (rt>0) {
if ((unsigned(leg)getStartTime()==Class->getRestartTime(leg)) || getNumShortening(leg)>0)
@@ -780,20 +780,21 @@ bool oTeam::isRunnerUsed(int Id) const
return false;
}
-void oTeam::setTeamNoStart(bool dns)
+void oTeam::setTeamNoStart(bool dns, RunnerStatus dnsStatus)
{
if (dns) {
- setStatus(StatusDNS, true, false);
+ assert(dnsStatus == StatusCANCEL || dnsStatus == StatusDNS);
+ setStatus(dnsStatus, true, false);
for(unsigned i=0;igetStatus()==StatusUnknown) {
- Runners[i]->setStatus(StatusDNS, true, false);
+ Runners[i]->setStatus(dnsStatus, true, false);
}
}
}
else {
setStatus(StatusUnknown, true, false);
for(unsigned i=0;igetStatus()==StatusDNS) {
+ if (Runners[i] && (Runners[i]->getStatus()==StatusDNS || Runners[i]->getStatus() == StatusCANCEL)) {
Runners[i]->setStatus(StatusUnknown, true, false);
}
}
@@ -1090,7 +1091,6 @@ bool oTeam::apply(bool sync, pRunner source, bool setTmpOnly) {
else {//The else below should only be run by mistake (for an incomplete team)
Runners[i]->setStartTime(Class->getRestartTime(i), false, setTmpOnly);
Runners[i]->tUseStartPunch=false;
- //Runners[i]->setStatus(StatusDNS);
}
}
break;
@@ -1546,6 +1546,9 @@ wstring oTeam::getLegStartTimeCompact(int leg) const
}
void oTeam::setBib(const wstring &bib, int bibnumerical, bool updateStartNo, bool setTmpOnly) {
+ if (updateStartNo)
+ updateStartNo = !Class || !Class->lockedForking();
+
if (setTmpOnly) {
tmpStore.bib = bib;
if (updateStartNo)
@@ -1745,8 +1748,10 @@ void oEvent::getTeams(int classId, vector &t, bool sort) {
wstring oTeam::getEntryDate(bool dummy) const {
oDataConstInterface dci = getDCI();
int date = dci.getInt("EntryDate");
- if (date == 0) {
- (const_cast(this)->getDI()).setDate("EntryDate", getLocalDateW());
+ if (date == 0 && !isVacant()) {
+ auto di = (const_cast(this)->getDI());
+ di.setDate("EntryDate", getLocalDate());
+ di.setInt("EntryTime", getLocalAbsTime());
}
return dci.getDate("EntryDate");
}
@@ -1968,14 +1973,14 @@ bool oTeam::inputData(int id, const wstring &input,
case TID_STATUS: {
RunnerStatus sIn = RunnerStatus(inputId);
- if (sIn != StatusDNS) {
- if (getStatus() == StatusDNS && sIn == StatusUnknown)
- setTeamNoStart(false);
+ if (sIn != StatusDNS && sIn != StatusCANCEL) {
+ if ((getStatus() == StatusDNS || getStatus() == StatusCANCEL) && sIn == StatusUnknown)
+ setTeamNoStart(false, StatusUnknown);
else
setStatus(sIn, true, false);
}
- else if (getStatus() != StatusDNS)
- setTeamNoStart(true);
+ else if (getStatus() != sIn)
+ setTeamNoStart(true, sIn);
apply(true, 0, false);
RunnerStatus sOut = getStatus();
diff --git a/code/oTeam.h b/code/oTeam.h
index 32e6781..408e9a0 100644
--- a/code/oTeam.h
+++ b/code/oTeam.h
@@ -139,7 +139,7 @@ public:
void prepareRemove();
bool skip() const {return isRemoved();}
- void setTeamNoStart(bool dns);
+ void setTeamNoStart(bool dns, RunnerStatus dnsStatus); // Set DNS or CANCEL
// If apply is triggered by a runner, don't go further than that runner.
bool apply(bool sync, pRunner source, bool setTmpOnly);
diff --git a/code/oTeamEvent.cpp b/code/oTeamEvent.cpp
index 1f93ccf..779b47b 100644
--- a/code/oTeamEvent.cpp
+++ b/code/oTeamEvent.cpp
@@ -592,9 +592,9 @@ void oEvent::setupRelay(oClass &cls, PredefinedTypes type, int nleg, const wstri
cls.setLegType(1, LTSum);
cls.setStartType(1, STHunting, false);
int t = convertAbsoluteTimeHMS(start, ZeroTime)+3600;
- cls.setStartData(1, formatTimeHMSW(t));
- cls.setRestartTime(1, formatTimeHMSW(t+1800));
- cls.setRopeTime(1, formatTimeHMSW(t+1800));
+ cls.setStartData(1, formatTimeHMS(t));
+ cls.setRestartTime(1, formatTimeHMS(t+1800));
+ cls.setRopeTime(1, formatTimeHMS(t+1800));
cls.setLegRunner(1, 0);
cls.setCoursePool(false);
break;
@@ -733,7 +733,7 @@ void oTeam::checkClassesWithReferences(oEvent &oe, std::set &clsWithRef) {
++pairedUnpairedPerClass[r[k]->getClassId()].second;
}
- for (auto it : pairedUnpairedPerClass) {
+ for (auto &it : pairedUnpairedPerClass) {
if (it.second.first > it.second.second)
clsWithRef.insert(it.first);
}
diff --git a/code/onlineinput.cpp b/code/onlineinput.cpp
index 2aacc40..8f1e959 100644
--- a/code/onlineinput.cpp
+++ b/code/onlineinput.cpp
@@ -302,7 +302,7 @@ void OnlineInput::processPunches(oEvent &oe, const xmlList &punches) {
int card = punches[k].getObjectInt("card");
int time = punches[k].getObjectInt("time") / 10;
- time = oe.getRelativeTime(formatTimeHMSW(time));
+ time = oe.getRelativeTime(formatTimeHMS(time));
if (startno.length() > 0)
r = oe.getRunnerByBibOrStartNo(startno, false);
diff --git a/code/onlineresults.cpp b/code/onlineresults.cpp
index 5ca1b1f..97e25ea 100644
--- a/code/onlineresults.cpp
+++ b/code/onlineresults.cpp
@@ -54,6 +54,12 @@ static int OnlineCB(gdioutput *gdi, int type, void *data) {
return ores.processButton(*gdi, bu);
}
case GUI_LISTBOX:{
+ ListBoxInfo lbi = *static_cast(data);
+ if (lbi.id == "Format") {
+ if (gdi->hasField("IncludeTotal")) {
+ gdi->setInputStatus("IncludeTotal", lbi.data == 1);
+ }
+ }
}
}
return 0;
@@ -113,13 +119,19 @@ void OnlineResults::settings(gdioutput &gdi, oEvent &oe, bool created) {
// gdi.dropLine();
// gdi.addInput("Interval", time, 10, 0, "Uppdateringsintervall (sekunder):");
- gdi.addSelection("Format", 200, 200, 0, L"Exportformat:");
+ gdi.addSelection("Format", 200, 200, OnlineCB, L"Exportformat:");
gdi.addItem("Format", L"MeOS Online Protocol XML", 1);
gdi.addItem("Format", L"IOF XML 2.0.3", 2);
gdi.addItem("Format", L"IOF XML 3.0", 3);
gdi.selectItemByData("Format", dataType);
gdi.addCheckbox("Zip", "Packa stora filer (zip)", 0, zipFile);
+ if (oe.hasPrevStage()) {
+ gdi.addCheckbox("IncludeTotal", "Inkludera resultat från tidigare etapper", 0, zipFile);
+ InfoCompetition &ic = getInfoServer();
+ gdi.check("IncludeTotal", ic.includeTotalResults());
+ gdi.setInputStatus("IncludeTotal", dataType == 1);
+ }
int cx = gdi.getCX();
gdi.fillRight();
@@ -239,10 +251,13 @@ void OnlineResults::save(oEvent &oe, gdioutput &gdi) {
prefix = gdi.getText("Prefix");
exportScript = gdi.getText("ExportScript");
zipFile = gdi.isChecked("Zip");
+ bool includeTotal = gdi.hasField("IncludeTotal") && gdi.isChecked("IncludeTotal");
ListBoxInfo lbi;
gdi.getSelectedItem("Format", lbi);
dataType = lbi.data;
+ if (dataType == 1)
+ getInfoServer().includeTotalResults(includeTotal);
gdi.getSelection("Classes", classes);
if (sendToFile) {
@@ -334,7 +349,7 @@ void OnlineResults::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
if (!sendToFile && !sendToURL)
return;
- ProgressWindow pwMain((sendToURL && ast == SyncNone) ? gdi.getHWND() : 0);
+ ProgressWindow pwMain((sendToURL && ast == SyncNone) ? gdi.getHWNDTarget() : 0);
pwMain.init();
wstring t;
@@ -342,7 +357,7 @@ void OnlineResults::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
InfoCompetition &ic = getInfoServer();
xmlbuffer xmlbuff;
if (dataType == 1) {
- if (ic.synchronize(*oe, classes, controls)) {
+ if (ic.synchronize(*oe, false, classes, controls)) {
lastSync = tick; // If error, avoid to quick retry
ic.getDiffXML(xmlbuff);
}
@@ -508,7 +523,7 @@ void OnlineResults::formatError(gdioutput &gdi) {
gdi.setRestorePoint("ServerError");
gdi.dropLine();
gdi.fillDown();
- gdi.addString("", boldText, "Server response X:#" + getLocalTime()).setColor(colorRed);
+ gdi.addString("", boldText, L"Server response X:#" + getLocalTime()).setColor(colorRed);
for (size_t k = 0; k < errorLines.size(); k++)
gdi.addStringUT(0, errorLines[k]);
gdi.scrollToBottom();
diff --git a/code/pdfwriter.cpp b/code/pdfwriter.cpp
index 3860a5e..744c020 100644
--- a/code/pdfwriter.cpp
+++ b/code/pdfwriter.cpp
@@ -147,6 +147,7 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
const wstring &pageTitleW,
const wstring &authorW,
const list &tl) {
+ checkWriteAccess(file);
string pageTitle = gdi.narrow(pageTitleW); // XXX WCS
string author = gdi.narrow(authorW);
diff --git a/code/printer.cpp b/code/printer.cpp
index 92e1570..806d952 100644
--- a/code/printer.cpp
+++ b/code/printer.cpp
@@ -623,6 +623,11 @@ struct PrintItemInfo {
const TextInfo *ti = dynamic_cast(obj);
return ti && ti->format == pageNewPage;
}
+
+ bool isNoPrint() const {
+ const TextInfo *ti = dynamic_cast(obj);
+ return ti && gdioutput::skipTextRender(ti->format);
+ }
};
void PageInfo::renderPages(const list &tl,
@@ -645,7 +650,7 @@ void PageInfo::renderPages(const list &tl,
const TextInfo &text = *it;
if (text.format == 10)
continue;
- if (text.format != pageNewPage && text.format != pagePageInfo) {
+ if (!text.isFormatInfo()) {
if (currentYP > text.yp) {
needSort = true;
}
@@ -740,6 +745,8 @@ void PageInfo::renderPages(const list &tl,
if (k + 1 < indexedTL.size() && tlp->yp != indexedTL[k+1].yp) {
size_t j = k + 1;
+ while (j + 1 < indexedTL.size() && indexedTL[j].isNoPrint() && !indexedTL[j].isNewPage())
+ j++;
// Required new page
if (indexedTL[j].isNewPage()) {
@@ -819,16 +826,16 @@ wstring PageInfo::pageInfo(const RenderedPage &page) const {
wchar_t bf[256];
if (nPagesTotal > 1) {
if (!page.info.empty())
- swprintf_s(bf, L"MeOS %s, %s, (%d/%d)", getLocalTimeW().c_str(),
- page.info.c_str(), page.nPage, nPagesTotal);//WCS
+ swprintf_s(bf, L"MeOS %s, %s, (%d/%d)", getLocalTime().c_str(),
+ page.info.c_str(), page.nPage, nPagesTotal);
else
- swprintf_s(bf, L"MeOS %s, (%d/%d)", getLocalTimeW().c_str(), page.nPage, nPagesTotal);
+ swprintf_s(bf, L"MeOS %s, (%d/%d)", getLocalTime().c_str(), page.nPage, nPagesTotal);
}
else {
if (!page.info.empty())
- swprintf_s(bf, L"MeOS %s, %s", getLocalTimeW().c_str(), page.info.c_str());
+ swprintf_s(bf, L"MeOS %s, %s", getLocalTime().c_str(), page.info.c_str());
else
- swprintf_s(bf, L"MeOS %s", getLocalTimeW().c_str());
+ swprintf_s(bf, L"MeOS %s", getLocalTime().c_str());
}
return bf;
}
diff --git a/code/restserver.cpp b/code/restserver.cpp
new file mode 100644
index 0000000..11c5bb9
--- /dev/null
+++ b/code/restserver.cpp
@@ -0,0 +1,261 @@
+/************************************************************************
+MeOS - Orienteering Software
+Copyright (C) 2009-2017 Melin Software HB
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+Melin Software HB - software@melin.nu - www.melin.nu
+Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
+
+************************************************************************/
+
+#include "stdafx.h"
+#include "oEvent.h"
+#include "xmlparser.h"
+#include
+
+#include "restbed/restbed"
+#include "meosexception.h"
+#include "restserver.h"
+#include "infoserver.h"
+#include
+
+using namespace restbed;
+
+vector< shared_ptr > RestServer::startedServers;
+
+
+shared_ptr RestServer::construct() {
+ shared_ptr obj(new RestServer());
+ startedServers.push_back(obj);
+ return obj;
+}
+
+void RestServer::remove(shared_ptr server) {
+// xxx std::remove(startedServers.begin(), startedServers.end(), server);
+}
+
+RestServer::RestServer() : hasAnyRequest(false) {
+}
+
+RestServer::~RestServer() {
+ stop();
+}
+
+class MeOSResource : public restbed::Resource {
+ RestServer *server;
+
+public:
+ MeOSResource(RestServer *server) : server(server) {}
+
+ ~MeOSResource() {
+ }
+
+ RestServer &getServer() const { return *server; }
+};
+
+static void method_handler(const shared_ptr< restbed::Session > session) {
+ RestServer &server = dynamic_cast(*session->get_resource()).getServer();
+ server.handleRequest(session);
+}
+
+void RestServer::handleRequest(const shared_ptr &session) {
+ const auto request = session->get_request();
+ size_t content_length = request->get_header("Content-Length", 0);
+
+ chrono::time_point start, end;
+ start = chrono::system_clock::now();
+
+ auto param = request->get_query_parameters();
+ auto answer = RestServer::addRequest(param);
+ {
+ unique_lock mlock(lock);
+ if (!waitForCompletion.wait_for(mlock, 10s, [answer] {return answer->isCompleted(); })) {
+ answer->answer = "Error (MeOS): Internal timeout";
+ }
+
+ end = chrono::system_clock::now();
+ chrono::duration elapsed_seconds = end - start;
+ responseTimes.push_back(int(1000 * elapsed_seconds.count()));
+ }
+ // lock.unlock();
+
+ session->fetch(content_length, [request, answer](const shared_ptr< Session > session, const Bytes & body)
+ {
+ //fprintf(stdout, "%.*s\n", (int)body.size(), body.data());
+ /*while (!answer->state) {
+ std::this_thread::yield();
+ }*/
+ session->close(restbed::OK, answer->answer, { { "Content-Length", itos(answer->answer.length()) },{ "Connection", "close" } });
+ });
+}
+
+void RestServer::startThread(int port) {
+ auto settings = make_shared();
+ settings->set_port(port);
+ auto resource = make_shared(this);
+ resource->set_path("/meos");
+
+ resource->set_method_handler("GET", method_handler);
+ restService->publish(resource);
+
+ restService->start(settings);
+}
+
+void RestServer::startService(int port) {
+ if (service)
+ throw meosException("Server started");
+
+ restService.reset(new restbed::Service());
+ service = make_shared(&RestServer::startThread, this, port);
+}
+
+void RestServer::stop() {
+ if (restService)
+ restService->stop();
+
+ if (service && service->joinable())
+ service->join();
+
+ restService.reset();
+ service.reset();
+}
+
+void RestServer::computeRequested(oEvent &ref) {
+ for (auto &server : startedServers) {
+ server->compute(ref);
+ }
+}
+
+void RestServer::compute(oEvent &ref) {
+ auto rq = getRequest();
+ if (!rq)
+ return;
+ if (rq->parameters.empty()) {
+ rq->answer = ""
+ "MeOS Information Service"
+ ""
+ ""
+ "MeOS
"
+ ""
+ "";
+ }
+ else if (rq->parameters.count("get") > 0) {
+ string what = rq->parameters.find("get")->second;
+ getData(ref, what, rq->parameters, rq->answer);
+ }
+ else {
+ rq->answer = "Error (MeOS): Unknown request";
+ }
+
+ {
+ lock_guard lg(lock);
+ rq->state = true;
+ }
+ waitForCompletion.notify_all();
+}
+
+void RestServer::getData(oEvent &oe, const string &what, const multimap ¶m, string &answer) {
+ xmlbuffer out;
+ out.setComplete(true);
+
+ if (what == "competition") {
+ InfoCompetition cmp(0);
+ cmp.synchronize(oe);
+ cmp.serialize(out, false);
+ }
+ else if (what == "class") {
+ vector cls;
+ oe.getClasses(cls, true);
+
+ for (auto c : cls) {
+ InfoClass iCls(c->getId());
+ set ctrl;
+ iCls.synchronize(*c, ctrl);
+ iCls.serialize(out, false);
+ }
+ }
+ else if (what == "competitor") {
+ vector r;
+ set selection;
+ if (param.count("id") > 0)
+ getSelection(param.find("id")->second, selection);
+
+ oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, true);
+
+ for (auto c : r) {
+ InfoCompetitor iR(c->getId());
+ iR.synchronize(false, *c);
+ iR.serialize(out, false);
+ }
+ }
+ if (out.size() > 0) {
+ xmlparser mem;
+ mem.openMemoryOutput(false);
+ mem.startTag("MOPComplete", "xmlns", "http://www.melin.nu/mop");
+ out.commit(mem, 100000);
+ mem.endTag();
+ mem.getMemoryOutput(answer);
+ }
+ else {
+ answer = "Error (MeOS): Unknown command '" + what + "'";
+ }
+}
+
+void RestServer::getSelection(const string ¶m, set &sel) {
+ vector sw;
+ split(param, ";,", sw);
+ for (auto &s : sw) {
+ int id = atoi(s.c_str());
+ if (id > 0)
+ sel.insert(id);
+ }
+}
+
+shared_ptr RestServer::getRequest() {
+ shared_ptr res;
+ if (hasAnyRequest) {
+ lock_guard lg(lock);
+ if (!requests.empty()) {
+ res = requests.front();
+ requests.pop_front();
+ }
+ if (requests.empty())
+ hasAnyRequest = false;
+ }
+ return res;
+}
+
+shared_ptr RestServer::addRequest(multimap ¶m) {
+ auto rq = make_shared();
+ rq->parameters.swap(param);
+ lock_guard lg(lock);
+ requests.push_back(rq);
+ hasAnyRequest = true;
+ return rq;
+}
+
+void RestServer::getStatistics(Statistics &s) {
+ lock_guard lg(lock);
+ s.numRequests = responseTimes.size();
+ s.maxResponseTime = 0;
+ s.averageResponseTime = 0;
+ for (int t : responseTimes) {
+ s.maxResponseTime = max(s.maxResponseTime, t);
+ s.averageResponseTime += t;
+ }
+ if (s.numRequests > 0) {
+ s.averageResponseTime /= s.numRequests;
+ }
+}
diff --git a/code/restserver.h b/code/restserver.h
new file mode 100644
index 0000000..2a10052
--- /dev/null
+++ b/code/restserver.h
@@ -0,0 +1,99 @@
+#pragma once
+
+/************************************************************************
+MeOS - Orienteering Software
+Copyright (C) 2009-2017 Melin Software HB
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+Melin Software HB - software@melin.nu - www.melin.nu
+Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
+
+************************************************************************/
+
+/** Class for providing a MeOS REST service */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace restbed {
+ class Service;
+ class Session;
+};
+
+class RestServer {
+private:
+ struct EventRequest {
+ EventRequest() : state(false) {}
+ multimap parameters;
+ string answer;
+ atomic_bool state; //false - asked, true - answerd
+
+ bool isCompleted() {
+ return state;
+ }
+ };
+
+ mutex lock;
+ atomic_bool hasAnyRequest;
+ shared_ptr service;
+ shared_ptr restService;
+ condition_variable waitForCompletion;
+
+ deque> requests;
+ void getData(oEvent &ref, const string &what, const multimap ¶m, string &answer);
+ void compute(oEvent &ref);
+ void startThread(int port);
+
+ static void getSelection(const string ¶m, set &sel);
+
+ void handleRequest(const shared_ptr &session);
+ friend void method_handler(const shared_ptr< restbed::Session > session);
+
+ shared_ptr addRequest(multimap ¶m);
+ shared_ptr getRequest();
+
+ vector responseTimes;
+
+ RestServer();
+ static vector< shared_ptr > startedServers;
+
+ RestServer(const RestServer &);
+ RestServer & operator=(const RestServer &) const;
+public:
+
+ ~RestServer();
+
+ void startService(int port);
+ void stop();
+
+ static shared_ptr construct();
+ static void remove(shared_ptr server);
+
+ static void computeRequested(oEvent &ref);
+
+ struct Statistics {
+ int numRequests;
+ int averageResponseTime;
+ int maxResponseTime;
+ };
+
+ void getStatistics(Statistics &s);
+};
+
+
diff --git a/code/speakermonitor.cpp b/code/speakermonitor.cpp
index bbbab6e..11fd840 100644
--- a/code/speakermonitor.cpp
+++ b/code/speakermonitor.cpp
@@ -380,7 +380,7 @@ void SpeakerMonitor::splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r) {
else
first = false;
- timeloss += pc->getControlOrdinal(j) + L". " + formatTimeW(delta[j]);
+ timeloss += pc->getControlOrdinal(j) + L". " + formatTime(delta[j]);
}
if (timeloss.length() > charlimit || (!timeloss.empty() && !first && j+1 == delta.size())) {
gdi.addStringUT(yp, xp, 0, timeloss).setColor(colorDarkRed);
@@ -405,7 +405,7 @@ wstring getTimeDesc(int t1, int t2) {
else if (tb <= 60)
stime = itow(tb) + lang.tl(L" sekunder");
else
- stime = formatTimeW(tb);
+ stime = formatTime(tb);
return stime;
}
@@ -504,7 +504,7 @@ void SpeakerMonitor::getMessage(const oEvent::ResultEvent &res,
deltaTime = after - prevAfter; // Positive -> more after.
}
- wstring timeS = formatTimeW(res.runTime);
+ wstring timeS = formatTime(res.runTime);
wstring detail;
const wstring *cname = 0;
diff --git a/code/swedish.lng b/code/swedish.lng
index e429cef..aaf5424 100644
--- a/code/swedish.lng
+++ b/code/swedish.lng
@@ -1865,7 +1865,7 @@ Byt till rätt klass (behåll eventuell starttid) = Byt till rätt klass (behål
Byt till vakansplats i rätt klass (om möjligt) = Byt till vakansplats i rätt klass (om möjligt)
Tillåt ny klass, behåll resultat från annan klass = Tillåt ny klass, behåll resultat från annan klass
Tillåt ny klass, inget totalresultat = Tillåt ny klass, inget totalresultat
-tooltip_explain_status = - = Okänd status\nOK = Godkänt resultat\nEj start = Startade inte\nFelst. = Felstämplat\nUtgått = Måltid saknas\nDisk. = Diskvalificerad\nDeltar ej = Springer inte tävlingen
+tooltip_explain_status = - = Okänd status\nOK = Godkänt resultat\nEj start = Startade inte\nÅterbud = Kommer ej att starta, visas i startlistan.\nFelst. = Felstämplat\nUtgått = Måltid saknas\nDisk. = Diskvalificerad\nDeltar ej = Springer inte tävlingen
Placering = Placering
Resultat från tidigare etapper = Resultat från tidigare etapper
Input Results = Ingångsresultat
@@ -2252,3 +2252,30 @@ Spara fönster- och speakerinställningar på datorn = Spara fönster- och speak
ask:loadspeaker = Vill du ladda tidigare sparade klass- och fönsterinställningar?
Ã…terskapa = Ã…terskapa
Återskapa tidigare sparade fönster- och speakerinställningar = Återskapa tidigare sparade fönster- och speakerinställningar
+Inkludera resultat från tidigare etapper = Inkludera resultat från tidigare etapper
+Animation = Animation
+Bakgrund = Bakgrund
+Bakgrundsfärg = Bakgrundsfärg
+Fullskärm (rullande) = Fullskärm (rullande)
+Fullskärm (sidvis) = Fullskärm (sidvis)
+Fönster = Fönster
+Fönster (rullande) = Fönster (rullande)
+Justera visningsinställningar = Justera visningsinställningar
+Marginal = Marginal
+Sidor per skärm = Sidor per skärm
+Textfärg = Textfärg
+Utseende = Utseende
+Visningsinställningar för 'X' = Visningsinställningar för 'X'
+Visningstid = Visningstid
+Visning = Visning
+ask:hasVacant = Tävlingen innehåller fortfarande vakanser.\n\nVill du ta bort samtliga vakanser innan resultaten exporteras?
+warn:missingResult = X deltagare saknar fortfarande resultat, och tas därför inte med.\n\nDu bör använda kvar-i-skogen för att tilldela återstående deltagare status .
+Återställ till = Återställ till
+Ã…terbud[status] = Ã…terbud
+LÃ¥s gafflingar = LÃ¥s gafflingar
+Markera för att förhindra oavsiktlig ändring av gafflingsnycklar = Markera för att förhindra oavsiktlig ändring av gafflingsnycklar
+Tillåt gafflingsändringar = Tillåt gafflingsändringar
+ask:updatetimes = Vill du behålla nuvarande starttider, om möjligt? Svara nej för att förskjuta tävlingen.
+X har en tid (Y) som inte är kompatibel med förändringen = X har en tid (Y) som inte är kompatibel med förändringen
+warn:latestarttime = Att använda starttider mer än X timmar efter nolltiden rekommenderas inte eftersom äldre SI brickor endast har en 12-timmarsklocka.\n\nVill du ändå använda starttiden?
+Anm. tid = Anm. tid
diff --git a/code/testmeos.cpp b/code/testmeos.cpp
index 8721989..19bb97e 100644
--- a/code/testmeos.cpp
+++ b/code/testmeos.cpp
@@ -172,7 +172,7 @@ void TestMeOS::runProtected(bool protect) const {
gdi_main->isTestMode = false;
subWindows.clear();
//oe_main->setProperty("PayModes", pmOrig);
- message = ex.what();
+ message = gdi_main->widen(ex.what());
if (!protect)
throw;
}
@@ -184,7 +184,7 @@ void TestMeOS::runProtected(bool protect) const {
gdi_main->isTestMode = false;
subWindows.clear();
//oe_main->setProperty("PayModes", pmOrig);
- message = "Unknown Exception";
+ message = L"Unknown Exception";
cleanup();
if (!protect)
throw;
@@ -274,7 +274,7 @@ string TestMeOS::selectString(const char *id, const char *data) const {
string TestMeOS::select(const char *id, size_t data) const {
string res = gdi_main->dbSelect(id, data);
- mainMessageLoop(0, 50);
+ mainMessageLoop(0, 100);
return res;
}
@@ -323,6 +323,13 @@ void TestMeOS::assertEquals(const string &expected,
throw meosAssertionFailure("Expected " + expected + " but got " + value);
}
+void TestMeOS::assertEquals(const wstring &expected,
+ const wstring &value) const {
+ if (expected != value)
+ throw meosAssertionFailure(L"Expected " + expected + L" but got " + value);
+}
+
+
void TestMeOS::assertEquals(int expected, int value) const {
assertEquals(itos(expected), itos(value));
}
@@ -344,6 +351,13 @@ void TestMeOS::assertEquals(const char *message,
assertEquals(string(message), string(expected), value);
}
+void TestMeOS::assertEquals(const wstring &message,
+ const wstring &expected,
+ const wstring &value) const {
+ if (expected != value)
+ throw meosAssertionFailure(message + L": Expected " + expected + L" but got " + value);
+}
+
void TestMeOS::checkString(const char *str, int count) const {
int c = gdi_main->dbGetStringCount(str, false);
assertEquals("String " + string(str) + " not found", itos(count), itos(c));
diff --git a/code/testmeos.h b/code/testmeos.h
index 2ef1826..5c7c311 100644
--- a/code/testmeos.h
+++ b/code/testmeos.h
@@ -41,9 +41,10 @@ enum TestStatus {
};
struct meosAssertionFailure {
- meosAssertionFailure() {message = "MeOS assertion failure";};
- meosAssertionFailure(const string &err) : message(err) {}
- string message;
+ meosAssertionFailure() {message = L"MeOS assertion failure";};
+ meosAssertionFailure(const string &err) : message(err.begin(), err.end()) {}
+ meosAssertionFailure(const wstring &err) : message(err) {}
+ wstring message;
};
class TestMeOS : public SubCommand {
@@ -57,7 +58,7 @@ private:
mutable vector tmpFiles;
mutable TestStatus status;
- mutable string message;
+ mutable wstring message;
int testId;
int *testIdMain; // Pointer to main test id
@@ -81,6 +82,10 @@ protected:
void assertEquals(const char *message, const char *expected, const string &value) const;
void assertEquals(const string &message, const string &expected, const string &value) const;
+ void assertEquals(const wstring &expected, const wstring &value) const;
+ void assertEquals(const wstring &message, const wstring &expected, const wstring &value) const;
+
+
void assertTrue(const char *message, bool condition) const;
int getResultModuleIndex(const char *tag) const;
diff --git a/code/toolbar.cpp b/code/toolbar.cpp
index 5e9ea64..4a30980 100644
--- a/code/toolbar.cpp
+++ b/code/toolbar.cpp
@@ -158,7 +158,7 @@ void Toolbar::createToolbar(const string &id, const wstring &title)
}
wstring t = lang.tl(title);
- HWND hParent = gdi.getHWND();
+ HWND hParent = gdi.getHWNDTarget();
RECT rc;
GetWindowRect(hParent, &rc);
if (hwndFloater == 0) {
@@ -281,7 +281,7 @@ LRESULT CALLBACK ToolProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Toolbar *tb = (Toolbar *)GetWindowLongPtr(hWnd, GWL_USERDATA);
if (tb) {
//DefWindowProc(tb->gdi.getHWND(), message, wParam, lParam);
- SendMessage(tb->gdi.getMain(), message, wParam, lParam);
+ SendMessage(tb->gdi.getHWNDMain(), message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
diff --git a/code/xmlparser.cpp b/code/xmlparser.cpp
index 01f31a2..27a4817 100644
--- a/code/xmlparser.cpp
+++ b/code/xmlparser.cpp
@@ -392,7 +392,7 @@ void xmlparser::openOutputT(const wchar_t *file, bool useCutMode, const string &
toString = false;
cutMode = useCutMode;
foutFile.open(file);
-
+ checkWriteAccess(file);
tagStackPointer=0;
if (foutFile.bad())
diff --git a/code/xmlparser.h b/code/xmlparser.h
index ffda789..ebe6d02 100644
--- a/code/xmlparser.h
+++ b/code/xmlparser.h
@@ -220,6 +220,18 @@ public:
return 0;
}
+ bool got(const char *pname) const {
+ xmlobject x(getObject(pname));
+ if (x)
+ return true;
+ else {
+ xmlattrib xa(getAttrib(pname));
+ if (xa)
+ return true;
+ }
+ return false;
+ }
+
bool getObjectBool(const char *pname) const;
string &getObjectString(const char *pname, string &out) const;