MeOS version 3.9.1399 Beta
This commit is contained in:
parent
0adbb266e9
commit
032a39ab1e
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -34,6 +34,9 @@
|
||||
#include "Printer.h"
|
||||
#include "oListInfo.h"
|
||||
#include "meosexception.h"
|
||||
#include "image.h"
|
||||
|
||||
extern Image image;
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
@ -139,10 +142,11 @@ public:
|
||||
|
||||
template<typename T, typename TI>
|
||||
void HTMLWriter::formatTL(ostream &fout,
|
||||
const map<pair<gdiFonts, string>, pair<string, string>> &styles,
|
||||
const T &tl,
|
||||
double &yscale, double &xscale,
|
||||
int &offsetY, int &offsetX) {
|
||||
ImageWriter& imageWriter,
|
||||
const map<pair<gdiFonts, string>, pair<string, string>> &styles,
|
||||
const T &tl,
|
||||
double &yscale, double &xscale,
|
||||
int &offsetY, int &offsetX) {
|
||||
|
||||
|
||||
auto itt = tl.begin();
|
||||
@ -158,6 +162,14 @@ void HTMLWriter::formatTL(ostream &fout,
|
||||
string yp = itos(int(yscale*TI::y(ctr_it)) + offsetY);
|
||||
string xp = itos(int(xscale*TI::x(ctr_it)) + offsetX);
|
||||
|
||||
if ((it.format & 0xFF) == textImage) {
|
||||
int imgW = int((it.textRect.right - it.textRect.left) * xscale);
|
||||
int imgH = int((it.textRect.bottom - it.textRect.top) * xscale);
|
||||
imageWriter.write(fout, xp, yp, it.text, imgW, imgH);
|
||||
++itt;
|
||||
continue;
|
||||
}
|
||||
|
||||
string estyle;
|
||||
if (it.format != 1 && it.format != boldSmall) {
|
||||
if (it.format & textRight)
|
||||
@ -274,17 +286,31 @@ void HTMLWriter::writeHTML(gdioutput &gdi, const wstring &file,
|
||||
if (fout.bad())
|
||||
throw std::exception("Bad output stream");
|
||||
|
||||
writeHTML(gdi, fout, title, refreshTimeOut, scale);
|
||||
wchar_t drive[20];
|
||||
wchar_t dir[MAX_PATH];
|
||||
wchar_t name[MAX_PATH];
|
||||
wchar_t ext[MAX_PATH];
|
||||
_wsplitpath_s(file.c_str(), drive, dir, name, ext);
|
||||
wstring path = wstring(drive) + dir;
|
||||
|
||||
writeHTML(gdi, fout, title, true, path, refreshTimeOut, scale);
|
||||
}
|
||||
|
||||
void HTMLWriter::writeHTML(gdioutput &gdi, ostream &fout, const wstring &title, int refreshTimeOut, double scale) {
|
||||
void HTMLWriter::writeHTML(gdioutput& gdi, ostream& fout,
|
||||
const wstring& title,
|
||||
bool includeImages,
|
||||
const wstring& imageDirectoryDestination,
|
||||
int refreshTimeOut, double scale) {
|
||||
|
||||
ImageWriter imgWriter(imageDirectoryDestination, includeImages);
|
||||
|
||||
if (scale <= 0)
|
||||
scale = 1.0;
|
||||
|
||||
fout << "<!DOCTYPE html>" << endl;
|
||||
fout << "<html>\n<head>\n";
|
||||
fout << "<meta charset=\"UTF-8\"/>\n";
|
||||
|
||||
|
||||
if (refreshTimeOut > 0)
|
||||
fout << "<meta http-equiv=\"refresh\" content=\"" << refreshTimeOut << "\">\n";
|
||||
|
||||
@ -299,16 +325,16 @@ void HTMLWriter::writeHTML(gdioutput &gdi, ostream &fout, const wstring &title,
|
||||
double yscale = 1.3 * scale;
|
||||
double xscale = 1.2 * scale;
|
||||
int offsetY = 0, offsetX = 0;
|
||||
HTMLWriter::formatTL<list<TextInfo>, InterpTextInfo>(fout, styles, gdi.getTL(), yscale, xscale, offsetY, offsetX);
|
||||
|
||||
fout << "<p style=\"position:absolute;left:10px;top:" << int(yscale*(gdi.getPageY()-45)) + offsetY << "px\">";
|
||||
HTMLWriter::formatTL<list<TextInfo>, InterpTextInfo>(fout, imgWriter, styles, gdi.getTL(), yscale, xscale, offsetY, offsetX);
|
||||
|
||||
fout << "<p style=\"position:absolute;left:10px;top:" << int(yscale * (gdi.getPageY() - 45)) + offsetY << "px\">";
|
||||
|
||||
char bf1[256];
|
||||
char bf2[256];
|
||||
GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256);
|
||||
GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256);
|
||||
//fout << "Skapad av <i>MeOS</i>: " << bf1 << " "<< bf2 << "\n";
|
||||
fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "<a href=\"http://www.melin.nu/meos\" target=\"_blank\"><i>MeOS</i></a>: " << bf1 << " "<< bf2 << "\n";
|
||||
fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "<a href=\"https://www.melin.nu/meos\" target=\"_blank\"><i>MeOS</i></a>: " << bf1 << " " << bf2 << "\n";
|
||||
fout << "</p>\n";
|
||||
|
||||
fout << "</body>\n";
|
||||
@ -341,18 +367,29 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
if (fout.bad())
|
||||
return throw std::exception("Bad output stream");
|
||||
|
||||
writeTableHTML(gdi, fout, title, false, refreshTimeOut, scale);
|
||||
wchar_t drive[20];
|
||||
wchar_t dir[MAX_PATH];
|
||||
wchar_t name[MAX_PATH];
|
||||
wchar_t ext[MAX_PATH];
|
||||
_wsplitpath_s(file.c_str(), drive, dir, name, ext);
|
||||
wstring path = wstring(drive) + dir;
|
||||
|
||||
writeTableHTML(gdi, fout, title, true, path, false, refreshTimeOut, scale);
|
||||
}
|
||||
|
||||
void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
ostream &fout,
|
||||
const wstring &title,
|
||||
void HTMLWriter::writeTableHTML(gdioutput& gdi,
|
||||
ostream& fout,
|
||||
const wstring& title,
|
||||
bool includeImages,
|
||||
const wstring& imageDirectoryDestination,
|
||||
bool simpleFormat,
|
||||
int refreshTimeOut,
|
||||
double scale) {
|
||||
if (scale <= 0)
|
||||
scale = 1.0;
|
||||
|
||||
ImageWriter imgWriter(imageDirectoryDestination, includeImages);
|
||||
|
||||
fout << "<!DOCTYPE html>" << endl;
|
||||
fout << "<html>\n<head>\n";
|
||||
fout << "<meta charset=\"UTF-8\"/>\n";
|
||||
@ -366,14 +403,14 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
fout << "</head>\n";
|
||||
|
||||
fout << "<body>\n";
|
||||
auto &TL = gdi.getTL();
|
||||
auto& TL = gdi.getTL();
|
||||
auto it = TL.begin();
|
||||
int MaxX = gdi.getPageX() - 100;
|
||||
map<int,int> tableCoordinates;
|
||||
map<int, int> tableCoordinates;
|
||||
|
||||
//Get x-coordinates
|
||||
while (it!=TL.end()) {
|
||||
tableCoordinates[it->xp]=0;
|
||||
while (it != TL.end()) {
|
||||
tableCoordinates[it->xp] = 0;
|
||||
++it;
|
||||
}
|
||||
|
||||
@ -384,47 +421,47 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
++mit;
|
||||
}
|
||||
tableCoordinates[MaxX] = kr;
|
||||
|
||||
|
||||
vector<bool> sizeSet(kr + 1, false);
|
||||
|
||||
fout << "<table cellspacing=\"0\" border=\"0\">\n";
|
||||
|
||||
int linecounter=0;
|
||||
it=TL.begin();
|
||||
int linecounter = 0;
|
||||
it = TL.begin();
|
||||
|
||||
vector< pair<int, vector<const TextInfo *> > > rows;
|
||||
vector< pair<int, vector<const TextInfo*> > > rows;
|
||||
rows.reserve(TL.size() / 3);
|
||||
vector<int> ypRow;
|
||||
int minHeight = 100000;
|
||||
|
||||
while (it!=TL.end()) {
|
||||
int y=it->yp;
|
||||
vector<const TextInfo *> row;
|
||||
while (it != TL.end()) {
|
||||
int y = it->yp;
|
||||
vector<const TextInfo*> row;
|
||||
|
||||
int subnormal = 0;
|
||||
int normal = 0;
|
||||
int header = 0;
|
||||
int mainheader = 0;
|
||||
while (it!=TL.end() && it->yp==y) {
|
||||
while (it != TL.end() && it->yp == y) {
|
||||
if (!gdioutput::skipTextRender(it->format)) {
|
||||
row.push_back(&*it);
|
||||
switch (it->getGdiFont()) {
|
||||
case fontLarge:
|
||||
case boldLarge:
|
||||
case boldHuge:
|
||||
mainheader++;
|
||||
break;
|
||||
case boldText:
|
||||
case italicMediumPlus:
|
||||
case fontMediumPlus:
|
||||
header++;
|
||||
break;
|
||||
case fontSmall:
|
||||
case italicSmall:
|
||||
subnormal++;
|
||||
break;
|
||||
default:
|
||||
normal++;
|
||||
case fontLarge:
|
||||
case boldLarge:
|
||||
case boldHuge:
|
||||
mainheader++;
|
||||
break;
|
||||
case boldText:
|
||||
case italicMediumPlus:
|
||||
case fontMediumPlus:
|
||||
header++;
|
||||
break;
|
||||
case fontSmall:
|
||||
case italicSmall:
|
||||
subnormal++;
|
||||
break;
|
||||
default:
|
||||
normal++;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
@ -444,27 +481,27 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
int last = ypRow.size();
|
||||
ypRow.push_back(y);
|
||||
if (last > 0) {
|
||||
minHeight = min(minHeight, ypRow[last] - ypRow[last-1]);
|
||||
minHeight = min(minHeight, ypRow[last] - ypRow[last - 1]);
|
||||
}
|
||||
}
|
||||
int numMin = 0;
|
||||
for (size_t gCount = 1; gCount < rows.size(); gCount++) {
|
||||
int h = ypRow[gCount] - ypRow[gCount-1];
|
||||
int h = ypRow[gCount] - ypRow[gCount - 1];
|
||||
if (h == minHeight)
|
||||
numMin++;
|
||||
}
|
||||
if (numMin == 0)
|
||||
numMin = 1;
|
||||
|
||||
int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5);
|
||||
int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5);
|
||||
for (size_t gCount = 1; gCount + 1 < rows.size(); gCount++) {
|
||||
int type = rows[gCount].first;
|
||||
int lastType = gCount > 0 ? rows[gCount-1].first : 0;
|
||||
int lastType = gCount > 0 ? rows[gCount - 1].first : 0;
|
||||
int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0;
|
||||
if (type == 0 && (lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2))
|
||||
continue; // No reclassify
|
||||
|
||||
int h = ypRow[gCount] - ypRow[gCount-1];
|
||||
int h = ypRow[gCount] - ypRow[gCount - 1];
|
||||
if (h > hdrLimit && rows[gCount].first == 0)
|
||||
rows[gCount].first = 2;
|
||||
}
|
||||
@ -472,12 +509,12 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
ypRow.clear();
|
||||
string lineclass;
|
||||
for (size_t gCount = 0; gCount < rows.size(); gCount++) {
|
||||
vector<const TextInfo *> &row = rows[gCount].second;
|
||||
vector<const TextInfo*>& row = rows[gCount].second;
|
||||
int type = rows[gCount].first;
|
||||
int lastType = gCount > 0 ? rows[gCount-1].first : 0;
|
||||
int lastType = gCount > 0 ? rows[gCount - 1].first : 0;
|
||||
int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0;
|
||||
|
||||
vector<const TextInfo *>::iterator rit;
|
||||
vector<const TextInfo*>::iterator rit;
|
||||
fout << "<tr>" << endl;
|
||||
|
||||
if (simpleFormat) {
|
||||
@ -498,48 +535,55 @@ void HTMLWriter::writeTableHTML(gdioutput &gdi,
|
||||
lineclass = "";
|
||||
}
|
||||
else
|
||||
lineclass = (linecounter&1) ? " class=\"e1\"" : " class=\"e0\"";
|
||||
lineclass = (linecounter & 1) ? " class=\"e1\"" : " class=\"e0\"";
|
||||
|
||||
linecounter++;
|
||||
}
|
||||
|
||||
for (size_t k=0;k<row.size();k++) {
|
||||
int thisCol=tableCoordinates[row[k]->xp];
|
||||
for (size_t k = 0; k < row.size(); k++) {
|
||||
int thisCol = tableCoordinates[row[k]->xp];
|
||||
|
||||
if (k == 0 && thisCol != 0)
|
||||
fout << "<td" << lineclass << " colspan=\"" << thisCol << "\"> </td>";
|
||||
if (k == 0 && thisCol != 0)
|
||||
fout << "<td" << lineclass << " colspan=\"" << thisCol << "\"> </td>";
|
||||
|
||||
int nextCol;
|
||||
if (row.size() == k + 1)
|
||||
nextCol = tableCoordinates.rbegin()->second;
|
||||
else
|
||||
nextCol = tableCoordinates[row[k + 1]->xp];
|
||||
int nextCol;
|
||||
if (row.size() == k + 1)
|
||||
nextCol = tableCoordinates.rbegin()->second;
|
||||
else
|
||||
nextCol = tableCoordinates[row[k + 1]->xp];
|
||||
|
||||
int colspan = nextCol - thisCol;
|
||||
int colspan = nextCol - thisCol;
|
||||
|
||||
assert(colspan > 0);
|
||||
assert(colspan > 0);
|
||||
|
||||
string style;
|
||||
string style;
|
||||
|
||||
if (row[k]->format&textRight)
|
||||
style = " style=\"text-align:right\"";
|
||||
if (row[k]->format & textRight)
|
||||
style = " style=\"text-align:right\"";
|
||||
|
||||
if (colspan == 1 && !sizeSet[thisCol]) {
|
||||
fout << " <td" << lineclass << style << " width=\"" << int((k + 1 < row.size()) ?
|
||||
(row[k + 1]->xp - row[k]->xp) : (MaxX - row[k]->xp)) << "\">";
|
||||
sizeSet[thisCol] = true;
|
||||
}
|
||||
else if (colspan > 1)
|
||||
fout << " <td" << lineclass << style << " colspan=\"" << colspan << "\">";
|
||||
else
|
||||
fout << " <td" << lineclass << style << ">";
|
||||
if (colspan == 1 && !sizeSet[thisCol]) {
|
||||
fout << " <td" << lineclass << style << " width=\"" << int((k + 1 < row.size()) ?
|
||||
(row[k + 1]->xp - row[k]->xp) : (MaxX - row[k]->xp)) << "\">";
|
||||
sizeSet[thisCol] = true;
|
||||
}
|
||||
else if (colspan > 1)
|
||||
fout << " <td" << lineclass << style << " colspan=\"" << colspan << "\">";
|
||||
else
|
||||
fout << " <td" << lineclass << style << ">";
|
||||
|
||||
gdiFonts font = row[k]->getGdiFont();
|
||||
string starttag, endtag;
|
||||
getStyle(styles, font, gdioutput::narrow(row[k]->font), "", starttag, endtag);
|
||||
|
||||
fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag << "</td>" << endl;
|
||||
if ((row[k]->format & 0xFF) == textImage) {
|
||||
int imgW = int((row[k]->textRect.right - row[k]->textRect.left) * scale);
|
||||
int imgH = int((row[k]->textRect.bottom - row[k]->textRect.top) * scale);
|
||||
imgWriter.write(fout, "", "", row[k]->text, imgW, imgH);
|
||||
fout << "</td>" << endl;
|
||||
}
|
||||
else {
|
||||
gdiFonts font = row[k]->getGdiFont();
|
||||
string starttag, endtag;
|
||||
getStyle(styles, font, gdioutput::narrow(row[k]->font), "", starttag, endtag);
|
||||
|
||||
fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag << "</td>" << endl;
|
||||
}
|
||||
}
|
||||
fout << "</tr>\n";
|
||||
|
||||
@ -555,7 +599,7 @@ fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag <
|
||||
GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256);
|
||||
GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256);
|
||||
wstring meos = getMeosCompectVersion();
|
||||
fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "<a href=\"http://www.melin.nu/meos\" target=\"_blank\"><i>MeOS "
|
||||
fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "<a href=\"https://www.melin.nu/meos\" target=\"_blank\"><i>MeOS "
|
||||
<< gdioutput::toUTF8(meos) << "</i></a>: " << bf1 << " " << bf2 << "\n";
|
||||
fout << "</p><br>\n";
|
||||
}
|
||||
@ -781,8 +825,11 @@ void HTMLWriter::generate(gdioutput &gdi,
|
||||
double scale) const {
|
||||
int w, h;
|
||||
gdi.getTargetDimension(w, h);
|
||||
|
||||
|
||||
ImageWriter imgWriter(L"", false);
|
||||
|
||||
string meos = "<a href=\"http://www.melin.nu/meos\" target=\"_blank\"><i>MeOS</i></a>: " + gdioutput::toUTF8(getMeosCompectVersion()) + "</a>";
|
||||
string meos = "<a href=\"https://www.melin.nu/meos\" target=\"_blank\"><i>MeOS</i></a>: " + gdioutput::toUTF8(getMeosCompectVersion()) + "</a>";
|
||||
|
||||
int margin = (w * marginPercent) / 100;
|
||||
int height = nRows * gdi.getLineHeight();
|
||||
@ -886,7 +933,7 @@ void HTMLWriter::generate(gdioutput &gdi,
|
||||
double xscale = 1.2 * scale;
|
||||
int offsetY = 0, offsetX = 0;
|
||||
|
||||
formatTL<vector<PrintTextInfo>, InterpPrintTextInfo>(sout, styles, p.text, yscale, xscale, offsetY, offsetX);
|
||||
formatTL<vector<PrintTextInfo>, InterpPrintTextInfo>(sout, imgWriter, styles, p.text, yscale, xscale, offsetY, offsetX);
|
||||
|
||||
output = innerpage;
|
||||
replaceAll(output, "@P", itos(ipCounter++));
|
||||
@ -921,17 +968,27 @@ void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title
|
||||
checkWriteAccess(file);
|
||||
ofstream fout(file.c_str());
|
||||
|
||||
write(gdi, fout, title, contentsDescription, respectPageBreak, typeTag, refresh,
|
||||
wchar_t drive[20];
|
||||
wchar_t dir[MAX_PATH];
|
||||
wchar_t name[MAX_PATH];
|
||||
wchar_t ext[MAX_PATH];
|
||||
_wsplitpath_s(file.c_str(), drive, dir, name, ext);
|
||||
wstring path = wstring(drive) + dir;
|
||||
|
||||
write(gdi, fout, title, true, path, contentsDescription, respectPageBreak, typeTag, refresh,
|
||||
rows, cols, time_ms, margin, scale);
|
||||
}
|
||||
|
||||
void HTMLWriter::write(gdioutput &gdi, ostream &fout, const wstring &title, const wstring &contentsDescription,
|
||||
void HTMLWriter::write(gdioutput &gdi, ostream &fout, const wstring &title,
|
||||
bool includeImages,
|
||||
const wstring& imageDirectoryDestination,
|
||||
const wstring &contentsDescription,
|
||||
bool respectPageBreak, const string &typeTag, int refresh,
|
||||
int rows, int cols, int time_ms, int margin, double scale) {
|
||||
if (typeTag == "table")
|
||||
writeTableHTML(gdi, fout, title, false, refresh, scale);
|
||||
writeTableHTML(gdi, fout, title, includeImages, imageDirectoryDestination, false, refresh, scale);
|
||||
else if (typeTag == "free") {
|
||||
writeHTML(gdi, fout, title, refresh, scale);
|
||||
writeHTML(gdi, fout, title, includeImages, imageDirectoryDestination, refresh, scale);
|
||||
}
|
||||
else {
|
||||
/* auto res = tCache.find(typeTag);
|
||||
@ -972,6 +1029,44 @@ void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title
|
||||
param.timePerPage, param.margin, param.htmlScale);
|
||||
}
|
||||
|
||||
void HTMLWriter::write(gdioutput& gdi, ostream& fout, const wstring& title, int refresh, oListParam& param, const oEvent& oe) {
|
||||
write(gdi, fout, title, true, L"", param.getContentsDescriptor(oe), param.pageBreak, param.htmlTypeTag,
|
||||
refresh != 0 ? refresh : param.timePerPage / 1000, param.htmlRows, param.nColumns,
|
||||
param.timePerPage, param.margin, param.htmlScale);
|
||||
}
|
||||
|
||||
void HTMLWriter::getPage(const oEvent &oe, string &out) const {
|
||||
out = page;
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLWriter::ImageWriter::write(ostream& fout, const string& xp, const string& yp, const wstring& img, int width, int height) {
|
||||
if (!writeImages) {
|
||||
if (xp.empty())
|
||||
fout << " ";
|
||||
}
|
||||
else {
|
||||
if (img.empty() || img[0] != 'L')
|
||||
throw meosException("Unsupported image");
|
||||
uint64_t imgId = _wcstoui64(img.c_str() + 1, nullptr, 10);
|
||||
|
||||
if (!savedFiles.count(imgId)) {
|
||||
if (!destination.empty()) {
|
||||
auto& data = image.getRawData(imgId);
|
||||
wstring d = destination + img + L".png";
|
||||
ofstream out(d, ofstream::out | ofstream::binary);
|
||||
out.write((const char *)data.data(), data.size());
|
||||
savedFiles[imgId] = "L" + itos(imgId) + ".png";
|
||||
}
|
||||
else {
|
||||
savedFiles[imgId] = "/meos?image=ID" + itos(imgId) + ".png";
|
||||
}
|
||||
}
|
||||
string style;
|
||||
if (xp.size() > 0)
|
||||
style = " style=\"position:absolute;left:" + xp + "px;top:" + yp + "px\"";
|
||||
|
||||
fout << "<img src=\"" << savedFiles[imgId] << "\" width=\"" <<
|
||||
width << "\" height=\"" << height << "\"" << style << ">";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -39,6 +39,29 @@ class HTMLWriter {
|
||||
|
||||
static string localize(const string &in);
|
||||
|
||||
|
||||
class ImageWriter {
|
||||
wstring destination;
|
||||
const bool writeImages;
|
||||
const wstring imageDirectoryDestination;
|
||||
map<uint64_t, string> savedFiles;
|
||||
public:
|
||||
ImageWriter(const wstring& dst, bool writeImages) : destination(dst), writeImages(writeImages) {}
|
||||
|
||||
|
||||
void write(ostream &fout, const string &xp, const string &yp, const wstring &img, int width, int height);
|
||||
};
|
||||
|
||||
template<typename T, typename TI>
|
||||
static void formatTL(ostream& fout,
|
||||
ImageWriter& imageWriter,
|
||||
const map< pair<gdiFonts, string>, pair<string, string> >& styles,
|
||||
const T& tl,
|
||||
double& yscale,
|
||||
double& xscale,
|
||||
int& offsetY,
|
||||
int& offsetX);
|
||||
|
||||
public:
|
||||
|
||||
static void reset() {
|
||||
@ -76,10 +99,15 @@ public:
|
||||
|
||||
void getPage(const oEvent &oe, string &out) const;
|
||||
|
||||
static void writeHTML(gdioutput &gdi, ostream &dout, const wstring &title, int refreshTimeOut, double scale);
|
||||
static void writeHTML(gdioutput &gdi, ostream &dout, const wstring &title,
|
||||
bool includeImages,
|
||||
const wstring& imageDirectoryDestination,
|
||||
int refreshTimeOut, double scale);
|
||||
|
||||
static void writeTableHTML(gdioutput &gdi, ostream &fout,
|
||||
const wstring &title,
|
||||
bool includeImages,
|
||||
const wstring &imageDirectoryDestination,
|
||||
bool simpleFormat,
|
||||
int refreshTimeOut,
|
||||
double scale);
|
||||
@ -92,23 +120,17 @@ public:
|
||||
static void writeHTML(gdioutput &gdi, const wstring &file,
|
||||
const wstring &title, int refreshTimeOut, double scale);
|
||||
|
||||
static void write(gdioutput &gdi, const wstring &file, const wstring &title, const wstring &contentsDescription,
|
||||
bool respectPageBreak, const string &typeTag, int refresh,
|
||||
int rows, int cols, int time_ms, int margin, double scale);
|
||||
static void write(gdioutput& gdi, const wstring& file, const wstring& title, int refresh, oListParam& param, const oEvent& oe);
|
||||
static void write(gdioutput& gdi, ostream& fout, const wstring& title, int refresh, oListParam& param, const oEvent& oe);
|
||||
|
||||
static void write(gdioutput &gdi, ostream &fout, const wstring &title, const wstring &contentsDescription,
|
||||
bool respectPageBreak, const string &typeTag, int refresh,
|
||||
int rows, int cols, int time_ms, int margin, double scale);
|
||||
|
||||
static void write(gdioutput &gdi, const wstring &file, const wstring &title, int refresh, oListParam ¶m, const oEvent &oe);
|
||||
|
||||
template<typename T, typename TI>
|
||||
static void formatTL(ostream &fout,
|
||||
const map< pair<gdiFonts, string>, pair<string, string> > &styles,
|
||||
const T &tl,
|
||||
double &yscale,
|
||||
double &xscale,
|
||||
int &offsetY,
|
||||
int &offsetX);
|
||||
static void write(gdioutput& gdi, const wstring& file, const wstring& title, const wstring& contentsDescription,
|
||||
bool respectPageBreak, const string& typeTag, int refresh,
|
||||
int rows, int cols, int time_ms, int margin, double scale);
|
||||
|
||||
static void write(gdioutput& gdi, ostream& fout, const wstring& title,
|
||||
bool includeImages,
|
||||
const wstring& imageDirectoryDestination,
|
||||
const wstring& contentsDescription,
|
||||
bool respectPageBreak, const string& typeTag, int refresh,
|
||||
int rows, int cols, int time_ms, int margin, double scale);
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
319
code/MeosSQL.cpp
319
code/MeosSQL.cpp
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -99,6 +99,11 @@ string C_INT64(string name)
|
||||
return " "+name+" BIGINT NOT NULL DEFAULT 0, ";
|
||||
}
|
||||
|
||||
string C_UINT64(string name)
|
||||
{
|
||||
return " " + name + " BIGINT UNSIGNED NOT NULL DEFAULT 0, ";
|
||||
}
|
||||
|
||||
string C_STRING(string name, int len=64)
|
||||
{
|
||||
char bf[16];
|
||||
@ -451,8 +456,21 @@ void MeosSQL::upgradeDB(const string &db, oDataContainer const * dc) {
|
||||
sql = sql.substr(0, sql.length() - 2);
|
||||
query.execute(sql);
|
||||
}
|
||||
if (!eCol.count("BDate")) {
|
||||
string sql = "ALTER TABLE " + db + " ";
|
||||
sql += "ADD COLUMN " + C_INT("BDate");
|
||||
sql = sql.substr(0, sql.length() - 2);
|
||||
query.execute(sql);
|
||||
}
|
||||
}
|
||||
else if (db == "oPunch") {
|
||||
if (!eCol.count("Unit")) {
|
||||
string sql = "ALTER TABLE " + db + " ";
|
||||
sql += "ADD COLUMN " + C_INT("Unit");
|
||||
sql = sql.substr(0, sql.length() - 2);
|
||||
query.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc) {
|
||||
// Ugrade table
|
||||
string sqlAdd = dc->generateSQLDefinition(eCol);
|
||||
@ -478,7 +496,8 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
return 0;
|
||||
}
|
||||
monitorId = 0;
|
||||
string dbname(oe->currentNameId.begin(), oe->currentNameId.end());//WCS
|
||||
string dbname(oe->currentNameId.begin(), oe->currentNameId.end());
|
||||
bool tookLock = false;
|
||||
|
||||
try {
|
||||
auto query = con->query();
|
||||
@ -489,11 +508,29 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
auto row = res.at(0);
|
||||
|
||||
int version = row["Version"];
|
||||
|
||||
if (version < oEvent::dbVersion) {
|
||||
if (version <= 88) {
|
||||
query.exec("LOCK TABLE MeOSMain.oEvent WRITE");
|
||||
tookLock = true;
|
||||
|
||||
query.reset();
|
||||
query << "SELECT Version FROM oEvent WHERE NameId=" << quote << dbname;
|
||||
auto resV = query.store();
|
||||
if (res && res.num_rows() >= 1) {
|
||||
version = res.at(0)["Version"];
|
||||
}
|
||||
}
|
||||
|
||||
query.reset();
|
||||
query << "UPDATE oEvent SET Version=" << oEvent::dbVersion << " WHERE Id=" << int(row["Id"]);
|
||||
query.execute();
|
||||
if (version <= 88) {
|
||||
upgradeTimeFormat(dbname);
|
||||
}
|
||||
|
||||
if (tookLock) {
|
||||
con->query().exec("UNLOCK TABLES");
|
||||
}
|
||||
}
|
||||
else if (version > oEvent::dbVersion) {
|
||||
alert("A newer version av MeOS is required.");
|
||||
@ -524,6 +561,10 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
}
|
||||
}
|
||||
catch (const Exception& er) {
|
||||
if (tookLock && con) {
|
||||
con->query().exec("UNLOCK TABLES");
|
||||
}
|
||||
|
||||
setDefaultDB();
|
||||
alert(string(er.what()) + " MySQL Error. Select DB.");
|
||||
return 0;
|
||||
@ -588,6 +629,7 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
<< C_INT("CardNo")
|
||||
<< C_UINT("ReadId")
|
||||
<< C_UINT("Voltage")
|
||||
<< C_INT("BDate")
|
||||
<< C_STRING("Punches", 16*190) << C_END();
|
||||
|
||||
query.execute();
|
||||
@ -657,9 +699,12 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
query << C_START("oPunch")
|
||||
<< C_INT("CardNo")
|
||||
<< C_INT("Time")
|
||||
<< C_INT("Type") << C_END();
|
||||
<< C_INT("Type")
|
||||
<< C_INT("Unit") << C_END();
|
||||
query.execute();
|
||||
|
||||
upgradeDB("oPunch", nullptr);
|
||||
|
||||
query.reset();
|
||||
query << C_START("oMonitor")
|
||||
<< C_STRING("Client")
|
||||
@ -691,6 +736,13 @@ bool MeosSQL::openDB(oEvent *oe)
|
||||
|
||||
// Create runner/club DB
|
||||
createRunnerDB(oe, query);
|
||||
|
||||
query.reset();
|
||||
query << C_START_noid("oImage")
|
||||
<< C_UINT64("Id")
|
||||
<< C_TEXT("Filename")
|
||||
<< " Image LONGBLOB)" << engine();
|
||||
query.execute();
|
||||
}
|
||||
catch (const Exception& er){
|
||||
alert(string(er.what()) + " MySQL Error.");
|
||||
@ -979,9 +1031,9 @@ OpFailStatus MeosSQL::uploadRunnerDB(oEvent *oe)
|
||||
auto query = con->query();
|
||||
query << "INSERT INTO dbRunner SET " <<
|
||||
"Name=" << quote << rdb[k].name <<
|
||||
", ExtId=" << rdb[k].extId << ", Club=" << rdb[k].clubNo <<
|
||||
", ExtId=" << rdb[k].getExtId() << ", Club=" << rdb[k].clubNo <<
|
||||
", CardNo=" << rdb[k].cardNo << ", Sex=" << quote << rdb[k].getSex() <<
|
||||
", Nation=" << quote << rdb[k].getNationality() << ", BirthYear=" << rdb[k].birthYear;
|
||||
", Nation=" << quote << rdb[k].getNationality() << ", BirthYear=" << rdb[k].getBirthDateInt();
|
||||
|
||||
try {
|
||||
query.execute();
|
||||
@ -1031,7 +1083,7 @@ bool MeosSQL::storeData(oDataInterface odi, const RowWrapper &row, unsigned long
|
||||
}
|
||||
}
|
||||
else {
|
||||
__int64 val = row[(const char*)it_int->name].ulonglong();
|
||||
__int64 val = row[(const char*)it_int->name].longlong();
|
||||
__int64 oldVal = *(it_int->data64);
|
||||
if (val != oldVal) {
|
||||
memcpy(it_int->data64, &val, 8);
|
||||
@ -1476,7 +1528,7 @@ OpFailStatus MeosSQL::SyncRead(oEvent *oe) {
|
||||
RunnerDBEntry &dbn = db->dbe();
|
||||
if (sex.length()==1)
|
||||
dbn.sex = sex[0];
|
||||
dbn.birthYear = short(atoi(birth.c_str()));
|
||||
dbn.setBirthDate(atoi(birth.c_str()));
|
||||
|
||||
if (nat.length()==3) {
|
||||
dbn.national[0] = nat[0];
|
||||
@ -1546,6 +1598,7 @@ void MeosSQL::storeCard(const RowWrapper &row, oCard &c)
|
||||
c.cardNo = row["CardNo"];
|
||||
c.readId = row["ReadId"];
|
||||
c.miliVolt = row["Voltage"];
|
||||
c.batteryDate = row["BDate"];
|
||||
c.importPunches(string(row["Punches"]));
|
||||
|
||||
c.sqlUpdated = row["Modified"];
|
||||
@ -1565,10 +1618,10 @@ void MeosSQL::storePunch(const RowWrapper &row, oFreePunch &p, bool rehash)
|
||||
}
|
||||
else {
|
||||
p.CardNo = row["CardNo"];
|
||||
p.Time = row["Time"];
|
||||
p.Type = row["Type"];
|
||||
p.punchTime = row["Time"];
|
||||
p.type = row["Type"];
|
||||
}
|
||||
|
||||
p.punchUnit = row["Unit"];
|
||||
p.sqlUpdated = row["Modified"];
|
||||
p.counter = row["Counter"];
|
||||
p.Removed = row["Removed"];
|
||||
@ -2178,6 +2231,7 @@ OpFailStatus MeosSQL::syncUpdate(oCard *c, bool forceWriteAll)
|
||||
auto queryset = con->query();
|
||||
queryset << " CardNo=" << c->cardNo
|
||||
<< ", ReadId=" << c->readId << ", Voltage=" << max(0, c->miliVolt)
|
||||
<< ", BDate=" << c->batteryDate
|
||||
<< ", Punches=" << quote << c->getPunchString();
|
||||
|
||||
return syncUpdate(queryset, "oCard", c);
|
||||
@ -2287,6 +2341,77 @@ OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t)
|
||||
return syncRead(forceRead, t, true);
|
||||
}
|
||||
|
||||
void MeosSQL::upgradeTimeFormat(const string & dbname) {
|
||||
bool ok = false;
|
||||
try {
|
||||
con->select_db(dbname);
|
||||
ok = true;
|
||||
}
|
||||
catch (const Exception &) {
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
auto query = con->query();
|
||||
query.exec("LOCK TABLES oEvent WRITE, oClass WRITE, oControl WRITE, "
|
||||
"oCourse WRITE, oPunch WRITE, oRunner WRITE, oTeam WRITE");
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
auto upgradeCol = [this](const string &db, const string &col) {
|
||||
auto query = con->query();
|
||||
string v = "UPDATE " + db + " SET " + col + "=" + col + "*10 WHERE " + col + "<>-1";
|
||||
try {
|
||||
query.execute(v);
|
||||
}
|
||||
catch (const Exception &) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto alter = [this](const string &db, const string &col) {
|
||||
auto query = con->query();
|
||||
string v = "ALTER TABLE " + db + " MODIFY COLUMN " + col + " INT NOT NULL DEFAULT 0";
|
||||
try {
|
||||
query.execute(v);
|
||||
}
|
||||
catch (const Exception &) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
};
|
||||
upgradeCol("oEvent", "ZeroTime");
|
||||
upgradeCol("oEvent", "MaxTime");
|
||||
upgradeCol("oEvent", "DiffTime");
|
||||
|
||||
upgradeCol("oClass", "FirstStart");
|
||||
upgradeCol("oClass", "StartInterval");
|
||||
upgradeCol("oClass", "MaxTime");
|
||||
|
||||
upgradeCol("oControl", "TimeAdjust");
|
||||
upgradeCol("oControl", "MinTime");
|
||||
|
||||
upgradeCol("oCourse", "RTimeLimit");
|
||||
|
||||
upgradeCol("oPunch", "Time");
|
||||
|
||||
upgradeCol("oRunner", "StartTime");
|
||||
upgradeCol("oRunner", "FinishTime");
|
||||
upgradeCol("oRunner", "InputTime");
|
||||
alter("oRunner", "TimeAdjust");
|
||||
upgradeCol("oRunner", "TimeAdjust");
|
||||
upgradeCol("oRunner", "EntryTime");
|
||||
|
||||
upgradeCol("oTeam", "StartTime");
|
||||
upgradeCol("oTeam", "FinishTime");
|
||||
upgradeCol("oTeam", "InputTime");
|
||||
alter("oTeam", "TimeAdjust");
|
||||
upgradeCol("oTeam", "TimeAdjust");
|
||||
upgradeCol("oTeam", "EntryTime");
|
||||
}
|
||||
|
||||
OpFailStatus MeosSQL::syncRead(bool forceRead, oTeam *t, bool readRecursive)
|
||||
{
|
||||
errorMessage.clear();
|
||||
@ -2536,7 +2661,7 @@ OpFailStatus MeosSQL::syncReadControls(oEvent *oe, const set<int> &controls) {
|
||||
int counter = row["Counter"];
|
||||
string modified = row["Modified"];
|
||||
|
||||
pControl pc = oe->getControl(id, false);
|
||||
pControl pc = oe->getControl(id, false, false);
|
||||
if (!pc) {
|
||||
oControl oc(oe, id);
|
||||
success = min(success, syncRead(true, &oc));
|
||||
@ -2550,7 +2675,7 @@ OpFailStatus MeosSQL::syncReadControls(oEvent *oe, const set<int> &controls) {
|
||||
|
||||
// processedCourses should now be empty, unless there are local controls not yet added.
|
||||
for(set<int>::iterator it = processedControls.begin(); it != processedControls.end(); ++it) {
|
||||
pControl pc = oe->getControl(*it, false);
|
||||
pControl pc = oe->getControl(*it, false, false);
|
||||
if (pc) {
|
||||
success = min(success, syncUpdate(pc, true));
|
||||
}
|
||||
@ -2647,7 +2772,7 @@ OpFailStatus MeosSQL::syncUpdate(oControl *c, bool forceWriteAll) {
|
||||
auto queryset = con->query();
|
||||
queryset << " Name=" << quote << toString(c->Name) << ", "
|
||||
<< " Numbers=" << quote << toString(c->codeNumbers()) << ","
|
||||
<< " Status=" << c->Status
|
||||
<< " Status=" << int(c->Status)
|
||||
<< c->getDI().generateSQLSet(forceWriteAll);
|
||||
|
||||
return syncUpdate(queryset, "oControl", c);
|
||||
@ -2826,8 +2951,9 @@ OpFailStatus MeosSQL::syncUpdate(oFreePunch *c, bool forceWriteAll)
|
||||
}
|
||||
auto queryset = con->query();
|
||||
queryset << " CardNo=" << c->CardNo << ", "
|
||||
<< " Type=" << c->Type << ","
|
||||
<< " Time=" << c->Time;
|
||||
<< " Type=" << c->type << ","
|
||||
<< " Time=" << c->punchTime << ","
|
||||
<< " Unit=" << c->punchUnit;
|
||||
|
||||
return syncUpdate(queryset, "oPunch", c);
|
||||
}
|
||||
@ -2974,38 +3100,55 @@ OpFailStatus MeosSQL::syncUpdate(QueryWrapper &updateqry,
|
||||
if (ob->isRemoved())
|
||||
return opStatusOK;
|
||||
bool setId = false;
|
||||
|
||||
bool update = false;
|
||||
if (ob->Id > 0) {
|
||||
query << "SELECT Id FROM " << oTable << " WHERE Id=" << ob->Id;
|
||||
query << "SELECT Removed FROM " << oTable << " WHERE Id=" << ob->Id;
|
||||
auto res=query.store();
|
||||
if (res.empty())
|
||||
setId = true;
|
||||
else if (ob->isImplicitlyCreated()) {
|
||||
return opStatusWarning;//XXX Should we read this object?
|
||||
}
|
||||
else {
|
||||
int removed = res.at(0).at(0);
|
||||
if (removed) {
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(!ob->isImplicitlyCreated());
|
||||
}
|
||||
|
||||
query.reset();
|
||||
query << "INSERT INTO " << oTable << " SET " << updateqry.str();
|
||||
if (update) {
|
||||
query << "UPDATE " << oTable << " SET Removed = 0, " << updateqry.str();
|
||||
}
|
||||
else {
|
||||
query << "INSERT INTO " << oTable << " SET " << updateqry.str();
|
||||
|
||||
if (setId)
|
||||
query << ", Id=" << ob->Id;
|
||||
if (setId)
|
||||
query << ", Id=" << ob->Id;
|
||||
}
|
||||
|
||||
if (writeTime) {
|
||||
query << ", Modified='" << ob->getTimeStampN() << "'";
|
||||
}
|
||||
|
||||
if (update) {
|
||||
query << " WHERE Id=" << ob->Id;
|
||||
}
|
||||
|
||||
ResNSel res=query.execute();
|
||||
if (res) {
|
||||
if (ob->Id > 0 && ob->Id!=(int)res.insert_id) {
|
||||
ob->correctionNeeded = true;
|
||||
}
|
||||
if (!update) {
|
||||
if (ob->Id > 0 && ob->Id != (int)res.insert_id) {
|
||||
ob->correctionNeeded = true;
|
||||
}
|
||||
|
||||
if (ob->Id != res.insert_id)
|
||||
ob->changeId((int)res.insert_id);
|
||||
if (ob->Id != res.insert_id)
|
||||
ob->changeId((int)res.insert_id);
|
||||
}
|
||||
|
||||
updateCounter(oTable, ob->Id, 0);
|
||||
ob->oe->updateFreeId(ob);
|
||||
@ -3059,8 +3202,12 @@ OpFailStatus MeosSQL::syncUpdate(QueryWrapper &updateqry,
|
||||
|
||||
bool MeosSQL::checkOldVersion(oEvent *oe, RowWrapper &row) {
|
||||
int dbv=int(row["BuildVersion"]);
|
||||
if ( dbv<buildVersion )
|
||||
oe->updateChanged();
|
||||
if (dbv < buildVersion) {
|
||||
string bv = "UPDATE oEvent SET BuildVersion=if (BuildVersion<" +
|
||||
itos(buildVersion) + "," + itos(buildVersion) + ",BuildVersion) WHERE Id = " + itos(oe->Id);
|
||||
|
||||
con->query().exec(bv);
|
||||
}
|
||||
else if (dbv>buildVersion)
|
||||
return true;
|
||||
|
||||
@ -3552,7 +3699,7 @@ bool MeosSQL::syncListControl(oEvent *oe) {
|
||||
|
||||
if (int(row["Removed"])) {
|
||||
st = opStatusOK;
|
||||
oControl *c = oe->getControl(Id, false);
|
||||
oControl *c = oe->getControl(Id, false, false);
|
||||
|
||||
if (c && !c->Removed) {
|
||||
c->Removed = true;
|
||||
@ -3562,7 +3709,7 @@ bool MeosSQL::syncListControl(oEvent *oe) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
oControl *c = oe->getControl(Id, false);
|
||||
oControl *c = oe->getControl(Id, false, false);
|
||||
if (c) {
|
||||
if (isOld(counter, modified, c))
|
||||
st = syncRead(false, c);
|
||||
@ -3848,11 +3995,12 @@ bool MeosSQL::dropDatabase(oEvent *oe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
string error;
|
||||
try {
|
||||
con->drop_db(CmpDataBase);
|
||||
}
|
||||
catch (const Exception& ) {
|
||||
//Don't care if we fail.
|
||||
catch (const Exception& ex) {
|
||||
error = ex.what();
|
||||
}
|
||||
|
||||
try {
|
||||
@ -3860,7 +4008,10 @@ bool MeosSQL::dropDatabase(oEvent *oe)
|
||||
query << "DELETE FROM oEvent WHERE NameId=" << quote << CmpDataBase;
|
||||
query.execute();
|
||||
}
|
||||
catch (const Exception& ) {
|
||||
catch (const Exception& ex) {
|
||||
if (!error.empty())
|
||||
error += ", ";
|
||||
error += ex.what();
|
||||
//Don't care if we fail.
|
||||
}
|
||||
|
||||
@ -3874,6 +4025,9 @@ bool MeosSQL::dropDatabase(oEvent *oe)
|
||||
catch (const Exception&) {
|
||||
}
|
||||
|
||||
if (!error.empty())
|
||||
throw meosException(error);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3930,7 +4084,9 @@ int getTypeId(const oBase &ob)
|
||||
}
|
||||
static int skipped = 0, notskipped = 0, readent = 0;
|
||||
|
||||
void MeosSQL::synchronized(const oBase &entity) {
|
||||
void MeosSQL::synchronized(oBase &entity) {
|
||||
entity.Modified.setStamp(entity.sqlUpdated);
|
||||
|
||||
int id = getTypeId(entity);
|
||||
readTimes[make_pair(id, entity.getId())] = GetTickCount();
|
||||
readent++;
|
||||
@ -4460,3 +4616,96 @@ OpFailStatus MeosSQL::synchronizeUpdate(oBase *obj) {
|
||||
return OpFailStatus::opStatusFail;
|
||||
}
|
||||
|
||||
OpFailStatus MeosSQL::enumerateImages(vector<pair<wstring, uint64_t>>& images) {
|
||||
try {
|
||||
auto query = con->query();
|
||||
images.clear();
|
||||
auto res = query.store("SELECT Id, Filename FROM oImage");
|
||||
if (res) {
|
||||
for (int i = 0; i < res.num_rows(); i++) {
|
||||
auto row = res.at(i);
|
||||
wstring fileName = fromUTF((string)row["Filename"]);
|
||||
uint64_t id = row["Id"].ulonglong();
|
||||
images.emplace_back(fileName, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Exception& ) {
|
||||
return OpFailStatus::opStatusFail;
|
||||
}
|
||||
|
||||
return OpFailStatus::opStatusOK;
|
||||
}
|
||||
|
||||
OpFailStatus MeosSQL::getImage(uint64_t id, wstring& fileName, vector<uint8_t>& data) {
|
||||
try {
|
||||
auto query = con->query();
|
||||
auto res = query.store("SELECT * FROM oImage WHERE id=" + itos(id));
|
||||
if (res && res.num_rows() > 0) {
|
||||
auto row = res.at(0);
|
||||
fileName = fromUTF((string)row["Filename"]);
|
||||
row["Image"].storeBlob(data);
|
||||
return OpFailStatus::opStatusOK;
|
||||
}
|
||||
}
|
||||
catch (const Exception&) {
|
||||
}
|
||||
|
||||
return OpFailStatus::opStatusFail;
|
||||
}
|
||||
|
||||
string hexEncode(const vector<uint8_t>& data) {
|
||||
string out;
|
||||
out.reserve(4 + data.size() * 2);
|
||||
out.append("X'");
|
||||
|
||||
char table[17] = "0123456789ABCDEF";
|
||||
char block[33];
|
||||
block[32] = 0;
|
||||
|
||||
for (int j = 0; j < data.size();) {
|
||||
if (j + 16 < data.size()) {
|
||||
for (int i = 0; i < 32; ) {
|
||||
uint8_t b = data[j];
|
||||
int bLow = b & 0xF;
|
||||
int bHigh = (b >> 4) & 0xF;
|
||||
block[i++] = table[bHigh];
|
||||
block[i++] = table[bLow];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i = 0;
|
||||
while (j < data.size()) {
|
||||
uint8_t b = data[j];
|
||||
int bLow = b & 0xF;
|
||||
int bHigh = (b >> 4) & 0xF;
|
||||
block[i++] = table[bHigh];
|
||||
block[i++] = table[bLow];
|
||||
j++;
|
||||
}
|
||||
block[i] = 0;
|
||||
}
|
||||
|
||||
out.append(block);
|
||||
}
|
||||
out.append("'");
|
||||
return out;
|
||||
}
|
||||
|
||||
OpFailStatus MeosSQL::storeImage(uint64_t id, const wstring& fileName, const vector<uint8_t>& data) {
|
||||
try {
|
||||
auto query = con->query();
|
||||
auto res = query.store("SELECT Id FROM oImage WHERE Id=" + itos(id));
|
||||
if (res.empty()) {
|
||||
query << ("INSERT INTO oImage SET Id=" + itos(id) + ", Filename=")
|
||||
<< quote << toString(fileName) << ", Image=" << hexEncode(data);
|
||||
query.execute();
|
||||
}
|
||||
}
|
||||
catch (Exception &) {
|
||||
return OpFailStatus::opStatusFail;
|
||||
}
|
||||
|
||||
return OpFailStatus::opStatusOK;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -131,7 +131,7 @@ protected:
|
||||
bool checkOldVersion(oEvent *oe, RowWrapper &row);
|
||||
|
||||
map<pair<int, int>, DWORD> readTimes;
|
||||
void synchronized(const oBase &entity);
|
||||
void synchronized(oBase &entity);
|
||||
bool skipSynchronize(const oBase &entity) const;
|
||||
|
||||
ResNSel updateCounter(const char *oTable, int id, QueryWrapper *updateqry);
|
||||
@ -186,9 +186,14 @@ protected:
|
||||
OpFailStatus syncUpdate(oTeam *t, bool forceWriteAll);
|
||||
OpFailStatus syncRead(bool forceRead, oTeam *t);
|
||||
|
||||
void upgradeTimeFormat(const string &dbname);
|
||||
|
||||
public:
|
||||
|
||||
OpFailStatus enumerateImages(vector<pair<wstring, uint64_t>>& images);
|
||||
OpFailStatus getImage(uint64_t id, wstring &fileName, vector<uint8_t> &data);
|
||||
OpFailStatus storeImage(uint64_t id, const wstring& fileName, const vector<uint8_t>& data);
|
||||
|
||||
bool synchronizeList(oEvent *oe, oListId lid);
|
||||
OpFailStatus synchronizeUpdate(oBase *obj);
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -237,12 +237,12 @@ wstring RunnerWDBEntry::getFamilyName() const
|
||||
|
||||
__int64 RunnerWDBEntry::getExtId() const
|
||||
{
|
||||
return dbe().extId;
|
||||
return dbe().getExtId();
|
||||
}
|
||||
|
||||
void RunnerWDBEntry::setExtId(__int64 id)
|
||||
{
|
||||
dbe().extId = id;
|
||||
dbe().setExtId(id);
|
||||
}
|
||||
|
||||
void RunnerDBEntryV2::init(const RunnerDBEntryV1 &dbe)
|
||||
@ -303,7 +303,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const wchar_t *name,
|
||||
en.cardNo = card;
|
||||
en.clubNo = club;
|
||||
e.setName(name);
|
||||
en.extId = extId;
|
||||
en.setExtId(extId);
|
||||
|
||||
if (!check(en) ) {
|
||||
rdb.pop_back();
|
||||
@ -336,7 +336,7 @@ RunnerWDBEntry *RunnerDB::addRunner(const char *nameUTF,
|
||||
en.cardNo = card;
|
||||
en.clubNo = club;
|
||||
e.setNameUTF(nameUTF);
|
||||
en.extId = extId;
|
||||
en.setExtId(extId);
|
||||
|
||||
if (!check(en) ) {
|
||||
rdb.pop_back();
|
||||
@ -550,16 +550,16 @@ RunnerWDBEntry *RunnerDB::getRunnerByName(const wstring &name, int clubId,
|
||||
int bestYear = 0;
|
||||
for (size_t k = 0;k<ix2.size(); k++) {
|
||||
const RunnerWDBEntry &re = rwdb[ix2[k]];
|
||||
if (abs(re.dbe().birthYear-expectedBirthYear) < abs(bestYear-expectedBirthYear)) {
|
||||
if (abs(re.dbe().getBirthDay() - expectedBirthYear) < abs(bestYear - expectedBirthYear)) {
|
||||
bestMatch = ix2[k];
|
||||
bestYear = re.dbe().birthYear;
|
||||
bestYear = re.dbe().getBirthYear();
|
||||
}
|
||||
}
|
||||
if (bestYear>0)
|
||||
return (RunnerWDBEntry *)&rwdb[bestMatch];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RunnerDB::setupIdHash() const
|
||||
@ -569,7 +569,7 @@ void RunnerDB::setupIdHash() const
|
||||
|
||||
for (size_t k=0; k<rdb.size(); k++) {
|
||||
if (!rdb[k].isRemoved())
|
||||
idhash[rdb[k].extId] = int(k);
|
||||
idhash[rdb[k].getExtId()] = int(k);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1076,13 +1076,13 @@ void RunnerDB::updateAdd(const oRunner &r, map<int, int> &clubIdMap)
|
||||
if (dbe == nullptr) {
|
||||
dbe = addRunner(r.getName().c_str(), 0, localClubId, r.getCardNo());
|
||||
if (dbe)
|
||||
dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
|
||||
dbe->dbe().setBirthYear(r.getDCI().getInt("BirthYear"));
|
||||
}
|
||||
else {
|
||||
if (dbe->getExtId() == 0) { // Only update entries not in national db.
|
||||
dbe->setName(r.getName().c_str());
|
||||
dbe->dbe().clubNo = localClubId;
|
||||
dbe->dbe().birthYear = r.getDCI().getInt("BirthYear");
|
||||
dbe->dbe().setBirthYear(r.getDCI().getInt("BirthYear"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1251,13 +1251,13 @@ const shared_ptr<Table> &RunnerDB::getRunnerTB() {
|
||||
auto table = make_shared<Table>(oe, 20, L"Löpardatabasen", "runnerdb");
|
||||
|
||||
table->addColumn("Index", 70, true, true);
|
||||
table->addColumn("Id", 70, true, true);
|
||||
table->addColumn("Externt Id", 70, true, true);
|
||||
table->addColumn("Namn", 200, false);
|
||||
table->addColumn("Klubb", 200, false);
|
||||
table->addColumn("SI", 70, true, true);
|
||||
table->addColumn("Nationalitet", 70, false, true);
|
||||
table->addColumn("Kön", 50, false, true);
|
||||
table->addColumn("Födelseår", 70, true, true);
|
||||
table->addColumn("RunnerBirthDate", 70, true, true);
|
||||
table->addColumn("Anmäl", 120, false, true);
|
||||
|
||||
table->setTableProp(Table::CAN_INSERT|Table::CAN_DELETE|Table::CAN_PASTE);
|
||||
@ -1330,8 +1330,8 @@ void RunnerDB::refreshRunnerTableData(Table &table) {
|
||||
bool found = false;
|
||||
|
||||
pRunner r = nullptr;
|
||||
if (rdb[k].extId != 0)
|
||||
found = runnerInEvent.lookup(rdb[k].extId, runnerId);
|
||||
if (rdb[k].getExtId() != 0)
|
||||
found = runnerInEvent.lookup(rdb[k].getExtId(), runnerId);
|
||||
else if (rdb[k].cardNo != 0) {
|
||||
found = runnerInEvent.lookup(rdb[k].cardNo + cardIdConstant, runnerId);
|
||||
if (found) {
|
||||
@ -1404,8 +1404,8 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
|
||||
table.set(row++, it, TID_INDEX, itow(index+1), false, cellEdit);
|
||||
|
||||
wchar_t bf[16];
|
||||
oBase::converExtIdentifierString(rn.extId, bf);
|
||||
table.set(row++, it, TID_ID, bf, false, cellEdit);
|
||||
oBase::converExtIdentifierString(rn.getExtId(), bf);
|
||||
table.set(row++, it, TID_ID, bf, canEdit, cellEdit);
|
||||
r.initName();
|
||||
table.set(row++, it, TID_NAME, r.name, canEdit, cellEdit);
|
||||
|
||||
@ -1421,14 +1421,14 @@ void oDBRunnerEntry::addTableRow(Table &table) const {
|
||||
table.set(row++, it, TID_NATIONAL, nat, canEdit, cellEdit);
|
||||
wchar_t sex[2] = {wchar_t(rn.sex), 0};
|
||||
table.set(row++, it, TID_SEX, sex, canEdit, cellEdit);
|
||||
table.set(row++, it, TID_YEAR, itow(rn.birthYear), canEdit, cellEdit);
|
||||
table.set(row++, it, TID_YEAR, rn.getBirthDate(), canEdit, cellEdit);
|
||||
|
||||
int runnerId;
|
||||
bool found = false;
|
||||
|
||||
pRunner cr = nullptr;
|
||||
if (rn.extId != 0)
|
||||
found = db->runnerInEvent.lookup(rn.extId, runnerId);
|
||||
if (rn.getExtId() != 0)
|
||||
found = db->runnerInEvent.lookup(rn.getExtId(), runnerId);
|
||||
else if (rn.cardNo != 0) {
|
||||
found = db->runnerInEvent.lookup(rn.cardNo + cardIdConstant, runnerId);
|
||||
if (found) {
|
||||
@ -1467,8 +1467,29 @@ pair<int, bool> oDBRunnerEntry::inputData(int id, const wstring &input,
|
||||
throw meosException("Not initialized");
|
||||
RunnerWDBEntry &r = db->rwdb[index];
|
||||
RunnerDBEntry &rd = db->rdb[index];
|
||||
static bool hasWarnedId = false;
|
||||
|
||||
switch(id) {
|
||||
case TID_ID: {
|
||||
wchar_t bf[16];
|
||||
auto key = oBase::converExtIdentifierString(input);
|
||||
oBase::converExtIdentifierString(key, bf);
|
||||
|
||||
if (compareStringIgnoreCase(bf, input)) {
|
||||
throw meosException(L"Cannot represent ID X#" + input);
|
||||
}
|
||||
|
||||
if (key != r.getExtId() && !hasWarnedId) {
|
||||
if (oe->gdiBase().askOkCancel(L"warn:changeid") == gdioutput::AskAnswer::AnswerCancel)
|
||||
throw meosCancel();
|
||||
hasWarnedId = true;
|
||||
}
|
||||
|
||||
r.setExtId(key);
|
||||
db->idhash.clear();
|
||||
output = bf;
|
||||
}
|
||||
break;
|
||||
case TID_NAME:
|
||||
r.setName(input.c_str());
|
||||
r.getName(output);
|
||||
@ -1503,8 +1524,8 @@ pair<int, bool> oDBRunnerEntry::inputData(int id, const wstring &input,
|
||||
output = r.getSex();
|
||||
break;
|
||||
case TID_YEAR:
|
||||
rd.birthYear = short(_wtoi(input.c_str()));
|
||||
output = itow(r.getBirthYear());
|
||||
rd.setBirthDate(input);
|
||||
output = rd.getBirthDate();
|
||||
break;
|
||||
|
||||
case TID_CLUB:
|
||||
@ -1529,7 +1550,7 @@ void oDBRunnerEntry::fillInput(int id, vector< pair<wstring, size_t> > &out, siz
|
||||
void oDBRunnerEntry::remove() {
|
||||
RunnerWDBEntry &r = db->rwdb[index];
|
||||
r.remove();
|
||||
db->idhash.remove(r.dbe().extId);
|
||||
db->idhash.remove(r.dbe().getExtId());
|
||||
wstring cname(canonizeName(r.name));
|
||||
multimap<wstring, int>::const_iterator it = db->nhash.find(cname);
|
||||
|
||||
@ -1823,6 +1844,20 @@ vector<pair<RunnerWDBEntry *, int>> RunnerDB::getRunnerSuggestions(const wstring
|
||||
else
|
||||
setupAutoCompleteHash(AutoHashMode::Runners);
|
||||
|
||||
// Check if database key
|
||||
int64_t id = 0;
|
||||
for (int j = 0; j < key.length(); j++) {
|
||||
if (key[j] >= '0' && key[j] <= '9') {
|
||||
id = oBase::converExtIdentifierString(key);
|
||||
wchar_t bf[16];
|
||||
oBase::converExtIdentifierString(id, bf);
|
||||
if (compareStringIgnoreCase(key, bf))
|
||||
id = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vector< pair<int, int> > outOrder;
|
||||
set<pair<int, int>> ix;
|
||||
wchar_t bf[256];
|
||||
@ -1866,8 +1901,15 @@ vector<pair<RunnerWDBEntry *, int>> RunnerDB::getRunnerSuggestions(const wstring
|
||||
if (res != runnerHash.end())
|
||||
res->second.match(*this, ix, nameParts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (id > 0) {
|
||||
auto r = getRunnerById(id);
|
||||
if (r) {
|
||||
ix.emplace(1000, r->getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
if (ix.empty())
|
||||
return ret;
|
||||
|
||||
@ -1896,3 +1938,85 @@ vector<pair<RunnerWDBEntry *, int>> RunnerDB::getRunnerSuggestions(const wstring
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const wstring& RunnerDBEntry::getBirthDate() const {
|
||||
int year = getBirthYear();
|
||||
if (year <= 0 || year>9999)
|
||||
return _EmptyWString;
|
||||
|
||||
int month = getBirthMonth();
|
||||
if (month > 0 && month <= 12) {
|
||||
int day = getBirthDay();
|
||||
if (day > 0 && day <= 31) {
|
||||
wchar_t bf[16];
|
||||
swprintf_s(bf, L"%d-%02d-%02d", year, month, day);
|
||||
wstring& res = StringCache::getInstance().wget();
|
||||
res = bf;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return itow(year);
|
||||
}
|
||||
|
||||
void RunnerDBEntry::setBirthDate(const wstring& in) {
|
||||
SYSTEMTIME st;
|
||||
if (convertDateYMS(in, st, true) > 0) {
|
||||
setBirthYear(st.wYear);
|
||||
setBirthMonth(st.wMonth);
|
||||
setBirthDay(st.wDay);
|
||||
}
|
||||
else {
|
||||
int year = _wtoi(in.c_str());
|
||||
if (year > 1900 && year < 9999)
|
||||
setBirthYear(year);
|
||||
else
|
||||
setBirthYear(0);
|
||||
|
||||
setBirthMonth(0);
|
||||
setBirthDay(0);
|
||||
}
|
||||
}
|
||||
|
||||
void RunnerDBEntry::setBirthDate(int dateOrYear) {
|
||||
if (dateOrYear > 0 && dateOrYear < 100)
|
||||
dateOrYear = extendYear(dateOrYear);
|
||||
|
||||
if ((dateOrYear > 1900 && dateOrYear < 9999) || dateOrYear == 0) {
|
||||
setBirthYear(dateOrYear);
|
||||
setBirthMonth(0);
|
||||
setBirthDay(0);
|
||||
return;
|
||||
}
|
||||
int d = dateOrYear % 100;
|
||||
dateOrYear /= 100;
|
||||
|
||||
int m = dateOrYear % 100;
|
||||
dateOrYear /= 100;
|
||||
|
||||
int y = extendYear(dateOrYear);
|
||||
if (d > 0 && d <= 31 && m > 0 && m <= 12 && y > 1900 && y < 9999) {
|
||||
setBirthYear(y);
|
||||
setBirthMonth(m);
|
||||
setBirthDay(d);
|
||||
}
|
||||
else if (y > 1900 && y < 9999) {
|
||||
setBirthYear(y);
|
||||
}
|
||||
else {
|
||||
setBirthYear(0);
|
||||
setBirthMonth(0);
|
||||
setBirthDay(0);
|
||||
}
|
||||
}
|
||||
|
||||
int RunnerDBEntry::getBirthDateInt() const {
|
||||
int y = getBirthYear();
|
||||
int m = getBirthMonth();
|
||||
int d = getBirthDay();
|
||||
|
||||
if (y > 0 && y < 9999 && m > 0 && d > 0)
|
||||
return y * 10000 + m * 100 + d;
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -97,11 +97,13 @@ struct RunnerDBEntry {
|
||||
int clubNo;
|
||||
char national[3];
|
||||
char sex;
|
||||
private:
|
||||
short int birthYear;
|
||||
short int reserved;
|
||||
/** End of V1*/
|
||||
__int64 extId;
|
||||
|
||||
public:
|
||||
bool isRemoved() const { return (reserved & 1) == 1; }
|
||||
void remove() { reserved |= 1; }
|
||||
|
||||
@ -111,6 +113,22 @@ struct RunnerDBEntry {
|
||||
bool operator==(const RunnerDBEntry &d) const {
|
||||
return memcmp(this, &d, sizeof(RunnerDBEntry)) == 0;
|
||||
}
|
||||
|
||||
int getBirthYear() const { return birthYear; }
|
||||
int getBirthMonth() const { return (reserved >> 2) & 0xF; }// 4 bits
|
||||
int getBirthDay() const { return (reserved >> 6) & 0x1F; } // 5 bits
|
||||
|
||||
void setBirthYear(int year) { birthYear = year; }
|
||||
void setBirthMonth(int month) { reserved = (reserved & (~(0xF << 2))) | ((0xF & month) << 2); }// 4 bits
|
||||
void setBirthDay(int day) { reserved = (reserved & (~(0x1F << 6))) | ((0x1F & day) << 6); } // 5 bits
|
||||
|
||||
const wstring& getBirthDate() const;
|
||||
void setBirthDate(const wstring& in);
|
||||
void setBirthDate(int dateOrYear);
|
||||
int getBirthDateInt() const;
|
||||
|
||||
void setExtId(__int64 id) { extId = id; }
|
||||
__int64 getExtId() const { return extId; }
|
||||
};
|
||||
|
||||
class RunnerDB;
|
||||
@ -125,6 +143,8 @@ public:
|
||||
void init(RunnerDB *p, size_t ix);
|
||||
RunnerWDBEntry();
|
||||
|
||||
size_t getIndex() const { return ix; }
|
||||
|
||||
// Link to narrow DB Entry
|
||||
const RunnerDBEntry &dbe() const;
|
||||
RunnerDBEntry &dbe();
|
||||
@ -145,14 +165,14 @@ public:
|
||||
wstring getFamilyName() const;
|
||||
|
||||
wstring getNationality() const;
|
||||
int getBirthYear() const {return dbe().birthYear;}
|
||||
int getBirthYear() const {return dbe().getBirthYear(); }
|
||||
wstring getSex() const;
|
||||
|
||||
__int64 getExtId() const;
|
||||
void setExtId(__int64 id);
|
||||
|
||||
bool isRemoved() const {return (dbe().reserved & 1) == 1;}
|
||||
void remove() {dbe().reserved |= 1;}
|
||||
bool isRemoved() const { return dbe().isRemoved(); }
|
||||
void remove() { dbe().remove(); }
|
||||
};
|
||||
|
||||
typedef vector<RunnerDBEntry> RunnerDBVector;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -46,11 +46,11 @@
|
||||
//#define DEBUG_SI
|
||||
|
||||
SI_StationData::SI_StationData() {
|
||||
stationNumber=0;
|
||||
stationMode=0;
|
||||
extended=false;
|
||||
handShake=false;
|
||||
autoSend=false;
|
||||
stationNumber = 0;
|
||||
stationMode = 0;
|
||||
extended = false;
|
||||
handShake = false;
|
||||
autoSend = false;
|
||||
radioChannel = 0;
|
||||
}
|
||||
|
||||
@ -64,19 +64,28 @@ SI_StationInfo::SI_StationInfo()
|
||||
localZeroTime=0;
|
||||
}
|
||||
|
||||
SportIdent::SportIdent(HWND hWnd, DWORD Id, bool readVoltage) : readVoltage(readVoltage)
|
||||
{
|
||||
ClassId=Id;
|
||||
hWndNotify=hWnd;
|
||||
SportIdent::SportIdent(HWND hWnd, DWORD Id, bool readVoltage) : readVoltage(readVoltage) {
|
||||
ClassId = Id;
|
||||
hWndNotify = hWnd;
|
||||
|
||||
//hComm=0;
|
||||
//ThreadHandle=0;
|
||||
n_SI_Info=0;
|
||||
n_SI_Info = 0;
|
||||
|
||||
InitializeCriticalSection(&SyncObj);
|
||||
|
||||
tcpPortOpen=0;
|
||||
serverSocket=0;
|
||||
tcpPortOpen = 0;
|
||||
serverSocket = 0;
|
||||
punchMap.resize(31, 0);
|
||||
punchMap[oPunch::SpecialPunch::PunchStart] = oPunch::SpecialPunch::PunchStart;
|
||||
punchMap[oPunch::SpecialPunch::PunchCheck] = oPunch::SpecialPunch::PunchCheck;
|
||||
punchMap[oPunch::SpecialPunch::PunchFinish] = oPunch::SpecialPunch::PunchFinish;
|
||||
}
|
||||
|
||||
void SportIdent::resetPunchMap() {
|
||||
punchMap.resize(31, 0);
|
||||
fill(punchMap.begin(), punchMap.end(), 0);
|
||||
punchMap[oPunch::SpecialPunch::PunchStart] = oPunch::SpecialPunch::PunchStart;
|
||||
punchMap[oPunch::SpecialPunch::PunchCheck] = oPunch::SpecialPunch::PunchCheck;
|
||||
punchMap[oPunch::SpecialPunch::PunchFinish] = oPunch::SpecialPunch::PunchFinish;
|
||||
}
|
||||
|
||||
SportIdent::~SportIdent()
|
||||
@ -299,7 +308,7 @@ string decode(BYTE *bf, int read)
|
||||
bool SportIdent::openComListen(const wchar_t *com, DWORD BaudRate) {
|
||||
closeCom(com);
|
||||
|
||||
SI_StationInfo *si = findStation(com);
|
||||
SI_StationInfo *si = findStationInt(com);
|
||||
|
||||
if (!si) {
|
||||
SI_Info[n_SI_Info].ComPort=com;
|
||||
@ -309,6 +318,9 @@ bool SportIdent::openComListen(const wchar_t *com, DWORD BaudRate) {
|
||||
}
|
||||
si->data.clear();
|
||||
|
||||
if (si->ComPort == L"TEST")
|
||||
return true; // Passive test
|
||||
|
||||
wstring comfile=wstring(L"//./")+com;
|
||||
si->hComm = CreateFile( comfile.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
@ -355,7 +367,7 @@ bool SportIdent::tcpAddPort(int port, DWORD zeroTime)
|
||||
{
|
||||
closeCom(L"TCP");
|
||||
|
||||
SI_StationInfo *si = findStation(L"TCP");
|
||||
SI_StationInfo *si = findStationInt(L"TCP");
|
||||
|
||||
if (!si) {
|
||||
SI_Info[n_SI_Info].ComPort=L"TCP";
|
||||
@ -374,7 +386,7 @@ bool SportIdent::openCom(const wchar_t *com)
|
||||
{
|
||||
closeCom(com);
|
||||
|
||||
SI_StationInfo *si = findStation(com);
|
||||
SI_StationInfo *si = findStationInt(com);
|
||||
|
||||
if (!si) {
|
||||
SI_Info[n_SI_Info].ComPort=com;
|
||||
@ -386,7 +398,7 @@ bool SportIdent::openCom(const wchar_t *com)
|
||||
si->data.clear();
|
||||
|
||||
if (si->ComPort == L"TEST") {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring comfile=wstring(L"//./")+com;
|
||||
@ -511,9 +523,7 @@ bool SportIdent::openCom(const wchar_t *com)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SI_StationInfo *SportIdent::findStation(const wstring &com)
|
||||
{
|
||||
SI_StationInfo* SportIdent::findStationInt(const wstring& com) {
|
||||
if (com == L"TEST" && n_SI_Info < 30) {
|
||||
if (n_SI_Info == 0 || SI_Info[n_SI_Info - 1].ComPort != com) {
|
||||
SI_Info[n_SI_Info].ComPort = com;
|
||||
@ -521,6 +531,26 @@ SI_StationInfo *SportIdent::findStation(const wstring &com)
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_SI_Info; i++)
|
||||
if (com == SI_Info[i].ComPort)
|
||||
return &SI_Info[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SportIdent::addTestStation(const wstring& com) {
|
||||
SI_Info[n_SI_Info].ComPort = com;
|
||||
n_SI_Info++;
|
||||
}
|
||||
|
||||
const SI_StationInfo *SportIdent::findStation(const wstring &com) const
|
||||
{
|
||||
if (com == L"TEST" && n_SI_Info < 30) {
|
||||
if (n_SI_Info == 0 || SI_Info[n_SI_Info - 1].ComPort != com) {
|
||||
const_cast<SportIdent*>(this)->addTestStation(com);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<n_SI_Info; i++)
|
||||
if (com == SI_Info[i].ComPort)
|
||||
return &SI_Info[i];
|
||||
@ -537,7 +567,7 @@ void SportIdent::closeCom(const wchar_t *com)
|
||||
}
|
||||
else
|
||||
{
|
||||
SI_StationInfo *si = findStation(com);
|
||||
SI_StationInfo *si = findStationInt(com);
|
||||
|
||||
if (si && si->ComPort==L"TCP") {
|
||||
if (tcpPortOpen) {
|
||||
@ -890,7 +920,7 @@ int SportIdent::MonitorTCPSI(WORD port, int localZeroTime)
|
||||
}
|
||||
}
|
||||
else
|
||||
addPunch(op.CodeTime/10, op.CodeNo, op.SICardNo, 0);
|
||||
addPunch(op.CodeTime, op.CodeNo, op.SICardNo, 0);
|
||||
}
|
||||
else r=-1;
|
||||
|
||||
@ -933,10 +963,10 @@ bool SportIdent::MonitorTEST(SI_StationInfo &si)
|
||||
|
||||
SICard card(ConvertedTimeStatus::Hour12);
|
||||
card.StartPunch.Code = 1;
|
||||
int t = card.StartPunch.Time = 3600*8 + rand()%1000;
|
||||
int t = card.StartPunch.Time = timeConstHour*8 + rand()%1000;
|
||||
|
||||
card.FinishPunch.Code = 2;
|
||||
card.FinishPunch.Time = card.StartPunch.Time + 1800 + rand() % 3600;
|
||||
card.FinishPunch.Time = card.StartPunch.Time + timeConstHour/2 + rand() % timeConstHour;
|
||||
card.CardNumber = tc.cardNo;
|
||||
|
||||
for (size_t k = 0; k < tc.punches.size(); k++) {
|
||||
@ -947,8 +977,8 @@ bool SportIdent::MonitorTEST(SI_StationInfo &si)
|
||||
}
|
||||
addCard(card);
|
||||
|
||||
//Sleep(300 + rand()%600);
|
||||
Sleep(0);
|
||||
Sleep(300 + rand()%600);
|
||||
//Sleep(0);
|
||||
if (++longSleepIter > 20) {
|
||||
Sleep(100 + rand() % 600);
|
||||
longSleepIter = 0;
|
||||
@ -1002,12 +1032,15 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
|
||||
DWORD Card=MAKELONG(MAKEWORD(bf[7], bf[6]), MAKEWORD(bf[5], bf[4]));
|
||||
|
||||
if (Series<=4 && Series>=1)
|
||||
Card=ShortCard+100000*Series;
|
||||
if (Series <= 4 && Series >= 1)
|
||||
Card = ShortCard + 100000 * Series;
|
||||
|
||||
DWORD Time=0;
|
||||
if (bf[8]&0x1) Time=3600*12;
|
||||
Time+=MAKEWORD(bf[10], bf[9]);
|
||||
if (bf[8] & 0x1) Time = timeConstHour * 12;
|
||||
Time += MAKEWORD(bf[10], bf[9])*timeConstSecond;
|
||||
uint8_t tss = bf[11]; // Sub second 1/256 seconds
|
||||
int tenth = (((100 * tss) / 256) + 4) / 10;
|
||||
Time += tenth;
|
||||
#ifdef DEBUG_SI
|
||||
char str[128];
|
||||
sprintf_s(str, "EXTENDED: Card = %d, Station = %d, StationMode = %d", Card, Station, si.StationMode);
|
||||
@ -1040,9 +1073,9 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
//if (Series!=1)
|
||||
// Card+=100000*Series;
|
||||
|
||||
DWORD Time=MAKEWORD(bf[8], bf[7]);
|
||||
DWORD Time = MAKEWORD(bf[8], bf[7]) * timeConstSecond;
|
||||
BYTE p=bf[1];
|
||||
if (p&0x1) Time+=3600*12;
|
||||
if (p&0x1) Time+=timeConstHour*12;
|
||||
|
||||
#ifdef DEBUG_SI
|
||||
char str[128];
|
||||
@ -1100,7 +1133,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
bf[0]=chRead;
|
||||
readBytes(bf+1, 200, hComm);
|
||||
//GetSI5DataExt(hComm);
|
||||
MessageBox(NULL, L"Programmera stationen utan AUTOSEND!", NULL, MB_OK);
|
||||
MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1108,7 +1141,7 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
BYTE bf[200];
|
||||
bf[0]=chRead;
|
||||
readBytes(bf+1, 200, hComm);
|
||||
MessageBox(NULL, L"Programmera stationen utan AUTOSEND!", NULL, MB_OK);
|
||||
MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
|
||||
}
|
||||
break;
|
||||
case 0xE8:{
|
||||
@ -1125,7 +1158,6 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
// MessageBox(NULL, "SI-card not supported", NULL, MB_OK);
|
||||
// break;
|
||||
default:
|
||||
|
||||
BYTE bf[128];
|
||||
bf[0]=chRead;
|
||||
int rb=readBytes(bf+1, 120, hComm);
|
||||
@ -1146,6 +1178,9 @@ bool SportIdent::MonitorSI(SI_StationInfo &si)
|
||||
st+=d;
|
||||
}
|
||||
}
|
||||
|
||||
if (chRead == 0xEF)
|
||||
MessageBox(NULL, lang.tl(L"Programmera stationen utan AUTOSEND").c_str(), NULL, MB_OK);
|
||||
//MessageBox(NULL, st.c_str(), "Unknown SI response", MB_OK);
|
||||
}
|
||||
}
|
||||
@ -1650,8 +1685,6 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card)
|
||||
analyseSI5Time(data+5, card.FinishPunch.Time, card.FinishPunch.Code);
|
||||
analyseSI5Time(data+9, card.CheckPunch.Time, card.CheckPunch.Code);
|
||||
|
||||
// card.StartPunch=MAKEWORD(data[4], data[3]);
|
||||
// card.FinishPunch=MAKEWORD(data[6], data[5]);
|
||||
card.nPunch=data[7]-1;
|
||||
|
||||
data+=16;
|
||||
@ -1660,7 +1693,7 @@ bool SportIdent::getCard5Data(BYTE *data, SICard &card)
|
||||
if (k<30) {
|
||||
DWORD basepointer=3*(k%5)+1+(k/5)*16;
|
||||
DWORD code=data[basepointer];
|
||||
DWORD time;//=MAKEWORD(data[basepointer+2],data[basepointer+1]);
|
||||
DWORD time;
|
||||
DWORD slask;
|
||||
analyseSI5Time(data+basepointer+1, time, slask);
|
||||
|
||||
@ -1710,29 +1743,29 @@ bool SportIdent::getCard9Data(BYTE *data, SICard &card)
|
||||
int series = data[24] & 15;
|
||||
|
||||
card.convertedTime = ConvertedTimeStatus::Hour24;
|
||||
analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code);
|
||||
analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code);
|
||||
analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code);
|
||||
analysePunch(data+12, card.StartPunch.Time, card.StartPunch.Code, useSubsecondMode);
|
||||
analysePunch(data+16, card.FinishPunch.Time, card.FinishPunch.Code, useSubsecondMode);
|
||||
analysePunch(data+8, card.CheckPunch.Time, card.CheckPunch.Code, false);
|
||||
|
||||
if (series == 1) {
|
||||
// SI Card 9
|
||||
card.nPunch=min(int(data[22]), 50);
|
||||
for(unsigned k=0;k<card.nPunch;k++) {
|
||||
analysePunch(14*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code);
|
||||
analysePunch(14*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code, false);
|
||||
}
|
||||
}
|
||||
else if (series == 2) {
|
||||
// SI Card 8
|
||||
card.nPunch=min(int(data[22]), 30);
|
||||
for(unsigned k=0;k<card.nPunch;k++) {
|
||||
analysePunch(34*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code);
|
||||
analysePunch(34*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code, false);
|
||||
}
|
||||
}
|
||||
else if (series == 4) {
|
||||
// pCard
|
||||
card.nPunch=min(int(data[22]), 20);
|
||||
for(unsigned k=0;k<card.nPunch;k++) {
|
||||
analysePunch(44*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code);
|
||||
analysePunch(44*4 + data + 4*k, card.Punch[k].Time, card.Punch[k].Code, false);
|
||||
}
|
||||
}
|
||||
else if (series == 6) {
|
||||
@ -1751,7 +1784,7 @@ bool SportIdent::getCard9Data(BYTE *data, SICard &card)
|
||||
// Card 10, 11, SIAC
|
||||
card.nPunch=min(int(data[22]), 128);
|
||||
for(unsigned k=0;k<card.nPunch;k++) {
|
||||
analysePunch(data + 128 + 4*k, card.Punch[k].Time, card.Punch[k].Code);
|
||||
analysePunch(data + 128 + 4*k, card.Punch[k].Time, card.Punch[k].Code, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1774,7 +1807,7 @@ void SportIdent::analyseTPunch(BYTE *data, DWORD &time, DWORD &control) {
|
||||
// BYTE day = (dt0 >> 1) & 0x1F;
|
||||
|
||||
control=cn;
|
||||
time=MAKEWORD(ptl, pth)+3600*12*(dt0&0x1);
|
||||
time = MAKEWORD(ptl, pth) * timeConstSecond + timeConstHour * 12 * (dt0 & 0x1);
|
||||
}
|
||||
else {
|
||||
control=-1;
|
||||
@ -1810,9 +1843,9 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
|
||||
// DWORD control;
|
||||
// DWORD time;
|
||||
card.convertedTime = ConvertedTimeStatus::Hour24;
|
||||
analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code);
|
||||
analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code);
|
||||
analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code);
|
||||
analysePunch(data+8, card.StartPunch.Time, card.StartPunch.Code, useSubsecondMode);
|
||||
analysePunch(data+4, card.FinishPunch.Time, card.FinishPunch.Code, useSubsecondMode);
|
||||
analysePunch(data+12, card.CheckPunch.Time, card.CheckPunch.Code, false);
|
||||
card.nPunch=min(int(data[2]), 192);
|
||||
|
||||
int i;
|
||||
@ -1843,12 +1876,12 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
|
||||
data+=128-16;
|
||||
|
||||
for(unsigned k=0;k<card.nPunch;k++) {
|
||||
analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code);
|
||||
analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code, false);
|
||||
}
|
||||
|
||||
// Check for extra punches, SI6-bug
|
||||
for (unsigned k = card.nPunch; k < 192; k++) {
|
||||
if (!analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code)) {
|
||||
if (!analysePunch(data+4*k, card.Punch[k].Time, card.Punch[k].Code, false)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
@ -1860,7 +1893,7 @@ bool SportIdent::getCard6Data(BYTE *data, SICard &card)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SportIdent::analysePunch(BYTE *data, DWORD &time, DWORD &control) {
|
||||
bool SportIdent::analysePunch(BYTE *data, DWORD &time, DWORD &control, bool subSecond) {
|
||||
if (*LPDWORD(data)!=0xEEEEEEEE && *LPDWORD(data)!=0x0)
|
||||
{
|
||||
BYTE ptd=data[0];
|
||||
@ -1868,8 +1901,16 @@ bool SportIdent::analysePunch(BYTE *data, DWORD &time, DWORD &control) {
|
||||
BYTE pth=data[2];
|
||||
BYTE ptl=data[3];
|
||||
|
||||
control=cn+256*((ptd>>6)&0x3);
|
||||
time=MAKEWORD(ptl, pth)+3600*12*(ptd&0x1);
|
||||
time = timeConstSecond * MAKEWORD(ptl, pth) + timeConstHour * 12 * (ptd & 0x1);
|
||||
if (!subSecond) {
|
||||
control = cn + 256 * ((ptd >> 6) & 0x3);
|
||||
}
|
||||
else {
|
||||
control = 0;
|
||||
uint8_t tss = data[1]; // Sub second 1/256 seconds
|
||||
int tenth = (((100 * tss) / 256) + 4) / 10;
|
||||
time += tenth;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -1880,15 +1921,15 @@ bool SportIdent::analysePunch(BYTE *data, DWORD &time, DWORD &control) {
|
||||
}
|
||||
}
|
||||
|
||||
void SportIdent::analyseSI5Time(BYTE *data, DWORD &time, DWORD &control)
|
||||
void SportIdent::analyseSI5Time(BYTE* data, DWORD& time, DWORD& control)
|
||||
{
|
||||
if (*LPWORD(data)!=0xEEEE) {
|
||||
time=MAKEWORD(data[1], data[0]);
|
||||
control=0;
|
||||
if (*LPWORD(data) != 0xEEEE) {
|
||||
time = MAKEWORD(data[1], data[0]) * timeConstSecond;
|
||||
control = 0;
|
||||
}
|
||||
else {
|
||||
control=-1;
|
||||
time=0;
|
||||
control = -1;
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1906,17 +1947,17 @@ void SICard::analyseHour12Time(DWORD zeroTime) {
|
||||
}
|
||||
|
||||
void SIPunch::analyseHour12Time(DWORD zeroTime) {
|
||||
if (Code != -1 && Time>=0 && Time <=12*3600) {
|
||||
if (zeroTime < 12 * 3600) {
|
||||
if (Code != -1 && Time>=0 && Time <=12*timeConstHour) {
|
||||
if (zeroTime < 12 * timeConstHour) {
|
||||
//Förmiddag
|
||||
if (Time < zeroTime)
|
||||
Time += 12 * 3600; //->Eftermiddag
|
||||
Time += 12 * timeConstHour; //->Eftermiddag
|
||||
}
|
||||
else {
|
||||
//Eftermiddag
|
||||
if (Time >= zeroTime % (12 * 3600)) {
|
||||
if (Time >= zeroTime % (12 * timeConstHour)) {
|
||||
//Eftermiddag
|
||||
Time += 12 * 3600;
|
||||
Time += 12 * timeConstHour;
|
||||
}
|
||||
// else Efter midnatt OK.
|
||||
}
|
||||
@ -1985,50 +2026,67 @@ void SportIdent::addCard(const SICard &sic)
|
||||
PostMessage(hWndNotify, WM_USER, ClassId, 0);
|
||||
}
|
||||
|
||||
void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode)
|
||||
{
|
||||
void SportIdent::addPunch(DWORD Time, int Station, int Card, int Mode) {
|
||||
if (!useSubsecondMode)
|
||||
Time -= (Time % timeConstSecond);
|
||||
|
||||
SICard sic(ConvertedTimeStatus::Hour24);
|
||||
sic.CardNumber=Card;
|
||||
sic.CardNumber = Card;
|
||||
sic.StartPunch.Code = -1;
|
||||
sic.CheckPunch.Code = -1;
|
||||
sic.FinishPunch.Code = -1;
|
||||
|
||||
if (Mode==0 || Mode == 11){ // 11 is dongle
|
||||
if (Station>30){
|
||||
sic.Punch[0].Code=Station;
|
||||
sic.Punch[0].Time=Time;
|
||||
sic.nPunch=1;
|
||||
auto mapPunch = [this](int code) {
|
||||
if (code > 0 && code < punchMap.size() && punchMap[code] > 0)
|
||||
return punchMap[code];
|
||||
else
|
||||
return code;
|
||||
};
|
||||
|
||||
if (Mode == 0 || Mode == 11) { // 11 is dongle
|
||||
int code = (Station & 0xFFFF);
|
||||
int mappedCode = mapPunch(code);
|
||||
int unit = 0;
|
||||
if (mappedCode != code)
|
||||
unit = code;
|
||||
else
|
||||
unit = (Station >> 16) & 0xFFFF;
|
||||
|
||||
if (mappedCode > 30) {
|
||||
sic.Punch[0].Code = Station;
|
||||
sic.Punch[0].Time = Time;
|
||||
sic.nPunch = 1;
|
||||
}
|
||||
else if (Station == oPunch::PunchStart) {
|
||||
else if (mappedCode == oPunch::PunchStart) {
|
||||
sic.StartPunch.Time = Time;
|
||||
sic.StartPunch.Code = oPunch::PunchStart;
|
||||
sic.StartPunch.Code = unit;
|
||||
}
|
||||
else if (Station == oPunch::PunchCheck) {
|
||||
else if (mappedCode == oPunch::PunchCheck) {
|
||||
sic.CheckPunch.Time = Time;
|
||||
sic.CheckPunch.Code = oPunch::PunchCheck;
|
||||
sic.CheckPunch.Code = unit;
|
||||
}
|
||||
else{
|
||||
sic.FinishPunch.Time=Time;
|
||||
sic.FinishPunch.Code = oPunch::PunchFinish;
|
||||
else {
|
||||
sic.FinishPunch.Time = Time;
|
||||
sic.FinishPunch.Code = unit;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (Mode==0x02 || Mode == 50){
|
||||
sic.Punch[0].Code=Station;
|
||||
sic.Punch[0].Time=Time;
|
||||
sic.nPunch=1;
|
||||
else {
|
||||
if (Mode == 0x02 || Mode == 50) {
|
||||
sic.Punch[0].Code = Station;
|
||||
sic.Punch[0].Time = Time;
|
||||
sic.nPunch = 1;
|
||||
}
|
||||
else if (Mode == 3) {
|
||||
sic.StartPunch.Time=Time;
|
||||
sic.StartPunch.Code = oPunch::PunchStart;
|
||||
sic.StartPunch.Time = Time;
|
||||
sic.StartPunch.Code = Station;
|
||||
}
|
||||
else if (Mode == 10) {
|
||||
sic.CheckPunch.Time=Time;
|
||||
sic.CheckPunch.Code = oPunch::PunchCheck;
|
||||
sic.CheckPunch.Time = Time;
|
||||
sic.CheckPunch.Code = Station;
|
||||
}
|
||||
else{
|
||||
sic.FinishPunch.Time=Time;
|
||||
sic.FinishPunch.Code = oPunch::PunchFinish;
|
||||
else {
|
||||
sic.FinishPunch.Time = Time;
|
||||
sic.FinishPunch.Code = Station;
|
||||
}
|
||||
}
|
||||
sic.punchOnly = true;
|
||||
@ -2084,9 +2142,8 @@ void start_si_thread(void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void SportIdent::startMonitorThread(const wchar_t *com)
|
||||
{
|
||||
SI_StationInfo *si = findStation(com);
|
||||
void SportIdent::startMonitorThread(const wchar_t *com) {
|
||||
SI_StationInfo *si = findStationInt(com);
|
||||
|
||||
if (si && (si->hComm || si->ComPort==L"TCP" || si->ComPort == L"TEST"))
|
||||
{
|
||||
@ -2119,7 +2176,7 @@ void checkport_si_thread(void *ptr)
|
||||
*port=0; //No SI found here
|
||||
else {
|
||||
bool valid = true;
|
||||
SI_StationInfo *sii = si.findStation(bf);
|
||||
const SI_StationInfo *sii = ((const SportIdent &)si).findStation(bf);
|
||||
if (sii) {
|
||||
if (sii->data.empty() || sii->data[0].stationNumber>=1024 || sii->data[0].stationMode>15 ||
|
||||
!(sii->data[0].autoSend || sii->data[0].handShake))
|
||||
@ -2178,7 +2235,7 @@ bool SportIdent::autoDetect(list<int> &ComPorts)
|
||||
|
||||
bool SportIdent::isPortOpen(const wstring &com)
|
||||
{
|
||||
SI_StationInfo *si = findStation(com);
|
||||
const SI_StationInfo *si = findStation(com);
|
||||
|
||||
if (si && si->ComPort==L"TCP")
|
||||
return tcpPortOpen && serverSocket;
|
||||
@ -2186,25 +2243,61 @@ bool SportIdent::isPortOpen(const wstring &com)
|
||||
return si!=0 && si->hComm && si->ThreadHandle;
|
||||
}
|
||||
|
||||
void SportIdent::getInfoString(const wstring &com, vector<wstring> &infov)
|
||||
{
|
||||
|
||||
bool SportIdent::isAnyOpenUnkownUnit() const {
|
||||
if (tcpPortOpen && serverSocket)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < n_SI_Info; i++) {
|
||||
auto& si = SI_Info[i];
|
||||
auto& com = si.ComPort;
|
||||
|
||||
if (com == L"TCP")
|
||||
continue;
|
||||
|
||||
if (com == L"TEST")
|
||||
return true;
|
||||
|
||||
if (!(si.hComm && si.ThreadHandle))
|
||||
continue; // Not open
|
||||
|
||||
if (si.data.empty())
|
||||
return true; // Listen mode (no contact made)
|
||||
|
||||
switch (si.data[0].stationMode) {
|
||||
case 2: // Known modes
|
||||
case 50:
|
||||
case 4:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 10:
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SportIdent::getInfoString(const wstring &com, vector<pair<bool, wstring>> &infov) const {
|
||||
infov.clear();
|
||||
SI_StationInfo *si = findStation(com);
|
||||
const SI_StationInfo *si = findStation(com);
|
||||
|
||||
if (com==L"TCP") {
|
||||
if (!si || !tcpPortOpen || !serverSocket) {
|
||||
infov.push_back(L"TCP: "+lang.tl(L"ej aktiv."));
|
||||
infov.emplace_back(false, L"TCP: "+lang.tl(L"ej aktiv."));
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t bf[128];
|
||||
swprintf_s(bf, lang.tl(L"TCP: Port %d, Nolltid: %s").c_str(), tcpPortOpen, L"00:00:00");//WCS
|
||||
infov.push_back(bf);
|
||||
infov.emplace_back(false, bf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(si!=0 && si->hComm && si->ThreadHandle)) {
|
||||
infov.push_back(com+L": "+lang.tl(L"ej aktiv."));
|
||||
infov.emplace_back(false, com+L": "+lang.tl(L"ej aktiv."));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2221,7 +2314,7 @@ void SportIdent::getInfoString(const wstring &com, vector<wstring> &infov)
|
||||
switch(da.stationMode){
|
||||
case 2:
|
||||
case 50:
|
||||
info+=lang.tl(L"Kontrol");
|
||||
info+=lang.tl(L"Kontroll");
|
||||
break;
|
||||
case 4:
|
||||
info+=lang.tl(L"Mål");
|
||||
@ -2256,12 +2349,15 @@ void SportIdent::getInfoString(const wstring &com, vector<wstring> &infov)
|
||||
else if (da.handShake) info+=lang.tl(L"handskakning.");
|
||||
else info+=lang.tl(L"[VARNING] ingen/okänd.");
|
||||
|
||||
infov.push_back(info);
|
||||
infov.emplace_back(false, info);
|
||||
|
||||
if (da.autoSend && da.stationMode == 5)
|
||||
infov.emplace_back(true, lang.tl("Programmera stationen utan AUTOSEND"));
|
||||
}
|
||||
}
|
||||
|
||||
static string formatTimeN(int t) {
|
||||
const wstring &wt = formatTime(t);
|
||||
const wstring &wt = formatTime(t, SubSecond::Auto);
|
||||
string nt(wt.begin(), wt.end());
|
||||
return nt;
|
||||
}
|
||||
@ -2411,7 +2507,7 @@ unsigned int SICard::calculateHash() const {
|
||||
}
|
||||
|
||||
string SICard::serializePunches() const {
|
||||
string ser;
|
||||
string ser = "*";// Mark of time factor
|
||||
if (CheckPunch.Code != -1)
|
||||
ser += "C-" + itos(CheckPunch.Time);
|
||||
|
||||
@ -2437,24 +2533,31 @@ void SICard::deserializePunches(const string &arg) {
|
||||
StartPunch.Code = -1;
|
||||
CheckPunch.Code = -1;
|
||||
vector<string> out;
|
||||
split(arg, ";", out);
|
||||
int timeFactor = 10;
|
||||
if (arg.length() > 1 && arg[0] == '*') {
|
||||
split(arg.c_str() + 2, ";", out);
|
||||
timeFactor = 1;
|
||||
}
|
||||
else {
|
||||
split(arg, ";", out);
|
||||
}
|
||||
nPunch = 0;
|
||||
for (size_t k = 0; k< out.size(); k++) {
|
||||
vector<string> mark;
|
||||
split(out[k], "-", mark);
|
||||
if (mark.size() != 2)
|
||||
if (mark.size() != 2 || mark[0].empty())
|
||||
throw std::exception("Invalid string");
|
||||
DWORD *tp = 0;
|
||||
if (mark[0] == "F") {
|
||||
FinishPunch.Code = 1;
|
||||
if (mark[0][0] == 'F') {
|
||||
FinishPunch.Code = atoi(mark[0].c_str() + 1);
|
||||
tp = &FinishPunch.Time;
|
||||
}
|
||||
else if (mark[0] == "S") {
|
||||
StartPunch.Code = 1;
|
||||
else if (mark[0][0] == 'S') {
|
||||
StartPunch.Code = atoi(mark[0].c_str() + 1);
|
||||
tp = &StartPunch.Time;
|
||||
}
|
||||
else if (mark[0] == "C") {
|
||||
CheckPunch.Code = 1;
|
||||
else if (mark[0][0] == 'C') {
|
||||
CheckPunch.Code = atoi(mark[0].c_str() + 1);
|
||||
tp = &CheckPunch.Time;
|
||||
}
|
||||
else {
|
||||
@ -2462,12 +2565,51 @@ void SICard::deserializePunches(const string &arg) {
|
||||
tp = &Punch[nPunch++].Time;
|
||||
}
|
||||
|
||||
*tp = atoi(mark[1].c_str());
|
||||
*tp = atoi(mark[1].c_str()) * timeFactor;
|
||||
}
|
||||
if (out.size() == 1)
|
||||
punchOnly = true;
|
||||
}
|
||||
|
||||
int SICard::getFirstTime() const {
|
||||
if (StartPunch.Time > 0)
|
||||
return StartPunch.Time;
|
||||
|
||||
for (int i = 0; i < nPunch; i++) {
|
||||
if (Punch[i].Time > 0)
|
||||
return Punch[i].Time;
|
||||
}
|
||||
|
||||
if (FinishPunch.Time > 0)
|
||||
return FinishPunch.Time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
map<int, oPunch::SpecialPunch> SportIdent::getSpecialMappings() const {
|
||||
map<int, oPunch::SpecialPunch> res;
|
||||
for (int j = 1; j < punchMap.size(); j++) {
|
||||
if (punchMap[j] > 0)
|
||||
res[j] = oPunch::SpecialPunch(punchMap[j]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void SportIdent::addSpecialMapping(int code, oPunch::SpecialPunch p) {
|
||||
if (code > 0 && code < punchMap.size())
|
||||
punchMap[code] = p;
|
||||
else
|
||||
throw std::exception("Not supported");
|
||||
}
|
||||
|
||||
void SportIdent::removeSpecialMapping(int code) {
|
||||
if (code > 0 && code < punchMap.size())
|
||||
punchMap[code] = 0;
|
||||
else
|
||||
throw std::exception("Not supported");
|
||||
}
|
||||
|
||||
void SportIdent::addTestCard(int cardNo, const vector<int> &punches) {
|
||||
testCards.emplace(cardNo, punches);
|
||||
}
|
||||
|
||||
@ -1,19 +1,15 @@
|
||||
// SportIdent.h: interface for the SportIdent class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_)
|
||||
#define AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "oPunch.h"
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -108,6 +104,8 @@ struct SICard
|
||||
|
||||
string serializePunches() const;
|
||||
void deserializePunches(const string &arg);
|
||||
|
||||
int getFirstTime() const;
|
||||
};
|
||||
|
||||
struct SI_StationData {
|
||||
@ -154,9 +152,11 @@ struct SI_StationInfo
|
||||
};
|
||||
|
||||
|
||||
class SportIdent
|
||||
{
|
||||
class SportIdent {
|
||||
protected:
|
||||
|
||||
bool useSubsecondMode = false;
|
||||
|
||||
bool readSI6Block(HANDLE hComm, BYTE *data);
|
||||
bool readSystemData(SI_StationInfo *si, int retry=2);
|
||||
bool readSystemDataV2(SI_StationInfo &si);
|
||||
@ -195,7 +195,7 @@ protected:
|
||||
void getSI9DataExt(HANDLE hComm);
|
||||
|
||||
void analyseSI5Time(BYTE *data, DWORD &time, DWORD &control);
|
||||
bool analysePunch(BYTE *data, DWORD &time, DWORD &control);
|
||||
bool analysePunch(BYTE *data, DWORD &time, DWORD &control, bool subSecond);
|
||||
void analyseTPunch(BYTE *data, DWORD &time, DWORD &control);
|
||||
|
||||
//Card read waiting to be processed.
|
||||
@ -227,13 +227,25 @@ protected:
|
||||
|
||||
bool readVoltage;
|
||||
|
||||
vector<int> punchMap;
|
||||
SI_StationInfo* findStationInt(const wstring& com);
|
||||
void addTestStation(const wstring& com);
|
||||
|
||||
public:
|
||||
SI_StationInfo *findStation(const wstring &com);
|
||||
|
||||
map<int, oPunch::SpecialPunch> getSpecialMappings() const;
|
||||
void addSpecialMapping(int code, oPunch::SpecialPunch);
|
||||
void removeSpecialMapping(int code);
|
||||
|
||||
const SI_StationInfo *findStation(const wstring &com) const;
|
||||
|
||||
/** Log debug data. */
|
||||
void debugLog(const wchar_t *ptr);
|
||||
|
||||
void getInfoString(const wstring &com, vector<wstring> &info);
|
||||
void getInfoString(const wstring &com, vector<pair<bool, wstring>> &info) const;
|
||||
|
||||
bool isAnyOpenUnkownUnit() const;
|
||||
|
||||
bool isPortOpen(const wstring &com);
|
||||
bool autoDetect(list<int> &ComPorts);
|
||||
void stopMonitorThread();
|
||||
@ -250,13 +262,14 @@ public:
|
||||
void closeCom(const wchar_t *com);
|
||||
bool openCom(const wchar_t *com);
|
||||
bool tcpAddPort(int port, DWORD zeroTime);
|
||||
|
||||
bool openComListen(const wchar_t *com, DWORD BaudRate);
|
||||
|
||||
SportIdent(HWND hWnd, DWORD Id, bool readVoltage);
|
||||
|
||||
void setSubSecondMode(bool subSec) { useSubsecondMode = subSec; }
|
||||
void resetPunchMap();
|
||||
|
||||
virtual ~SportIdent();
|
||||
friend void start_si_thread(void *ptr);
|
||||
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_SPORTIDENT_H__F13F5795_8FA9_4CE6_8497_7407CD590139__INCLUDED_)
|
||||
|
||||
@ -1,21 +1,12 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
|
||||
#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#define NOMINMAX
|
||||
// Windows Header Files:
|
||||
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "timeconstants.hpp"
|
||||
|
||||
// C RunTime Header Files
|
||||
|
||||
@ -51,4 +42,3 @@ const extern string _EmptyString;
|
||||
const extern string _VacantName;
|
||||
const extern wstring _EmptyWString;
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -716,7 +716,7 @@ void AutoMachine::startCancelInterval(gdioutput &gdi, const char *startCommand,
|
||||
|
||||
void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
|
||||
settingsTitle(gdi, "Resultatutskrift / export");
|
||||
wstring time = (state == State::Create && interval <= 0) ? L"10:00" : getTimeMS(interval);
|
||||
wstring time = (state == State::Create && interval <= 0) ? L"10:00" : formatTimeMS(interval, false, SubSecond::Off);
|
||||
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
|
||||
|
||||
if (state == State::Create) {
|
||||
@ -822,12 +822,12 @@ void PrintResultMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
|
||||
}
|
||||
}
|
||||
|
||||
void PrintResultMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
|
||||
void PrintResultMachine::save(oEvent& oe, gdioutput& gdi, bool doProcess) {
|
||||
AutoMachine::save(oe, gdi, doProcess);
|
||||
wstring minute = gdi.getText("Interval");
|
||||
int t = convertAbsoluteTimeMS(minute);
|
||||
int t = convertAbsoluteTimeMS(minute) / timeConstSecond;
|
||||
|
||||
if (t < 2 || t>7200) {
|
||||
if (t < 2 || t > 7200) {
|
||||
throw meosException("Intervallet måste anges på formen MM:SS.");
|
||||
}
|
||||
doExport = gdi.isChecked("DoExport");
|
||||
@ -980,7 +980,7 @@ void PrewarningMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
|
||||
gdi.pushX();
|
||||
gdi.fillDown();
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe.fillControls(d, oEvent::CTCourseControl);
|
||||
oe.fillControls(d, oEvent::ControlType::CourseControl);
|
||||
gdi.addItem("Controls", d);
|
||||
gdi.setSelection("Controls", controls);
|
||||
gdi.popX();
|
||||
@ -998,7 +998,7 @@ void PrewarningMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
|
||||
|
||||
controlsSI.clear();
|
||||
for (set<int>::iterator it = controls.begin(); it != controls.end(); ++it) {
|
||||
pControl pc = oe.getControl(*it, false);
|
||||
pControl pc = oe.getControl(*it, false, false);
|
||||
if (pc) {
|
||||
vector<int> n;
|
||||
pc->getNumbers(n);
|
||||
@ -1152,7 +1152,7 @@ void PunchMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
|
||||
sic.punchOnly = true;
|
||||
sic.nPunch = 1;
|
||||
sic.Punch[0].Code = radio;
|
||||
sic.Punch[0].Time = 600 + rand() % 1200 + r->getStartTime();
|
||||
sic.Punch[0].Time = timeConstHour/10 + rand() % (1200*timeConstSecond) + r->getStartTime();
|
||||
si.addCard(sic);
|
||||
}
|
||||
}
|
||||
@ -1205,7 +1205,7 @@ void SplitsMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
|
||||
if (doProcess) {
|
||||
//Try exporting.
|
||||
oe.exportIOFSplits(oEvent::IOF20, file.c_str(), true, false,
|
||||
set<int>(), -1, false, true, true, false);
|
||||
set<int>(), -1, false, true, true, false, false);
|
||||
interval = iv;
|
||||
synchronize = true;
|
||||
}
|
||||
@ -1245,7 +1245,7 @@ void SplitsMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast)
|
||||
if ((interval>0 && ast==SyncTimer) || (interval==0 && ast==SyncDataUp)) {
|
||||
if (!file.empty())
|
||||
oe->exportIOFSplits(oEvent::IOF20, file.c_str(), true, false, classes,
|
||||
leg, false, true, true, false);
|
||||
leg, false, true, true, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1276,16 +1276,16 @@ void SaveMachine::status(gdioutput &gdi) {
|
||||
void SaveMachine::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
|
||||
if (interval>0 && ast==SyncTimer) {
|
||||
if (!baseFile.empty()) {
|
||||
wstring file = baseFile + L"meos_backup_" + oe->getDate() + L"_" + itow(saveIter++) + L".xml";
|
||||
wstring file = baseFile + L"meos_backup_" + oe->getDate() + L"_" + itow(saveIter++) + L".meosxml";
|
||||
oe->autoSynchronizeLists(true);
|
||||
oe->save(file);
|
||||
oe->save(file, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SaveMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
|
||||
settingsTitle(gdi, "Säkerhetskopiering");
|
||||
wstring time=state == State::Create ? L"10:00" : getTimeMS(interval);
|
||||
wstring time=state == State::Create ? L"10:00" : formatTimeMS(interval, false, SubSecond::Off);
|
||||
startCancelInterval(gdi, "Save", state, IntervalMinute, time);
|
||||
|
||||
int cx = gdi.getCX();
|
||||
@ -1295,12 +1295,12 @@ void SaveMachine::settings(gdioutput &gdi, oEvent &oe, State state) {
|
||||
gdi.setCX(cx);
|
||||
}
|
||||
|
||||
void SaveMachine::save(oEvent &oe, gdioutput &gdi, bool doProcess) {
|
||||
void SaveMachine::save(oEvent& oe, gdioutput& gdi, bool doProcess) {
|
||||
AutoMachine::save(oe, gdi, doProcess);
|
||||
wstring minute=gdi.getText("Interval");
|
||||
int t=convertAbsoluteTimeMS(minute);
|
||||
wstring minute = gdi.getText("Interval");
|
||||
int t = convertAbsoluteTimeMS(minute) / timeConstSecond;
|
||||
|
||||
if (t<2 || t>7200) {
|
||||
if (t < 2 || t>7200) {
|
||||
throw meosException("Intervallet måste anges på formen MM:SS.");
|
||||
}
|
||||
wstring f = gdi.getText("BaseFile");
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -76,10 +76,10 @@ TabClass::TabClass(oEvent *poe):TabBase(poe)
|
||||
void TabClass::clearCompetitionData() {
|
||||
currentResultModuleTags.clear();
|
||||
pSettings.clear();
|
||||
pSavedDepth = 3600;
|
||||
pFirstRestart = 3600;
|
||||
pSavedDepth = timeConstHour;
|
||||
pFirstRestart = timeConstHour;
|
||||
pTimeScaling = 1.0;
|
||||
pInterval = 120;
|
||||
pInterval = 2 * timeConstMinute;
|
||||
|
||||
currentStage = -1;
|
||||
EditChanged = false;
|
||||
@ -241,6 +241,9 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
|
||||
return true;
|
||||
}
|
||||
else if (bi.id == "ApplyForking") {
|
||||
int maxForking = gdi.getTextNo("MaxForkings");
|
||||
if (maxForking < 2)
|
||||
throw meosException("Du måste ange minst två gafflingsvarienater");
|
||||
showForkingGuide = false;
|
||||
pClass pc = oe->getClass(ClassId);
|
||||
|
||||
@ -259,7 +262,7 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
|
||||
allR[k]->setCourseId(0);
|
||||
}
|
||||
}
|
||||
pair<int,int> res = pc->autoForking(forkingSetup);
|
||||
pair<int,int> res = pc->autoForking(forkingSetup, maxForking);
|
||||
gdi.alert("Created X distinct forkings using Y courses.#" +
|
||||
itos(res.first) + "#" + itos(res.second));
|
||||
loadPage(gdi);
|
||||
@ -307,6 +310,10 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.setSelection("AllStages", set<int>());
|
||||
gdi.disableInput("AssignCourses");
|
||||
}
|
||||
else if (bi.id == "AllCourses") {
|
||||
gdi.setSelection("AllCourses", { -1 });
|
||||
//gdi.enableInput("AssignCourses");
|
||||
}
|
||||
else if (bi.id == "ShowForking") {
|
||||
if (!checkClassSelected(gdi))
|
||||
return false;
|
||||
@ -469,7 +476,7 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
int nst = oe->convertAbsoluteTime(st);
|
||||
if (nst >= 0 && warnDrawStartTime(gdi, nst, true)) {
|
||||
nst = 3600;
|
||||
nst = timeConstHour;
|
||||
st = oe->getAbsTime(nst);
|
||||
}
|
||||
if (nst>0)
|
||||
@ -695,8 +702,27 @@ int TabClass::multiCB(gdioutput &gdi, int type, void *data)
|
||||
EditChanged=true;
|
||||
if (ii.id=="NStage")
|
||||
gdi.enableInput("SetNStage");
|
||||
else if (ii.id == "CourseFilter") {
|
||||
gdi.addTimeoutMilli(500, "FilterCourseTimer", MultiCB);
|
||||
}
|
||||
//else if (ii.id=="")
|
||||
}
|
||||
else if (type == GUI_TIMER) {
|
||||
TimerInfo& ti = *(TimerInfo*)(data);
|
||||
if (ti.id == "FilterCourseTimer") {
|
||||
const wstring &filter = gdi.getText("CourseFilter");
|
||||
if (filter != courseFilter) {
|
||||
courseFilter = filter;
|
||||
vector<pair<wstring, size_t>> out;
|
||||
oe->getCourses(out, courseFilter, true, false);
|
||||
set<int> sel;
|
||||
gdi.getSelection("AllCourses", sel);
|
||||
gdi.addItem("AllCourses", out);
|
||||
gdi.setSelection("AllCourses", sel);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -832,8 +858,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
else ds.ctrl = 0;
|
||||
|
||||
// Save settings with class
|
||||
ds.firstStart = 3600;
|
||||
ds.interval = 120;
|
||||
ds.firstStart = timeConstHour;
|
||||
ds.interval = 2 * timeConstMinute;
|
||||
ds.vacant = 1;
|
||||
|
||||
res.push_back(ds);
|
||||
@ -1023,7 +1049,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, L"Första (ordinarie) start:");
|
||||
gdi.addInput("FirstStart", oe->getAbsTime(timeConstHour), 10, 0, L"Första (ordinarie) start:");
|
||||
gdi.addInput("MinInterval", L"2:00", 10, 0, L"Minsta startintervall:");
|
||||
gdi.addInput("Vacances", getDefaultVacant(), 10, 0, L"Andel vakanser:");
|
||||
gdi.fillDown();
|
||||
@ -1085,7 +1111,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id == "SelectAllNoneP") {
|
||||
bool select = bi.getExtraInt() != 0;
|
||||
for (int k = 0; k < oe->getNumClasses(); k++) {
|
||||
const int nc = oe->getNumClasses();
|
||||
for (int k = 0; k < nc; k++) {
|
||||
gdi.check("PLUse" + itos(k), select);
|
||||
gdi.setInputStatus("First" + itos(k), select);
|
||||
}
|
||||
@ -1107,8 +1134,8 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
pInterval = interval;
|
||||
|
||||
oListParam par;
|
||||
|
||||
for (int k = 0; k < oe->getNumClasses(); k++) {
|
||||
const int nc = oe->getNumClasses();
|
||||
for (int k = 0; k < nc; k++) {
|
||||
if (!gdi.hasWidget("PLUse" + itos(k)))
|
||||
continue;
|
||||
BaseInfo *biu = gdi.setText("PLUse" + itos(k), L"", false);
|
||||
@ -1260,7 +1287,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id == "DrawAll") {
|
||||
int origin = bi.getExtraInt();
|
||||
wstring firstStart = oe->getAbsTime(3600);
|
||||
wstring firstStart = oe->getAbsTime(timeConstHour);
|
||||
wstring minInterval = L"2:00";
|
||||
wstring vacances = getDefaultVacant();
|
||||
if (gdi.hasWidget("Vacances")) {
|
||||
@ -2529,7 +2556,7 @@ void TabClass::showClassSettings(gdioutput &gdi)
|
||||
if (ci.hasFixedTime) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
ii = &gdi.addInput(xp + classW + width, y, "I" + itos(id), formatTime(ci.interval*drawInfo.baseInterval), 7, DrawClassesCB);
|
||||
ii = &gdi.addInput(xp + classW + width, y, "I" + itos(id), formatTime(ci.interval*drawInfo.baseInterval, SubSecond::Auto), 7, DrawClassesCB);
|
||||
if (ci.hasFixedTime) {
|
||||
ii->setBgColor(fixedColor).setExtra(fixedColor);
|
||||
}
|
||||
@ -3323,9 +3350,24 @@ bool TabClass::loadPage(gdioutput &gdi)
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.addListBox("Classes", 200, showAdvanced ? 512 : 420, ClassesCB, L"").isEdit(false).ignore(true);
|
||||
gdi.setTabStops("Classes", 185);
|
||||
gdi.setTabStops("Classes", 170);
|
||||
oe->fillClasses(gdi, "Classes", oEvent::extraDrawn, oEvent::filterNone);
|
||||
|
||||
|
||||
bool hasIgnoreStart = false;
|
||||
bool hasFreeStart = false;
|
||||
|
||||
if (!showAdvanced) {
|
||||
vector<pClass> clsList;
|
||||
oe->getClasses(clsList, false);
|
||||
for (auto c : clsList) {
|
||||
if (c->ignoreStartPunch())
|
||||
hasIgnoreStart = true;
|
||||
if (c->hasFreeStart())
|
||||
hasFreeStart = true;
|
||||
}
|
||||
}
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.dropLine(2);
|
||||
|
||||
@ -3419,11 +3461,15 @@ bool TabClass::loadPage(gdioutput &gdi)
|
||||
gdi.addCheckbox("NoTiming", "Utan tidtagning", 0);
|
||||
}
|
||||
|
||||
if (showAdvanced) {
|
||||
if (showAdvanced || hasIgnoreStart || hasFreeStart) {
|
||||
gdi.dropLine(2);
|
||||
gdi.popX();
|
||||
gdi.addCheckbox("FreeStart", "Fri starttid", 0, false, "Klassen lottas inte, startstämpling");
|
||||
gdi.addCheckbox("IgnoreStart", "Ignorera startstämpling", 0, false, "Uppdatera inte starttiden vid startstämpling");
|
||||
|
||||
if (showAdvanced || hasFreeStart)
|
||||
gdi.addCheckbox("FreeStart", "Fri starttid", 0, false, "Klassen lottas inte, startstämpling");
|
||||
|
||||
if (showAdvanced || hasIgnoreStart)
|
||||
gdi.addCheckbox("IgnoreStart", "Ignorera startstämpling", 0, false, "Uppdatera inte starttiden vid startstämpling");
|
||||
gdi.dropLine(2);
|
||||
gdi.popX();
|
||||
}
|
||||
@ -3721,8 +3767,8 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
|
||||
return;
|
||||
}
|
||||
|
||||
int firstStart = 3600,
|
||||
interval = 120,
|
||||
int firstStart = timeConstHour,
|
||||
interval = 2 * timeConstMinute,
|
||||
vac = _wtoi(lastNumVac.c_str());
|
||||
|
||||
int pairSize = lastPairSize;
|
||||
@ -3787,12 +3833,12 @@ void TabClass::drawDialog(gdioutput &gdi, oEvent::DrawMethod method, const oClas
|
||||
|
||||
if (method == oEvent::DrawMethod::Pursuit || method == oEvent::DrawMethod::ReversePursuit) {
|
||||
gdi.addInput("MaxAfter", lastMaxAfter, 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart").setSynchData(&lastMaxAfter);
|
||||
gdi.addInput("TimeRestart", oe->getAbsTime(firstStart + 3600), 8, 0, L"Första omstartstid:");
|
||||
gdi.addInput("TimeRestart", oe->getAbsTime(firstStart + timeConstHour), 8, 0, L"Första omstartstid:");
|
||||
gdi.addInput("ScaleFactor", lastScaleFactor, 8, 0, L"Tidsskalning:").setSynchData(&lastScaleFactor);
|
||||
}
|
||||
|
||||
if (method != oEvent::DrawMethod::Simultaneous)
|
||||
gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
|
||||
gdi.addInput("Interval", formatTime(interval, SubSecond::Auto), 10, 0, L"Startintervall (min):").setSynchData(&lastInterval);
|
||||
|
||||
if ((method == oEvent::DrawMethod::Random ||
|
||||
method == oEvent::DrawMethod::SOFT ||
|
||||
@ -3944,9 +3990,9 @@ void TabClass::pursuitDialog(gdioutput &gdi) {
|
||||
|
||||
gdi.fillRight();
|
||||
|
||||
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");
|
||||
gdi.addInput("MaxAfter", formatTime(pSavedDepth, SubSecond::Off), 10, 0, L"Maxtid efter:", L"Maximal tid efter ledaren för att delta i jaktstart");
|
||||
gdi.addInput("TimeRestart", L"+" + formatTime(pFirstRestart, SubSecond::Off), 8, 0, L"Första omstartstid:", L"Ange tiden relativt klassens första start");
|
||||
gdi.addInput("Interval", formatTime(pInterval, SubSecond::Off), 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:");
|
||||
@ -4027,7 +4073,7 @@ void TabClass::showClassSelection(gdioutput &gdi, int &bx, int &by, GUICALLBACK
|
||||
int cx = gdi.getCX();
|
||||
int width = gdi.scaleLength(230);
|
||||
gdi.addListBox("Classes", 200, 480, classesCB, L"Klasser:", L"", true);
|
||||
gdi.setTabStops("Classes", 185);
|
||||
gdi.setTabStops("Classes", 170);
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
|
||||
@ -4258,6 +4304,9 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
|
||||
|
||||
gdi.dropLine(2);
|
||||
gdi.pushY();
|
||||
|
||||
courseFilter = L"";
|
||||
gdi.addInput("CourseFilter", courseFilter, 16, MultiCB, L"Filtrera:");
|
||||
gdi.addListBox("AllCourses", 180, 300, 0, L"Banor:", L"", true);
|
||||
oe->fillCourses(gdi, "AllCourses", true);
|
||||
int bxp = gdi.getCX();
|
||||
@ -4292,6 +4341,9 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
|
||||
}
|
||||
}
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.addInput("MaxForkings", L"100", 5, nullptr, L"Max antal gaffllingsvarianter att skapa:",
|
||||
L"Det uppskattade antalet startade lag i klassen är ett lämpligt värde.");
|
||||
gdi.dropLine();
|
||||
gdi.fillRight();
|
||||
gdi.addButton("ApplyForking", "Calculate and apply forking", MultiCB);
|
||||
@ -4300,9 +4352,11 @@ void TabClass::defineForking(gdioutput &gdi, bool clearSettings) {
|
||||
|
||||
gdi.setCX(bxp);
|
||||
gdi.setCY(byp);
|
||||
gdi.addButton("AllCourses", "Välj allt", MultiCB);
|
||||
gdi.fillDown();
|
||||
gdi.addButton("ClearCourses", "Clear selections", MultiCB);
|
||||
|
||||
gdi.setCX(bxp);
|
||||
gdi.addString("", 10, "help:assignforking");
|
||||
gdi.addString("", ty, tx, boldLarge, L"Assign courses and apply forking to X#" + pc->getName());
|
||||
|
||||
@ -4384,7 +4438,7 @@ void TabClass::getClassSettingsTable(gdioutput &gdi, GUICALLBACK cb) {
|
||||
gdi.addString("", yp, f, 1, "Direktanmälan");
|
||||
|
||||
vector< pair<wstring,size_t> > arg;
|
||||
oe->fillCourses(arg, true);
|
||||
oe->getCourses(arg, L"", true);
|
||||
|
||||
for (size_t k = 0; k < cls.size(); k++) {
|
||||
pClass it = cls[k];
|
||||
@ -4534,8 +4588,11 @@ void TabClass::updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDe
|
||||
if (st == STChange) {
|
||||
if (typeid(sdataBase) != typeid(ListBoxInfo)) {
|
||||
InputInfo sdII = dynamic_cast<InputInfo &>(sdataBase);
|
||||
string rp;
|
||||
gdi.getWidgetRestorePoint(sdKey, rp);
|
||||
gdi.removeWidget(sdKey);
|
||||
gdi.addSelection(sdII.getX(), sdII.getY(), sdKey, sdII.getWidth(), 200, MultiCB);
|
||||
gdi.addSelection(sdII.getX(), sdII.getY(), sdKey, int(sdII.getWidth()/gdi.getScale()), 200, MultiCB);
|
||||
gdi.setWidgetRestorePoint(sdKey, rp);
|
||||
setParallelOptions(sdKey, gdi, pc, leg);
|
||||
}
|
||||
else if (forceWrite) {
|
||||
@ -4545,9 +4602,12 @@ void TabClass::updateStartData(gdioutput &gdi, pClass pc, int leg, bool updateDe
|
||||
else {
|
||||
if (typeid(sdataBase) != typeid(InputInfo)) {
|
||||
ListBoxInfo sdLBI = dynamic_cast<ListBoxInfo &>(sdataBase);
|
||||
string rp;
|
||||
gdi.getWidgetRestorePoint(sdKey, rp);
|
||||
gdi.removeWidget(sdKey);
|
||||
string val = "-";
|
||||
gdi.addInput(sdLBI.getX(), sdLBI.getY(), sdKey, pc->getStartDataS(leg), 8, MultiCB);
|
||||
gdi.setWidgetRestorePoint(sdKey, rp);
|
||||
}
|
||||
else if (forceWrite) {
|
||||
gdi.setText(sdKey, pc->getStartDataS(leg), true);
|
||||
@ -4678,12 +4738,12 @@ 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", formatTime(drawInfoIn.baseInterval));
|
||||
gdi.setText("BaseInterval", formatTime(drawInfoIn.baseInterval, SubSecond::Off));
|
||||
|
||||
gdi.check("AllowNeighbours", drawInfoIn.allowNeighbourSameCourse);
|
||||
gdi.check("CoursesTogether", drawInfoIn.coursesTogether);
|
||||
gdi.setText("MinInterval", formatTime(drawInfoIn.minClassInterval));
|
||||
gdi.setText("MaxInterval", formatTime(drawInfoIn.maxClassInterval));
|
||||
gdi.setText("MinInterval", formatTime(drawInfoIn.minClassInterval, SubSecond::Off));
|
||||
gdi.setText("MaxInterval", formatTime(drawInfoIn.maxClassInterval, SubSecond::Off));
|
||||
gdi.setText("nFields", drawInfoIn.nFields);
|
||||
gdi.setText("FirstStart", oe->getAbsTime(drawInfoIn.firstStart));
|
||||
}
|
||||
@ -4739,10 +4799,10 @@ bool TabClass::warnDrawStartTime(gdioutput &gdi, const wstring &firstStart) {
|
||||
|
||||
bool TabClass::warnDrawStartTime(gdioutput &gdi, int time, bool absTime) {
|
||||
if (absTime)
|
||||
time = oe->getRelativeTime(formatTimeHMS(time));
|
||||
time = oe->getRelativeTime(formatTimeHMS(time, SubSecond::Off));
|
||||
|
||||
if (!hasWarnedStartTime && (time > 3600 * 11 && !oe->useLongTimes())) {
|
||||
bool res = gdi.ask(L"warn:latestarttime#" + itow(time/3600));
|
||||
if (!hasWarnedStartTime && (time > timeConstHour * 11 && !oe->useLongTimes())) {
|
||||
bool res = gdi.ask(L"warn:latestarttime#" + itow(time/timeConstHour));
|
||||
if (res)
|
||||
hasWarnedStartTime = true;
|
||||
return !res;
|
||||
@ -4812,7 +4872,7 @@ void DrawSettingsCSV::write(gdioutput &gdi, const oEvent &oe, const wstring &fn,
|
||||
else line.emplace_back("");
|
||||
|
||||
line.push_back(gdi.narrow(oe.getAbsTime(ci.firstStart)));
|
||||
line.push_back(gdi.narrow(formatTime(ci.interval)));
|
||||
line.push_back(gdi.narrow(formatTime(ci.interval, SubSecond::Off)));
|
||||
line.push_back(itos(ci.vacant));
|
||||
writer.outputRow(line);
|
||||
}
|
||||
@ -5130,8 +5190,8 @@ public:
|
||||
else if (type == GuiEventType::GUI_BUTTON) {
|
||||
if (info.id == "AddGroup") {
|
||||
int id = 1;
|
||||
int firstStart = 3600;
|
||||
int length = 3600;
|
||||
int firstStart = timeConstHour;
|
||||
int length = timeConstHour;
|
||||
for (auto &g : oe.getStartGroups(false)) {
|
||||
id = max(id, g.first+1);
|
||||
firstStart = max(firstStart, g.second.lastStart);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -33,9 +33,9 @@ class TabClass :
|
||||
int maxTime;
|
||||
|
||||
PursuitSettings(oClass &c) {
|
||||
firstTime = 3600;
|
||||
firstTime = timeConstHour;
|
||||
use = c.interpretClassType() != ctOpen;
|
||||
maxTime = 3600;
|
||||
maxTime = timeConstHour;
|
||||
}
|
||||
};
|
||||
|
||||
@ -103,6 +103,9 @@ class TabClass :
|
||||
wstring lastScaleFactor;
|
||||
wstring lastMaxAfter;
|
||||
|
||||
// Filter for course assignment
|
||||
wstring courseFilter;
|
||||
|
||||
bool lastHandleBibs;
|
||||
// Generate a table with class settings
|
||||
void showClassSettings(gdioutput &gdi);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -351,8 +351,8 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
|
||||
TabList::customTextLines(*oe, "IVExtra", gdi);
|
||||
gdi.dropLine(2.5);
|
||||
TabList::customTextLines(*oe, "IVExtra", true, gdi);
|
||||
|
||||
gdi.dropLine(1);
|
||||
|
||||
@ -364,7 +364,8 @@ int TabClub::clubCB(gdioutput &gdi, int type, void *data)
|
||||
oe->getDI().fillDataFields(gdi);
|
||||
}
|
||||
else if (bi.id == "SaveSettings") {
|
||||
oe->getDI().saveDataFields(gdi);
|
||||
set<string> modified;
|
||||
oe->getDI().saveDataFields(gdi, modified);
|
||||
|
||||
TabList::saveExtraLines(*oe, "IVExtra", gdi);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -133,6 +133,8 @@ bool TabCompetition::save(gdioutput &gdi, bool write)
|
||||
oe->updateStartTimes(delta);
|
||||
}
|
||||
|
||||
oe->supportSubSeconds(gdi.isChecked("SubSecond"));
|
||||
|
||||
oe->setDate(date, true);
|
||||
oe->useLongTimes(longTimes);
|
||||
oe->setName(gdi.getText("Name"), true);
|
||||
@ -163,7 +165,7 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
|
||||
return false;
|
||||
|
||||
gdi.setWaitCursor(true);
|
||||
if (oe->open(fileName, true, false)) {
|
||||
if (oe->open(fileName, true, false, false)) {
|
||||
gdi.setWindowTitle(oe->getTitleName());
|
||||
resetSaveTimer();
|
||||
|
||||
@ -171,7 +173,7 @@ bool TabCompetition::importFile(HWND hWnd, gdioutput &gdi)
|
||||
wstring base = constructBase(L"base", L"");
|
||||
wchar_t newBase[_MAX_PATH];
|
||||
getUserFile(newBase, base.c_str());
|
||||
oe->save(newBase);
|
||||
oe->save(newBase, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -188,7 +190,7 @@ bool TabCompetition::exportFileAs(HWND hWnd, gdioutput &gdi)
|
||||
return false;
|
||||
|
||||
gdi.setWaitCursor(true);
|
||||
if (!oe->save(fileName.c_str())) {
|
||||
if (!oe->save(fileName.c_str(), false)) {
|
||||
gdi.alert(L"Fel: Filen " + fileName+ L" kunde inte skrivas.");
|
||||
return false;
|
||||
}
|
||||
@ -662,7 +664,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
gdi.addCheckbox("Clear", "Nollställ databaser", 0, true);
|
||||
gdi.addCheckbox("Clear", "Nollställ databaser");
|
||||
gdi.addCheckbox("IncludeWithoutClub", "Inkludera klubblösa");
|
||||
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.popX();
|
||||
@ -680,6 +684,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.setWaitCursor(true);
|
||||
gdi.addString("", 0, "Importerar...");
|
||||
bool clear = gdi.isChecked("Clear");
|
||||
bool requireClub = !gdi.isChecked("IncludeWithoutClub");
|
||||
wstring club = gdi.getText("ClubFile");
|
||||
wstring cmp = gdi.getText("CmpFile");
|
||||
if (club == cmp)
|
||||
@ -698,7 +703,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
if (clubCsv)
|
||||
throw meosException("Klubbfil får inte anges vid CSV import.");
|
||||
|
||||
oe->importXML_IOF_Data(club, cmp, clear);
|
||||
oe->importXML_IOF_Data(club, cmp, requireClub, clear);
|
||||
}
|
||||
|
||||
gdi.dropLine();
|
||||
@ -780,7 +785,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
wchar_t newBase[_MAX_PATH];
|
||||
getUserFile(newBase, base.c_str());
|
||||
if (!fileExists(newBase))
|
||||
oe->save(newBase);
|
||||
oe->save(newBase, false);
|
||||
|
||||
loadConnectionPage(gdi);
|
||||
}
|
||||
@ -911,7 +916,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
oEvent nextStage(gdi);
|
||||
|
||||
if (!file.empty())
|
||||
success = nextStage.open(file.c_str(), false, false);
|
||||
success = nextStage.open(file.c_str(), false, false, false);
|
||||
|
||||
if (success)
|
||||
success = nextStage.getNameId(0) == oe->getDCI().getString("PostEvent");
|
||||
@ -1138,7 +1143,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
wstring startlist = getTempFile();
|
||||
bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0;
|
||||
oe->exportIOFStartlist(oEvent::IOF30, startlist.c_str(), eventorUTC,
|
||||
set<int>(), false, false, true);
|
||||
set<int>(), false, false, true, true);
|
||||
vector<wstring> fileList;
|
||||
fileList.push_back(startlist);
|
||||
|
||||
@ -1232,7 +1237,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
bool eventorUTC = oe->getPropertyInt("UseEventorUTC", 0) != 0;
|
||||
oe->exportIOFSplits(oEvent::IOF30, resultlist.c_str(), false,
|
||||
eventorUTC, classes, -1, false, true,
|
||||
false, true);
|
||||
false, true, true);
|
||||
vector<wstring> fileList;
|
||||
fileList.push_back(resultlist);
|
||||
|
||||
@ -1332,6 +1337,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
gdi.addCheckbox("EventorDb", "Uppdatera löpardatabasen", CompetitionCB, true);
|
||||
gdi.addCheckbox("IncludeWithoutClub", "Inkludera klubblösa");
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.popX();
|
||||
gdi.addButton("Cancel", "Avbryt", CompetitionCB);
|
||||
@ -1339,14 +1346,16 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id == "EventorCmp") {
|
||||
gdi.setInputStatus("EventorSel", gdi.isChecked(bi.id));
|
||||
gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorDb"));
|
||||
gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) || gdi.isChecked("EventorDb"));
|
||||
}
|
||||
else if (bi.id == "EventorDb") {
|
||||
gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) | gdi.isChecked("EventorCmp"));
|
||||
gdi.setInputStatus("EventorNext", gdi.isChecked(bi.id) || gdi.isChecked("EventorCmp"));
|
||||
}
|
||||
else if (bi.id == "EventorNext") {
|
||||
bool cmp = gdi.isChecked("EventorCmp");
|
||||
bool db = gdi.isChecked("EventorDb");
|
||||
bool withNoClub = gdi.isChecked("IncludeWithoutClub");
|
||||
|
||||
ListBoxInfo lbi;
|
||||
gdi.getSelectedItem("EventorSel", lbi);
|
||||
const CompetitionInfo *ci = 0;
|
||||
@ -1355,6 +1364,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.clearPage(true);
|
||||
gdi.setData("UpdateDB", db);
|
||||
gdi.setData("IncludeWithoutClub", withNoClub);
|
||||
|
||||
gdi.pushX();
|
||||
if (cmp && ci) {
|
||||
gdi.setData("EventIndex", lbi.data);
|
||||
@ -1412,11 +1423,14 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.popX();
|
||||
}
|
||||
else if (bi.id == "EventorImport") {
|
||||
const int diffZeroTime = 3600;
|
||||
const int diffZeroTime = timeConstHour;
|
||||
DWORD id;
|
||||
DWORD db;
|
||||
DWORD withNoClub;
|
||||
|
||||
gdi.getData("EventorId", id);
|
||||
gdi.getData("UpdateDB", db);
|
||||
gdi.getData("IncludeWithoutClub", withNoClub);
|
||||
|
||||
DWORD eventIndex;
|
||||
gdi.getData("EventIndex", eventIndex);
|
||||
@ -1444,7 +1458,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
firstStart = t;
|
||||
zeroTime = t - diffZeroTime;
|
||||
if (zeroTime<0)
|
||||
zeroTime += 3600*24;
|
||||
zeroTime += timeConstHour * 24;
|
||||
|
||||
startType = gdi.getSelectedItem("StartType").first;
|
||||
lastEntry = gdi.getText("LastEntryDate");
|
||||
@ -1509,8 +1523,8 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
else
|
||||
tRunnerDB = extractedFiles[0];
|
||||
}
|
||||
|
||||
oe->importXML_IOF_Data(tClubs, tRunnerDB, true);
|
||||
|
||||
oe->importXML_IOF_Data(tClubs, tRunnerDB, withNoClub == 0, true);
|
||||
removeTempFile(tClubs);
|
||||
|
||||
if (id > 0) {
|
||||
@ -1522,6 +1536,12 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
if (createNew && id>0) {
|
||||
gdi.addString("", 1, "Skapar ny tävling");
|
||||
oe->newCompetition(L"New");
|
||||
oe->loadDefaults();
|
||||
|
||||
bool importHiredCard = true;
|
||||
if (importHiredCard)
|
||||
importDefaultHiredCards(gdi);
|
||||
|
||||
oe->importXML_EntryData(gdi, tEvent, false, false, noFilter, noType);
|
||||
oe->setZeroTime(formatTimeHMS(zeroTime), false);
|
||||
oe->getDI().setDate("OrdinaryEntry", lastEntry);
|
||||
@ -1546,7 +1566,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
if (!course.empty()) {
|
||||
gdi.dropLine();
|
||||
TabCourse::runCourseImport(gdi, course, oe, true);
|
||||
TabCourse::runCourseImport(gdi, course, oe, true, false);
|
||||
}
|
||||
|
||||
set<int> clsWithRef;
|
||||
@ -1563,7 +1583,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
switch (startType) {
|
||||
case SMCommon:
|
||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0",
|
||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart, SubSecond::Off), L"0",
|
||||
L"0", oEvent::VacantPosition::Mixed,
|
||||
false, false, oEvent::DrawMethod::Random, 1);
|
||||
break;
|
||||
@ -1589,7 +1609,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
}
|
||||
if (!skip)
|
||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00",
|
||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart, SubSecond::Off), L"2:00",
|
||||
L"2", oEvent::VacantPosition::Mixed,
|
||||
true, false, oEvent::DrawMethod::MeOS, 1);
|
||||
break;
|
||||
@ -1780,7 +1800,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
if (filterIndex == ImportFormats::IOF30 || filterIndex == ImportFormats::IOF203) {
|
||||
bool useUTC = oe->getDCI().getInt("UTC") != 0;
|
||||
oe->exportIOFStartlist(filterIndex == ImportFormats::IOF30 ? oEvent::IOF30 : oEvent::IOF20,
|
||||
save.c_str(), useUTC, allTransfer, individual, includeStage, false);
|
||||
save.c_str(), useUTC, allTransfer, individual, includeStage, false, false);
|
||||
}
|
||||
else if (filterIndex == ImportFormats::OE) {
|
||||
oe->exportOECSV(save.c_str(), cSVLanguageHeaderIndex, false);
|
||||
@ -1838,7 +1858,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
if (!gdi.hasWidget("LegType")) {
|
||||
oe->exportIOFSplits(ver, save.c_str(), true, useUTC,
|
||||
allTransfer, -1, false, unroll, includeStage, false);
|
||||
allTransfer, -1, false, unroll, includeStage, false, false);
|
||||
}
|
||||
else {
|
||||
ListBoxInfo leglbi;
|
||||
@ -1860,17 +1880,17 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
for (int leg = 0; leg<legMax; leg++) {
|
||||
file = fileBase + L"_" + itow(leg+1) + fileEnd;
|
||||
oe->exportIOFSplits(ver, file.c_str(), true, useUTC,
|
||||
allTransfer, leg, false, unroll, includeStage, false);
|
||||
allTransfer, leg, false, unroll, includeStage, false, false);
|
||||
}
|
||||
}
|
||||
else if (leglbi.data == 3) {
|
||||
oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer,
|
||||
-1, true, unroll, includeStage, false);
|
||||
-1, true, unroll, includeStage, false, false);
|
||||
}
|
||||
else {
|
||||
int leg = leglbi.data == 1 ? -1 : leglbi.data - 10;
|
||||
oe->exportIOFSplits(ver, file.c_str(), true, useUTC, allTransfer,
|
||||
leg, false, unroll, includeStage, false);
|
||||
leg, false, unroll, includeStage, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1951,6 +1971,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
|
||||
oe->newCompetition(lang.tl(L"Ny tävling"));
|
||||
oe->loadDefaults();
|
||||
gdi.setWindowTitle(L"");
|
||||
|
||||
if (useEventor()) {
|
||||
@ -2077,15 +2098,18 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.disableInput("Cancel");
|
||||
gdi.disableInput("BrowseCourse");
|
||||
gdi.disableInput("AddClasses");
|
||||
gdi.disableInput("CreateClasses");
|
||||
|
||||
try {
|
||||
TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"));
|
||||
TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"),
|
||||
gdi.isChecked("CreateClasses"));
|
||||
}
|
||||
catch (std::exception &) {
|
||||
catch (const std::exception &) {
|
||||
gdi.enableInput("DoImportCourse");
|
||||
gdi.enableInput("Cancel");
|
||||
gdi.enableInput("BrowseCourse");
|
||||
gdi.enableInput("AddClasses");
|
||||
gdi.enableInput("CreateClasses");
|
||||
throw;
|
||||
}
|
||||
gdi.dropLine();
|
||||
@ -2136,7 +2160,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.setWaitCursor(true);
|
||||
xml.openOutput(fileName.c_str(), false);
|
||||
IOF30Interface writer(oe, false);
|
||||
IOF30Interface writer(oe, false, false);
|
||||
writer.writeRunnerDB(oe->getRunnerDatabase(), xml);
|
||||
gdi.setWaitCursor(false);
|
||||
}
|
||||
@ -2151,7 +2175,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
gdi.setWaitCursor(true);
|
||||
xml.openOutput(fileName.c_str(), false);
|
||||
IOF30Interface writer(oe, false);
|
||||
IOF30Interface writer(oe, false, false);
|
||||
writer.writeClubDB(oe->getRunnerDatabase(), xml);
|
||||
gdi.setWaitCursor(false);
|
||||
}
|
||||
@ -2242,6 +2266,9 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.setInputStatus(gdi.narrow(fn).c_str(), !ii.text.empty());
|
||||
}
|
||||
}
|
||||
else if (ii.id == "Name") {
|
||||
updateWarning(gdi);
|
||||
}
|
||||
}
|
||||
else if (type==GUI_EVENT) {
|
||||
EventInfo ei=*(EventInfo *)data;
|
||||
@ -2277,16 +2304,16 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.setData("RunnerIx", ix);
|
||||
gdi.dropLine();
|
||||
gdi.addSelection("Classes", 200, 300, 0, L"Klasser:");
|
||||
oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterNone);
|
||||
oe->fillClasses(gdi, "Classes", oEvent::extraNone, oEvent::filterOnlySingle);
|
||||
|
||||
if (lastSelectedClass != -1)
|
||||
gdi.selectItemByData("Classes", lastSelectedClass);
|
||||
else
|
||||
if (lastSelectedClass == -1 || !gdi.selectItemByData("Classes", lastSelectedClass))
|
||||
gdi.selectFirstItem("Classes");
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillRight();
|
||||
gdi.addButton("DBEntry", "Anmäl", CompetitionCB).setDefault();
|
||||
gdi.setInputStatus("DBEntry", gdi.getSelectedItem("Classes").first > 0); // Cannot change
|
||||
|
||||
gdi.addButton("CancelEntry", "Avbryt", CompetitionCB).setCancel();
|
||||
gdi.refresh();
|
||||
}
|
||||
@ -2339,7 +2366,7 @@ int TabCompetition::restoreCB(gdioutput &gdi, int type, void *data) {
|
||||
|
||||
if (ti.id == "") {
|
||||
wstring fi(bi.FullPath);
|
||||
if (!oe->open(fi, false, false)) {
|
||||
if (!oe->open(fi, false, false, false)) {
|
||||
gdi.alert("Kunde inte öppna tävlingen.");
|
||||
}
|
||||
else {
|
||||
@ -2392,7 +2419,7 @@ void TabCompetition::copyrightLine(gdioutput &gdi) const
|
||||
|
||||
gdi.dropLine(0.4);
|
||||
gdi.fillDown();
|
||||
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2022 Melin Software HB"));
|
||||
gdi.addString("", 0, makeDash(L"#Copyright © 2007-2023 Melin Software HB"));
|
||||
gdi.dropLine(1);
|
||||
gdi.popX();
|
||||
|
||||
@ -2422,7 +2449,7 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
|
||||
gdi.dropLine(1.5);
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
|
||||
|
||||
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2022 Melin Software HB"));
|
||||
gdi.addStringUT(1, makeDash(L"Copyright © 2007-2023 Melin Software HB"));
|
||||
gdi.dropLine();
|
||||
gdi.addStringUT(10, "The database connection used is MySQL++\nCopyright "
|
||||
"(c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by MySQL AB,"
|
||||
@ -2463,6 +2490,20 @@ void TabCompetition::loadAboutPage(gdioutput &gdi) const
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void TabCompetition::updateWarning(gdioutput &gdi) const {
|
||||
const wstring &n = gdi.getText("Name");
|
||||
const wstring &w = gdi.getText("cmpwarning");
|
||||
constexpr int limit = 32;
|
||||
if (n.length() < limit && !w.empty()) {
|
||||
gdi.setText("warningicon", L"", true);
|
||||
gdi.setText("cmpwarning", L"", true);
|
||||
}
|
||||
else if (n.length() >= limit && w.empty()) {
|
||||
gdi.setText("warningicon", L"514", true);
|
||||
gdi.setText("cmpwarning", L"Ett långt tävlingsnamn kan ge oväntad nerskalning av utskrifter.", true);
|
||||
}
|
||||
}
|
||||
|
||||
bool TabCompetition::useEventor() const {
|
||||
return oe->getPropertyInt("UseEventor", 0) == 1;
|
||||
}
|
||||
@ -2566,7 +2607,7 @@ bool TabCompetition::loadPage(gdioutput &gdi)
|
||||
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
gdi.addInput("Name", oe->getName(), 24, 0, L"Tävlingsnamn:");
|
||||
gdi.addInput("Name", oe->getName(), 24, CompetitionCB, L"Tävlingsnamn:");
|
||||
gdi.fillDown();
|
||||
|
||||
gdi.addInput("Annotation", oe->getAnnotation(), 20, 0, L"Kommentar / version:")
|
||||
@ -2579,12 +2620,16 @@ bool TabCompetition::loadPage(gdioutput &gdi)
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.dropLine(1.2);
|
||||
//int ccx = gdi.getCX();
|
||||
gdi.addCheckbox("LongTimes", "Aktivera stöd för tider över 24 timmar", CompetitionCB, oe->useLongTimes());
|
||||
|
||||
gdi.addCheckbox("SubSecond", "Aktivera stöd för tiondels sekunder", CompetitionCB, oe->supportSubSeconds());
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
if (false && oe->isClient()) {
|
||||
gdi.popX();
|
||||
gdi.disableInput("ZeroTime");
|
||||
gdi.disableInput("LongTimes");
|
||||
gdi.disableInput("SubSecond");
|
||||
if (oe->useLongTimes())
|
||||
gdi.disableInput("Date");
|
||||
}
|
||||
@ -2651,6 +2696,14 @@ bool TabCompetition::loadPage(gdioutput &gdi)
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.addString("warningicon", textImage, "S25");
|
||||
gdi.dropLine(0.2);
|
||||
gdi.fillDown();
|
||||
gdi.addString("cmpwarning", 0, "");
|
||||
updateWarning(gdi);
|
||||
gdi.popX();
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.dropLine(3);
|
||||
gdi.setCX(gdi.getCX()+gdi.scaleLength(60));
|
||||
@ -2908,26 +2961,26 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
|
||||
date.getObjectString("Clock", ci.firstStart);
|
||||
|
||||
if (useEventorUTC()) {
|
||||
int offset = getTimeZoneInfo(ci.Date);
|
||||
int offset = getTimeZoneInfo(ci.Date) * timeConstSecond;
|
||||
int t = convertAbsoluteTimeISO(ci.firstStart);
|
||||
int nt = t - offset;
|
||||
int dayOffset = 0;
|
||||
if (nt < 0) {
|
||||
nt += 24*3600;
|
||||
nt += 24 * timeConstHour;
|
||||
dayOffset = -1;
|
||||
}
|
||||
else if (nt > 24*3600) {
|
||||
nt -= 24*3600;
|
||||
else if (nt > 24* timeConstHour) {
|
||||
nt -= 24* timeConstHour;
|
||||
dayOffset = 1;
|
||||
}
|
||||
ci.firstStart = formatTimeHMS(nt);
|
||||
ci.firstStart = formatTimeHMS(nt, SubSecond::Off);
|
||||
//TODO: Take dayoffset into account
|
||||
}
|
||||
|
||||
xmlEvents[k].getObjectString("WebURL", ci.url);
|
||||
xmlobject aco = xmlEvents[k].getObject("Account");
|
||||
if (aco) {
|
||||
string type = aco.getAttrib("type").get();
|
||||
string type = aco.getAttrib("type").getStr();
|
||||
wstring no;
|
||||
aco.getObjectString("AccountNo", no);
|
||||
|
||||
@ -2960,8 +3013,8 @@ void TabCompetition::getEventorCompetitions(gdioutput &gdi,
|
||||
|
||||
SYSTEMTIME st;
|
||||
convertDateYMS(breakDate, st, false);
|
||||
__int64 time = SystemTimeToInt64Second(st) - 1;
|
||||
breakDate = convertSystemDate(Int64SecondToSystemTime(time));
|
||||
__int64 time = SystemTimeToInt64TenthSecond(st) - 10;
|
||||
breakDate = convertSystemDate(Int64TenthSecondToSystemTime(time));
|
||||
|
||||
if (ci.lastNormalEntryDate.empty() || ci.lastNormalEntryDate >= breakDate)
|
||||
ci.lastNormalEntryDate = breakDate;
|
||||
@ -3080,7 +3133,9 @@ void TabCompetition::getEventorCmpData(gdioutput &gdi, int id,
|
||||
if (dbFile.length() > 0) {
|
||||
gdi.addString("", 0, "Hämtar löpardatabasen...");
|
||||
gdi.refreshFast();
|
||||
dwl.downloadFile(eventorBase + L"export/cachedcompetitors?organisationIds=1&includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
|
||||
//dwl.downloadFile(eventorBase + L"export/cachedcompetitors?organisationIds=1&includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
|
||||
dwl.downloadFile(eventorBase + L"export/cachedcompetitors?includePreselectedClasses=false&zip=true" + iofExportVersion, dbFile, key);
|
||||
|
||||
dwl.createDownloadThread();
|
||||
while (dwl.isWorking()) {
|
||||
Sleep(100);
|
||||
@ -3640,7 +3695,7 @@ FlowOperation TabCompetition::checkStageFilter(gdioutput & gdi,
|
||||
xml.read(fname);
|
||||
xmlobject xo = xml.getObject("EntryList");
|
||||
set<int> scanFilter;
|
||||
IOF30Interface reader(oe, false);
|
||||
IOF30Interface reader(oe, false, false);
|
||||
vector<string> idProviders;
|
||||
if (xo) {
|
||||
if (xo.getAttrib("iofVersion")) {
|
||||
@ -3967,9 +4022,7 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
gdi.addString("", 1, "Tidszon");
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
gdi.addCheckbox("UTC", "Exportera tider i UTC", 0,
|
||||
oe->getDCI().getInt("UTC") == 1);
|
||||
|
||||
gdi.addCheckbox("UTC", "Exportera tider i UTC", nullptr, oe->getDCI().getInt("UTC") != 0);
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.popY();
|
||||
@ -3999,16 +4052,60 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addString("", 1, "Åldersgränser, reducerad anmälningsavgift");
|
||||
fields.clear();
|
||||
fields.push_back("YouthAge");
|
||||
fields.push_back("SeniorAge");
|
||||
gdi.addString("", 0, "Ungdomar och äldre kan få reducerad avgift");
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
gdi.fillRight();
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
auto yfields = oe->getDI().buildDataFields(gdi, { "YouthAge" , "SeniorAge" }, 10);
|
||||
|
||||
class HandleAge : public GuiHandler {
|
||||
public:
|
||||
void handle(gdioutput &gdi, BaseInfo &info, GuiEventType type) final {
|
||||
if (type == GuiEventType::GUI_INPUT)
|
||||
update(gdi, true);
|
||||
}
|
||||
|
||||
void update(gdioutput &gdi, bool update) {
|
||||
int youth = gdi.getTextNo("YouthAge_odc");
|
||||
int senior = gdi.getTextNo("SeniorAge_odc");
|
||||
|
||||
InputInfo &ii = dynamic_cast<InputInfo &>(gdi.getBaseInfo("SeniorAge_odc"));
|
||||
bool warn = senior > 1 && senior <= youth + 1;
|
||||
ii.setBgColor(warn ? colorLightRed : colorDefault);
|
||||
|
||||
string i1, i2, i3;
|
||||
if (youth <= 0 && senior <= 0) {
|
||||
i1 = "Ingen reducerad avgift";
|
||||
}
|
||||
else {
|
||||
i1 = "Reducerad avgift för:";
|
||||
|
||||
if (youth > 0)
|
||||
i2 = "Unga, till och med X år#" + itos(youth);
|
||||
else
|
||||
i2 = "Äldre, från och med X år#" + itos(senior);
|
||||
|
||||
if (youth > 0 && senior > 0)
|
||||
i3 = "Äldre, från och med X år#" + itos(senior);
|
||||
}
|
||||
gdi.setText("ReduceInfo", lang.tl(i1), update);
|
||||
gdi.setText("ReduceInfoL1", i2.empty() ? L"" : L"\u25AA " + lang.tl(i2), update);
|
||||
gdi.setText("ReduceInfoL2", i3.empty() ? L"" : L"\u25AA " + lang.tl(i3), update);
|
||||
}
|
||||
};
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
gdi.dropLine(2.8);
|
||||
gdi.addString("ReduceInfo", 0, "Ingen reducerad avgift");
|
||||
gdi.addString("ReduceInfoL1", 0, "-");
|
||||
gdi.addString("ReduceInfoL2", 0, "-");
|
||||
|
||||
auto handler = make_shared<HandleAge>();
|
||||
yfields[0]->setHandler(handler);
|
||||
yfields[1]->setHandler(handler);
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
|
||||
gdi.addString("", 1, "Valuta");
|
||||
fields.clear();
|
||||
@ -4053,6 +4150,8 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
oe->getDI().buildDataFields(gdi, fields, 10);
|
||||
oe->getDI().fillDataFields(gdi);
|
||||
|
||||
handler->update(gdi, false);
|
||||
|
||||
gdi.dropLine(1);
|
||||
int bottom = gdi.getCY();
|
||||
|
||||
@ -4097,17 +4196,16 @@ void TabCompetition::loadSettings(gdioutput &gdi) {
|
||||
}
|
||||
|
||||
void TabCompetition::saveSettings(gdioutput &gdi) {
|
||||
vector<string> fields;
|
||||
vector<string> fields = { "CardFee" ,"EliteFee" ,"EntryFee","YouthFee" };
|
||||
vector<int> fees(4);
|
||||
fields.push_back("CardFee");
|
||||
fields.push_back("EliteFee");
|
||||
fields.push_back("EntryFee");
|
||||
fields.push_back("YouthFee");
|
||||
|
||||
|
||||
for (int k = 0; k<4; k++)
|
||||
fees[k] = oe->getDCI().getInt(fields[k]);
|
||||
|
||||
wstring factor = oe->getDCI().getString("LateEntryFactor");
|
||||
oe->getDI().saveDataFields(gdi);
|
||||
set<string> modified;
|
||||
|
||||
oe->getDI().saveDataFields(gdi, modified);
|
||||
|
||||
bool changedFee = false;
|
||||
bool changedCardFee = false;
|
||||
@ -4119,33 +4217,60 @@ void TabCompetition::saveSettings(gdioutput &gdi) {
|
||||
else {
|
||||
changedCardFee = true;
|
||||
if (oe->getDCI().getInt(fields[k]) == 0)
|
||||
oe->getDI().setInt(fields[k].c_str(), -1); // Disallow zero card fee. -1 means no fee.
|
||||
oe->getDI().setInt(fields[k], -1); // Disallow zero card fee. -1 means no fee.
|
||||
}
|
||||
}
|
||||
}
|
||||
if (factor != oe->getDCI().getString("LateEntryFactor"))
|
||||
changedFee = true;
|
||||
|
||||
oe->getDI().setInt("UTC", gdi.isChecked("UTC") ? 1 : 0);
|
||||
if (oe->getDI().setInt("UTC", gdi.isChecked("UTC") ? 1 : 0))
|
||||
setEventorUTC(gdi.isChecked("UTC"));
|
||||
|
||||
if (oe->getDI().setInt("CurrencyFactor", gdi.isChecked("UseFraction") ? 100 : 1))
|
||||
modified.insert("CurrencyFactor");
|
||||
|
||||
if (oe->getDI().setInt("CurrencyPreSymbol", gdi.isChecked("PreSymbol") ? 1 : 0))
|
||||
modified.insert("CurrencyPreSymbol");
|
||||
|
||||
oe->getDI().setInt("CurrencyFactor", gdi.isChecked("UseFraction") ? 100 : 1);
|
||||
oe->getDI().setInt("CurrencyPreSymbol", gdi.isChecked("PreSymbol") ? 1 : 0);
|
||||
oe->setCurrency(-1, L"", L"", false);
|
||||
|
||||
vector< pair<wstring, size_t> > modes;
|
||||
wstring pm = oe->getDCI().getString("PayModes");
|
||||
vector<pair<wstring, size_t>> modes;
|
||||
oe->getPayModes(modes);
|
||||
for (size_t k = 0; k < modes.size(); k++) {
|
||||
string field = "M"+itos(k);
|
||||
if (gdi.hasWidget(field)) {
|
||||
wstring mode = gdi.getText("M"+itos(k));
|
||||
int id = gdi.getBaseInfo(field.c_str()).getExtraInt();
|
||||
int id = gdi.getBaseInfo(field).getExtraInt();
|
||||
oe->setPayMode(id, mode);
|
||||
}
|
||||
}
|
||||
if (pm != oe->getDCI().getString("PayModes"))
|
||||
modified.insert("PayModes");
|
||||
|
||||
// Read from model
|
||||
if (oe->isChanged()) {
|
||||
oe->setProperty("Organizer", oe->getDCI().getString("Organizer"));
|
||||
vector<string> props = { "Organizer" ,"Street" ,"Address" ,"EMail" ,"Homepage" ,
|
||||
"YouthAge","SeniorAge","Account", "LateEntryFactor","CurrencySymbol",
|
||||
"CurrencyFactor","CurrencyPreSymbol","CurrencySeparator",
|
||||
"CardFee","EliteFee","EntryFee","YouthFee", "PayModes" };
|
||||
|
||||
auto dci = oe->getDCI();
|
||||
for (const string &p : props) {
|
||||
if (modified.count(p)) {
|
||||
if (dci.isString(p))
|
||||
oe->setProperty(p.c_str(), dci.getString(p));
|
||||
else if (dci.isInt(p))
|
||||
oe->setProperty(p.c_str(), dci.getInt(p));
|
||||
else
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
|
||||
//oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
|
||||
|
||||
/*oe->setProperty("Organizer", oe->getDCI().getString("Organizer"));
|
||||
oe->setProperty("Street", oe->getDCI().getString("Street"));
|
||||
oe->setProperty("Address", oe->getDCI().getString("Address"));
|
||||
oe->setProperty("EMail", oe->getDCI().getString("EMail"));
|
||||
@ -4166,8 +4291,8 @@ void TabCompetition::saveSettings(gdioutput &gdi) {
|
||||
oe->setProperty("CurrencyFactor", oe->getDCI().getInt("CurrencyFactor"));
|
||||
oe->setProperty("CurrencyPreSymbol", oe->getDCI().getInt("CurrencyPreSymbol"));
|
||||
oe->setProperty("CurrencySeparator", oe->getDCI().getString("CurrencySeparator"));
|
||||
|
||||
oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
|
||||
*/
|
||||
//oe->setProperty("PayModes", oe->getDCI().getString("PayModes"));
|
||||
}
|
||||
oe->synchronize(true);
|
||||
set<int> dummy;
|
||||
@ -4260,7 +4385,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
|
||||
if (!thisFile.empty()) {
|
||||
wchar_t newBase[_MAX_PATH];
|
||||
getUserFile(newBase, thisFile.c_str());
|
||||
mergeEvent->save(newBase);
|
||||
mergeEvent->save(newBase, false);
|
||||
}
|
||||
|
||||
tc->oe->merge(*mergeEvent, baseEvent.get(), allowRemove, numAdd, numRemove, numUpdate);
|
||||
@ -4285,7 +4410,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
|
||||
gdi.refresh();
|
||||
}
|
||||
else if (bi.id == "Browse") {
|
||||
wstring fn = gdi.browseForOpen({ make_pair(L"xml", L"*.xml") }, L"xml");
|
||||
wstring fn = gdi.browseForOpen({ make_pair(L"MeOS-data", L"*.meosxml;*.xml;*.bu?") }, L"meosxml");
|
||||
if (fn.empty())
|
||||
return;
|
||||
|
||||
@ -4296,7 +4421,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
|
||||
else if (bi.id == "Read") {
|
||||
mergeEvent = make_shared<oEvent>(gdi);
|
||||
|
||||
if (!mergeEvent->open(tc->mergeFile, true, true))
|
||||
if (!mergeEvent->open(tc->mergeFile, true, true, false))
|
||||
return;
|
||||
|
||||
gdi.restore("merge", false);
|
||||
@ -4384,7 +4509,7 @@ void TabCompetition::mergeCompetition(gdioutput &gdi) {
|
||||
baseEvent = make_shared<oEvent>(gdi);
|
||||
bool ok = false;
|
||||
try {
|
||||
ok = baseEvent->open(base, true, true);
|
||||
ok = baseEvent->open(base, true, true, false);
|
||||
ok = true;
|
||||
}
|
||||
catch (...) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -60,6 +60,8 @@ class TabCompetition :
|
||||
void copyrightLine(gdioutput &gdi) const;
|
||||
void loadAboutPage(gdioutput &gdi) const;
|
||||
|
||||
void updateWarning(gdioutput &gdi) const;
|
||||
|
||||
int organizorId;
|
||||
|
||||
int lastChangeClassType;
|
||||
@ -118,6 +120,7 @@ class TabCompetition :
|
||||
void meosFeatures(gdioutput &gdi, bool newGuide);
|
||||
|
||||
void newCompetitionGuide(gdioutput &gdi, int step);
|
||||
void createNewCmp(gdioutput &gdi, bool useExisting);
|
||||
|
||||
void entryForm(gdioutput &gdi, bool isGuide);
|
||||
FlowOperation saveEntries(gdioutput &gdi, bool removeRemoved, bool isGuide);
|
||||
@ -132,6 +135,8 @@ class TabCompetition :
|
||||
void entryChoice(gdioutput &gdi);
|
||||
void createCompetition(gdioutput &gdi);
|
||||
|
||||
void importDefaultHiredCards(gdioutput& gdi);
|
||||
|
||||
void listBackups(gdioutput &gdi);
|
||||
|
||||
shared_ptr<GuiHandler> mergeHandler;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -55,35 +55,46 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
|
||||
if (pc) {
|
||||
pc->synchronize();
|
||||
|
||||
if (pc->getStatus() == oControl::StatusStart ||
|
||||
pc->getStatus() == oControl::StatusFinish) {
|
||||
if (oControl::isSpecialControl(pc->getStatus())) {
|
||||
gdi.selectItemByData("Controls", pc->getId());
|
||||
gdi.selectItemByData("Status", oControl::StatusOK);
|
||||
gdi.selectItemByData("Status", int(oControl::ControlStatus::StatusOK));
|
||||
gdi.setText("ControlID", makeDash(L"-"), true);
|
||||
|
||||
gdi.setText("Code", L"");
|
||||
gdi.setText("Name", pc->getName());
|
||||
gdi.setText("TimeAdjust", L"00:00");
|
||||
gdi.setText("TimeAdjust", pc->getTimeAdjustS());
|
||||
gdi.setText("MinTime", makeDash(L"-"));
|
||||
gdi.setText("Point", L"");
|
||||
gdi.disableInput("Visitors");
|
||||
gdi.disableInput("Courses");
|
||||
|
||||
controlId = pc->getId();
|
||||
|
||||
gdi.enableInput("Remove");
|
||||
gdi.enableInput("Save");
|
||||
gdi.enableEditControls(false);
|
||||
gdi.enableInput("Name");
|
||||
|
||||
if (pc->getUnitCode() > 0) {
|
||||
gdi.setText("Code", itow(pc->getUnitCode()));
|
||||
gdi.enableInput("TimeAdjust");
|
||||
gdi.setText("Info", lang.tl("Du kan justera tiden för en viss enhet"), true);
|
||||
}
|
||||
else {
|
||||
gdi.setText("Info", L"", true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gdi.selectItemByData("Controls", pc->getId());
|
||||
gdi.selectItemByData("Status", pc->getStatus());
|
||||
gdi.selectItemByData("Status", int(pc->getStatus()));
|
||||
const int numVisit = pc->getNumVisitors(true);
|
||||
const int numVisitExp = pc->getNumVisitors(false);
|
||||
|
||||
wstring info;
|
||||
if (numVisit > 0) {
|
||||
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());
|
||||
itow(numVisit) + L" (" + itow(numVisitExp) + L")#" + formatTimeMS(pc->getMissedTimeTotal() / numVisit, false, SubSecond::Off) +
|
||||
L"#" + formatTimeMS(pc->getMissedTimeMax(), false, SubSecond::Off);
|
||||
}
|
||||
else if (numVisitExp > 0) {
|
||||
info = L"Förväntat antal besökare: X#" + itow(numVisitExp);
|
||||
@ -108,19 +119,20 @@ void TabControl::selectControl(gdioutput &gdi, pControl pc)
|
||||
gdi.enableEditControls(true);
|
||||
|
||||
oControl::ControlStatus st = pc->getStatus();
|
||||
if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
|
||||
if (st == oControl::ControlStatus::StatusRogaining || st == oControl::ControlStatus::StatusRogainingRequired ||
|
||||
st == oControl::ControlStatus::StatusNoTiming || st == oControl::ControlStatus::StatusBadNoTiming)
|
||||
gdi.disableInput("MinTime");
|
||||
|
||||
if (st == oControl::StatusNoTiming || st == oControl::StatusBadNoTiming)
|
||||
if (st == oControl::ControlStatus::StatusNoTiming || st == oControl::ControlStatus::StatusBadNoTiming)
|
||||
gdi.disableInput("TimeAdjust");
|
||||
|
||||
if (gdi.hasWidget("Point") && st != oControl::StatusRogaining)
|
||||
if (gdi.hasWidget("Point") && st != oControl::ControlStatus::StatusRogaining && st != oControl::ControlStatus::StatusRogainingRequired)
|
||||
gdi.disableInput("Point");
|
||||
}
|
||||
}
|
||||
else {
|
||||
gdi.selectItemByData("Controls", -1);
|
||||
gdi.selectItemByData("Status", oControl::StatusOK);
|
||||
gdi.selectItemByData("Status", int(oControl::ControlStatus::StatusOK));
|
||||
gdi.setText("Code", L"");
|
||||
gdi.setText("Name", L"");
|
||||
controlId = 0;
|
||||
@ -145,26 +157,58 @@ int ControlsCB(gdioutput *gdi, int type, void *data)
|
||||
return tc.controlCB(*gdi, type, data);
|
||||
}
|
||||
|
||||
void TabControl::save(gdioutput &gdi)
|
||||
{
|
||||
void TabControl::save(gdioutput &gdi) {
|
||||
if (controlId==0)
|
||||
return;
|
||||
|
||||
DWORD pcid = controlId;
|
||||
|
||||
pControl pc;
|
||||
pc = oe->getControl(pcid, false);
|
||||
pControl pc = oe->getControl(controlId, false, true);
|
||||
|
||||
if (!pc)
|
||||
throw std::exception("Internal error");
|
||||
if (pc->getStatus() != oControl::StatusFinish && pc->getStatus() != oControl::StatusStart) {
|
||||
|
||||
if (!pc->isAddedToEvent()) {
|
||||
if (gdi.getText("TimeAdjust") == pc->getTimeAdjustS()
|
||||
&& gdi.getText("Name") == pc->getName())
|
||||
return; // Virtual control with no change.
|
||||
|
||||
oe->synchronizeList(oListId::oLControlId);
|
||||
pc = oe->getControl(controlId, false, true);
|
||||
|
||||
if (!pc->isAddedToEvent())
|
||||
pc = oe->addControl(*pc);
|
||||
|
||||
if (!pc)
|
||||
throw std::exception("Internal error");
|
||||
}
|
||||
|
||||
bool defaultName = false;
|
||||
|
||||
if (!oControl::isSpecialControl(pc->getStatus())) {
|
||||
int oldFirst = pc->getFirstNumber();
|
||||
|
||||
if (!pc->setNumbers(gdi.getText("Code")))
|
||||
gdi.alert("Kodsiffran måste vara ett heltal. Flera kodsiffror måste separeras med komma.");
|
||||
|
||||
int newFirst = pc->getFirstNumber();
|
||||
if (oldFirst != newFirst && pc->getId() == oldFirst) {
|
||||
// Update id if possible (make new control and remove old)
|
||||
if (!oe->isControlUsed(pc->getId()) && oe->getControl(newFirst) == nullptr) {
|
||||
pc->setName(gdi.getText("Name"));
|
||||
if (!pc->hasName())
|
||||
defaultName = true;
|
||||
|
||||
pc = oe->addControl(newFirst, newFirst, L"");
|
||||
pc->synchronize();
|
||||
controlId = pc->getId();
|
||||
pc->setNumbers(gdi.getText("Code"));
|
||||
oe->removeControl(oldFirst);
|
||||
}
|
||||
}
|
||||
|
||||
pc->setStatus(oControl::ControlStatus(gdi.getSelectedItem("Status").first));
|
||||
pc->setTimeAdjust(gdi.getText("TimeAdjust"));
|
||||
if (pc->getStatus() != oControl::StatusRogaining) {
|
||||
if (pc->getStatus() != oControl::StatusNoTiming && pc->getStatus() != oControl::StatusBadNoTiming)
|
||||
if (pc->getStatus() != oControl::ControlStatus::StatusRogaining && pc->getStatus() != oControl::ControlStatus::StatusRogainingRequired) {
|
||||
if (pc->getStatus() != oControl::ControlStatus::StatusNoTiming && pc->getStatus() != oControl::ControlStatus::StatusBadNoTiming)
|
||||
pc->setMinTime(gdi.getText("MinTime"));
|
||||
pc->setRogainingPoints(0);
|
||||
}
|
||||
@ -175,12 +219,65 @@ void TabControl::save(gdioutput &gdi)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pc->isUnit()) {
|
||||
// Ensure cache is up-to-date
|
||||
auto type = pc->getUnitType();
|
||||
int oldAdjust = oe->getUnitAdjustment(type, pc->getUnitCode());
|
||||
|
||||
pc->setName(gdi.getText("Name"));
|
||||
if (pc->setTimeAdjust(gdi.getText("TimeAdjust"))) {
|
||||
|
||||
// Cache is not updated. No new adjustment applied
|
||||
assert(oldAdjust == oe->getUnitAdjustment(type, pc->getUnitCode()));
|
||||
|
||||
vector<pair<pRunner, pFreePunch>> adjustList;
|
||||
|
||||
if (type == oPunch::SpecialPunch::PunchStart) {
|
||||
auto pList = oe->getPunchesByType(type, pc->getUnitCode());
|
||||
for (auto p : pList) {
|
||||
pRunner r = oe->getRunnerByCardNo(p->getCardNo(), p->getTimeInt(), oEvent::CardLookupProperty::Any);
|
||||
if (r && !r->getCard() && r->getStartTime() == p->getTimeInt()) {
|
||||
// Need not adjust runners with card.
|
||||
adjustList.emplace_back(r, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == oPunch::SpecialPunch::PunchFinish) {
|
||||
auto pList = oe->getPunchesByType(type, pc->getUnitCode());
|
||||
for (auto p : pList) {
|
||||
pRunner r = oe->getRunnerByCardNo(p->getCardNo(), p->getTimeInt(), oEvent::CardLookupProperty::Any);
|
||||
if (r && !r->getCard() && r->getFinishTime() == p->getTimeInt()) {
|
||||
// Need not adjust runners with card.
|
||||
adjustList.emplace_back(r, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear cache to make sure adjustment takes effect
|
||||
pc->clearCache();
|
||||
oe->clearUnitAdjustmentCache();
|
||||
|
||||
// With new adjustment applied
|
||||
assert(oldAdjust != oe->getUnitAdjustment(type, pc->getUnitCode()));
|
||||
|
||||
for (auto& rp : adjustList) {
|
||||
if (type == oPunch::SpecialPunch::PunchStart) {
|
||||
rp.first->setStartTime(rp.second->getTimeInt(), true, oBase::ChangeType::Update, true);
|
||||
}
|
||||
else if (type == oPunch::SpecialPunch::PunchFinish) {
|
||||
rp.first->setFinishTime(rp.second->getTimeInt());
|
||||
}
|
||||
rp.first->synchronize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaultName)
|
||||
pc->setName(gdi.getText("Name"));
|
||||
|
||||
pc->synchronize();
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe->fillControls(d, oEvent::CTAll);
|
||||
|
||||
vector<pair<wstring, size_t>> d;
|
||||
oe->fillControls(d, oEvent::ControlType::All);
|
||||
gdi.addItem("Controls", d);
|
||||
|
||||
oe->reEvaluateAll(set<int>(), true);
|
||||
@ -239,8 +336,8 @@ void TabControl::courseTable(Table &table) const {
|
||||
|
||||
void TabControl::visitorTable(Table &table) const {
|
||||
vector<pCard> c;
|
||||
oe->getCards(c);
|
||||
pControl pc = oe->getControl(controlId, false);
|
||||
oe->getCards(c, true, false);
|
||||
pControl pc = oe->getControl(controlId, false, true);
|
||||
|
||||
if (!pc)
|
||||
return;
|
||||
@ -297,7 +394,7 @@ void TabControl::visitorTable(Table &table) const {
|
||||
lang.tl("Ja") : lang.tl("Nej"), false);
|
||||
table.set(row++, it, TID_CARD, it.getCardNoString(), false);
|
||||
|
||||
table.set(row++, it, TID_STATUS, punch->getTime(), false);
|
||||
table.set(row++, it, TID_STATUS, punch->getTime(false, SubSecond::Auto), false);
|
||||
table.set(row++, it, TID_CONTROL, punch->getType(), false);
|
||||
table.set(row++, it, TID_CODES, j>0 ? p[j-1]->getType() : L"-", true);
|
||||
}
|
||||
@ -316,15 +413,24 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
|
||||
bool rogaining = false;
|
||||
if (controlId>0) {
|
||||
save(gdi);
|
||||
pControl pc = oe->getControl(controlId, false);
|
||||
rogaining = pc && pc->getStatus() == oControl::StatusRogaining;
|
||||
pControl pc = oe->getControl(controlId, false, true);
|
||||
rogaining = pc && (pc->getStatus() == oControl::ControlStatus::StatusRogaining || pc->getStatus() == oControl::ControlStatus::StatusRogainingRequired);
|
||||
}
|
||||
pControl pc = oe->addControl(0,oe->getNextControlNumber(), L"");
|
||||
int nextCtrl = oe->getNextControlNumber();
|
||||
int nextId = nextCtrl;
|
||||
if (oe->getControl(nextId)) {
|
||||
nextId += 1000;
|
||||
if (oe->getControl(nextId))
|
||||
nextId = 0; // Use default
|
||||
}
|
||||
pControl pc = oe->addControl(nextId, nextCtrl, L"");
|
||||
|
||||
if (rogaining)
|
||||
pc->setStatus(oControl::StatusRogaining);
|
||||
pc->setStatus(oControl::ControlStatus::StatusRogaining);
|
||||
|
||||
pc->synchronize();
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe->fillControls(d, oEvent::CTAll);
|
||||
oe->fillControls(d, oEvent::ControlType::All);
|
||||
gdi.addItem("Controls", d);
|
||||
selectControl(gdi, pc);
|
||||
}
|
||||
@ -342,7 +448,7 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
|
||||
oe->removeControl(cid);
|
||||
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe->fillControls(d, oEvent::CTAll);
|
||||
oe->fillControls(d, oEvent::ControlType::All);
|
||||
gdi.addItem("Controls", d);
|
||||
selectControl(gdi, 0);
|
||||
}
|
||||
@ -409,16 +515,17 @@ int TabControl::controlCB(gdioutput &gdi, int type, void *data)
|
||||
if (gdi.isInputChanged(""))
|
||||
save(gdi);
|
||||
|
||||
pControl pc=oe->getControl(bi.data, false);
|
||||
pControl pc=oe->getControl(bi.data, false, true);
|
||||
if (!pc)
|
||||
throw std::exception("Internal error");
|
||||
|
||||
selectControl(gdi, pc);
|
||||
}
|
||||
else if (bi.id == "Status" ) {
|
||||
gdi.setInputStatus("MinTime", bi.data != oControl::StatusRogaining && bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
|
||||
gdi.setInputStatus("Point", bi.data == oControl::StatusRogaining, true);
|
||||
gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming && bi.data != oControl::StatusBadNoTiming, true);
|
||||
oControl::ControlStatus st = (oControl::ControlStatus)bi.data;
|
||||
gdi.setInputStatus("MinTime", st != oControl::ControlStatus::StatusRogaining && st != oControl::ControlStatus::StatusRogainingRequired && st != oControl::ControlStatus::StatusNoTiming && st != oControl::ControlStatus::StatusBadNoTiming, true);
|
||||
gdi.setInputStatus("Point", st == oControl::ControlStatus::StatusRogaining || st != oControl::ControlStatus::StatusRogainingRequired, true);
|
||||
gdi.setInputStatus("TimeAdjust", st != oControl::ControlStatus::StatusNoTiming && st != oControl::ControlStatus::StatusBadNoTiming, true);
|
||||
}
|
||||
}
|
||||
else if (type==GUI_CLEAR) {
|
||||
@ -454,10 +561,10 @@ bool TabControl::loadPage(gdioutput &gdi)
|
||||
|
||||
gdi.pushY();
|
||||
gdi.addListBox("Controls", 250, 530, ControlsCB).isEdit(false).ignore(true);
|
||||
gdi.setTabStops("Controls", 40, 160);
|
||||
gdi.setTabStops("Controls", 44, 160);
|
||||
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe->fillControls(d, oEvent::CTAll);
|
||||
oe->fillControls(d, oEvent::ControlType::All);
|
||||
gdi.addItem("Controls", d);
|
||||
|
||||
gdi.newColumn();
|
||||
@ -515,7 +622,7 @@ bool TabControl::loadPage(gdioutput &gdi)
|
||||
gdi.dropLine(1.5);
|
||||
gdi.addString("", 10, "help:89064");
|
||||
|
||||
selectControl(gdi, oe->getControl(controlId, false));
|
||||
selectControl(gdi, oe->getControl(controlId, false, true));
|
||||
|
||||
gdi.setOnClearCb(ControlsCB);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -459,7 +459,7 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
|
||||
ext.push_back(make_pair(L"IOF CourseData, version 3.0 (xml)", L"*.xml"));
|
||||
wstring save = gdi.browseForSave(ext, L"xml", FilterIndex);
|
||||
if (save.length()>0) {
|
||||
IOF30Interface iof30(oe, false);
|
||||
IOF30Interface iof30(oe, false, false);
|
||||
xmlparser xml;
|
||||
xml.openOutput(save.c_str(), false);
|
||||
iof30.writeCourses(xml);
|
||||
@ -477,15 +477,19 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.disableInput("Cancel");
|
||||
gdi.disableInput("BrowseCourse");
|
||||
gdi.disableInput("AddClasses");
|
||||
gdi.disableInput("CreateClasses");
|
||||
|
||||
try {
|
||||
TabCourse::runCourseImport(gdi, filename, oe, gdi.isChecked("AddClasses"));
|
||||
TabCourse::runCourseImport(gdi, filename, oe,
|
||||
gdi.isChecked("AddClasses"),
|
||||
gdi.isChecked("CreateClasses"));
|
||||
}
|
||||
catch (std::exception &) {
|
||||
catch (const std::exception &) {
|
||||
gdi.enableInput("DoImportCourse");
|
||||
gdi.enableInput("Cancel");
|
||||
gdi.enableInput("BrowseCourse");
|
||||
gdi.enableInput("AddClasses");
|
||||
gdi.enableInput("CreateClasses");
|
||||
throw;
|
||||
}
|
||||
gdi.addButton("Cancel", "OK", CourseCB);
|
||||
@ -525,8 +529,8 @@ int TabCourse::courseCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.pushX();
|
||||
|
||||
gdi.fillRight();
|
||||
int firstStart = 3600;
|
||||
int interval = 2*60;
|
||||
int firstStart = timeConstHour;
|
||||
int interval = 2*timeConstMinute;
|
||||
int vac = 1;
|
||||
gdi.addInput("FirstStart", oe->getAbsTime(firstStart), 10, 0, L"Första start:");
|
||||
gdi.addInput("Interval", formatTime(interval), 10, 0, L"Startintervall (min):");
|
||||
@ -891,14 +895,14 @@ bool TabCourse::loadPage(gdioutput &gdi) {
|
||||
}
|
||||
|
||||
void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
|
||||
oEvent *oe, bool addClasses) {
|
||||
oEvent *oe, bool addToClasses, bool createClasses) {
|
||||
if (csvparser::iscsv(filename) != csvparser::CSV::NoCSV) {
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
gdi.addString("", 0, "Importerar OCAD csv-fil...");
|
||||
gdi.refreshFast();
|
||||
csvparser csv;
|
||||
if (csv.importOCAD_CSV(*oe, filename, addClasses)) {
|
||||
if (csv.importOCAD_CSV(*oe, filename, addToClasses)) {
|
||||
gdi.addString("", 1, "Klart.").setColor(colorGreen);
|
||||
}
|
||||
else gdi.addString("", 0, "Operationen misslyckades.").setColor(colorRed);
|
||||
@ -906,12 +910,64 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
|
||||
gdi.dropLine(2.5);
|
||||
gdi.fillDown();
|
||||
}
|
||||
else if (filename.find(L".txt") != wstring::npos || filename.find(L".TXT") != wstring::npos) {
|
||||
ifstream fin(filename);
|
||||
|
||||
if (!fin.good())
|
||||
throw meosException(L"Cannot read " + filename);
|
||||
|
||||
char bf[2048];
|
||||
vector<string> sw;
|
||||
int importedC = oe->getNumCourses() + 1;
|
||||
int line = 0;
|
||||
while (fin.good()) {
|
||||
fin.getline(bf, 2048);
|
||||
if (strlen(bf) < 2)
|
||||
continue;
|
||||
|
||||
if (0 == line && uint8_t(bf[0]) == 0xEF && uint8_t(bf[1]) == 0xBB && uint8_t(bf[2]) == 0xBF)
|
||||
split(bf+3, " ;,", sw);
|
||||
else
|
||||
split(bf, " ;,", sw);
|
||||
line++;
|
||||
|
||||
if (sw.size() <= 1)
|
||||
continue;
|
||||
|
||||
wstring name;
|
||||
int first = 0;
|
||||
if (atoi(sw[0].c_str()) < 30 && trim(sw[0]).length() > 2) {
|
||||
name = gdioutput::fromUTF8(trim(sw[0]));
|
||||
first = 1;
|
||||
}
|
||||
if (name.empty())
|
||||
name = lang.tl("Bana X#" + itos(importedC++));
|
||||
|
||||
string cs;
|
||||
for (int i = first; i < sw.size(); i++) {
|
||||
if (trim(sw[i]).empty())
|
||||
continue;
|
||||
int c = atoi(sw[i].c_str());
|
||||
if (c >= 30 && c < 1000)
|
||||
cs += itos(c) + " ";
|
||||
else {
|
||||
throw meosException("Kan inte tolka 'X' som en bana#" + string(bf));
|
||||
}
|
||||
}
|
||||
|
||||
pCourse pc = oe->addCourse(name);
|
||||
pc->importControls(cs, true, false);
|
||||
pc->synchronize();
|
||||
}
|
||||
|
||||
fin.close();
|
||||
}
|
||||
else {
|
||||
set<int> noFilter;
|
||||
string noType;
|
||||
oe->importXML_EntryData(gdi, filename.c_str(), addClasses, false, noFilter, noType);
|
||||
oe->importXML_EntryData(gdi, filename.c_str(), addToClasses, false, noFilter, noType);
|
||||
}
|
||||
if (addClasses) {
|
||||
if (addToClasses) {
|
||||
// There is specific course-class matching inside the import of each format,
|
||||
// that uses additional information. Here we try to match based on a generic approach.
|
||||
vector<pClass> cls;
|
||||
@ -1012,6 +1068,34 @@ void TabCourse::runCourseImport(gdioutput& gdi, const wstring &filename,
|
||||
gdi.dropLine();
|
||||
}
|
||||
|
||||
if (createClasses) {
|
||||
vector<pClass> cls;
|
||||
vector<pCourse> crs;
|
||||
oe->getClasses(cls, false);
|
||||
oe->getCourses(crs);
|
||||
unordered_set<int> usedCourseId;
|
||||
vector<pCourse> usedCrs;
|
||||
for (size_t k = 0; k < cls.size(); k++) {
|
||||
cls[k]->getCourses(-1, usedCrs);
|
||||
for (pCourse pc : usedCrs)
|
||||
usedCourseId.insert(pc->getId());
|
||||
}
|
||||
|
||||
set<wstring> usedNames;
|
||||
for (pCourse pc : crs) {
|
||||
if (usedCourseId.count(pc->getId()))
|
||||
continue;
|
||||
|
||||
pClass matchCls = oe->getClassCreate(-1, pc->getName(), usedNames);
|
||||
if (!matchCls || matchCls->getCourse(false)) {
|
||||
oe->addClass(pc->getName() + lang.tl(" Bana"), pc->getId());
|
||||
}
|
||||
else {
|
||||
matchCls->setCourse(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdi.addButton(gdi.getWidth()+20, 45, gdi.scaleLength(baseButtonWidth),
|
||||
"Print", "Skriv ut...", CourseCB,
|
||||
"Skriv ut listan.", true, false);
|
||||
@ -1043,6 +1127,7 @@ void TabCourse::setupCourseImport(gdioutput& gdi, GUICALLBACK cb) {
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.addCheckbox("AddClasses", "Lägg till klasser", 0, true);
|
||||
gdi.addCheckbox("CreateClasses", "Skapa en klass för varje bana", 0, false);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillRight();
|
||||
@ -1060,9 +1145,9 @@ void TabCourse::fillCourseControls(gdioutput &gdi, const wstring &ctrl) {
|
||||
vector< pair<wstring, size_t> > item;
|
||||
map<int, int> used;
|
||||
for (size_t k = 0; k < nr.size(); k++) {
|
||||
pControl pc = oe->getControl(nr[k], false);
|
||||
pControl pc = oe->getControl(nr[k], false, false);
|
||||
if (pc) {
|
||||
if (pc->getStatus() == oControl::StatusOK)
|
||||
if (pc->getStatus() == oControl::ControlStatus::StatusOK)
|
||||
++used[pc->getFirstNumber()];
|
||||
}
|
||||
else
|
||||
@ -1085,7 +1170,7 @@ void TabCourse::fillCourseControls(gdioutput &gdi, const wstring &ctrl) {
|
||||
|
||||
void TabCourse::fillOtherCourses(gdioutput &gdi, oCourse &crs, bool withLoops) {
|
||||
vector< pair<wstring, size_t> > ac;
|
||||
oe->fillCourses(ac, true);
|
||||
oe->getCourses(ac, L"", true);
|
||||
set<int> skipped;
|
||||
skipped.insert(crs.getId());
|
||||
pCourse longer = crs.getLongerVersion();
|
||||
@ -1223,7 +1308,7 @@ wstring TabCourse::encodeCourse(const wstring &in, bool rogaining, bool firstSta
|
||||
}
|
||||
|
||||
const wstring &TabCourse::formatControl(int id, wstring &bf) const {
|
||||
pControl ctrl = oe->getControl(id, false);
|
||||
pControl ctrl = oe->getControl(id, false, true);
|
||||
if (ctrl) {
|
||||
bf = ctrl->getString();
|
||||
return bf;
|
||||
@ -1231,3 +1316,4 @@ const wstring &TabCourse::formatControl(int id, wstring &bf) const {
|
||||
else
|
||||
return itow(id);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -70,7 +70,7 @@ public:
|
||||
~TabCourse(void);
|
||||
|
||||
static void runCourseImport(gdioutput& gdi, const wstring &filename,
|
||||
oEvent *oe, bool addClasses);
|
||||
oEvent *oe, bool addToClasses, bool createClasses);
|
||||
|
||||
static void setupCourseImport(gdioutput& gdi, GUICALLBACK cb);
|
||||
|
||||
|
||||
181
code/TabList.cpp
181
code/TabList.cpp
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -341,7 +341,7 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
else if (bi.id=="Copy") {
|
||||
ostringstream fout;
|
||||
HTMLWriter::writeTableHTML(gdi, fout, L"MeOS", true, 0, 1.0);
|
||||
HTMLWriter::writeTableHTML(gdi, fout, L"MeOS", false, L"", true, 0, 1.0);
|
||||
string res = fout.str();
|
||||
gdi.copyToClipboard(res, L"");
|
||||
}
|
||||
@ -570,32 +570,44 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
else if (bi.id=="CancelPS") {
|
||||
gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi);
|
||||
}
|
||||
else if (bi.id=="SavePS") {
|
||||
else if (bi.id == "SavePS") {
|
||||
string ctype;
|
||||
gdi.getData("Type", ctype);
|
||||
saveExtraLines(*oe, ctype.c_str(), gdi);
|
||||
|
||||
if (gdi.hasWidget("SplitAnalysis")) {
|
||||
int aflag = (gdi.isChecked("SplitAnalysis") ? 0 : 1) + (gdi.isChecked("Speed") ? 0 : 2)
|
||||
+ (gdi.isChecked("Results") ? 0 : 4);
|
||||
+ (gdi.isChecked("Results") ? 0 : 4);
|
||||
oe->getDI().setInt("Analysis", aflag);
|
||||
}
|
||||
|
||||
|
||||
if (gdi.hasWidget("WideFormat")) {
|
||||
bool wide = gdi.isChecked("WideFormat");
|
||||
oe->setProperty("WideSplitFormat", wide);
|
||||
|
||||
if (wide && gdi.hasWidget("NumPerPage")) {
|
||||
pair<int, bool> res = gdi.getSelectedItem("NumPerPage");
|
||||
if (res.second)
|
||||
oe->setProperty("NumSplitsOnePage", res.first);
|
||||
if (gdi.hasWidget("SplitPrintList")) {
|
||||
auto res = gdi.getSelectedItem("SplitPrintList");
|
||||
if (res.second) {
|
||||
if (res.first == -10)
|
||||
oe->getDI().setString("SplitPrint", L"");
|
||||
else {
|
||||
EStdListType type = oe->getListContainer().getType(res.first);
|
||||
string id = oe->getListContainer().getUniqueId(type);
|
||||
oe->getDI().setString("SplitPrint", gdioutput::widen(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gdi.hasWidget("WideFormat")) {
|
||||
bool wide = gdi.isChecked("WideFormat");
|
||||
oe->setProperty("WideSplitFormat", wide);
|
||||
|
||||
int no = gdi.getTextNo("MaxWaitTime");
|
||||
if (no >= 0)
|
||||
oe->setProperty("SplitPrintMaxWait", no);
|
||||
}
|
||||
}
|
||||
if (wide && gdi.hasWidget("NumPerPage")) {
|
||||
pair<int, bool> res = gdi.getSelectedItem("NumPerPage");
|
||||
if (res.second)
|
||||
oe->setProperty("NumSplitsOnePage", res.first);
|
||||
|
||||
int no = gdi.getTextNo("MaxWaitTime");
|
||||
if (no >= 0)
|
||||
oe->setProperty("SplitPrintMaxWait", no);
|
||||
}
|
||||
}
|
||||
gdi.getTabs().get(TabType(bi.getExtraInt()))->loadPage(gdi);
|
||||
}
|
||||
else if (bi.id == "PrinterSetup") {
|
||||
@ -1071,11 +1083,21 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
return listCB(gdi, GUI_BUTTON, &bi);
|
||||
}
|
||||
|
||||
|
||||
gdi.clearPage(false);
|
||||
gdi.addString("", boldLarge, "Tillgängliga listor");
|
||||
int xx = gdi.getCX() + gdi.scaleLength(360);
|
||||
int bx = gdi.getCX();
|
||||
int xx = bx + gdi.scaleLength(360);
|
||||
TextInfo ti;
|
||||
for (size_t k = 0; k < installedLists.size(); k++) {
|
||||
ti.text = installedLists[k].first;
|
||||
gdi.calcStringSize(ti);
|
||||
xx = max(xx, bx + ti.realWidth + 10);
|
||||
}
|
||||
for (size_t k = 0; k < lists.size(); k++) {
|
||||
ti.text = lists[k].first;
|
||||
gdi.calcStringSize(ti);
|
||||
xx = max(xx, bx + ti.realWidth + 10);
|
||||
}
|
||||
if (!installedLists.empty()) {
|
||||
gdi.dropLine();
|
||||
gdi.addString("", 1, "Listor i tävlingen");
|
||||
@ -1141,8 +1163,13 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
xmlobject xlist = xml.getObject(0);
|
||||
oe->synchronize();
|
||||
oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false);
|
||||
oe->synchronize(true);
|
||||
|
||||
set<uint64_t> imgUsed;
|
||||
oe->getListContainer().getUsedImages(imgUsed);
|
||||
for (uint64_t id : imgUsed)
|
||||
oe->saveImage(id);
|
||||
|
||||
oe->synchronize(true);
|
||||
loadPage(gdi);
|
||||
}
|
||||
}
|
||||
@ -1218,6 +1245,12 @@ int TabList::listCB(gdioutput &gdi, int type, void *data)
|
||||
|
||||
oe->synchronize(false);
|
||||
oe->getListContainer().load(MetaListContainer::ExternalList, xlist, false);
|
||||
|
||||
set<uint64_t> imgUsed;
|
||||
oe->getListContainer().getUsedImages(imgUsed);
|
||||
for (uint64_t id : imgUsed)
|
||||
oe->saveImage(id);
|
||||
|
||||
oe->synchronize(true);
|
||||
oe->loadGeneralResults(true, false);
|
||||
}
|
||||
@ -1286,7 +1319,7 @@ pair<gdioutput *, TabList *> TabList::makeOwnWindow(gdioutput &gdi) {
|
||||
|
||||
void TabList::enableFromTo(oEvent &oe, gdioutput &gdi, bool from, bool to) {
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe.fillControls(d, oEvent::CTCourseControl);
|
||||
oe.fillControls(d, oEvent::ControlType::CourseControl);
|
||||
|
||||
if (from) {
|
||||
gdi.enableInput("ResultSpecialFrom");
|
||||
@ -2216,7 +2249,7 @@ void TabList::settingsResultList(gdioutput &gdi)
|
||||
vector< pair<wstring, size_t> > lists;
|
||||
vector< pair<wstring, size_t> > dlists;
|
||||
const MetaListContainer &lc = oe->getListContainer();
|
||||
lc.getLists(dlists, false, true, !oe->hasTeam());
|
||||
lc.getLists(dlists, false, true, !oe->hasTeam(), false);
|
||||
set<int> usedListIx;
|
||||
map<string, int> tag2ListIx;
|
||||
for (size_t k = 0; k < dlists.size(); k++) {
|
||||
@ -2725,31 +2758,72 @@ void TabList::splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter,
|
||||
gdi.addString("", boldLarge, "Inställningar startbevis");
|
||||
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
if (setupPrinter) {
|
||||
gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
|
||||
gdi.dropLine(0.3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!oe.empty() && type == Splits) {
|
||||
bool withSplitAnalysis = (oe.getDCI().getInt("Analysis") & 1) == 0;
|
||||
gdi.fillRight();
|
||||
gdi.addSelection("SplitPrintList", 200, 200, nullptr, L"Sträcktidslista:");
|
||||
if (setupPrinter) {
|
||||
gdi.dropLine(0.9);
|
||||
gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
|
||||
gdi.dropLine(2.8);
|
||||
}
|
||||
else {
|
||||
gdi.dropLine(3);
|
||||
}
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
gdi.addString("", 10, "info:customsplitprint");
|
||||
gdi.dropLine();
|
||||
vector<pair<wstring, size_t>> lists;
|
||||
oe.getListContainer().getLists(lists, false, false, false, true);
|
||||
lists.insert(lists.begin(), make_pair(lang.tl("Standard"), -10));
|
||||
gdi.addItem("SplitPrintList", lists);
|
||||
wstring listId = oe.getDCI().getString("SplitPrint");
|
||||
EStdListType type = oe.getListContainer().getCodeFromUnqiueId(gdioutput::narrow(listId));
|
||||
if (type == EStdListType::EStdNone)
|
||||
gdi.selectFirstItem("SplitPrintList");
|
||||
else {
|
||||
for (auto& t : lists) {
|
||||
if (type == oe.getListContainer().getType(t.second))
|
||||
gdi.selectItemByData("SplitPrintList", t.second);
|
||||
}
|
||||
}
|
||||
//if ()
|
||||
/* bool withSplitAnalysis = (oe.getDCI().getInt("Analysis") & 1) == 0;
|
||||
bool withSpeed = (oe.getDCI().getInt("Analysis") & 2) == 0;
|
||||
bool withResult = (oe.getDCI().getInt("Analysis") & 4) == 0;
|
||||
|
||||
gdi.addCheckbox("SplitAnalysis", "Med sträcktidsanalys", 0, withSplitAnalysis);
|
||||
gdi.addCheckbox("Speed", "Med km-tid", 0, withSpeed);
|
||||
gdi.addCheckbox("Results", "Med resultat", 0, withResult);
|
||||
|
||||
gdi.addCheckbox("Results", "Med resultat", 0, withResult);*/
|
||||
}
|
||||
else if (setupPrinter) {
|
||||
gdi.dropLine(0.2);
|
||||
gdi.addButton("PrinterSetup", "Skrivare...", ListsCB, "Skrivarinställningar");
|
||||
}
|
||||
|
||||
gdi.popX();
|
||||
gdi.fillDown();
|
||||
|
||||
RECT rc;
|
||||
rc.top = gdi.getCY();
|
||||
rc.left = gdi.getCX();
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(8));
|
||||
gdi.dropLine();
|
||||
|
||||
const char *ctype = type == Splits ? "SPExtra" : "EntryExtra";
|
||||
customTextLines(oe, ctype, gdi);
|
||||
customTextLines(oe, ctype, !oe.empty(), gdi);
|
||||
|
||||
gdi.dropLine();
|
||||
|
||||
rc.right = gdi.getWidth();
|
||||
rc.bottom = gdi.getCY();
|
||||
|
||||
gdi.addRectangle(rc, colorLightCyan);
|
||||
|
||||
if (type == Splits) {
|
||||
gdi.dropLine(1.5);
|
||||
const bool wideFormat = oe.getPropertyInt("WideSplitFormat", 0) == 1;
|
||||
gdi.addCheckbox("WideFormat", "Sträcktider i kolumner (för standardpapper)", ListsCB, wideFormat);
|
||||
|
||||
@ -2769,7 +2843,7 @@ void TabList::splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillRight();
|
||||
gdi.setData("Type", ctype);
|
||||
gdi.addButton("SavePS", "OK", ListsCB).setDefault().setExtra(returnMode);
|
||||
@ -2791,11 +2865,12 @@ void TabList::saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi)
|
||||
oe.setExtraLines(dataField, lines);
|
||||
}
|
||||
|
||||
void TabList::customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi) {
|
||||
gdi.dropLine(2.5);
|
||||
void TabList::customTextLines(oEvent &oe, const char *dataField, bool withSymbols, gdioutput &gdi) {
|
||||
gdi.addString("", fontMediumPlus, "Egna textrader");
|
||||
gdi.dropLine(0.3);
|
||||
gdi.addString("", 10, "help:custom_text_lines");
|
||||
if (withSymbols) {
|
||||
gdi.dropLine(0.3);
|
||||
gdi.addString("", 10, "help:custom_text_lines");
|
||||
}
|
||||
gdi.dropLine(0.8);
|
||||
int yp = gdi.getCY();
|
||||
|
||||
@ -2825,18 +2900,20 @@ void TabList::customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi)
|
||||
gdi.fillDown();
|
||||
gdi.dropLine(2);
|
||||
}
|
||||
gdi.pushX();
|
||||
gdi.pushY();
|
||||
if (withSymbols) {
|
||||
gdi.pushX();
|
||||
gdi.pushY();
|
||||
|
||||
gdi.setCX(xp);
|
||||
gdi.setCY(yp);
|
||||
gdi.addListBox("Symbols", 500, 160);
|
||||
gdi.setTabStops("Symbols", 300);
|
||||
vector < pair<wstring, size_t>> symb;
|
||||
MetaList::fillSymbols(symb);
|
||||
gdi.addItem("Symbols", symb);
|
||||
gdi.popX();
|
||||
gdi.popY();
|
||||
gdi.setCX(xp);
|
||||
gdi.setCY(yp);
|
||||
gdi.addListBox("Symbols", 500, 160);
|
||||
gdi.setTabStops("Symbols", 300);
|
||||
vector < pair<wstring, size_t>> symb;
|
||||
MetaList::fillSymbols(symb);
|
||||
gdi.addItem("Symbols", symb);
|
||||
gdi.popX();
|
||||
gdi.popY();
|
||||
}
|
||||
}
|
||||
|
||||
void TabList::liveResult(gdioutput &gdi, oListInfo &li) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -147,7 +147,7 @@ public:
|
||||
};
|
||||
|
||||
static void splitPrintSettings(oEvent &oe, gdioutput &gdi, bool setupPrinter, TabType returnMode, PrintSettingsSelection type);
|
||||
static void customTextLines(oEvent &oe, const char *dataField, gdioutput &gdi);
|
||||
static void customTextLines(oEvent &oe, const char *dataField, bool withSymbols, gdioutput &gdi);
|
||||
static void saveExtraLines(oEvent &oe, const char *dataField, gdioutput &gdi);
|
||||
static void enableWideFormat(gdioutput &gdi, bool wide);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -28,6 +28,9 @@
|
||||
#include <commdlg.h>
|
||||
|
||||
#include "oEvent.h"
|
||||
#include "metalist.h"
|
||||
#include "generalresult.h"
|
||||
|
||||
#include "xmlparser.h"
|
||||
#include "gdioutput.h"
|
||||
#include "gdiconstants.h"
|
||||
@ -197,7 +200,7 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
|
||||
gdi.setText("Team", L"");
|
||||
}
|
||||
|
||||
gdi.setText("TimeAdjust", getTimeMS(r->getTimeAdjustment()));
|
||||
gdi.setText("TimeAdjust", formatTimeMS(r->getTimeAdjustment(false), false));
|
||||
gdi.setText("PointAdjust", -r->getPointAdjustment());
|
||||
|
||||
#ifdef _DEBUG
|
||||
@ -221,13 +224,13 @@ void TabRunner::selectRunner(gdioutput &gdi, pRunner r) {
|
||||
out += L" (" + itow(placeAcc[k]) + L")";
|
||||
|
||||
if (after[k] > 0)
|
||||
out += L" +" + getTimeMS(after[k]);
|
||||
out += L" +" + formatTimeMS(after[k], false);
|
||||
|
||||
if (k < afterAcc.size() && afterAcc[k]>0)
|
||||
out += L" (+" + getTimeMS(afterAcc[k]) + L")";
|
||||
out += L" (+" + formatTimeMS(afterAcc[k], false) + L")";
|
||||
|
||||
if (delta[k] > 0)
|
||||
out += L" B: " + getTimeMS(delta[k]);
|
||||
out += L" B: " + formatTimeMS(delta[k], false);
|
||||
|
||||
out += L" | ";
|
||||
|
||||
@ -528,7 +531,7 @@ pRunner TabRunner::save(gdioutput &gdi, int runnerId, bool willExit) {
|
||||
else
|
||||
classId = lbi.data;
|
||||
|
||||
int year = 0;
|
||||
const wstring year;
|
||||
pRunner r;
|
||||
bool cardNoChanged = false;
|
||||
if (runnerId==0) {
|
||||
@ -926,11 +929,12 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
if (!r) return 0;
|
||||
|
||||
gdioutput gdiprint(2.0, gdi.getHWNDTarget(), splitPrinter);
|
||||
if (bi.getExtraInt() == 0)
|
||||
if (bi.getExtraInt() == 0)
|
||||
r->printSplits(gdiprint);
|
||||
else
|
||||
r->printStartInfo(gdiprint);
|
||||
gdiprint.print(oe, 0, false, true);
|
||||
|
||||
gdiprint.print(oe, nullptr, false, true);
|
||||
gdiprint.fetchPrinterSettings(splitPrinter);
|
||||
}
|
||||
else if (bi.id == "PrintSettings") {
|
||||
@ -961,7 +965,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
pRunner r = oe->getRunner(runnerId, 0);
|
||||
if (!name.empty() && r && r->getName() != name && r->getNameRaw() != name) {
|
||||
if (gdi.ask(L"Vill du lägga till deltagaren 'X'?#" + name)) {
|
||||
r = oe->addRunner(name, 0, 0, 0,0, false);
|
||||
r = oe->addRunner(name, 0, 0, 0, L"", false);
|
||||
runnerId = r->getId();
|
||||
}
|
||||
save(gdi, runnerId, false);
|
||||
@ -973,7 +977,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
ListBoxInfo lbi;
|
||||
gdi.getSelectedItem("RClass", lbi);
|
||||
|
||||
pRunner r = oe->addRunner(oe->getAutoRunnerName(), 0,0,0,0, false);
|
||||
pRunner r = oe->addRunner(oe->getAutoRunnerName(), 0, 0, 0, L"", false);
|
||||
int clsId = lbi.data;
|
||||
if (clsId > 0) {
|
||||
pClass tCls = oe->getClass(clsId);
|
||||
@ -1095,7 +1099,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
r->synchronize();
|
||||
card->fillPunches(gdi, "Punches", r->getCourse(true));
|
||||
|
||||
gdi.setText("Time", r->getRunningTimeS(true));
|
||||
gdi.setText("Time", r->getRunningTimeS(true, SubSecond::Auto));
|
||||
gdi.selectItemByData("Status", r->getStatus());
|
||||
}
|
||||
else if (bi.id=="Check") {
|
||||
@ -1123,8 +1127,46 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
gdi.clearAutoComplete(ii.id);
|
||||
}
|
||||
}
|
||||
else if (ii.id == "CardNo") {
|
||||
bool show = false;
|
||||
if (ii.text.length() > 0) {
|
||||
vector<AutoCompleteRecord> records;
|
||||
getAutoCompleteUnpairedCards(gdi, ii.text, records);
|
||||
if (!records.empty()) {
|
||||
auto& ac = gdi.addAutoComplete(ii.id);
|
||||
ac.setAutoCompleteHandler(this);
|
||||
ac.setData(records);
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(ii.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type==GUI_INPUT) {
|
||||
else if (type == GUI_FOCUS) {
|
||||
InputInfo ii = *(InputInfo*)data;
|
||||
if (ii.id == "CardNo") {
|
||||
pRunner r = runnerId > 0 ? oe->getRunner(runnerId, 0) : nullptr;
|
||||
if (r && r->getCard() == nullptr) {
|
||||
bool show = false;
|
||||
vector<AutoCompleteRecord> records;
|
||||
getAutoCompleteUnpairedCards(gdi, L"", records);
|
||||
if (!records.empty()) {
|
||||
auto& ac = gdi.addAutoComplete(ii.id);
|
||||
ac.setAutoCompleteHandler(this);
|
||||
ac.setData(records);
|
||||
ac.show();
|
||||
show = true;
|
||||
}
|
||||
if (!show) {
|
||||
gdi.clearAutoComplete(ii.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == GUI_INPUT) {
|
||||
InputInfo ii=*(InputInfo *)data;
|
||||
|
||||
if (ii.id=="CardNo") {
|
||||
@ -1311,7 +1353,7 @@ int TabRunner::runnerCB(gdioutput &gdi, int type, void *data)
|
||||
ac.setAutoCompleteHandler(this);
|
||||
vector<AutoCompleteRecord> items;
|
||||
for (auto club : clubs)
|
||||
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
|
||||
items.emplace_back(club->getDisplayName(), -int(items.size()), club->getName(), club->getId());
|
||||
|
||||
ac.setData(items);
|
||||
ac.show();
|
||||
@ -1650,12 +1692,12 @@ void TabRunner::showRunnerReport(gdioutput &gdi) {
|
||||
}
|
||||
|
||||
wstring tInfo = t->getName();
|
||||
if (t->statusOK(true)) {
|
||||
tInfo += L", " + t->getRunningTimeS(true) + lang.tl(", Placering: ") + t->getPlaceS();
|
||||
if (t->getTimeAfter(-1) > 0)
|
||||
tInfo += L", +" + formatTime(t->getTimeAfter(-1));
|
||||
if (t->statusOK(true, true)) {
|
||||
tInfo += L", " + t->getRunningTimeS(true, SubSecond::Auto) + lang.tl(", Placering: ") + t->getPlaceS();
|
||||
if (t->getTimeAfter(-1, true) > 0)
|
||||
tInfo += L", +" + formatTime(t->getTimeAfter(-1, true));
|
||||
}
|
||||
else if (t->getStatusComputed() != StatusUnknown) {
|
||||
else if (t->getStatusComputed(true) != StatusUnknown) {
|
||||
tInfo += L" " + t->getStatusS(true, true);
|
||||
}
|
||||
|
||||
@ -1719,7 +1761,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
|
||||
gdi.dropLine(0.3);
|
||||
|
||||
if (r->statusOK(true)) {
|
||||
if (r->statusOK(true, true)) {
|
||||
int total, finished, dns;
|
||||
r->getClassRef(true)->getNumResults(r->getLegNumber(), total, finished, dns);
|
||||
|
||||
@ -1736,7 +1778,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (r->getStatusComputed() != StatusUnknown) {
|
||||
else if (r->getStatusComputed(true) != StatusUnknown) {
|
||||
gdi.addStringUT(fontMediumPlus, str).setColor(colorRed);
|
||||
}
|
||||
|
||||
@ -1747,7 +1789,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
gdi.addString("", fontMedium, L"Starttid: X #" + r->getStartTimeCompact());
|
||||
|
||||
if (r->getFinishTime() > 0)
|
||||
gdi.addString("", fontMedium, L"Måltid: X #" + r->getFinishTimeS());
|
||||
gdi.addString("", fontMedium, L"Måltid: X #" + r->getFinishTimeS(false, SubSecond::Auto));
|
||||
|
||||
const wstring &after = oe.formatListString(lRunnerTimeAfter, r);
|
||||
if (!after.empty()) {
|
||||
@ -1811,7 +1853,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
GDICOLOR color = colorDefault;
|
||||
if (k < int(after.size()) ) {
|
||||
if (after[k] > 0)
|
||||
split += L" (" + itow(place[k]) + L", +" + getTimeMS(after[k]) + L")";
|
||||
split += L" (" + itow(place[k]) + L", +" + formatTimeMS(after[k], false) + L")";
|
||||
else if (place[k] == 1)
|
||||
split += lang.tl(" (sträckseger)");
|
||||
else if (place[k] > 0)
|
||||
@ -1823,11 +1865,11 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
gdi.addStringUT(yp + lh, cx, fontMedium, split, limit);
|
||||
|
||||
if (k>0 && k < int(placeAcc.size())) {
|
||||
split = r->getPunchTimeS(k, false);
|
||||
split = r->getPunchTimeS(k, false, false, SubSecond::Auto);
|
||||
wstring pl = placeAcc[k] > 0 ? itow(placeAcc[k]) : L"-";
|
||||
if (k < int(afterAcc.size()) ) {
|
||||
if (afterAcc[k] > 0)
|
||||
split += L" (" + pl + L", +" + getTimeMS(afterAcc[k]) + L")";
|
||||
split += L" (" + pl + L", +" + formatTimeMS(afterAcc[k], false) + L")";
|
||||
else if (placeAcc[k] == 1)
|
||||
split += lang.tl(" (ledare)");
|
||||
else if (placeAcc[k] > 0)
|
||||
@ -1837,7 +1879,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
}
|
||||
|
||||
if (k < int(delta.size()) && delta[k] > 0 ) {
|
||||
gdi.addString("", yp + 3*lh, cx, fontMedium, L"Bomtid: X#" + getTimeMS(delta[k]));
|
||||
gdi.addString("", yp + 3*lh, cx, fontMedium, L"Bomtid: X#" + formatTimeMS(delta[k], false, SubSecond::Off));
|
||||
|
||||
color = (delta[k] > bestTime * 0.5 && delta[k]>60 ) ?
|
||||
colorMediumDarkRed : colorMediumRed;
|
||||
@ -1897,7 +1939,7 @@ void TabRunner::runnerReport(oEvent &oe, gdioutput &gdi, int id, bool compact) {
|
||||
if (st > 0 && t > st) {
|
||||
wstring split = formatTimeHMS(t-st);
|
||||
if (lastT>0 && st != lastT && lastT < t)
|
||||
split += L" (" + getTimeMS(t-lastT) + L")";
|
||||
split += L" (" + formatTimeMS(t-lastT, false) + L")";
|
||||
gdi.addStringUT(yp + 2*lh, cx, normalText, split, limit);
|
||||
}
|
||||
}
|
||||
@ -2267,8 +2309,8 @@ void TabRunner::updateStatus(gdioutput &gdi, pRunner r) {
|
||||
if (!r) return;
|
||||
|
||||
gdi.setText("Start", r->getStartTimeS());
|
||||
gdi.setText("Finish", r->getFinishTimeS());
|
||||
gdi.setText("Time", r->getRunningTimeS(false));
|
||||
gdi.setText("Finish", r->getFinishTimeS(false, SubSecond::Auto));
|
||||
gdi.setText("Time", r->getRunningTimeS(false, SubSecond::Auto));
|
||||
gdi.setText("Points", itow(r->getRogainingPoints(false, false)));
|
||||
|
||||
gdi.selectItemByData("Status", r->getStatus());
|
||||
@ -2321,7 +2363,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data) {
|
||||
|
||||
wstring ptime;
|
||||
if (punch->getTimeInt() > 0)
|
||||
ptime = punch->getTime();
|
||||
ptime = punch->getTime(false, SubSecond::Auto);
|
||||
|
||||
gdi.setText("PTime", ptime);
|
||||
|
||||
@ -2386,7 +2428,7 @@ int TabRunner::punchesCB(gdioutput &gdi, int type, void *data) {
|
||||
if (!oc) return 0;
|
||||
vector<int> nmp;
|
||||
|
||||
if (oc->getStatus() == oControl::StatusRogaining) {
|
||||
if (oc->getStatus() == oControl::ControlStatus::StatusRogaining || oc->getStatus() == oControl::ControlStatus::StatusRogainingRequired) {
|
||||
r->evaluateCard(true, nmp, oc->getFirstNumber(), oBase::ChangeType::Update); //Add this punch
|
||||
}
|
||||
else {
|
||||
@ -2524,6 +2566,9 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
|
||||
gdi.pushX();
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
const int hy = gdi.getCY();
|
||||
|
||||
gdi.addString("", boldLarge, "Deltagare");
|
||||
gdi.fillRight();
|
||||
gdi.registerEvent("SearchRunner", runnerSearchCB).setKeyCommand(KC_FIND);
|
||||
@ -2552,7 +2597,7 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
gdi.newColumn();
|
||||
gdi.fillDown();
|
||||
|
||||
gdi.dropLine(1);
|
||||
gdi.setCY(hy);
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
gdi.addInput("Name", L"", 16, RunnerCB, L"Namn:");
|
||||
@ -2736,11 +2781,11 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
gdi.fillDown();
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.setCY(hy);
|
||||
int hx = gdi.getCX();
|
||||
int hy = gdi.getCY();
|
||||
gdi.setCX(hx + gdi.scaleLength(5));
|
||||
|
||||
gdi.dropLine(2.5);
|
||||
gdi.dropLine(2.0);
|
||||
gdi.addListBox("Punches", 150, 300, PunchesCB, L"Stämplingar:").ignore(true);
|
||||
gdi.addButton("RemoveC", "Ta bort stämpling >>", RunnerCB);
|
||||
|
||||
@ -2755,7 +2800,8 @@ bool TabRunner::loadPage(gdioutput &gdi)
|
||||
int contY = gdi.getCY();
|
||||
|
||||
gdi.newColumn();
|
||||
gdi.dropLine(2.5);
|
||||
gdi.setCY(hy);
|
||||
gdi.dropLine(2.0);
|
||||
gdi.fillDown();
|
||||
gdi.addListBox("Course", 140, 300, PunchesCB, L"Banmall:").ignore(true);
|
||||
gdi.addButton("AddC", "<< Lägg till stämpling", PunchesCB);
|
||||
@ -3136,7 +3182,7 @@ void TabRunner::loadEconomy(gdioutput &gdi, oRunner &r) {
|
||||
|
||||
void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
|
||||
auto bi = gdi.setText(info.getTarget(), info.getCurrent().c_str());
|
||||
if (bi) {
|
||||
if (bi->id == "Name") {
|
||||
int ix = info.getCurrentInt();
|
||||
bi->setExtra(ix);
|
||||
if (info.getTarget() == "Name") {
|
||||
@ -3153,6 +3199,10 @@ void TabRunner::handleAutoComplete(gdioutput &gdi, AutoCompleteInfo &info) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bi->id == "CardNo") {
|
||||
|
||||
}
|
||||
|
||||
gdi.clearAutoComplete("");
|
||||
gdi.TabFocus(1);
|
||||
}
|
||||
@ -3173,3 +3223,81 @@ pClub TabRunner::extractClub(oEvent *oe, gdioutput &gdi) {
|
||||
}
|
||||
return dbClub;
|
||||
}
|
||||
|
||||
void TabRunner::getAutoCompleteUnpairedCards(gdioutput & gdi,
|
||||
const wstring& w,
|
||||
vector<AutoCompleteRecord>& records) {
|
||||
|
||||
pCourse matchCourse = nullptr;
|
||||
ListBoxInfo lbi;
|
||||
auto cls = gdi.getSelectedItem("RClass");
|
||||
if (runnerId) {
|
||||
pRunner r = oe->getRunner(runnerId, 0);
|
||||
if (r && r->getClassId(true) == cls.first)
|
||||
matchCourse = r->getCourse(false);
|
||||
}
|
||||
if (!matchCourse && cls.first) {
|
||||
pClass cPtr = oe->getClass(cls.first);
|
||||
|
||||
matchCourse = cPtr ? cPtr->getCourse(true) : nullptr;
|
||||
}
|
||||
|
||||
records.clear();
|
||||
int nr = _wtoi(w.c_str());
|
||||
char sIn[32];
|
||||
char sComp[32];
|
||||
|
||||
vector<pCard> cards;
|
||||
oe->getCards(cards, false, true);
|
||||
if (w.empty())
|
||||
sIn[0] = 0;
|
||||
else
|
||||
sprintf_s(sIn, "%d", nr);
|
||||
|
||||
vector<pair<int, pCard>> matchedCards;
|
||||
|
||||
for (pCard c : cards) {
|
||||
sprintf_s(sComp, "%d", c->getCardNo());
|
||||
bool match = true;
|
||||
int i = 0;
|
||||
while (sIn[i]) {
|
||||
if (sComp[i] != sIn[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (match) {
|
||||
int score = 0;
|
||||
if (matchCourse) {
|
||||
int d = matchCourse->distance(*c);
|
||||
if (d < 0)
|
||||
d = min(10 - d, 20);
|
||||
else
|
||||
d = max(d, 10);
|
||||
|
||||
int age = c->getAge();
|
||||
if (age > 10000)
|
||||
age = 10000;
|
||||
if (age < 0)
|
||||
age = 0;
|
||||
|
||||
score = d * 10000 + age;
|
||||
|
||||
matchedCards.emplace_back(score, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort(matchedCards.begin(), matchedCards.end());
|
||||
|
||||
wstring star;
|
||||
for (auto &mc : matchedCards) {
|
||||
wstring m = mc.second->getModified().getUpdateTime();
|
||||
const wstring& cno = mc.second->getCardNoString();
|
||||
star = mc.first < 3 * 10000 ? L"*" : L""; // Star if contents matches course
|
||||
records.emplace_back(cno + star + L", "
|
||||
+ lang.tl("X stämplingar#" + itos(mc.second->getNumControlPunches(-1, -1)))
|
||||
+ L" (" + m + L")", -int(records.size()), cno, mc.second->getCardNo());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -25,6 +25,7 @@
|
||||
#include "autocompletehandler.h"
|
||||
|
||||
class Table;
|
||||
struct AutoCompleteRecord;
|
||||
|
||||
class TabRunner :
|
||||
public TabBase, AutoCompleteHandler
|
||||
@ -107,6 +108,8 @@ private:
|
||||
shared_ptr<EconomyHandler> ecoHandler;
|
||||
EconomyHandler *getEconomyHandler(oRunner &r);
|
||||
|
||||
void getAutoCompleteUnpairedCards(gdioutput &gdi, const wstring& w, vector<AutoCompleteRecord>& records);
|
||||
|
||||
protected:
|
||||
void clearCompetitionData();
|
||||
public:
|
||||
|
||||
1696
code/TabSI.cpp
1696
code/TabSI.cpp
File diff suppressed because it is too large
Load Diff
66
code/TabSI.h
66
code/TabSI.h
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -30,9 +30,9 @@ struct PunchInfo;
|
||||
class csvparser;
|
||||
struct AutoCompleteRecord;
|
||||
|
||||
class TabSI : public TabBase, AutoCompleteHandler {
|
||||
class TabSI final : public TabBase, AutoCompleteHandler {
|
||||
public:
|
||||
enum SIMode {
|
||||
enum class SIMode {
|
||||
ModeReadOut,
|
||||
ModeAssignCards,
|
||||
ModeCheckCards,
|
||||
@ -40,9 +40,15 @@ public:
|
||||
ModeCardData,
|
||||
ModeRegisterCards,
|
||||
};
|
||||
|
||||
|
||||
map<SIMode, string> modeName;
|
||||
|
||||
void setMode(SIMode m) { mode = m; }
|
||||
private:
|
||||
|
||||
|
||||
|
||||
|
||||
/** Try to automatcally assign a class to runner (if none is given)
|
||||
Return true if runner has a class on exist */
|
||||
bool autoAssignClass(pRunner r, const SICard &sic);
|
||||
@ -57,13 +63,13 @@ private:
|
||||
bool silent=false);
|
||||
bool processUnmatched(gdioutput &gdi, const SICard &csic, bool silent);
|
||||
|
||||
void rentCardInfo(gdioutput &gdi, int width);
|
||||
|
||||
bool interactiveReadout;
|
||||
bool useDatabase;
|
||||
bool printSplits;
|
||||
bool printStartInfo;
|
||||
bool manualInput;
|
||||
bool multipleStarts = false;
|
||||
|
||||
PrinterObject splitPrinter;
|
||||
list< pair<unsigned, int> > printPunchRunnerIdQueue;
|
||||
void addToPrintQueue(pRunner r);
|
||||
@ -97,10 +103,9 @@ private:
|
||||
//Operation mode
|
||||
SIMode mode;
|
||||
bool lockedFunction = false;
|
||||
bool allowControl = true;
|
||||
bool allowFinish = true;
|
||||
bool allowStart = false;
|
||||
|
||||
void changeMapping(gdioutput& gdi) const;
|
||||
void fillMappings(gdioutput& gdi) const;
|
||||
int currentAssignIndex;
|
||||
|
||||
void printSIInfo(gdioutput &gdi, const wstring &port) const;
|
||||
@ -219,10 +224,47 @@ private:
|
||||
int readoutFunctionX = 0;
|
||||
int readoutFunctionY = 0;
|
||||
|
||||
int optionBarPosY = 0;
|
||||
int optionBarPosX = 0;
|
||||
int check_toolbar_xb = 0;
|
||||
int check_toolbar_yb = 0;
|
||||
|
||||
enum class CheckBox {
|
||||
Interactive,
|
||||
UseDB,
|
||||
PrintSplits,
|
||||
PrintStart,
|
||||
Manual,
|
||||
SeveralTurns,
|
||||
AutoTie,
|
||||
AutoTieRent
|
||||
};
|
||||
|
||||
void checkBoxToolBar(gdioutput& gdi, const set<CheckBox> &items) const;
|
||||
|
||||
|
||||
void playSoundResource(int res) const;
|
||||
void playSoundFile(const wstring& file) const;
|
||||
|
||||
struct StoredReadout {
|
||||
wstring info;
|
||||
wstring warnings;
|
||||
wstring cardno;
|
||||
wstring statusline;
|
||||
vector<int> MP;
|
||||
GDICOLOR color;
|
||||
bool rentCard = false;
|
||||
|
||||
RECT computeRC(gdioutput &gdi) const;
|
||||
void render(gdioutput &gdi, const RECT &rc) const;
|
||||
static void rentCardInfo(gdioutput &gdi, const RECT &rcIn);
|
||||
};
|
||||
|
||||
list<StoredReadout> readCards;
|
||||
void renderReadCard(gdioutput &gdi, int maxNumber);
|
||||
|
||||
protected:
|
||||
void clearCompetitionData();
|
||||
void clearCompetitionData() final;
|
||||
|
||||
static wstring getPlace(const oRunner *r);
|
||||
static wstring getTimeString(const oRunner *r);
|
||||
@ -271,6 +313,8 @@ public:
|
||||
|
||||
int siCB(gdioutput &gdi, int type, void *data);
|
||||
|
||||
void writeDefaultHiredCards();
|
||||
|
||||
void logCard(gdioutput &gdi, const SICard &card);
|
||||
|
||||
void setCardNumberField(const string &fieldId) {insertCardNumberField=fieldId;}
|
||||
@ -286,7 +330,7 @@ public:
|
||||
void clearQueue() { CardQueue.clear(); }
|
||||
void refillComPorts(gdioutput &gdi);
|
||||
|
||||
bool loadPage(gdioutput &gdi);
|
||||
bool loadPage(gdioutput &gdi) final;
|
||||
void showReadoutMode(gdioutput & gdi);
|
||||
|
||||
void showReadoutStatus(gdioutput &gdi, const oRunner *r,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -176,7 +176,7 @@ int TabSpeaker::processButton(gdioutput &gdi, const ButtonInfo &bu)
|
||||
gdi.fillDown();
|
||||
|
||||
vector< pair<wstring, size_t> > d;
|
||||
oe->fillControls(d, oEvent::CTCourseControl);
|
||||
oe->fillControls(d, oEvent::ControlType::CourseControl);
|
||||
gdi.addItem("Controls", d);
|
||||
|
||||
gdi.setSelection("Controls", controlsToWatch);
|
||||
@ -382,7 +382,7 @@ int TabSpeaker::processButton(gdioutput &gdi, const ButtonInfo &bu)
|
||||
controlsToWatch.insert(-2); // Non empty but no control
|
||||
|
||||
for (set<int>::iterator it=controlsToWatch.begin();it!=controlsToWatch.end();++it) {
|
||||
pControl pc=oe->getControl(*it, false);
|
||||
pControl pc=oe->getControl(*it, false, false);
|
||||
if (pc) {
|
||||
pc->setRadio(true);
|
||||
pc->synchronize(true);
|
||||
@ -722,7 +722,7 @@ void TabSpeaker::splitAnalysis(gdioutput &gdi, int xp, int yp, pRunner r)
|
||||
else
|
||||
first = false;
|
||||
|
||||
timeloss += pc->getControlOrdinal(j) + L". " + formatTime(delta[j]);
|
||||
timeloss += pc->getControlOrdinal(j) + L". " + formatTime(delta[j], SubSecond::Auto);
|
||||
}
|
||||
if (timeloss.length() > charlimit || (!timeloss.empty() && !first && j+1 == delta.size())) {
|
||||
gdi.addStringUT(yp, xp, 0, timeloss).setColor(colorDarkRed);
|
||||
@ -1223,7 +1223,7 @@ void TabSpeaker::storeManualTime(gdioutput &gdi)
|
||||
throw std::exception(bf);
|
||||
}
|
||||
|
||||
oe->addFreePunch(itime, punch, sino, true);
|
||||
oe->addFreePunch(itime, punch, 0, sino, true);
|
||||
|
||||
gdi.restore("manual", false);
|
||||
gdi.addString("", 0, L"Löpare: X, kontroll: Y, kl Z#" + Name + L"#" + oPunch::getType(punch) + L"#" + oe->getAbsTime(itime));
|
||||
@ -1432,7 +1432,7 @@ void TabSpeaker::loadSettings(vector< multimap<string, wstring> > &settings) {
|
||||
xmlList allS;
|
||||
s.getObjects(allS);
|
||||
for (auto &prop : allS) {
|
||||
settings.back().insert(make_pair(prop.getName(), prop.getw()));
|
||||
settings.back().insert(make_pair(prop.getName(), prop.getWStr()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -274,9 +274,9 @@ void TabTeam::updateTeamStatus(gdioutput &gdi, pTeam t)
|
||||
}
|
||||
|
||||
gdi.setText("Start", t->getStartTimeS());
|
||||
gdi.setText("Finish",t->getFinishTimeS());
|
||||
gdi.setText("Time", t->getRunningTimeS(true));
|
||||
gdi.setText("TimeAdjust", getTimeMS(t->getTimeAdjustment()));
|
||||
gdi.setText("Finish",t->getFinishTimeS(false, SubSecond::Auto));
|
||||
gdi.setText("Time", t->getRunningTimeS(true, SubSecond::Auto));
|
||||
gdi.setText("TimeAdjust", formatTimeMS(t->getTimeAdjustment(false), false, SubSecond::Auto));
|
||||
gdi.setText("PointAdjust", -t->getPointAdjustment());
|
||||
gdi.selectItemByData("Status", t->getStatus());
|
||||
|
||||
@ -474,7 +474,7 @@ bool TabTeam::save(gdioutput &gdi, bool dontReloadTeams) {
|
||||
}
|
||||
}
|
||||
else
|
||||
r = oe->addRunner(name, t->getClubId(), t->getClassId(false), cardNo, 0, false);
|
||||
r = oe->addRunner(name, t->getClubId(), t->getClassId(false), cardNo, L"", false);
|
||||
|
||||
r->setName(name, true);
|
||||
r->setCardNo(cardNo, true);
|
||||
@ -659,7 +659,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
|
||||
bool rent = gdi.isChecked("DirRent");
|
||||
|
||||
if (r == 0) {
|
||||
r = oe->addRunner(name, clb ? clb->getId() : t->getClubId(), t->getClassId(false), card, 0, false);
|
||||
r = oe->addRunner(name, clb ? clb->getId() : t->getClubId(), t->getClassId(false), card, L"", false);
|
||||
}
|
||||
if (rent)
|
||||
r->getDI().setInt("CardFee", oe->getBaseCardFee());
|
||||
@ -728,7 +728,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
|
||||
pTeam t = oe->getTeam(teamId);
|
||||
if (!t || !t->getClassRef(false))
|
||||
return 0;
|
||||
|
||||
t->synchronize();
|
||||
pClass pc = t->getClassRef(false);
|
||||
int nf = pc->getNumForks();
|
||||
ListBoxInfo lbi;
|
||||
@ -745,7 +745,13 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
|
||||
continue;
|
||||
|
||||
int currentKey = max(newSno-1, 0) % nf;
|
||||
if (currentKey == lbi.data) {
|
||||
if (currentKey == lbi.data) {
|
||||
for (int j = 0; j < t->getNumRunners(); j++) {
|
||||
if (t->getRunner(j)) {
|
||||
t->getRunner(j)->setCourseId(0);
|
||||
t->synchronize(true);
|
||||
}
|
||||
}
|
||||
t->setStartNo(newSno, oBase::ChangeType::Update);
|
||||
t->synchronize(true);
|
||||
t->evaluate(oBase::ChangeType::Update);
|
||||
@ -1163,6 +1169,9 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (ii.id == "R" + itos(i)) {
|
||||
enableRunner(gdi, i, !ii.text.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1177,7 +1186,7 @@ int TabTeam::teamCB(gdioutput &gdi, int type, void *data)
|
||||
ac.setAutoCompleteHandler(this);
|
||||
vector<AutoCompleteRecord> items;
|
||||
for (auto club : clubs)
|
||||
items.emplace_back(club->getDisplayName(), club->getName(), club->getId());
|
||||
items.emplace_back(club->getDisplayName(), -int(items.size()), club->getName(), club->getId());
|
||||
|
||||
ac.setData(items);
|
||||
ac.show();
|
||||
@ -1228,32 +1237,37 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
|
||||
int yp = gdi.getCY();
|
||||
int numberPos = xp;
|
||||
xp += gdi.scaleLength(25);
|
||||
int dx[6] = {0, 184, 220, 290, 316, 364};
|
||||
dx[1] = gdi.getInputDimension(18).first + gdi.scaleLength(4);
|
||||
for (int i = 2; i<6; i++)
|
||||
dx[i] = dx[1] + gdi.scaleLength(dx[i]-188);
|
||||
const int dxIn[6] = {0, 184, 220, 300, 326, 374};
|
||||
int dx[6];
|
||||
dx[0] = 0;
|
||||
|
||||
for (int i = 1; i < 6; i++) {
|
||||
if (i == 1)
|
||||
dx[i] = gdi.getInputDimension(18).first + gdi.scaleLength(4);
|
||||
else if (i == 3)
|
||||
dx[i] = dx[i-1] + gdi.getInputDimension(7).first + gdi.scaleLength(4);
|
||||
else
|
||||
dx[i] = dx[i-1] + gdi.scaleLength(dxIn[i] - dxIn[i-1]);
|
||||
}
|
||||
gdi.addString("", yp, xp + dx[0], 0, "Namn:");
|
||||
gdi.addString("", yp, xp + dx[2], 0, "Bricka:");
|
||||
gdi.addString("", yp, xp + dx[3], 0, "Hyrd:");
|
||||
gdi.addString("", yp, xp + dx[3]- gdi.scaleLength(5), 0, "Hyrd:");
|
||||
gdi.addString("", yp, xp + dx[5], 0, "Status:");
|
||||
gdi.dropLine(0.5);
|
||||
|
||||
const int textOffY = gdi.scaleLength(4);
|
||||
for (unsigned i = 0; i < pc->getNumStages(); i++) {
|
||||
yp = gdi.getCY() - gdi.scaleLength(3);
|
||||
|
||||
sprintf_s(bf, "R%d", i);
|
||||
gdi.pushX();
|
||||
bool hasSI = false;
|
||||
gdi.addStringUT(yp, numberPos, 0, pc->getLegNumber(i) + L".");
|
||||
gdi.addStringUT(yp + textOffY, numberPos, 0, pc->getLegNumber(i) + L".");
|
||||
if (pc->getLegRunner(i) == i) {
|
||||
|
||||
gdi.addInput(xp + dx[0], yp, bf, L"", 18, TeamCB);//Name
|
||||
gdi.addButton(xp + dx[1], yp - 2, gdi.scaleLength(28), "DR" + itos(i), "<>", TeamCB, "Knyt löpare till sträckan.", false, false); // Change
|
||||
sprintf_s(bf_si, "SI%d", i);
|
||||
hasSI = true;
|
||||
gdi.addInput(xp + dx[2], yp, bf_si, L"", 5, TeamCB).setExtra(i); //Si
|
||||
|
||||
gdi.addInput(xp + dx[2], yp, bf_si, L"", 7, TeamCB).setExtra(i); //Si
|
||||
gdi.addCheckbox(xp + dx[3], yp + gdi.scaleLength(10), "RENT" + itos(i), "", 0, false); //Rentcard
|
||||
}
|
||||
else {
|
||||
@ -1262,16 +1276,17 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
|
||||
}
|
||||
gdi.addButton(xp + dx[4], yp - 2, gdi.scaleLength(38), "MR" + itos(i), "...", TeamCB, "Redigera deltagaren.", false, false); // Change
|
||||
|
||||
gdi.addString(("STATUS" + itos(i)).c_str(), yp + gdi.scaleLength(5), xp + dx[5], 0, "#MMMMMMMMMMMMMMMM");
|
||||
gdi.addString(("STATUS" + itos(i)).c_str(), yp + textOffY, xp + dx[5], 0, "#MMMMMMMMMMMMMMMM");
|
||||
gdi.setText("STATUS" + itos(i), L"", false);
|
||||
gdi.dropLine(0.5);
|
||||
gdi.popX();
|
||||
|
||||
if (t) {
|
||||
pRunner r = t->getRunner(i);
|
||||
enableRunner(gdi, i, r != nullptr);
|
||||
if (r) {
|
||||
gdi.setText(bf, r->getNameRaw())->setExtra(r->getId());
|
||||
|
||||
r->getPlace(true); // Ensure computed status is up-to-date
|
||||
if (hasSI) {
|
||||
int cno = r->getCardNo();
|
||||
gdi.setText(bf_si, cno > 0 ? itow(cno) : L"");
|
||||
@ -1279,13 +1294,13 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
|
||||
gdi.check("RENT" + itos(i), r->getDCI().getInt("CardFee") != 0);
|
||||
}
|
||||
string sid = "STATUS" + itos(i);
|
||||
if (r->statusOK(true)) {
|
||||
TextInfo * ti = (TextInfo *)gdi.setText(sid, L"OK, " + r->getRunningTimeS(true), false);
|
||||
if (r->statusOK(true, true)) {
|
||||
TextInfo * ti = (TextInfo *)gdi.setText(sid, L"OK, " + r->getRunningTimeS(true, SubSecond::Auto), false);
|
||||
if (ti)
|
||||
ti->setColor(colorGreen);
|
||||
}
|
||||
else if (r->getStatusComputed() != StatusUnknown) {
|
||||
TextInfo * ti = (TextInfo *)gdi.setText(sid, r->getStatusS(false, true) + L", " + r->getRunningTimeS(true), false);
|
||||
else if (r->getStatusComputed(true) != StatusUnknown) {
|
||||
TextInfo * ti = (TextInfo *)gdi.setText(sid, r->getStatusS(false, true) + L", " + r->getRunningTimeS(true, SubSecond::Auto), false);
|
||||
if (ti)
|
||||
ti->setColor(colorRed);
|
||||
}
|
||||
@ -1334,6 +1349,15 @@ void TabTeam::loadTeamMembers(gdioutput &gdi, int ClassId, int ClubId, pTeam t)
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void TabTeam::enableRunner(gdioutput& gdi, int index, bool enable) {
|
||||
string ix = itos(index);
|
||||
string si = ("SI" + ix);
|
||||
bool hasSI = enable || !gdi.getText(si, true).empty();
|
||||
gdi.setInputStatus(si.c_str(), hasSI, true);
|
||||
gdi.setInputStatus(("RENT" + ix).c_str(), hasSI, true);
|
||||
gdi.setInputStatus(("MR" + ix).c_str(), enable, true);
|
||||
}
|
||||
|
||||
bool TabTeam::loadPage(gdioutput &gdi, int id) {
|
||||
teamId = id;
|
||||
return loadPage(gdi);
|
||||
@ -1457,12 +1481,13 @@ bool TabTeam::loadPage(gdioutput &gdi)
|
||||
gdi.popX();
|
||||
gdi.selectItemByData("Status", 0);
|
||||
|
||||
gdi.addString("TeamInfo", 0, "").setColor(colorRed);
|
||||
gdi.dropLine(0.4);
|
||||
|
||||
if (oe->hasAnyRestartTime()) {
|
||||
gdi.addCheckbox("NoRestart", "Förhindra omstart", 0, false, "Förhindra att laget deltar i någon omstart");
|
||||
}
|
||||
|
||||
gdi.addString("TeamInfo", 0, " ").setColor(colorRed);
|
||||
gdi.dropLine(1.5);
|
||||
|
||||
const bool multiDay = oe->hasPrevStage();
|
||||
@ -1694,7 +1719,7 @@ void TabTeam::saveTeamImport(gdioutput &gdi, bool useExisting) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
r = oe->addRunner(member.name, member.club, 0, member.cardNo, 0, false);
|
||||
r = oe->addRunner(member.name, member.club, 0, member.cardNo, L"", false);
|
||||
|
||||
if (r && !member.course.empty()) {
|
||||
pCourse pc = oe->getCourse(member.course);
|
||||
@ -1783,7 +1808,7 @@ void TabTeam::doAddTeamMembers(gdioutput &gdi) {
|
||||
continue;
|
||||
pRunner r = 0;
|
||||
if (withFee) {
|
||||
r = oe->addRunner(nn, mt->getClubId(), 0, 0, 0, false);
|
||||
r = oe->addRunner(nn, mt->getClubId(), 0, 0, L"", false);
|
||||
r->synchronize();
|
||||
mt->setRunner(j, r, false);
|
||||
r->addClassDefaultFee(true);
|
||||
@ -1849,7 +1874,7 @@ void TabTeam::showRunners(gdioutput &gdi, const char *title,
|
||||
void TabTeam::processChangeRunner(gdioutput &gdi, pTeam t, int leg, pRunner r) {
|
||||
if (r && t && leg < t->getNumRunners()) {
|
||||
pRunner oldR = t->getRunner(leg);
|
||||
gdioutput::AskAnswer ans = gdioutput::AnswerNo;
|
||||
gdioutput::AskAnswer ans = gdioutput::AskAnswer::AnswerNo;
|
||||
if (r == oldR) {
|
||||
gdi.restore("SelectR");
|
||||
return;
|
||||
@ -1868,9 +1893,9 @@ void TabTeam::processChangeRunner(gdioutput &gdi, pTeam t, int leg, pRunner r) {
|
||||
ans = gdi.askCancel(L"Vill du att X går in i laget?#" + r->getName());
|
||||
}
|
||||
|
||||
if (ans == gdioutput::AnswerNo)
|
||||
if (ans == gdioutput::AskAnswer::AnswerNo)
|
||||
return;
|
||||
else if (ans == gdioutput::AnswerCancel) {
|
||||
else if (ans == gdioutput::AskAnswer::AnswerCancel) {
|
||||
gdi.restore("SelectR");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -74,6 +74,10 @@ private:
|
||||
|
||||
void switchRunners(pTeam team, int leg, pRunner r, pRunner oldR);
|
||||
|
||||
/** Enable or disable edit for a team runner*/
|
||||
void enableRunner(gdioutput &gdi, int index, bool enable);
|
||||
|
||||
|
||||
protected:
|
||||
void clearCompetitionData();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -278,7 +278,8 @@ void Table::filter(int col, const wstring &filt, bool forceFilter)
|
||||
|
||||
sortIndex.resize(2);
|
||||
for (size_t k=2;k<baseIndex.size();k++) {
|
||||
if (filterMatchString(Data[baseIndex[k].index].cells[col].contents, filt_lc))
|
||||
int score;
|
||||
if (filterMatchString(Data[baseIndex[k].index].cells[col].contents, filt_lc, score))
|
||||
sortIndex.push_back(baseIndex[k]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -415,6 +415,7 @@ struct TableSortIndex {
|
||||
enum {TID_CLASSNAME, TID_COURSE, TID_NUM, TID_ID, TID_MODIFIED,
|
||||
TID_RUNNER, TID_CLUB, TID_START, TID_TIME,
|
||||
TID_FINISH, TID_STATUS, TID_RUNNINGTIME, TID_PLACE, TID_POINTS,
|
||||
TID_CARD, TID_TEAM, TID_LEG, TID_CONTROL, TID_CODES, TID_FEE, TID_PAID,
|
||||
TID_CARD, TID_TEAM, TID_LEG, TID_CONTROL, TID_UNIT, TID_CODES, TID_FEE, TID_PAID,
|
||||
TID_INPUTTIME, TID_INPUTSTATUS, TID_INPUTPOINTS, TID_INPUTPLACE,
|
||||
TID_NAME, TID_NATIONAL, TID_SEX, TID_YEAR, TID_INDEX, TID_ENTER, TID_STARTNO, TID_VOLTAGE};
|
||||
TID_NAME, TID_NATIONAL, TID_SEX, TID_YEAR, TID_INDEX,
|
||||
TID_ENTER, TID_STARTNO, TID_VOLTAGE, TID_BATTERYDATE};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -62,7 +62,7 @@ void TimeStamp::update()
|
||||
|
||||
__int64 ¤ttime=*(__int64*)&ft;
|
||||
|
||||
Time=unsigned((currenttime/10000000L) - minYearConstant*365*24*3600);
|
||||
Time=unsigned((currenttime/10000000L) - minYearConstant*365*24*timeConstSecPerHour);
|
||||
}
|
||||
|
||||
int TimeStamp::getAge() const
|
||||
@ -73,7 +73,7 @@ int TimeStamp::getAge() const
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
__int64 ¤ttime=*(__int64*)&ft;
|
||||
|
||||
int CTime=int((currenttime/10000000)-minYearConstant*365*24*3600);
|
||||
int CTime=int((currenttime/10000000)-minYearConstant*365*24* timeConstSecPerHour);
|
||||
|
||||
return CTime-Time;
|
||||
}
|
||||
@ -84,7 +84,7 @@ const string &TimeStamp::getStamp() const
|
||||
return stampCode;
|
||||
|
||||
stampCodeTime = Time;
|
||||
__int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000;
|
||||
__int64 ft64=(__int64(Time)+minYearConstant*365*24* timeConstSecPerHour)*10000000;
|
||||
FILETIME &ft=*(FILETIME*)&ft64;
|
||||
SYSTEMTIME st;
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
@ -105,9 +105,20 @@ const string &TimeStamp::getStamp(const string &sqlStampIn) const {
|
||||
return stampCode;
|
||||
}
|
||||
|
||||
const wstring TimeStamp::getUpdateTime() const {
|
||||
__int64 ft64 = (__int64(Time) + minYearConstant * 365 * 24 * timeConstSecPerHour) * 10000000;
|
||||
FILETIME& ft = *(FILETIME*)&ft64;
|
||||
SYSTEMTIME st;
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
wchar_t bf[32];
|
||||
swprintf_s(bf, L"%02d:%02d", st.wHour, st.wMinute);
|
||||
return bf;
|
||||
}
|
||||
|
||||
|
||||
wstring TimeStamp::getStampString() const
|
||||
{
|
||||
__int64 ft64=(__int64(Time)+minYearConstant*365*24*3600)*10000000;
|
||||
__int64 ft64=(__int64(Time)+minYearConstant*365*24* timeConstSecPerHour)*10000000;
|
||||
FILETIME &ft=*(FILETIME*)&ft64;
|
||||
SYSTEMTIME st;
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
@ -120,7 +131,7 @@ wstring TimeStamp::getStampString() const
|
||||
|
||||
string TimeStamp::getStampStringN() const
|
||||
{
|
||||
__int64 ft64 = (__int64(Time) + minYearConstant * 365 * 24 * 3600) * 10000000;
|
||||
__int64 ft64 = (__int64(Time) + minYearConstant * 365 * 24 * timeConstSecPerHour) * 10000000;
|
||||
FILETIME &ft = *(FILETIME*)&ft64;
|
||||
SYSTEMTIME st;
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
@ -147,19 +158,41 @@ void TimeStamp::setStamp(const string &s)
|
||||
SYSTEMTIME st;
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
auto parse = [](const char* data, int size, const char*& next) -> int {
|
||||
int ix = 0;
|
||||
int out = 0;
|
||||
while (ix < size && data[ix] >= '0' && data[ix] <= '9') {
|
||||
out = (out << 1) + (out << 3) + data[ix] - '0';
|
||||
ix++;
|
||||
}
|
||||
while (data[ix] && (data[ix] == ' ' || data[ix] == '-' || data[ix] == ':')) {
|
||||
ix++;
|
||||
}
|
||||
next = data + ix;
|
||||
return out;
|
||||
};
|
||||
|
||||
//const char *ptr=s.c_str();
|
||||
//sscanf(s.c_str(), "%4hd%2hd%2hd%2hd%2hd%2hd", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
st.wYear=atoi(s.substr(0, 4).c_str());
|
||||
/*st.wYear = atoi(s.substr(0, 4).c_str());
|
||||
st.wMonth=atoi(s.substr(4, 2).c_str());
|
||||
st.wDay=atoi(s.substr(6, 2).c_str());
|
||||
st.wHour=atoi(s.substr(8, 2).c_str());
|
||||
st.wMinute=atoi(s.substr(10, 2).c_str());
|
||||
st.wSecond=atoi(s.substr(12, 2).c_str());
|
||||
*/
|
||||
const char* ptr = s.data();
|
||||
|
||||
st.wYear = parse(ptr, 4, ptr);
|
||||
st.wMonth = parse(ptr, 2, ptr);
|
||||
st.wDay = parse(ptr, 2, ptr);
|
||||
st.wHour = parse(ptr, 2, ptr);
|
||||
st.wMinute = parse(ptr, 2, ptr);
|
||||
st.wSecond = parse(ptr, 2, ptr);
|
||||
FILETIME ft;
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
|
||||
__int64 ¤ttime=*(__int64*)&ft;
|
||||
|
||||
Time = unsigned((currenttime/10000000)-minYearConstant*365*24*3600);
|
||||
Time = unsigned((currenttime/10000000)-minYearConstant*365*24* timeConstSecPerHour);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#endif // _MSC_VER > 1000
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -39,6 +39,8 @@ public:
|
||||
const string &getStamp() const;
|
||||
const string &getStamp(const string &sqlStampIn) const;
|
||||
|
||||
const wstring getUpdateTime() const;
|
||||
|
||||
wstring getStampString() const;
|
||||
string getStampStringN() const;
|
||||
int getAge() const;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -42,7 +42,7 @@ AnimationData::AnimationData(gdioutput &gdi, int timePerPage, int nCol,
|
||||
double w = (gdi.getWidth() + 20) *nCol + margin;
|
||||
double s = width / w;
|
||||
if ((fabs(s - 1.0) > 1e-3)) {
|
||||
gdi.scaleSize(s, true, false);
|
||||
gdi.scaleSize(s, true, gdioutput::ScaleOperation::NoRefresh);
|
||||
}
|
||||
pageInfo.topMargin = 20;
|
||||
pageInfo.scaleX = 1.0f;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -176,7 +176,10 @@ void AutoCompleteInfo::enter() {
|
||||
}
|
||||
}
|
||||
|
||||
void AutoCompleteInfo::setData(const vector<AutoCompleteRecord> &items) {
|
||||
void AutoCompleteInfo::setData(const vector<AutoCompleteRecord> &itemsIn) {
|
||||
vector<AutoCompleteRecord> items = itemsIn;
|
||||
stable_sort(items.begin(), items.end());
|
||||
|
||||
int newDataIx = -1;
|
||||
if (modifedAutoComplete && size_t(currentIx) < data.size()) {
|
||||
for (size_t k = 0; k < items.size(); k++) {
|
||||
@ -188,6 +191,6 @@ void AutoCompleteInfo::setData(const vector<AutoCompleteRecord> &items) {
|
||||
newDataIx = 0;
|
||||
modifedAutoComplete = false;
|
||||
}
|
||||
data = items;
|
||||
data = std::move(items);
|
||||
currentIx = newDataIx;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -29,10 +29,17 @@ class AutoCompleteHandler;
|
||||
|
||||
struct AutoCompleteRecord {
|
||||
AutoCompleteRecord() : id(-1) {}
|
||||
AutoCompleteRecord(const wstring &display, const wstring &name, int id) : display(display), name(name), id(id) {}
|
||||
AutoCompleteRecord(const wstring &display, int prio, const wstring &name, int id) : display(display), prio(prio), name(name), id(id) {}
|
||||
wstring display;
|
||||
wstring name;
|
||||
int id;
|
||||
int prio = 0;
|
||||
bool operator<(const AutoCompleteRecord& rec) const {
|
||||
if (prio != rec.prio)
|
||||
return prio > rec.prio;
|
||||
else
|
||||
return display < rec.display;
|
||||
}
|
||||
};
|
||||
|
||||
class AutoCompleteInfo {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
204
code/binencoder.cpp
Normal file
204
code/binencoder.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Melin Software HB - software@melin.nu - www.melin.nu
|
||||
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "meos_util.h"
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include "binencoder.h"
|
||||
|
||||
Encoder92::Encoder92() {
|
||||
int d = 32;
|
||||
fill(reverse_table, reverse_table + 128, 0);
|
||||
fill(used, used + 128, false);
|
||||
for (int j = 0; j < 92; j++) {
|
||||
table[j] = d++;
|
||||
while (d == '"' || d == '<' || d == '&' || d=='>')
|
||||
d++;
|
||||
}
|
||||
table[91] = '\t';
|
||||
swap(table[0], table[1]);
|
||||
|
||||
for (int j = 0; j < 92; j++) {
|
||||
reverse_table[table[j]] = j;
|
||||
used[table[j]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder92::encode92(const uint8_t datain[13], uint8_t dataout[16]) {
|
||||
uint64_t w64bitA = *(uint64_t*)&datain[0];
|
||||
uint32_t w32bitB = *(uint32_t*)&datain[8];
|
||||
uint32_t w8bitC = datain[12];
|
||||
|
||||
// Consume 60 bits of data from w64bitA (4 bits will remain)
|
||||
for (int i = 0; i < 10; i++) {
|
||||
dataout[i] = w64bitA & 0b00111111;
|
||||
w64bitA = w64bitA >> 6;
|
||||
}
|
||||
|
||||
// Consume 30 bits of data from w32bitB (2 bits will remain)
|
||||
for (int i = 10; i < 15; i++) {
|
||||
dataout[i] = w32bitB & 0b00111111;
|
||||
w32bitB = w32bitB >> 6;
|
||||
}
|
||||
|
||||
// Consume remaining 2 + 4 bits
|
||||
dataout[15] = int8_t(w32bitB | (w64bitA << 2));
|
||||
|
||||
for (int i = 0; i < 16; i+=2) {
|
||||
int extraData = (w8bitC & 0x1);
|
||||
w8bitC = w8bitC >> 1;
|
||||
int combined = (extraData << 12) | dataout[i] | (dataout[i+1] << 6); // 13 bits 0 -- 8192
|
||||
dataout[i] = combined % 92;
|
||||
dataout[i+1] = combined / 92;
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder92::decode92(const uint8_t datain[16], uint8_t dataout[13]) {
|
||||
uint8_t datain_64[16];
|
||||
uint32_t w8bitC = 0;
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
int combined = datain[i] + datain[i + 1] * 92;
|
||||
datain_64[i] = combined & 0b00111111;
|
||||
combined = combined >> 6;
|
||||
datain_64[i+1] = combined & 0b00111111;
|
||||
combined = combined >> 6;
|
||||
w8bitC |= (combined << (i/2));
|
||||
}
|
||||
|
||||
uint64_t w64bitA = 0;
|
||||
uint32_t w32bitB = 0;
|
||||
|
||||
// Reconstruct 60 bits of data to w64bitA
|
||||
for (int i = 9; i >= 0; i--) {
|
||||
w64bitA <<= 6;
|
||||
w64bitA |= datain_64[i];
|
||||
}
|
||||
|
||||
// Reconstruct 30 bits of data to w32bitB
|
||||
for (int i = 14; i >= 10; i--) {
|
||||
w32bitB <<= 6;
|
||||
w32bitB |= datain_64[i];
|
||||
}
|
||||
|
||||
// Add remaining bits
|
||||
w32bitB = w32bitB | ((datain_64[15] & 0b11) << 30);
|
||||
uint64_t highBits = (datain_64[15] >> 2) & 0b1111;
|
||||
w64bitA = w64bitA | (highBits << 60ll);
|
||||
|
||||
*((uint64_t*)&dataout[0]) = w64bitA;
|
||||
*((uint32_t*)&dataout[8]) = w32bitB;
|
||||
dataout[12] = int8_t(w8bitC);
|
||||
}
|
||||
|
||||
|
||||
void Encoder92::encode92(const vector<uint8_t>& bytesIn, string& encodedString) {
|
||||
int m13 = bytesIn.size()%13;
|
||||
int extra = m13 > 0 ? 13 - m13 : 0;
|
||||
int blocks = (bytesIn.size() + extra) / 13;
|
||||
|
||||
encodedString = itos(bytesIn.size()) + ":";
|
||||
int outLen = encodedString.length();
|
||||
encodedString.resize(encodedString.size() + blocks * 16, ' ');
|
||||
const uint8_t* inPtr = bytesIn.data();
|
||||
//uint8_t* outPtr = encodedString.data() + outLen;
|
||||
uint8_t datain[13];
|
||||
fill(datain, datain + 13, 0);
|
||||
uint8_t dataout[16];
|
||||
int fullBlocks = blocks;
|
||||
if (extra > 0)
|
||||
fullBlocks--;
|
||||
|
||||
for (int i = 0; i < fullBlocks; i++) {
|
||||
//for (int j = 0; j < 13; j++)
|
||||
encode92(inPtr, dataout);
|
||||
inPtr += 13;
|
||||
for (int j = 0; j < 16; j++)
|
||||
encodedString[outLen++] = table[dataout[j]];
|
||||
}
|
||||
|
||||
if (extra > 0) {
|
||||
for (int j = 0; j < m13; j++) {
|
||||
datain[j] = inPtr[j];
|
||||
}
|
||||
encode92(datain, dataout);
|
||||
for (int j = 0; j < 16; j++)
|
||||
encodedString[outLen++] = table[dataout[j]];
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder92::decode92(const string& encodedString, vector<uint8_t>& bytesOut) {
|
||||
bytesOut.clear();
|
||||
if (encodedString.empty())
|
||||
return;
|
||||
|
||||
unsigned size = atoi(encodedString.c_str());
|
||||
string start = itos(size);
|
||||
int len = start.length();
|
||||
if (encodedString.size() < len || encodedString[len] != ':' || size<0)
|
||||
throw std::exception("Invalid data");
|
||||
|
||||
int m13 = size % 13;
|
||||
int extra = m13 > 0 ? 13 - m13 : 0;
|
||||
int blocks = (size + extra) / 13;
|
||||
|
||||
int inDataSize = blocks * 16;
|
||||
if (encodedString.size() < len + 1 + inDataSize)
|
||||
throw std::exception("Invalid data");
|
||||
|
||||
bytesOut.resize(size);
|
||||
auto outPtr = bytesOut.data();
|
||||
|
||||
uint8_t datain[16];
|
||||
uint8_t dataout[13];
|
||||
int fullBlocks = blocks;
|
||||
if (extra > 0)
|
||||
fullBlocks--;
|
||||
|
||||
const char *inPtr = encodedString.c_str() + len + 1;
|
||||
|
||||
for (int i = 0; i < fullBlocks; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
int v = inPtr[j];
|
||||
if (v < 0 || v > 127 || !used[v])
|
||||
throw std::exception("Invalid data");
|
||||
datain[j] = reverse_table[inPtr[j]];
|
||||
}
|
||||
decode92(datain, outPtr);
|
||||
inPtr += 16;
|
||||
outPtr += 13;
|
||||
}
|
||||
|
||||
if (extra > 0) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
int v = inPtr[j];
|
||||
if (v < 0 || v > 127 || !used[v])
|
||||
throw std::exception("Invalid data");
|
||||
datain[j] = reverse_table[inPtr[j]];
|
||||
}
|
||||
decode92(datain, dataout);
|
||||
for (int j = 0; j < m13; j++)
|
||||
outPtr[j] = dataout[j];
|
||||
}
|
||||
}
|
||||
|
||||
39
code/binencoder.h
Normal file
39
code/binencoder.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Melin Software HB - software@melin.nu - www.melin.nu
|
||||
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
||||
|
||||
************************************************************************/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class Encoder92 {
|
||||
int8_t table[92];
|
||||
int8_t reverse_table[128];
|
||||
bool used[128];
|
||||
public:
|
||||
Encoder92();
|
||||
|
||||
void encode92(const uint8_t datain[13], uint8_t dataout[16]);
|
||||
void decode92(const uint8_t datain[16], uint8_t dataout[13]);
|
||||
|
||||
void encode92(const vector<uint8_t>& bytesIn, string& encodedString);
|
||||
void decode92(const string& encodedString, vector<uint8_t>& bytesOut);
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -220,7 +220,7 @@ void oEvent::getClassConfigurationInfo(ClassConfigInfo &cnf) const
|
||||
|
||||
for (size_t k = 0; k < it->getNumStages(); k++) {
|
||||
StartTypes st = it->getStartType(k);
|
||||
if (st == STDrawn || st == STHunting) {
|
||||
if (st == STDrawn || st == STPursuit) {
|
||||
cnf.legNStart[k].push_back(it->getId());
|
||||
if (cnf.timeStart.size() <= k)
|
||||
cnf.timeStart.resize(k+1);
|
||||
@ -243,7 +243,7 @@ void oEvent::getClassConfigurationInfo(ClassConfigInfo &cnf) const
|
||||
|
||||
for (size_t k = 0; k < it->getNumStages(); k++) {
|
||||
StartTypes st = it->getStartType(k);
|
||||
if (st == STDrawn || st == STHunting) {
|
||||
if (st == STDrawn || st == STPursuit) {
|
||||
cnf.raceNStart[k].push_back(it->getId());
|
||||
if (cnf.timeStart.size() <= k)
|
||||
cnf.timeStart.resize(k+1);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -189,11 +189,10 @@ bool csvparser::importOS_CSV(oEvent &event, const wstring &file)
|
||||
//Import runners!
|
||||
int runner=0;
|
||||
while( (rindex+OSRrentcard)<sp.size() && sp[rindex+OSRfname].length()>0 ){
|
||||
int year = extendYear(wtoi(sp[rindex+OSRyb]));
|
||||
int cardNo = wtoi(sp[rindex+OSRcard]);
|
||||
wstring sname = sp[rindex+OSRsname] + L", " + sp[rindex+OSRfname];
|
||||
pRunner r = event.addRunner(sname, ClubId,
|
||||
ClassId, cardNo, year, false);
|
||||
ClassId, cardNo, sp[rindex + OSRyb], false);
|
||||
|
||||
r->setEntrySource(externalSourceId);
|
||||
oDataInterface DI=r->getDI();
|
||||
@ -697,10 +696,10 @@ bool csvparser::importRAID(oEvent &event, const wstring &file)
|
||||
}
|
||||
|
||||
//Import runners!
|
||||
pRunner r1=event.addRunner(sp[RAIDrunner1], ClubId, ClassId, 0, 0, false);
|
||||
pRunner r1=event.addRunner(sp[RAIDrunner1], ClubId, ClassId, 0, L"", false);
|
||||
team->setRunner(0, r1, false);
|
||||
|
||||
pRunner r2=event.addRunner(sp[RAIDrunner2], ClubId, ClassId, 0, 0, false);
|
||||
pRunner r2=event.addRunner(sp[RAIDrunner2], ClubId, ClassId, 0, L"", false);
|
||||
team->setRunner(1, r2, false);
|
||||
|
||||
team->evaluate(oBase::ChangeType::Update);
|
||||
@ -812,15 +811,16 @@ bool csvparser::importPunches(const oEvent &oe, const wstring &file, vector<Punc
|
||||
if (ret == -1)
|
||||
return false; // Invalid file
|
||||
if (ret > 0) {
|
||||
int card = wtoi(sp[cardIndex]);
|
||||
int time = oe.getRelativeTime(processedTime);
|
||||
const int card = wtoi(sp[cardIndex]);
|
||||
const int time = oe.getRelativeTime(processedTime);
|
||||
|
||||
if (card>0) {
|
||||
PunchInfo pi;
|
||||
pi.card = card;
|
||||
pi.time = time;
|
||||
string pd(processedDate.begin(), processedDate.end());
|
||||
strncpy_s(pi.date, sizeof(pi.date), pd.c_str(), 26);
|
||||
//string pd(processedDate.begin(), processedDate.end());
|
||||
string pd = gdioutput::narrow(processedDate);
|
||||
strncpy_s(pi.date, pd.c_str(), 26);
|
||||
pi.date[26] = 0;
|
||||
punches.push_back(pi);
|
||||
nimport++;
|
||||
@ -1204,7 +1204,7 @@ void csvparser::parse(const wstring &file, list< vector<wstring> > &data) {
|
||||
string rbf;
|
||||
|
||||
if (!fin.good())
|
||||
throw meosException("Failed to read file");
|
||||
throw meosException(L"Failed to read file, " + file);
|
||||
|
||||
bool isUTF8 = false;
|
||||
bool firstLine = true;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -162,10 +162,11 @@ ClassResultFraction = Fraction of class complete
|
||||
ClassStartName = Start name
|
||||
ClassStartTime = Class, start time, name
|
||||
ClassStartTimeClub = Class, start time, club
|
||||
ClubClassStartTime = Club, class, start time
|
||||
ClassTotalResult = Class, total result
|
||||
Club = Club
|
||||
ClubName = Club
|
||||
ClubRunner = Club (competitor)
|
||||
ClubRunner = Club (Competitors)
|
||||
CmpDate = Competition date
|
||||
CmpName = Competition name
|
||||
CourseClimb = Course climb
|
||||
@ -282,7 +283,7 @@ FilterHasCard = With card
|
||||
FilterNoCard = Without card
|
||||
FilterNotVacant = Not vacant
|
||||
FilterOnlyVacant = Only vacant
|
||||
FilterRentCard = Borrowed card
|
||||
FilterRentCard = Hired card
|
||||
FilterResult = With result
|
||||
FilterStarted = Has started
|
||||
Filtrering = Filtering
|
||||
@ -357,10 +358,10 @@ Hjälp = Help
|
||||
Hoppar över stafettklass: X = Skipping relay class: X
|
||||
Huvudlista = Main list
|
||||
Hyravgift = Card hire
|
||||
Hyrbricka = Borrowed card
|
||||
Hyrbricksrapport = Report with Borrowed Cards
|
||||
Hyrbricksrapport - %s = Borrowed Cards - %s
|
||||
Hyrd = Borrowed
|
||||
Hyrbricka = Hired card
|
||||
Hyrbricksrapport = Report with Hired Cards
|
||||
Hyrbricksrapport - %s = Hired Cards - %s
|
||||
Hyrd = Hired
|
||||
Hämta (efter)anmälningar från Eventor = Fetch (late) entries from Eventor
|
||||
Hämta data från Eventor = Fetch Data from Eventor
|
||||
Hämta efteranmälningar = Fetch Late Entries
|
||||
@ -393,7 +394,7 @@ Importera = Import
|
||||
Importera IOF (xml) = Import IOF (xml)
|
||||
Importera anmälningar = Import Entries
|
||||
Importera banor = Import Courses
|
||||
Importera banor/klasser = Import courses/classes
|
||||
Importera banor/klasser = Import Courses and Classes
|
||||
Importera en tävling från fil = Import competition from file
|
||||
Importera fil = Import File
|
||||
Importera från OCAD = Import from OCAD
|
||||
@ -1041,7 +1042,7 @@ TeamClub = Team's club
|
||||
TeamLegTimeAfter = Team's time behind on leg
|
||||
TeamLegTimeStatus = Team's time / status on leg
|
||||
TeamName = Team name
|
||||
TeamPlace = Team's place
|
||||
TeamPlace = Team's place after leg
|
||||
TeamRogainingPoint = Team's rogaining points
|
||||
TeamRunner = Name of team member
|
||||
TeamRunnerCard = Card number of team member
|
||||
@ -1242,7 +1243,7 @@ Välj vilka kolumner du vill visa = Choose columns to show
|
||||
Välj vy = Choose view
|
||||
Välkommen till MeOS = Welcome to MeOS
|
||||
Vänligen betala senast = Please pay at latest
|
||||
Vänligen återlämna hyrbrickan = Please return your borrowed card
|
||||
Vänligen återlämna hyrbrickan = Please return your hired card
|
||||
Växling = Changeover
|
||||
Webb = Web Document
|
||||
Webbdokument = Web document
|
||||
@ -1319,7 +1320,7 @@ help:41072 = Select a punch from the list to change or remove it. You can add mi
|
||||
help:41641 = Enter a first start time and start interval. Draw random gives an unconditionally random start order. Swedish draw method uses special rules to distribute runners from the same club. Clumped start means the whole class starts in small groups during the specified interval (extended mass start). In the field leg, you can specify which leg is to be drawn, if the class has several.
|
||||
help:425188 = You can handle runners that didn't start automatically by reading out SI stations (clear/check/start/controls) in SportIdent Config+. Save the readout as a semi colon separated text file and import this file into MeOS. Runners in this import get a registration. Then you can give DNS status to all runners without registration. If you later import more runners, you can reset the status (from DNS to Unknown) on the runners now imported.
|
||||
info:readoutbase = Activate the SI unit by selecting its COM-port, or by searching for installed SI units. Press Information to get status for the selected port.\n\nInteractive readout lets you directly handle problems, such as wrong card number. Do not use this option when runners with problems are handled separately.\n\nThe runner database is used if you want to automatically add new runners. The punches are used to find (guess) the right class.
|
||||
info:readoutmore = Sound selection lets you enable sound signals to be played back on reading out a card.\n\nShow readout in window opens a new window designed to be shown on a screen turned towards the competitor.\n\nIf you have connected a punching unit (for example finish punch) you can decide if you want to accept start, radio, or finish punches. This is a filter to prevent (for example) unexpected start punches from being recieved by mistake, which could overwrite the drawn starting time.
|
||||
info:readoutmore = Lock the function to prevent accidental changes.\n\nSound selection lets you enable sound signals to be played back on reading out a card.\n\nOpen Readout Window shows a new window designed to be shown on a screen turned towards the competitor, showing information about the last readout.\n\nSeveral races per competitor can be used if you are allowed do several attempts on the course. A new entry is created for each readout.
|
||||
help:50431 = You are now connected to a server. To open a competition on the server, select it in the list and click open. Do add a competition to the server, open the competition locally and select upload. When you have opened a competition on the server, you will see all other connected MeOS clients.
|
||||
help:52726 = Connect to a server below.\n\nInstallation\nDownload and install MySQL 5 (Community Edition) from www.mysql.com. You can use default settings. It is only necessary to install MySQL on the computer acting server. When MySQL is installed, start MySQL Command Line Client and create a user account for MeOS. You write like this:\n\n> CREATE USER meos;\nGRANT ALL ON *.* TO meos;\n\nYou have now created a user meos with no password. Enter the name of the server below (you may have to configure firewalls to let through the traffic).\n\nAs an alternative you can use the built-in root account of MySQL. User name is 'root' and password is the one you provided when installing MySQL.
|
||||
help:5422 = Found no SI unit. Are they connected and started?
|
||||
@ -2596,3 +2597,64 @@ Duplicerad nummerlapp: X, Y = Duplicated bib: X, Y
|
||||
Saknat lag mellan X och Y = Missing team between X and Y
|
||||
Lag utan nummerlapp: X = Team with no bib: X
|
||||
Brickavläsning = Card Readout
|
||||
Ett långt tävlingsnamn kan ge oväntad nerskalning av utskrifter = A long competition name may cause unwanted downscale of printed lists
|
||||
Ingen reducerad avgift = No reduced fee
|
||||
Reducerad avgift = Reduced fee
|
||||
Reducerad avgift för = Reduced fee for
|
||||
Unga, till och med X år = Young people, up to X years
|
||||
Ungdomar och äldre kan få reducerad avgift = Elder and younger people can have a reduced fee
|
||||
Äldre, från och med X år = Elders, X years and above
|
||||
Programmera stationen utan AUTOSEND = Program the unit with AUTO SEND off
|
||||
Aktivera stöd för tiondels sekunder = Activate support for subsecond timing.
|
||||
Automatisk hyrbrickshantering genom registrerade hyrbrickor = Automatic handling of hired cards using pre-registered card numbers
|
||||
prefsAutoTieRent = Automatic handling of hired cards
|
||||
prefsExpResFilename = Default export filename
|
||||
prefsExpTypeIOF = Default export type
|
||||
prefsExpWithRaceNo = Include race number when exporting
|
||||
Ignorerade X duplikat = Ignored X duplicates
|
||||
info:customsplitprint = You can use a cusom list for the split printout. Design the list and use the function 'For Split Times' in the list editor to make changes for split printout.\n\nYou can control the list to use per class by using the table mode.
|
||||
Sträcktidslista = Split time list
|
||||
info:nosplitprint = Cannot load the specified list.\n\nUsing defaults instead.
|
||||
Välj deltagare för förhandsgranskning = Select competitor for preview
|
||||
Inkludera bomanalys = Include analysis of lost time
|
||||
Inkludera individuellt resultat = Include indiviual result
|
||||
Inkludera sträcktider = Include splits
|
||||
Inkludera tempo = Include tempo
|
||||
Skapa en klass för varje bana = Create a class for each course
|
||||
Ingen[competition] = None
|
||||
Basera på en tidigare tävling = Base on existing competition
|
||||
Baserad på X = Based on X
|
||||
info:multiple_start = A competitor may do multiple starts with the same card. Automatic new entry for each readout.
|
||||
Flera starter per deltagare = Several races per competitor
|
||||
Image = Image
|
||||
NumEntries = Number of entries
|
||||
NumStarts = Numer of starts
|
||||
TotalRunLength = Total running distance
|
||||
TotalRunTime = Total running time
|
||||
X stämplingar = X punches
|
||||
RunnerBirthDate = Birth date
|
||||
Avbryt inläsning = Cancel readout
|
||||
Spara oparad bricka = Save unpaired card
|
||||
warn:changeid = The field External Id is usually used to match entities with other databases (such as entry, result, or economy systems). If you make incomaptible changes, various and hard-to-understand problems might arise.
|
||||
Cannot represent ID X = Cannot represent ID 'X'
|
||||
Batteridatum = Battery date
|
||||
Enhet = Unit
|
||||
Öppna avläsningsfönster = Open readout window
|
||||
info:readoutwindow = The readout window shows information on the latest card readout.
|
||||
info:mapcontrol = MeOS is unable to determine what function a unit has unless it is directly attached to the computer. Therefore the programmed punch code is used to determine the type. You can control the interpretation below. Numbers higher than 30 are always interpreted as controls.\n\nBe careful when using start punches; they may permanently overwrite the drawn starting time.
|
||||
Checkenhet = Check unit
|
||||
Målenhet = Finish unit
|
||||
Startenhet = Start unit
|
||||
Du kan justera tiden för en viss enhet = You can adjust the time for a single unit
|
||||
ClubTeam = Club (Teams)
|
||||
CourseNumber = Course number
|
||||
Enhetskod = Unit code
|
||||
Tolkning av radiostämplingar med okänd typ = Interpretation of punches of unknown type
|
||||
TeamCourseName = Course name for team/leg
|
||||
TeamCourseNumber = Course number for team/leg
|
||||
TeamLegName = Namn på sträcka
|
||||
Du måste ange minst två gafflingsvarienater = You must specify at least 2 variants
|
||||
Max antal gaffllingsvarianter att skapa = Maximum number of forking keys to create
|
||||
Det uppskattade antalet startade lag i klassen är ett lämpligt värde = The estimated number of teams in the class is a suitable value
|
||||
Lägg till bild = Add image
|
||||
Använd listan för sträcktidsutskrift = Use list for split time printing
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -61,6 +61,7 @@ constexpr int absolutePosition = 1 << 17;
|
||||
constexpr int skipBoundingBox = 1 << 18;
|
||||
constexpr int hiddenText = 1 << 19;
|
||||
constexpr int textLimitEllipsis = 1 << 20;
|
||||
constexpr int imageNoUpdatePos = 1 << 21;
|
||||
|
||||
enum GDICOLOR {
|
||||
colorBlack = RGB(0, 0, 0),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
675
code/gdioutput.h
675
code/gdioutput.h
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -99,7 +99,7 @@ class AutoCompleteInfo;
|
||||
|
||||
class Recorder;
|
||||
|
||||
class gdioutput {
|
||||
class gdioutput {
|
||||
protected:
|
||||
string tag;
|
||||
// Database error state warning
|
||||
@ -109,30 +109,30 @@ protected:
|
||||
bool useTables;
|
||||
// Set to true when in test mode
|
||||
bool isTestMode;
|
||||
|
||||
|
||||
bool highContrast;
|
||||
|
||||
void deleteFonts();
|
||||
void constructor(double _scale);
|
||||
|
||||
void updateStringPosCache();
|
||||
vector<TextInfo *> shownStrings;
|
||||
vector<TextInfo*> shownStrings;
|
||||
|
||||
void enableCheckBoxLink(TextInfo &ti, bool enable);
|
||||
void enableCheckBoxLink(TextInfo& ti, bool enable);
|
||||
|
||||
//void CalculateCS(TextInfo &text);
|
||||
//void printPage(PrinterObject &po, int StartY, int &EndY, bool calculate);
|
||||
void printPage(PrinterObject &po, const PageInfo &pageInfo, RenderedPage &page);
|
||||
bool startDoc(PrinterObject &po);
|
||||
void printPage(PrinterObject& po, const PageInfo& pageInfo, RenderedPage& page);
|
||||
bool startDoc(PrinterObject& po);
|
||||
|
||||
bool getSelectedItem(ListBoxInfo &lbi);
|
||||
bool doPrint(PrinterObject &po, PageInfo &pageInfo, pEvent oe, bool respectPageBreak);
|
||||
bool getSelectedItem(ListBoxInfo& lbi);
|
||||
bool doPrint(PrinterObject& po, PageInfo& pageInfo, pEvent oe, bool respectPageBreak);
|
||||
|
||||
PrinterObject *po_default;
|
||||
PrinterObject* po_default;
|
||||
|
||||
void restoreInternal(const RestoreInfo &ri);
|
||||
void restoreInternal(const RestoreInfo& ri);
|
||||
|
||||
void drawCloseBox(HDC hDC, RECT &Close, bool pressed);
|
||||
void drawCloseBox(HDC hDC, RECT& Close, bool pressed);
|
||||
|
||||
void setFontCtrl(HWND hWnd);
|
||||
|
||||
@ -145,14 +145,20 @@ protected:
|
||||
//by avoiding to loop through complete TL.
|
||||
list<TextInfo>::iterator itTL;
|
||||
|
||||
// References into TL for all images
|
||||
vector<TextInfo*> imageReferences;
|
||||
|
||||
// Needed after removing images to clear unused references
|
||||
void updateImageReferences();
|
||||
|
||||
list<ButtonInfo> BI;
|
||||
unordered_map<HWND, ButtonInfo *> biByHwnd;
|
||||
unordered_map<HWND, ButtonInfo*> biByHwnd;
|
||||
|
||||
list<InputInfo> II;
|
||||
unordered_map<HWND, InputInfo *> iiByHwnd;
|
||||
unordered_map<HWND, InputInfo*> iiByHwnd;
|
||||
|
||||
list<ListBoxInfo> LBI;
|
||||
unordered_map<HWND, ListBoxInfo *> lbiByHwnd;
|
||||
unordered_map<HWND, ListBoxInfo*> lbiByHwnd;
|
||||
|
||||
list<DataStore> DataInfo;
|
||||
list<EventInfo> Events;
|
||||
@ -160,7 +166,7 @@ protected:
|
||||
list<TableInfo> Tables;
|
||||
list<TimerInfo> timers;
|
||||
|
||||
Toolbar *toolbar;
|
||||
Toolbar* toolbar;
|
||||
ToolList toolTips;
|
||||
|
||||
map<string, RestoreInfo> restorePoints;
|
||||
@ -191,10 +197,10 @@ protected:
|
||||
mutable map<pair<int, wstring>, int> fontHeightCache;
|
||||
|
||||
map<wstring, GDIImplFontSet> fonts;
|
||||
const GDIImplFontSet &getCurrentFont() const;
|
||||
const GDIImplFontSet &getFont(const wstring &font) const;
|
||||
const GDIImplFontSet &loadFont(const wstring &font);
|
||||
mutable const GDIImplFontSet *currentFontSet;
|
||||
const GDIImplFontSet& getCurrentFont() const;
|
||||
const GDIImplFontSet& getFont(const wstring& font) const;
|
||||
const GDIImplFontSet& loadFont(const wstring& font);
|
||||
mutable const GDIImplFontSet* currentFontSet;
|
||||
|
||||
int MaxX;
|
||||
int MaxY;
|
||||
@ -203,16 +209,25 @@ protected:
|
||||
int SX;
|
||||
int SY;
|
||||
|
||||
int Direction;
|
||||
enum class FlowDirection {
|
||||
Down,
|
||||
Right,
|
||||
None,
|
||||
};
|
||||
|
||||
FlowDirection flowDirection;
|
||||
|
||||
int OffsetY; //Range 0 -- MaxY
|
||||
int OffsetX; //Range 0 -- MaxX
|
||||
|
||||
// Maximum height of a text block of the current view.
|
||||
int maxTextBlockHeight = 0;
|
||||
|
||||
//Set to true if we should not update window during "addText" operations
|
||||
bool manualUpdate;
|
||||
|
||||
LRESULT ProcessMsgWrp(UINT iMessage, LPARAM lParam, WPARAM wParam);
|
||||
void getWindowText(HWND hWnd, wstring &text);
|
||||
void getWindowText(HWND hWnd, wstring& text);
|
||||
double scale;
|
||||
HFONT getGUIFont() const;
|
||||
|
||||
@ -223,18 +238,18 @@ protected:
|
||||
mutable DWORD lastColor;
|
||||
mutable wstring lastFont;
|
||||
|
||||
void initCommon(double scale, const wstring &font);
|
||||
void initCommon(double scale, const wstring& font);
|
||||
|
||||
void processButtonMessage(ButtonInfo &bi, WPARAM wParam);
|
||||
void processEditMessage(InputInfo &bi, WPARAM wParam);
|
||||
void processComboMessage(ListBoxInfo &bi, WPARAM wParam);
|
||||
void processListMessage(ListBoxInfo &bi, WPARAM wParam);
|
||||
void processButtonMessage(ButtonInfo& bi, WPARAM wParam);
|
||||
void processEditMessage(InputInfo& bi, WPARAM wParam);
|
||||
void processComboMessage(ListBoxInfo& bi, WPARAM wParam);
|
||||
void processListMessage(ListBoxInfo& bi, WPARAM wParam);
|
||||
|
||||
void doEnter();
|
||||
void doEscape();
|
||||
bool doUpDown(int direction);
|
||||
|
||||
FixedTabs *tabs;
|
||||
FixedTabs* tabs;
|
||||
|
||||
wstring currentFont;
|
||||
vector< GDIImplFontEnum > enumeratedFonts;
|
||||
@ -265,7 +280,7 @@ protected:
|
||||
wstring str;
|
||||
bool reached;
|
||||
|
||||
ScreenStringInfo(const RECT &r, const wstring &s) {
|
||||
ScreenStringInfo(const RECT& r, const wstring& s) {
|
||||
rc = r;
|
||||
str = s;
|
||||
reached = false;
|
||||
@ -283,146 +298,156 @@ protected:
|
||||
friend class TestMeOS;
|
||||
|
||||
// Recorder, the second member is true if the recorder is owned and should be deleted
|
||||
pair<Recorder *, bool> recorder;
|
||||
list< pair<const SubCommand *, string> > subCommands;
|
||||
pair<Recorder*, bool> recorder;
|
||||
list< pair<const SubCommand*, string> > subCommands;
|
||||
|
||||
shared_ptr<AnimationData> animationData;
|
||||
|
||||
shared_ptr<AutoCompleteInfo> autoCompleteInfo;
|
||||
|
||||
wstring delayedAlert;
|
||||
|
||||
struct GuiMeasure {
|
||||
int height = 0;
|
||||
int extraX = 0;
|
||||
int letterWidth = 0;
|
||||
float avgCharWidth = 0;
|
||||
};
|
||||
|
||||
mutable shared_ptr<GuiMeasure> guiMeasure;
|
||||
|
||||
public:
|
||||
|
||||
AutoCompleteInfo &addAutoComplete(const string &key);
|
||||
void clearAutoComplete(const string &key);
|
||||
AutoCompleteInfo& addAutoComplete(const string& key);
|
||||
void clearAutoComplete(const string& key);
|
||||
bool hasAutoComplete() const { return autoCompleteInfo != nullptr; }
|
||||
// Return the bounding dimension of the desktop
|
||||
void getVirtualScreenSize(RECT &rc);
|
||||
void getVirtualScreenSize(RECT& rc);
|
||||
|
||||
void getWindowsPosition(RECT &rc) const;
|
||||
void setWindowsPosition(const RECT &rc);
|
||||
void getWindowsPosition(RECT& rc) const;
|
||||
void setWindowsPosition(const RECT& rc);
|
||||
|
||||
|
||||
void initRecorder(Recorder *rec);
|
||||
Recorder &getRecorder();
|
||||
string dbPress(const string &id, int extra);
|
||||
string dbPress(const string &id, const char *extra);
|
||||
|
||||
string dbSelect(const string &id, int data);
|
||||
void dbInput(const string &id, const string &test);
|
||||
void dbCheck(const string &id, bool state);
|
||||
string dbClick(const string &id, int extra);
|
||||
void dbDblClick(const string &id, int data);
|
||||
|
||||
void dbRegisterSubCommand(const SubCommand *cmd, const string &action);
|
||||
void initRecorder(Recorder* rec);
|
||||
Recorder& getRecorder();
|
||||
string dbPress(const string& id, int extra);
|
||||
string dbPress(const string& id, const char* extra);
|
||||
|
||||
string dbSelect(const string& id, int data);
|
||||
void dbInput(const string& id, const string& test);
|
||||
void dbCheck(const string& id, bool state);
|
||||
string dbClick(const string& id, int extra);
|
||||
void dbDblClick(const string& id, int data);
|
||||
|
||||
void dbRegisterSubCommand(const SubCommand* cmd, const string& action);
|
||||
void runSubCommand();
|
||||
|
||||
// Add the next answer for a dialog popup
|
||||
void dbPushDialogAnswer(const string &answer);
|
||||
void dbPushDialogAnswer(const string& answer);
|
||||
mutable list<string> cmdAnswers;
|
||||
|
||||
int dbGetStringCount(const string &str, bool subString) const;
|
||||
int dbGetStringCount(const string& str, bool subString) const;
|
||||
|
||||
// Ensure list of stored answers is empty
|
||||
void clearDialogAnswers(bool checkEmpty);
|
||||
|
||||
void internalSelect(ListBoxInfo &bi);
|
||||
void internalSelect(ListBoxInfo& bi);
|
||||
|
||||
bool isTest() const {return isTestMode;}
|
||||
const string &getTag() const {return tag;}
|
||||
bool hasTag(const string &t) const {return tag == t;}
|
||||
static const wstring &recodeToWide(const string &input);
|
||||
static const string &recodeToNarrow(const wstring &input);
|
||||
|
||||
static const wstring &widen(const string &input);
|
||||
static const string &narrow(const wstring &input);
|
||||
|
||||
static const string &toUTF8(const wstring &input);
|
||||
static const wstring &fromUTF8(const string &input);
|
||||
bool isTest() const { return isTestMode; }
|
||||
const string& getTag() const { return tag; }
|
||||
bool hasTag(const string& t) const { return tag == t; }
|
||||
static const wstring& recodeToWide(const string& input);
|
||||
static const string& recodeToNarrow(const wstring& input);
|
||||
|
||||
static const wstring& widen(const string& input);
|
||||
static const string& narrow(const wstring& input);
|
||||
|
||||
static const string& toUTF8(const wstring& input);
|
||||
static const wstring& fromUTF8(const string& input);
|
||||
|
||||
//void setEncoding(FontEncoding encoding);
|
||||
//FontEncoding getEncoding() const;
|
||||
|
||||
void getFontInfo(const TextInfo &ti, FontInfo &fi) const;
|
||||
void getFontInfo(const TextInfo& ti, FontInfo& fi) const;
|
||||
|
||||
/** Return true if rendering text should be skipped for
|
||||
this format. */
|
||||
static bool skipTextRender(int format);
|
||||
|
||||
const list<TextInfo> &getTL() const {return TL;}
|
||||
const list<TextInfo>& getTL() const { return TL; }
|
||||
|
||||
void getEnumeratedFonts(vector< pair<wstring, size_t> > &output) const;
|
||||
const wstring &getFontName(int id);
|
||||
double getRelativeFontScale(gdiFonts font, const wchar_t *fontFace) const;
|
||||
void getEnumeratedFonts(vector< pair<wstring, size_t> >& output) const;
|
||||
const wstring& getFontName(int id);
|
||||
double getRelativeFontScale(gdiFonts font, const wchar_t* fontFace) const;
|
||||
|
||||
bool isFullScreen() const {return fullScreen;}
|
||||
bool isFullScreen() const { return fullScreen; }
|
||||
void setFullScreen(bool useFullScreen);
|
||||
void setColorMode(DWORD bgColor1, DWORD bgColor2 = -1,
|
||||
DWORD fgColor = -1, const wstring &bgImage = L"");
|
||||
|
||||
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;
|
||||
const wstring& getBGImage() const;
|
||||
|
||||
void setAnimationMode(const shared_ptr<AnimationData> &mode);
|
||||
void setAnimationMode(const shared_ptr<AnimationData>& mode);
|
||||
|
||||
void setAutoScroll(double speed);
|
||||
void getAutoScroll(double &speed, double &pos) const;
|
||||
void getAutoScroll(double& speed, double& pos) const;
|
||||
void storeAutoPos(double pos);
|
||||
int getAutoScrollDir() const {return (autoSpeed > 0 ? 1:-1);}
|
||||
int getAutoScrollDir() const { return (autoSpeed > 0 ? 1 : -1); }
|
||||
int setHighContrastMaxWidth();
|
||||
void hideBackground(bool hide) {hideBG = hide;}
|
||||
void hideBackground(bool hide) { hideBG = hide; }
|
||||
HWND getToolbarWindow() const;
|
||||
bool hasToolbar() const;
|
||||
void activateToolbar(bool active);
|
||||
|
||||
void processToolbarMessage(const string &id, Table *data);
|
||||
void processToolbarMessage(const string& id, Table* data);
|
||||
|
||||
void synchronizeListScroll(const string &id1, const string &id2);
|
||||
void synchronizeListScroll(const string& id1, const string& id2);
|
||||
|
||||
FixedTabs &getTabs();
|
||||
FixedTabs& getTabs();
|
||||
|
||||
// True if up/down is locked, i.e, don't move page
|
||||
bool lockUpDown;
|
||||
|
||||
|
||||
double getScale() const {return scale;}
|
||||
double getScale() const { return scale; }
|
||||
void enableEditControls(bool enable, bool processAll = false);
|
||||
|
||||
bool hasEditControl() const;
|
||||
|
||||
void setFont(int size, const wstring &font);
|
||||
void setFont(int size, const wstring& font);
|
||||
|
||||
int getButtonHeight() const;
|
||||
int scaleLength(int input) const {return int(scale*input + 0.5);}
|
||||
|
||||
int scaleLength(int input) const { return int(scale * input + 0.5); }
|
||||
|
||||
// Fill in current printer settings
|
||||
void fetchPrinterSettings(PrinterObject &po) const;
|
||||
void fetchPrinterSettings(PrinterObject& po) const;
|
||||
|
||||
void tableCB(ButtonInfo &bu, Table *t);
|
||||
void tableCB(ButtonInfo& bu, Table* t);
|
||||
|
||||
wchar_t *getExtra(const char *id) const;
|
||||
int getExtraInt(const char *id) const;
|
||||
wchar_t* getExtra(const char* id) const;
|
||||
int getExtraInt(const char* id) const;
|
||||
|
||||
void enableTables();
|
||||
void disableTables();
|
||||
|
||||
void pasteText(const char *id);
|
||||
void print(pEvent oe, Table *t = 0, bool printMeOSHeader = true, bool noMargin = false, bool respectPageBreak = true);
|
||||
void print(PrinterObject &po, pEvent oe, bool printMeOSHeader = true, bool noMargin=false, bool respectPageBreak = true);
|
||||
void printSetup(PrinterObject &po);
|
||||
void destroyPrinterDC(PrinterObject &po);
|
||||
void pasteText(const char* id);
|
||||
void print(pEvent oe, Table* t = nullptr, bool printMeOSHeader = true, bool noMargin = false, bool respectPageBreak = true);
|
||||
void print(PrinterObject& po, pEvent oe, bool printMeOSHeader = true, bool noMargin = false, bool respectPageBreak = true);
|
||||
void printSetup(PrinterObject& po);
|
||||
void destroyPrinterDC(PrinterObject& po);
|
||||
|
||||
void setSelection(const string &id, const set<int> &selection);
|
||||
void setSelection(const wstring &id, const set<int> &selection) {
|
||||
void setSelection(const string& id, const set<int>& selection);
|
||||
void setSelection(const wstring& id, const set<int>& selection) {
|
||||
setSelection(narrow(id), selection);
|
||||
}
|
||||
|
||||
void getSelection(const string &id, set<int> &selection);
|
||||
|
||||
HWND getHWNDTarget() const {return hWndTarget;}
|
||||
HWND getHWNDMain() const {return hWndAppMain;}
|
||||
void getSelection(const string& id, set<int>& selection);
|
||||
|
||||
HWND getHWNDTarget() const { return hWndTarget; }
|
||||
HWND getHWNDMain() const { return hWndAppMain; }
|
||||
|
||||
void scrollToBottom();
|
||||
void scrollTo(int x, int y);
|
||||
@ -430,84 +455,88 @@ public:
|
||||
|
||||
void selectTab(int Id);
|
||||
|
||||
void addTable(const shared_ptr<Table> &table, int x, int y);
|
||||
Table &getTable() const; //Get the (last) table. If needed, add support for named tables...
|
||||
void addTable(const shared_ptr<Table>& table, int x, int y);
|
||||
Table& getTable() const; //Get the (last) table. If needed, add support for named tables...
|
||||
|
||||
|
||||
ToolInfo &addToolTip(const string &id, const wstring &tip, HWND hWnd, RECT *rc=0);
|
||||
ToolInfo *getToolTip(const string &id);
|
||||
ToolInfo &updateToolTip(const string &id, const wstring &tip);
|
||||
|
||||
HWND getToolTip(){return hWndToolTip;}
|
||||
ToolInfo& addToolTip(const string& id, const wstring& tip, HWND hWnd, RECT* rc = nullptr);
|
||||
ToolInfo* getToolTip(const string& id);
|
||||
ToolInfo& updateToolTip(const string& id, const wstring& tip);
|
||||
|
||||
HWND getToolTip() { return hWndToolTip; }
|
||||
|
||||
void init(HWND hWnd, HWND hMainApp, HWND hTab);
|
||||
bool openDoc(const wchar_t *doc);
|
||||
wstring browseForSave(const vector< pair<wstring, wstring> > &filter,
|
||||
const wstring &defext, int &FilterIndex);
|
||||
wstring browseForOpen(const vector< pair<wstring, wstring> > &filter,
|
||||
const wstring &defext);
|
||||
wstring browseForFolder(const wstring &folderStart, const wchar_t *descr);
|
||||
|
||||
bool clipOffset(int PageX, int PageY, int &MaxOffsetX, int &MaxOffsetY);
|
||||
RectangleInfo &addRectangle(RECT &rc, GDICOLOR Color = GDICOLOR(-1),
|
||||
bool DrawBorder = true, bool addFirst = false);
|
||||
|
||||
RectangleInfo &getRectangle(const char *id);
|
||||
|
||||
DWORD makeEvent(const string &id, const string &origin,
|
||||
DWORD data, int extraData, bool flushEvent);
|
||||
bool openDoc(const wchar_t* doc);
|
||||
wstring browseForSave(const vector< pair<wstring, wstring> >& filter,
|
||||
const wstring& defext, int& FilterIndex);
|
||||
wstring browseForOpen(const vector< pair<wstring, wstring> >& filter,
|
||||
const wstring& defext);
|
||||
wstring browseForFolder(const wstring& folderStart, const wchar_t* descr);
|
||||
|
||||
void unregisterEvent(const string &id);
|
||||
EventInfo ®isterEvent(const string &id, GUICALLBACK cb);
|
||||
bool clipOffset(int PageX, int PageY, int& MaxOffsetX, int& MaxOffsetY);
|
||||
RectangleInfo& addRectangle(const RECT& rc, GDICOLOR Color = GDICOLOR(-1),
|
||||
bool DrawBorder = true, bool addFirst = false);
|
||||
|
||||
int sendCtrlMessage(const string &id);
|
||||
RectangleInfo& getRectangle(const char* id);
|
||||
|
||||
DWORD makeEvent(const string& id, const string& origin,
|
||||
DWORD data, int extraData, bool flushEvent);
|
||||
|
||||
void unregisterEvent(const string& id);
|
||||
EventInfo& registerEvent(const string& id, GUICALLBACK cb);
|
||||
|
||||
int sendCtrlMessage(const string& id);
|
||||
bool canClear();
|
||||
void setOnClearCb(GUICALLBACK cb);
|
||||
void setPostClearCb(GUICALLBACK cb);
|
||||
|
||||
void restore(const string &id="", bool DoRefresh=true);
|
||||
void restore(const string& id = "", bool DoRefresh = true);
|
||||
|
||||
/// Restore, but do not update client area size,
|
||||
/// position, zoom, scrollbars, and do not refresh
|
||||
void restoreNoUpdate(const string &id);
|
||||
void restoreNoUpdate(const string& id);
|
||||
|
||||
void setRestorePoint();
|
||||
void setRestorePoint(const string &id);
|
||||
void setRestorePoint(const string& id);
|
||||
|
||||
bool removeWidget(const string &id);
|
||||
bool hideWidget(const string &id, bool hide = true);
|
||||
bool removeWidget(const string& id);
|
||||
bool hideWidget(const string& id, bool hide = true);
|
||||
|
||||
// Get and set restore point presence for a widget
|
||||
bool getWidgetRestorePoint(const string& id, string& restorePoint) const;
|
||||
void setWidgetRestorePoint(const string& id, const string& restorePoint);
|
||||
|
||||
void CheckInterfaceTimeouts(DWORD T);
|
||||
bool RemoveFirstInfoBox(const string &id);
|
||||
void drawBoxText(HDC hDC, RECT &tr, InfoBox &Box, bool highligh);
|
||||
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);
|
||||
bool RemoveFirstInfoBox(const string& id);
|
||||
void drawBoxText(HDC hDC, RECT& tr, InfoBox& Box, bool highligh);
|
||||
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 = nullptr);
|
||||
void updateObjectPositions();
|
||||
void drawBackground(HDC hDC, RECT &rc);
|
||||
void renderRectangle(HDC hDC, RECT *clipRegion, const RectangleInfo &ri);
|
||||
void drawBackground(HDC hDC, RECT& rc);
|
||||
void renderRectangle(HDC hDC, RECT* clipRegion, const RectangleInfo& ri);
|
||||
|
||||
void updateScrollbars() const;
|
||||
|
||||
void setOffsetY(int oy) {OffsetY=oy;}
|
||||
void setOffsetX(int ox) {OffsetX=ox;}
|
||||
void setOffsetY(int oy) { OffsetY = oy; }
|
||||
void setOffsetX(int ox) { OffsetX = ox; }
|
||||
int getPageY() const;
|
||||
int getPageX() const;
|
||||
int getOffsetY() const {return OffsetY;}
|
||||
int getOffsetX() const {return OffsetX;}
|
||||
int getOffsetY() const { return OffsetY; }
|
||||
int getOffsetX() const { return OffsetX; }
|
||||
|
||||
void RenderString(TextInfo &ti, const wstring &text, HDC hDC);
|
||||
void RenderString(TextInfo &ti, HDC hDC=0);
|
||||
void calcStringSize(TextInfo &ti, HDC hDC=0) const;
|
||||
void formatString(const TextInfo &ti, HDC hDC) const;
|
||||
void RenderString(TextInfo& ti, const wstring& text, HDC hDC);
|
||||
void RenderString(TextInfo& ti, HDC hDC = 0);
|
||||
void calcStringSize(TextInfo& ti, HDC hDC = 0) const;
|
||||
void formatString(const TextInfo& ti, HDC hDC) const;
|
||||
|
||||
static wstring getTimerText(TextInfo *tit, DWORD T);
|
||||
static wstring getTimerText(TextInfo* tit, DWORD T);
|
||||
static wstring getTimerText(int ZeroTime, int format);
|
||||
|
||||
void fadeOut(string Id, int ms);
|
||||
void setWaitCursor(bool wait);
|
||||
void setWindowTitle(const wstring &title);
|
||||
bool selectFirstItem(const string &name);
|
||||
void setWindowTitle(const wstring& title);
|
||||
bool selectFirstItem(const string& name);
|
||||
void removeString(string Id);
|
||||
void refresh() const;
|
||||
void refreshFast() const;
|
||||
@ -515,269 +544,295 @@ public:
|
||||
void takeShownStringsSnapshot();
|
||||
void refreshSmartFromSnapshot(bool allowMoveOffset);
|
||||
|
||||
void dropLine(double lines=1){CurrentY+=int(lineHeight*lines); MaxY=max(MaxY, CurrentY);}
|
||||
int getCX() const {return CurrentX;}
|
||||
int getCY() const {return CurrentY;}
|
||||
int getWidth() const {return MaxX;}
|
||||
int getHeight() const {return MaxY;}
|
||||
void getTargetDimension(int &x, int &y) const;
|
||||
void dropLine(double lines = 1) { CurrentY += int(lineHeight * lines); MaxY = max(MaxY, CurrentY); }
|
||||
int getCX() const { return CurrentX; }
|
||||
int getCY() const { return CurrentY; }
|
||||
int getWidth() const { return MaxX; }
|
||||
int getHeight() const { return MaxY; }
|
||||
void getTargetDimension(int& x, int& y) const;
|
||||
|
||||
pair<int, int> getPos() const { return make_pair(CurrentX, CurrentY); }
|
||||
void setPos(const pair<int, int> &p) { CurrentX = p.first; CurrentY = p.second; }
|
||||
void setPos(const pair<int, int>& p) { CurrentX = p.first; CurrentY = p.second; }
|
||||
|
||||
void setCX(int cx){CurrentX=cx;}
|
||||
void setCY(int cy){CurrentY=cy;}
|
||||
int getLineHeight() const {return lineHeight;}
|
||||
int getLineHeight(gdiFonts font, const wchar_t *face) const;
|
||||
void setCX(int cx) { CurrentX = cx; }
|
||||
void setCY(int cy) { CurrentY = cy; }
|
||||
int getLineHeight() const { return lineHeight; }
|
||||
int getLineHeight(gdiFonts font, const wchar_t* face) const;
|
||||
|
||||
BaseInfo *setInputFocus(const string &id, bool select=false);
|
||||
InputInfo *getInputFocus();
|
||||
BaseInfo* setInputFocus(const string& id, bool select = false);
|
||||
InputInfo* getInputFocus();
|
||||
|
||||
void enableInput(const char *id, bool acceptMissing = false,
|
||||
int requireExtraMatch = -1) {setInputStatus(id, true, acceptMissing, requireExtraMatch);}
|
||||
void disableInput(const char *id, bool acceptMissing = false,
|
||||
int requireExtraMatch = -1) {setInputStatus(id, false, acceptMissing, requireExtraMatch);}
|
||||
void setInputStatus(const char *id, bool status, bool acceptMissing = false, int requireExtraMatch = -1);
|
||||
void setInputStatus(const string &id, bool status, bool acceptMissing = false, int requireExtraMatch = -1)
|
||||
{setInputStatus(id.c_str(), status, acceptMissing, requireExtraMatch);}
|
||||
void enableInput(const char* id, bool acceptMissing = false,
|
||||
int requireExtraMatch = -1) {
|
||||
setInputStatus(id, true, acceptMissing, requireExtraMatch);
|
||||
}
|
||||
void disableInput(const char* id, bool acceptMissing = false,
|
||||
int requireExtraMatch = -1) {
|
||||
setInputStatus(id, false, acceptMissing, requireExtraMatch);
|
||||
}
|
||||
void setInputStatus(const char* id, bool status, bool acceptMissing = false, int requireExtraMatch = -1);
|
||||
void setInputStatus(const string& id, bool status, bool acceptMissing = false, int requireExtraMatch = -1)
|
||||
{
|
||||
setInputStatus(id.c_str(), status, acceptMissing, requireExtraMatch);
|
||||
}
|
||||
|
||||
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 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;
|
||||
int getDataInt(const string &id) const { return int(size_t(getData(id))); }
|
||||
void* getData(const string& id) const;
|
||||
int getDataInt(const string& id) const { return int(size_t(getData(id))); }
|
||||
|
||||
bool getData(const string &id, string &out) const;
|
||||
bool getData(const string& id, string& out) const;
|
||||
|
||||
|
||||
DWORD selectColor(wstring &def, DWORD input);
|
||||
DWORD selectColor(wstring& def, DWORD input);
|
||||
|
||||
void autoRefresh(bool flag) {manualUpdate = !flag;}
|
||||
void autoRefresh(bool flag) { manualUpdate = !flag; }
|
||||
|
||||
bool getData(const string &id, DWORD &data) const;
|
||||
bool hasData(const char *id) const;
|
||||
bool getData(const string& id, DWORD& data) const;
|
||||
bool hasData(const char* id) const;
|
||||
|
||||
int getItemDataByName(const char *id, const char *name) const;
|
||||
bool selectItemByData(const char *id, int data);
|
||||
bool selectItemByIndex(const char *id, int index);
|
||||
int getItemDataByName(const char* id, const char* name) const;
|
||||
bool selectItemByData(const char* id, int data);
|
||||
bool selectItemByIndex(const char* id, int index);
|
||||
|
||||
void removeSelected(const char *id);
|
||||
void removeSelected(const char* id);
|
||||
|
||||
bool selectItemByData(const string &id, int data) {
|
||||
bool selectItemByData(const string& id, int data) {
|
||||
return selectItemByData(id.c_str(), data);
|
||||
}
|
||||
|
||||
enum AskAnswer {AnswerNo = 0, AnswerYes = 1, AnswerCancel = 2};
|
||||
bool ask(const wstring &s);
|
||||
AskAnswer askCancel(const wstring &s);
|
||||
enum class AskAnswer { AnswerNo = 0, AnswerYes = 1, AnswerCancel = 2, AnswerOK = 3 };
|
||||
bool ask(const wstring& s);
|
||||
AskAnswer askOkCancel(const wstring& s);
|
||||
AskAnswer askCancel(const wstring& s);
|
||||
|
||||
void alert(const string &msg) const;
|
||||
void alert(const wstring &msg) const;
|
||||
void alert(const string& msg) const;
|
||||
void alert(const wstring& msg) const;
|
||||
// Alert from main thread (via callback)
|
||||
void delayAlert(const wstring& msg);
|
||||
// Get and clear any delayed alert
|
||||
wstring getDelayedAlert();
|
||||
|
||||
void fillDown(){Direction=1;}
|
||||
void fillRight(){Direction=0;}
|
||||
void fillNone(){Direction=-1;}
|
||||
void newColumn(){CurrentY=START_YP; CurrentX=MaxX+10;}
|
||||
void newRow(){CurrentY=MaxY; CurrentX=10;}
|
||||
void fillDown() { flowDirection = FlowDirection::Down; }
|
||||
void fillRight() { flowDirection = FlowDirection::Right; }
|
||||
void fillNone() { flowDirection = FlowDirection::None; }
|
||||
|
||||
void pushX(){SX=CurrentX;}
|
||||
void pushY(){SY=CurrentY;}
|
||||
void popX(){CurrentX=SX;}
|
||||
void popY(){CurrentY=SY;}
|
||||
void newColumn() { CurrentY = START_YP; CurrentX = MaxX + 10; }
|
||||
void newRow() { CurrentY = MaxY; CurrentX = 10; }
|
||||
|
||||
void pushX() { SX = CurrentX; }
|
||||
void pushY() { SY = CurrentY; }
|
||||
void popX() { CurrentX = SX; }
|
||||
void popY() { CurrentY = SY; }
|
||||
|
||||
bool updatePos(int x, int y, int width, int height);
|
||||
void adjustDimension(int width, int height);
|
||||
|
||||
/** Return a selected item*/
|
||||
bool getSelectedItem(const string &id, ListBoxInfo &lbi);
|
||||
bool getSelectedItem(const string& id, ListBoxInfo& lbi);
|
||||
|
||||
/** Get number of items in a list box.'*/
|
||||
int getNumItems(const char *id);
|
||||
int getNumItems(const char* id);
|
||||
|
||||
/** Return the selected data in first, second indicates if data was available*/
|
||||
pair<int, bool> getSelectedItem(const string &id);
|
||||
pair<int, bool> getSelectedItem(const char *id);
|
||||
pair<int, bool> getSelectedItem(const string& id);
|
||||
pair<int, bool> getSelectedItem(const char* id);
|
||||
|
||||
bool addItem(const string &id, const wstring &text, size_t data = 0);
|
||||
bool addItem(const string &id, const vector< pair<wstring, size_t> > &items);
|
||||
|
||||
void filterOnData(const string &id, const unordered_set<int> &filter);
|
||||
bool addItem(const string& id, const wstring& text, size_t data = 0);
|
||||
bool addItem(const string& id, const vector< pair<wstring, size_t> >& items);
|
||||
|
||||
bool clearList(const string &id);
|
||||
void filterOnData(const string& id, const unordered_set<int>& filter);
|
||||
|
||||
bool hasWidget(const string &id) const;
|
||||
|
||||
const wstring &getText(const char *id, bool acceptMissing = false, int requireExtraMatch = -1) const;
|
||||
|
||||
BaseInfo &getBaseInfo(const string &id) const {
|
||||
return getBaseInfo(id.c_str());
|
||||
bool clearList(const string& id);
|
||||
|
||||
bool hasWidget(const string& id) const;
|
||||
|
||||
const wstring& getText(const char* id, bool acceptMissing = false, int requireExtraMatch = -1) const;
|
||||
|
||||
BaseInfo& getBaseInfo(const string& id, int requireExtraMatch = -1) const {
|
||||
return getBaseInfo(id.c_str(), requireExtraMatch);
|
||||
}
|
||||
BaseInfo &getBaseInfo(const char *id) const;
|
||||
BaseInfo &getBaseInfo(const wchar_t *id) const {
|
||||
return getBaseInfo(narrow(id).c_str());
|
||||
BaseInfo& getBaseInfo(const char* id, int requireExtraMatch = -1) const;
|
||||
BaseInfo& getBaseInfo(const wchar_t* id, int requireExtraMatch = -1) const {
|
||||
return getBaseInfo(narrow(id).c_str(), requireExtraMatch);
|
||||
}
|
||||
|
||||
int getTextNo(const char *id, bool acceptMissing = false) const;
|
||||
int getTextNo(const string &id, bool acceptMissing = false) const
|
||||
{return getTextNo(id.c_str(), acceptMissing);}
|
||||
int getTextNo(const char* id, bool acceptMissing = false) const;
|
||||
int getTextNo(const string& id, bool acceptMissing = false) const
|
||||
{
|
||||
return getTextNo(id.c_str(), acceptMissing);
|
||||
}
|
||||
|
||||
const wstring &getText(const string &id, bool acceptMissing = false) const
|
||||
{return getText(id.c_str(), acceptMissing);}
|
||||
const wstring& getText(const string& id, bool acceptMissing = false) const
|
||||
{
|
||||
return getText(id.c_str(), acceptMissing);
|
||||
}
|
||||
|
||||
// Insert text and notify "focusList"
|
||||
bool insertText(const string &id, const wstring &text);
|
||||
// Insert text and notify "focusList"
|
||||
bool insertText(const string& id, const wstring& text);
|
||||
|
||||
int getFontHeight(int format, const wstring &fontFace) const;
|
||||
int getFontHeight(int format, const wstring& fontFace) const;
|
||||
|
||||
// The html version should be UTF-8.
|
||||
void copyToClipboard(const string &html,
|
||||
const wstring &txt) const;
|
||||
void copyToClipboard(const string& html,
|
||||
const wstring& txt) const;
|
||||
|
||||
BaseInfo *setTextTranslate(const char *id, const wstring &text, bool update=false);
|
||||
BaseInfo *setTextTranslate(const char *id, const wchar_t *text, bool update=false);
|
||||
BaseInfo *setTextTranslate(const string &id, const wstring &text, bool update=false);
|
||||
BaseInfo* setTextTranslate(const char* id, const wstring& text, bool update = false);
|
||||
BaseInfo* setTextTranslate(const char* id, const wchar_t* text, bool update = false);
|
||||
BaseInfo* setTextTranslate(const string& id, const wstring& text, bool update = false);
|
||||
|
||||
|
||||
BaseInfo *setText(const char *id, const wstring &text, bool update=false, int requireExtraMatch = -1);
|
||||
BaseInfo *setText(const wchar_t *id, const wstring &text, bool update=false) {
|
||||
BaseInfo* setText(const char* id, const wstring& text, bool update = false, int requireExtraMatch = -1);
|
||||
BaseInfo* setText(const wchar_t* id, const wstring& text, bool update = false) {
|
||||
return setText(narrow(id), text, update);
|
||||
}
|
||||
BaseInfo *setText(const char *id, int number, bool update=false);
|
||||
BaseInfo *setText(const string &id, const wstring &text, bool update=false)
|
||||
{return setText(id.c_str(), text, update);}
|
||||
BaseInfo *setTextZeroBlank(const char *id, int number, bool update=false);
|
||||
BaseInfo *setText(const string &id, int number, bool update=false)
|
||||
{return setText(id.c_str(), number, update);}
|
||||
BaseInfo* setText(const char* id, int number, bool update = false);
|
||||
BaseInfo* setText(const string& id, const wstring& text, bool update = false)
|
||||
{
|
||||
return setText(id.c_str(), text, update);
|
||||
}
|
||||
BaseInfo* setTextZeroBlank(const char* id, int number, bool update = false);
|
||||
BaseInfo* setText(const string& id, int number, bool update = false)
|
||||
{
|
||||
return setText(id.c_str(), number, update);
|
||||
}
|
||||
|
||||
void clearPage(bool autoRefresh, bool keepToolbar = false);
|
||||
|
||||
void TabFocus(int direction=1);
|
||||
void TabFocus(int direction = 1);
|
||||
void enter();
|
||||
void escape();
|
||||
bool upDown(int direction);
|
||||
void keyCommand(KeyCommandCode code);
|
||||
|
||||
LRESULT ProcessMsg(UINT iMessage, LPARAM lParam, WPARAM wParam);
|
||||
void setWindow(HWND hWnd){hWndTarget=hWnd;}
|
||||
void setWindow(HWND hWnd) { hWndTarget = hWnd; }
|
||||
|
||||
void scaleSize(double scale, bool allowSmallScale = false, bool doRefresh = true);
|
||||
enum class ScaleOperation {
|
||||
NoRefresh,
|
||||
Refresh,
|
||||
NoUpdate
|
||||
};
|
||||
|
||||
ButtonInfo &addButton(const string &id, const wstring &text, GUICALLBACK cb = 0,
|
||||
const wstring &tooltip = L"");
|
||||
void scaleSize(double scale, bool allowSmallScale = false, ScaleOperation type = ScaleOperation::Refresh);
|
||||
|
||||
ButtonInfo &addButton(int x, int y, const string &id, const wstring &text,
|
||||
GUICALLBACK cb = 0, const wstring &tooltop=L"");
|
||||
ButtonInfo& addButton(const string& id, const wstring& text, GUICALLBACK cb = nullptr,
|
||||
const wstring& tooltip = L"");
|
||||
|
||||
ButtonInfo &addButton(int x, int y, int w, const string &id, const wstring &text,
|
||||
GUICALLBACK cb, const wstring &tooltop, bool absPos, bool hasState);
|
||||
ButtonInfo& addButton(int x, int y, const string& id, const wstring& text,
|
||||
GUICALLBACK cb = nullptr, const wstring& tooltop = L"");
|
||||
|
||||
ButtonInfo& addButton(int x, int y, int w, const string& id, const wstring& text,
|
||||
GUICALLBACK cb, const wstring& tooltop, bool absPos, bool hasState);
|
||||
|
||||
ButtonInfo& addCheckbox(const string& id, const wstring& text, GUICALLBACK cb = nullptr,
|
||||
bool Checked = true, const wstring& tooltip = L"");
|
||||
ButtonInfo& addCheckbox(int x, int y, const string& id,
|
||||
const wstring& text, GUICALLBACK cb = nullptr,
|
||||
bool checked = true, const wstring& tooltop = L"", bool absPos = false);
|
||||
|
||||
ButtonInfo &addCheckbox(const string &id, const wstring &text, GUICALLBACK cb=0,
|
||||
bool Checked=true, const wstring &tooltip = L"");
|
||||
ButtonInfo &addCheckbox(int x, int y, const string &id,
|
||||
const wstring &text, GUICALLBACK cb=0,
|
||||
bool checked=true, const wstring &tooltop = L"", bool absPos=false);
|
||||
|
||||
|
||||
/// XXX Temporary
|
||||
ButtonInfo &addButton(const string &id, const string &text, GUICALLBACK cb = 0, const string &tooltip="");
|
||||
ButtonInfo& addButton(const string& id, const string& text, GUICALLBACK cb = nullptr, const string& tooltip = "");
|
||||
|
||||
ButtonInfo &addButton(int x, int y, const string &id, const string &text,
|
||||
GUICALLBACK cb = 0, const string &tooltop="");
|
||||
ButtonInfo &addButton(int x, int y, int w, const string &id, const string &text,
|
||||
GUICALLBACK cb, const string &tooltop, bool AbsPos, bool hasState);
|
||||
ButtonInfo& addButton(int x, int y, const string& id, const string& text,
|
||||
GUICALLBACK cb = nullptr, const string& tooltop = "");
|
||||
ButtonInfo& addButton(int x, int y, int w, const string& id, const string& text,
|
||||
GUICALLBACK cb, const string& tooltop, bool AbsPos, bool hasState);
|
||||
|
||||
ButtonInfo &addCheckbox(const string &id, const string &text, GUICALLBACK cb=0, bool Checked=true, const string &Help="");
|
||||
ButtonInfo &addCheckbox(int x, int y, const string &id, const string &text, GUICALLBACK cb=0, bool Checked=true, const string &Help="", bool AbsPos=false);
|
||||
ButtonInfo& addCheckbox(const string& id, const string& text, GUICALLBACK cb = nullptr, bool Checked = true, const string& Help = "");
|
||||
ButtonInfo& addCheckbox(int x, int y, const string& id, const string& text, GUICALLBACK cb = nullptr, bool Checked = true, const string& Help = "", bool AbsPos = false);
|
||||
/// XXX
|
||||
|
||||
bool isChecked(const string &id);
|
||||
void check(const string &id, bool state, bool keepOriginalState = false);
|
||||
|
||||
bool isInputChanged(const string &exclude);
|
||||
bool isChecked(const string& id);
|
||||
void check(const string& id, bool state, bool keepOriginalState = false);
|
||||
|
||||
bool isInputChanged(const string& exclude);
|
||||
|
||||
/** Get width of input widget with specified length (chars)*/
|
||||
pair<int,int> getInputDimension(int length) const;
|
||||
pair<int, int> getInputDimension(int length) const;
|
||||
|
||||
InputInfo &addInput(const string &id, const wstring &text = L"", int length=16, GUICALLBACK cb=0,
|
||||
const wstring &Explanation = L"", const wstring &tooltip=L"");
|
||||
InputInfo &addInput(int x, int y, const string &id, const wstring &text, int length,
|
||||
GUICALLBACK cb=0, const wstring &Explanation = L"", const wstring &tooltip=L"");
|
||||
InputInfo& addInput(const string& id, const wstring& text = L"", int length = 16, GUICALLBACK cb = nullptr,
|
||||
const wstring& Explanation = L"", const wstring& tooltip = L"");
|
||||
InputInfo& addInput(int x, int y, const string& id, const wstring& text, int length,
|
||||
GUICALLBACK cb = nullptr, const wstring& Explanation = L"", const wstring& tooltip = L"");
|
||||
|
||||
InputInfo *replaceSelection(const char *id, const wstring &text);
|
||||
InputInfo* replaceSelection(const char* id, const wstring& text);
|
||||
|
||||
InputInfo &addInputBox(const string &id, int width, int height, const wstring &text,
|
||||
GUICALLBACK cb, const wstring &explanation);
|
||||
InputInfo& addInputBox(const string& id, int width, int height, const wstring& text,
|
||||
GUICALLBACK cb, const wstring& explanation);
|
||||
|
||||
InputInfo &addInputBox(const string &id, int x, int y, int width, int height,
|
||||
const wstring &text, GUICALLBACK cb, const wstring &explanation);
|
||||
InputInfo& addInputBox(const string& id, int x, int y, int width, int height,
|
||||
const wstring& text, GUICALLBACK cb, const wstring& explanation);
|
||||
|
||||
ListBoxInfo &addListBox(const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"", bool multiple=false);
|
||||
ListBoxInfo &addListBox(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"", bool multiple=false);
|
||||
ListBoxInfo& addListBox(const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"", bool multiple = false);
|
||||
ListBoxInfo& addListBox(int x, int y, const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"", bool multiple = false);
|
||||
|
||||
ListBoxInfo &addSelection(const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"");
|
||||
ListBoxInfo &addSelection(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"");
|
||||
ListBoxInfo& addSelection(const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"");
|
||||
ListBoxInfo& addSelection(int x, int y, const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"");
|
||||
|
||||
ListBoxInfo &addCombo(const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"");
|
||||
ListBoxInfo &addCombo(int x, int y, const string &id, int width, int height, GUICALLBACK cb=0, const wstring &explanation=L"", const wstring &tooltip=L"");
|
||||
ListBoxInfo& addCombo(const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"");
|
||||
ListBoxInfo& addCombo(int x, int y, const string& id, int width, int height, GUICALLBACK cb = nullptr, const wstring& explanation = L"", const wstring& tooltip = L"");
|
||||
|
||||
// Grows a listbox, selection, combo in X-direction to fit current contents. Returns true if changed.
|
||||
bool autoGrow(const char *id);
|
||||
bool autoGrow(const char* id);
|
||||
|
||||
void setListDescription(const wstring& desc);
|
||||
|
||||
void setListDescription(const wstring &desc);
|
||||
|
||||
// Wide versions
|
||||
TextInfo &addString(const string &id, int format, const wstring &text, GUICALLBACK cb=0);
|
||||
TextInfo &addString(const string &id, int yp, int xp, int format, const wstring &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo &addString(const char *id, int format, const wstring &text, GUICALLBACK cb=0);
|
||||
TextInfo &addString(const char *id, int yp, int xp, int format, const wstring &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo& addString(const string& id, int format, const wstring& text, GUICALLBACK cb = nullptr);
|
||||
TextInfo& addString(const string& id, int yp, int xp, int format, const wstring& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
TextInfo& addString(const char* id, int format, const wstring& text, GUICALLBACK cb = nullptr);
|
||||
TextInfo& addString(const char* id, int yp, int xp, int format, const wstring& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
// Untranslated versions
|
||||
TextInfo &addStringUT(int yp, int xp, int format, const wstring &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo &addStringUT(int format, const wstring &text, GUICALLBACK cb=0);
|
||||
TextInfo& addStringUT(int yp, int xp, int format, const wstring& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
TextInfo& addStringUT(int format, const wstring& text, GUICALLBACK cb = nullptr);
|
||||
|
||||
// Temporary XXX
|
||||
TextInfo &addString(const string &id, int format, const string &text, GUICALLBACK cb=0);
|
||||
TextInfo &addString(const string &id, int yp, int xp, int format, const string &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo &addString(const char *id, int format, const string &text, GUICALLBACK cb=0);
|
||||
TextInfo &addString(const char *id, int yp, int xp, int format, const string &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo& addString(const string& id, int format, const string& text, GUICALLBACK cb = nullptr);
|
||||
TextInfo& addString(const string& id, int yp, int xp, int format, const string& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
TextInfo& addString(const char* id, int format, const string& text, GUICALLBACK cb = nullptr);
|
||||
TextInfo& addString(const char* id, int yp, int xp, int format, const string& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
// Untranslated versions
|
||||
TextInfo &addStringUT(int yp, int xp, int format, const string &text,
|
||||
int xlimit=0, GUICALLBACK cb=0, const wchar_t *fontFace = 0);
|
||||
TextInfo &addStringUT(int format, const string &text, GUICALLBACK cb=0);
|
||||
TextInfo& addStringUT(int yp, int xp, int format, const string& text,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, const wchar_t* fontFace = nullptr);
|
||||
TextInfo& addStringUT(int format, const string& text, GUICALLBACK cb = nullptr);
|
||||
// XXX Temporary
|
||||
|
||||
TextInfo &addTimer(int yp, int xp, int format, DWORD ZeroTime,
|
||||
int xlimit=0, GUICALLBACK cb=0, int TimeOut=NOTIMEOUT, const wchar_t *fontFace = 0);
|
||||
TextInfo &addTimeout(int TimeOut, GUICALLBACK cb);
|
||||
TextInfo& addImage(const string& id, int yp, int xp, int format, const wstring& imageId,
|
||||
int width = 0, int height = 0, GUICALLBACK cb = nullptr);
|
||||
|
||||
void removeTimeoutMilli(const string &id);
|
||||
TimerInfo &addTimeoutMilli(int timeOut, const string &id, GUICALLBACK cb);
|
||||
void timerProc(TimerInfo &timer, DWORD timeout);
|
||||
TextInfo& addTimer(int yp, int xp, int format, DWORD ZeroTime,
|
||||
int xlimit = 0, GUICALLBACK cb = nullptr, int TimeOut = NOTIMEOUT, const wchar_t* fontFace = nullptr);
|
||||
|
||||
void removeHandler(GuiHandler *h);
|
||||
TextInfo& addTimeout(int TimeOut, GUICALLBACK cb);
|
||||
|
||||
void draw(HDC hDC, RECT &windowArea, RECT &drawArea);
|
||||
void removeTimeoutMilli(const string& id);
|
||||
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();
|
||||
|
||||
int popupMenu(int x, int y, const vector<pair<wstring, int>> &menuItems) const;
|
||||
int popupMenu(int x, int y, const vector<pair<wstring, int>>& menuItems) const;
|
||||
|
||||
void setDBErrorState(bool state);
|
||||
friend class Table;
|
||||
friend gdioutput *createExtraWindow(const string &tag, const wstring &title, int max_x, int max_y, bool fixedSize);
|
||||
friend gdioutput* createExtraWindow(const string& tag, const wstring& title, int max_x, int max_y, bool fixedSize);
|
||||
|
||||
gdioutput(const string &tag, double _scale);
|
||||
gdioutput(double _scale, HWND hWndTarget, const PrinterObject &defprn);
|
||||
gdioutput(const string& tag, double _scale);
|
||||
gdioutput(double _scale, HWND hWndTarget, const PrinterObject& defprn);
|
||||
virtual ~gdioutput();
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -82,6 +82,10 @@ public:
|
||||
GuiHandler &getHandler() const;
|
||||
BaseInfo &setHandler(const GuiHandler *h) {handler = const_cast<GuiHandler *>(h); return *this;}
|
||||
BaseInfo &setHandler(const shared_ptr<GuiHandler> &h) { managedHandler = h; return *this; }
|
||||
void clearHandler() {
|
||||
handler = nullptr;
|
||||
managedHandler.reset();
|
||||
}
|
||||
};
|
||||
|
||||
class RestoreInfo : public BaseInfo
|
||||
@ -108,6 +112,12 @@ public:
|
||||
GUICALLBACK onClear;
|
||||
GUICALLBACK postClear;
|
||||
|
||||
set<string> restorePoints;
|
||||
|
||||
bool operator<(const RestoreInfo &r) const {
|
||||
return nLBI < r.nLBI || nBI < r.nBI || nII < r.nII || nTL < r.nTL || nRect < r.nRect || nData < r.nData;
|
||||
}
|
||||
|
||||
HWND getControlWindow() const {throw std::exception("Unsupported");}
|
||||
};
|
||||
|
||||
@ -387,11 +397,12 @@ private:
|
||||
DWORD dataInt;
|
||||
wstring dataString;
|
||||
gdioutput *parent;
|
||||
TimerInfo(gdioutput *gdi, GUICALLBACK cb) : parent(gdi), callBack(cb), setWnd(0), timerId(++globalTimerId) {}
|
||||
HWND setWnd;
|
||||
public:
|
||||
~TimerInfo();
|
||||
|
||||
TimerInfo(gdioutput* gdi, GUICALLBACK cb) : parent(gdi), callBack(cb), setWnd(0), timerId(++globalTimerId) {}
|
||||
TimerInfo(const TimerInfo&) = delete;
|
||||
TimerInfo& operator=(const TimerInfo&) = delete;
|
||||
int getId() const { return timerId; }
|
||||
BaseInfo &setExtra(const wchar_t *e) {return BaseInfo::setExtra(e);}
|
||||
BaseInfo &setExtra(int e) {return BaseInfo::setExtra(e);}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -266,7 +266,7 @@ template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const
|
||||
ps = None;
|
||||
|
||||
vector< pair<int, oAbstractRunner *> > arr(rt.size());
|
||||
const int maxT = 3600 * 100;
|
||||
const int maxT = timeConstHour * 100;
|
||||
for (size_t k = 0; k < rt.size(); k++) {
|
||||
arr[k].first = 0;
|
||||
if (ps == ClassWise) {
|
||||
@ -293,7 +293,7 @@ template<class T> void GeneralResult::sort(vector<T *> &rt, SortOrder so) const
|
||||
ord = maxT - ord;
|
||||
}
|
||||
else if (so == SortByStartTime || so == ClassStartTime ||
|
||||
so == ClassStartTimeClub) {
|
||||
so == ClassStartTimeClub || so == ClubClassStartTime) {
|
||||
ord = tr.getStartTime();
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ int TotalResultAtControl::deduceTime(oRunner &runner, int startTime) const {
|
||||
pair<int,int> TotalResultAtControl::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const {
|
||||
if (asTeamMember)
|
||||
return make_pair(runner.getLegNumber(), 0);
|
||||
const int TK = 3600 * 24 * 7;
|
||||
const int TK = timeConstHour * 24 * 7;
|
||||
RunnerStatus inputStatus = StatusOK;
|
||||
|
||||
if (runner.getTeam()) {
|
||||
@ -781,7 +781,7 @@ RunnerStatus DynamicResult::toStatus(int status) const {
|
||||
|
||||
pair<int,int> DynamicResult::score(oTeam &team, RunnerStatus st, int time, int points) const {
|
||||
if (getMethod(MTScore)) {
|
||||
parser.addSymbol("ComputedTime", time);
|
||||
parser.addSymbol("ComputedTime", time / timeConstSecond);
|
||||
parser.addSymbol("ComputedStatus", st);
|
||||
parser.addSymbol("ComputedPoints", points);
|
||||
return make_pair(0, getMethod(MTScore)->evaluate(parser));
|
||||
@ -801,7 +801,7 @@ RunnerStatus DynamicResult::deduceStatus(oTeam &team) const {
|
||||
|
||||
int DynamicResult::deduceTime(oTeam &team) const {
|
||||
if (getMethod(MDeduceTTime))
|
||||
return getMethod(MDeduceTTime)->evaluate(parser);
|
||||
return getMethod(MDeduceTTime)->evaluate(parser) * timeConstSecond + team.getSubSeconds();
|
||||
else if (getMethodSource(MDeduceTTime).empty())
|
||||
return GeneralResult::deduceTime(team);
|
||||
else throw meosException("Syntax error");
|
||||
@ -817,7 +817,7 @@ int DynamicResult::deducePoints(oTeam &team) const {
|
||||
|
||||
pair<int,int> DynamicResult::score(oRunner &runner, RunnerStatus st, int time, int points, bool asTeamMember) const {
|
||||
if (getMethod(MRScore)) {
|
||||
parser.addSymbol("ComputedTime", time);
|
||||
parser.addSymbol("ComputedTime", time / timeConstSecond);
|
||||
parser.addSymbol("ComputedStatus", st);
|
||||
parser.addSymbol("ComputedPoints", points);
|
||||
return make_pair(0, getMethod(MRScore)->evaluate(parser));
|
||||
@ -837,7 +837,7 @@ RunnerStatus DynamicResult::deduceStatus(oRunner &runner) const {
|
||||
|
||||
int DynamicResult::deduceTime(oRunner &runner, int startTime) const {
|
||||
if (getMethod(MDeduceRTime))
|
||||
return getMethod(MDeduceRTime)->evaluate(parser);
|
||||
return getMethod(MDeduceRTime)->evaluate(parser) * timeConstSecond + runner.getSubSeconds();
|
||||
else if (getMethodSource(MDeduceRTime).empty())
|
||||
return GeneralResult::deduceTime(runner, startTime);
|
||||
else throw meosException("Syntax error");
|
||||
@ -1160,24 +1160,24 @@ void DynamicResult::prepareCommon(oAbstractRunner &runner, bool classResult) con
|
||||
if (st == StatusUnknown && ft > 0)
|
||||
st = StatusOK;
|
||||
parser.addSymbol("Status", st);
|
||||
parser.addSymbol("Start", runner.getStartTime());
|
||||
parser.addSymbol("Finish", ft);
|
||||
parser.addSymbol("Time", runner.getRunningTime(useComputed));
|
||||
parser.addSymbol("Start", runner.getStartTime() / timeConstSecond);
|
||||
parser.addSymbol("Finish", ft / timeConstSecond);
|
||||
parser.addSymbol("Time", runner.getRunningTime(useComputed) / timeConstSecond);
|
||||
parser.addSymbol("Place", runner.getPlace(false));
|
||||
parser.addSymbol("Points", runner.getRogainingPoints(useComputed, false));
|
||||
parser.addSymbol("PointReduction", runner.getRogainingReduction(useComputed));
|
||||
parser.addSymbol("PointOvertime", runner.getRogainingOvertime(useComputed));
|
||||
parser.addSymbol("PointOvertime", runner.getRogainingOvertime(useComputed) / timeConstSecond);
|
||||
parser.addSymbol("PointGross", runner.getRogainingPointsGross(useComputed));
|
||||
|
||||
parser.addSymbol("PointAdjustment", runner.getPointAdjustment());
|
||||
parser.addSymbol("TimeAdjustment", runner.getTimeAdjustment());
|
||||
parser.addSymbol("TimeAdjustment", runner.getTimeAdjustment(true) / timeConstSecond);
|
||||
|
||||
parser.addSymbol("TotalStatus", runner.getTotalStatus());
|
||||
parser.addSymbol("TotalTime", runner.getTotalRunningTime());
|
||||
parser.addSymbol("TotalStatus", runner.getTotalStatus(false));
|
||||
parser.addSymbol("TotalTime", runner.getTotalRunningTime()/timeConstSecond);
|
||||
parser.addSymbol("TotalPlace", runner.getTotalPlace(false));
|
||||
|
||||
parser.addSymbol("InputStatus", runner.getInputStatus());
|
||||
parser.addSymbol("InputTime", runner.getInputTime());
|
||||
parser.addSymbol("InputTime", runner.getInputTime() / timeConstSecond);
|
||||
parser.addSymbol("InputPlace", runner.getInputPlace());
|
||||
parser.addSymbol("InputPoints", runner.getInputPoints());
|
||||
parser.addSymbol("Shorten", runner.getNumShortening());
|
||||
@ -1191,13 +1191,16 @@ void DynamicResult::prepareCommon(oAbstractRunner &runner, bool classResult) con
|
||||
for (RunnerStatus s : inst)
|
||||
iinst.push_back(s);
|
||||
|
||||
for (int &t : times)
|
||||
t /= timeConstSecond;
|
||||
|
||||
parser.addSymbol("StageStatus", iinst);
|
||||
parser.addSymbol("StageTime", times);
|
||||
parser.addSymbol("StagePlace", places);
|
||||
parser.addSymbol("StagePoints", points);
|
||||
|
||||
parser.addSymbol("InputStatus", runner.getInputStatus());
|
||||
parser.addSymbol("InputTime", runner.getInputTime());
|
||||
parser.addSymbol("InputTime", runner.getInputTime() / timeConstSecond);
|
||||
parser.addSymbol("InputPlace", runner.getInputPlace());
|
||||
parser.addSymbol("InputPoints", runner.getInputPoints());
|
||||
|
||||
@ -1226,13 +1229,13 @@ void DynamicResult::prepareCalculations(oTeam &team, bool classResult) const {
|
||||
for (int k = 0; k < nr; k++) {
|
||||
pRunner r = team.getRunner(k);
|
||||
if (r) {
|
||||
oAbstractRunner::TempResult &res = r->getTempResult();
|
||||
const oAbstractRunner::TempResult &res = r->getTempResult();
|
||||
status[k] = res.getStatus();
|
||||
time[k] = res.getRunningTime();
|
||||
time[k] = res.getRunningTime() / timeConstSecond;
|
||||
if (time[k] > 0 && status[k] == StatusUnknown)
|
||||
status[k] = StatusOK;
|
||||
start[k] = res.getStartTime();
|
||||
finish[k] = res.getFinishTime();
|
||||
start[k] = res.getStartTime() / timeConstSecond;
|
||||
finish[k] = res.getFinishTime() / timeConstSecond;
|
||||
points[k] = res.getPoints();
|
||||
if (classResult) {
|
||||
r->updateComputedResultFromTemp();
|
||||
@ -1281,7 +1284,7 @@ void DynamicResult::prepareCalculations(oTeam &team, bool classResult) const {
|
||||
pClass cls = team.getClassRef(true);
|
||||
if (cls) {
|
||||
int nl = max<int>(1, cls->getNumStages() - 1);
|
||||
parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, nl, false, false));
|
||||
parser.addSymbol("ShortestClassTime", cls->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, nl, false, false) / timeConstSecond);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1303,7 +1306,7 @@ void DynamicResult::prepareCalculations(oRunner &runner, bool classResult) const
|
||||
int ip = 0;
|
||||
for (size_t k = 0; k < punches.size(); k++) {
|
||||
if (punches[k]->getTypeCode() >= 30) {
|
||||
times[ip] = punches[k]->getAdjustedTime();
|
||||
times[ip] = punches[k]->getAdjustedTime() / timeConstSecond;
|
||||
codes[ip] = punches[k]->getTypeCode();
|
||||
controls[ip] = punches[k]->isUsedInCourse() ? punches[k]->getControlId() : -1;
|
||||
ip++;
|
||||
@ -1345,16 +1348,16 @@ void DynamicResult::prepareCalculations(oRunner &runner, bool classResult) const
|
||||
if (ctrl->isSingleStatusOK()) {
|
||||
eCrs.push_back(ctrl->getFirstNumber());
|
||||
if (size_t(k) < sp.size()) {
|
||||
if (sp[k].status == SplitData::OK) {
|
||||
eAccTime.push_back(sp[k].time - start);
|
||||
eSplitTime.push_back(sp[k].time - st);
|
||||
st = sp[k].time;
|
||||
if (sp[k].hasTime()) {
|
||||
eAccTime.push_back((sp[k].getTime(false) - start) / timeConstSecond);
|
||||
eSplitTime.push_back((sp[k].getTime(false) - st) / timeConstSecond);
|
||||
st = sp[k].getTime(false);
|
||||
}
|
||||
else if (sp[k].status == SplitData::NoTime) {
|
||||
eAccTime.push_back(st - start);
|
||||
else if (sp[k].getStatus() == SplitData::SplitStatus::NoTime) {
|
||||
eAccTime.push_back( (st - start) / timeConstSecond);
|
||||
eSplitTime.push_back(0);
|
||||
}
|
||||
else if (sp[k].status == SplitData::Missing) {
|
||||
else if (sp[k].isMissing()) {
|
||||
eAccTime.push_back(0);
|
||||
eSplitTime.push_back(-1);
|
||||
}
|
||||
@ -1362,8 +1365,8 @@ void DynamicResult::prepareCalculations(oRunner &runner, bool classResult) const
|
||||
}
|
||||
}
|
||||
if (runner.getFinishTime() > 0) {
|
||||
eAccTime.push_back(runner.getFinishTime() - start);
|
||||
eSplitTime.push_back(runner.getFinishTime() - st);
|
||||
eAccTime.push_back((runner.getFinishTime() - start) / timeConstSecond);
|
||||
eSplitTime.push_back((runner.getFinishTime() - st) / timeConstSecond);
|
||||
}
|
||||
else if (!eAccTime.empty()) {
|
||||
eAccTime.push_back(0);
|
||||
@ -1394,7 +1397,7 @@ void DynamicResult::prepareCalculations(oRunner &runner, bool classResult) const
|
||||
pClass cls = runner.getClassRef(true);
|
||||
if (cls) {
|
||||
int nl = runner.getLegNumber();
|
||||
parser.addSymbol("ShortestClassTime", cls->getBestLegTime(oClass::AllowRecompute::Yes, nl, false));
|
||||
parser.addSymbol("ShortestClassTime", cls->getBestLegTime(oClass::AllowRecompute::Yes, nl, false) / timeConstSecond);
|
||||
}
|
||||
vector<int> delta;
|
||||
vector<int> place;
|
||||
@ -1523,7 +1526,7 @@ void GeneralResult::calculateIndividualResults(vector<pRunner> &runners,
|
||||
else {
|
||||
oe.calculateResults(set<int>(), oEvent::ResultType::TotalResult, inclPreliminary);
|
||||
for (pRunner r : runners) {
|
||||
ri.status = r->getTotalStatus();
|
||||
ri.status = r->getTotalStatus(false);
|
||||
if (ri.status == StatusUnknown && r->getInputStatus() == StatusOK) {
|
||||
if (r->getFinishTime() == 0) {
|
||||
if (!inclForestRunners)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
193
code/image.cpp
193
code/image.cpp
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -89,9 +89,9 @@ vector<uint8_t> Image::loadResourceToMemory(LPCTSTR lpName, LPCTSTR lpType) {
|
||||
return result;
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png(vector<uint8_t> &inData, int &width, int &height, ImageMethod method) {
|
||||
HBITMAP Image::read_png(vector<uint8_t> &&inData, int &width, int &height, ImageMethod method) {
|
||||
PngData inputStream;
|
||||
inputStream.memory.swap(inData);
|
||||
inputStream.memory = std::move(inData);
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png)
|
||||
return nullptr;
|
||||
@ -196,25 +196,57 @@ HBITMAP Image::read_png(vector<uint8_t> &inData, int &width, int &height, ImageM
|
||||
row[x + 3] = src[x + 3];
|
||||
}
|
||||
}
|
||||
else if (method == ImageMethod::WhiteTransparent) {
|
||||
for (size_t x = 0; x < cbStride; x += 4) {
|
||||
row[x + 2] = src[x + 0]; // Red
|
||||
row[x + 1] = src[x + 1]; // Green
|
||||
row[x + 0] = src[x + 2]; // Blue
|
||||
row[x + 3] = src[x + 3];
|
||||
if (src[x + 0] == 0xFF && src[x + 1] == 0xFF && src[x + 2] == 0xFF) {
|
||||
row[x + 3] = 0;
|
||||
row[x + 2] = 0;
|
||||
row[x + 1] = 0;
|
||||
row[x + 0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png_file(const wstring &filename, int &width, int &height, ImageMethod method) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
PngData inputStream;
|
||||
inputStream.memory;
|
||||
uint64_t Image::computeHash(const vector<uint8_t>& data) {
|
||||
uint64_t h = data.size();
|
||||
size_t siz4 = data.size() / 4;
|
||||
const uint32_t* ptr = (const uint32_t *)data.data();
|
||||
size_t lim = siz4 * 4;
|
||||
for (size_t e = siz4 * 4; e < data.size(); e++)
|
||||
h = h * 256 + data[e];
|
||||
|
||||
for (size_t e = 0; e < siz4; e++) {
|
||||
h = 997 * h + ptr[e];
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void Image::read_file(const wstring& filename, vector<uint8_t>& data) {
|
||||
ifstream fin;
|
||||
fin.open(filename, ios::binary);
|
||||
fin.seekg(0, ios::end);
|
||||
int p2 = (int)fin.tellg();
|
||||
fin.seekg(0, ios::beg);
|
||||
inputStream.memory.resize(p2);
|
||||
fin.read((char *)&inputStream.memory[0], inputStream.memory.size());
|
||||
data.resize(p2);
|
||||
fin.read((char*)data.data(), data.size());
|
||||
fin.close();
|
||||
return read_png(inputStream.memory, width, height, method);
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png_file(const wstring &filename, int &width, int &height, uint64_t &hash, ImageMethod method) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
PngData inputStream;
|
||||
read_file(filename, inputStream.memory);
|
||||
hash = computeHash(inputStream.memory);
|
||||
return read_png(std::move(inputStream.memory), width, height, method);
|
||||
}
|
||||
|
||||
HBITMAP Image::read_png_resource(LPCTSTR lpName, LPCTSTR lpType, int &width, int &height, ImageMethod method) {
|
||||
@ -224,7 +256,7 @@ HBITMAP Image::read_png_resource(LPCTSTR lpName, LPCTSTR lpType, int &width, int
|
||||
inputStream.memory = loadResourceToMemory(lpName, lpType);
|
||||
if (inputStream.memory.empty())
|
||||
return nullptr;
|
||||
return read_png(inputStream.memory, width, height, method);
|
||||
return read_png(std::move(inputStream.memory), width, height, method);
|
||||
}
|
||||
|
||||
Image::Image()
|
||||
@ -236,7 +268,7 @@ Image::~Image()
|
||||
}
|
||||
|
||||
// Loads the PNG containing the splash image into a HBITMAP.
|
||||
HBITMAP Image::loadImage(int resource, ImageMethod method) {
|
||||
HBITMAP Image::loadImage(uint64_t resource, ImageMethod method) {
|
||||
if (images.count(resource))
|
||||
return images[resource].image;
|
||||
|
||||
@ -250,18 +282,22 @@ HBITMAP Image::loadImage(int resource, ImageMethod method) {
|
||||
return hbmp;
|
||||
}
|
||||
|
||||
int Image::getWidth(int resource) {
|
||||
int Image::getWidth(uint64_t resource) {
|
||||
loadImage(resource, ImageMethod::Default);
|
||||
return images[resource].width;
|
||||
}
|
||||
|
||||
int Image::getHeight(int resource) {
|
||||
int Image::getHeight(uint64_t resource) {
|
||||
loadImage(resource, ImageMethod::Default);
|
||||
return images[resource].height;
|
||||
}
|
||||
|
||||
void Image::drawImage(int resource, ImageMethod method, HDC hDC, int x, int y, int width, int height) {
|
||||
void Image::drawImage(uint64_t resource, ImageMethod method, HDC hDC, int x, int y, int width, int height) {
|
||||
HBITMAP bmp = loadImage(resource, method);
|
||||
auto res = images.find(resource);
|
||||
if (res == images.end())
|
||||
return;
|
||||
|
||||
HDC memdc = CreateCompatibleDC(hDC);
|
||||
SelectObject(memdc, bmp);
|
||||
|
||||
@ -270,7 +306,130 @@ void Image::drawImage(int resource, ImageMethod method, HDC hDC, int x, int y, i
|
||||
bf.BlendFlags = 0;
|
||||
bf.SourceConstantAlpha =0xFF;
|
||||
bf.AlphaFormat = AC_SRC_ALPHA;
|
||||
AlphaBlend(hDC, x, y, width, height, memdc, 0, 0, width, height, bf);
|
||||
AlphaBlend(hDC, x, y, width, height, memdc, 0, 0, res->second.width, res->second.height, bf);
|
||||
|
||||
DeleteDC(memdc);
|
||||
}
|
||||
|
||||
uint64_t Image::loadFromFile(const wstring& path, ImageMethod method) {
|
||||
vector<uint8_t> bytes;
|
||||
read_file(path, bytes);
|
||||
|
||||
uint64_t hash = computeHash(bytes);
|
||||
|
||||
auto res = images.emplace(hash, Bmp());
|
||||
if (res.second) {
|
||||
wchar_t drive[20];
|
||||
wchar_t dir[MAX_PATH];
|
||||
wchar_t name[MAX_PATH];
|
||||
wchar_t ext[MAX_PATH];
|
||||
_wsplitpath_s(path.c_str(), drive, dir, name, ext);
|
||||
Bmp &out = res.first->second;
|
||||
out.fileName = wstring(name) + ext;
|
||||
out.rawData = bytes;
|
||||
out.image = read_png(std::move(bytes), out.width, out.height, method);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint64_t Image::loadFromMemory(const wstring& fileName, const vector<uint8_t>& bytes, ImageMethod method) {
|
||||
uint64_t hash = computeHash(bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void Image::provideFromMemory(uint64_t id, const wstring& fileName, const vector<uint8_t>& bytes) {
|
||||
uint64_t hash = computeHash(bytes);
|
||||
if (id != hash)
|
||||
throw meosException(L"Corrupted image: " + fileName);
|
||||
|
||||
images[id].fileName = fileName;
|
||||
images[id].rawData = bytes;
|
||||
}
|
||||
|
||||
void Image::addImage(uint64_t id, const wstring& fileName) {
|
||||
images[id].fileName = fileName;
|
||||
}
|
||||
|
||||
void Image::reloadImage(uint64_t imgId, ImageMethod method) {
|
||||
auto res = images.find(imgId);
|
||||
if (res != images.end() && res->second.rawData.size() > 0) {
|
||||
auto copy = res->second.rawData;
|
||||
res->second.destroy();
|
||||
res->second.image = read_png(std::move(copy), res->second.width, res->second.height, method);
|
||||
return;
|
||||
}
|
||||
throw meosException("Unknown image " + itos(imgId));
|
||||
}
|
||||
|
||||
void Image::clearLoaded() {
|
||||
for (auto iter = images.begin(); iter != images.end(); ) {
|
||||
if (iter->second.fileName.empty())
|
||||
++iter;
|
||||
else {
|
||||
iter = images.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image::Bmp::~Bmp() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void Image::Bmp::destroy() {
|
||||
if (image) {
|
||||
DeleteObject(image);
|
||||
image = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Image::enumerateImages(vector<pair<wstring, size_t>>& img) const {
|
||||
img.clear();
|
||||
for (auto& bmp : images) {
|
||||
if (bmp.second.fileName.size() > 0)
|
||||
img.emplace_back(bmp.second.fileName, img.size());
|
||||
}
|
||||
sort(img.begin(), img.end());
|
||||
}
|
||||
|
||||
uint64_t Image::getIdFromEnumeration(int enumerationIx) const {
|
||||
int ix = 0;
|
||||
for (auto& bmp : images) {
|
||||
if (bmp.second.fileName.size() > 0) {
|
||||
if (enumerationIx == ix++) {
|
||||
return bmp.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw meosException("Internal error");
|
||||
}
|
||||
|
||||
int Image::getEnumerationIxFromId(uint64_t imgId) const {
|
||||
int ix = 0;
|
||||
for (auto& bmp : images) {
|
||||
if (bmp.second.fileName.size() > 0) {
|
||||
if (imgId == bmp.first)
|
||||
return ix;
|
||||
ix++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const wstring& Image::getFileName(uint64_t imgId) const {
|
||||
if (!hasImage(imgId))
|
||||
throw meosException("Missing image: " + itos(imgId));
|
||||
return images.at(imgId).fileName;
|
||||
}
|
||||
|
||||
const vector<uint8_t>& Image::getRawData(uint64_t imgId) const {
|
||||
if (!hasImage(imgId))
|
||||
throw meosException("Missing image: " + itos(imgId));
|
||||
return images.at(imgId).rawData;
|
||||
}
|
||||
|
||||
|
||||
bool Image::hasImage(uint64_t imgId) const {
|
||||
auto res = images.find(imgId);
|
||||
return res != images.end() && res->second.rawData.size() > 0;
|
||||
}
|
||||
|
||||
51
code/image.h
51
code/image.h
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -29,34 +29,57 @@ class Image {
|
||||
public:
|
||||
enum class ImageMethod {
|
||||
Default,
|
||||
MonoAlpha
|
||||
MonoAlpha,
|
||||
WhiteTransparent
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static HBITMAP read_png_file(const wstring &filename, int &width, int &height, ImageMethod method);
|
||||
static uint64_t computeHash(const vector<uint8_t>& data);
|
||||
|
||||
static void read_file(const wstring& filename, vector<uint8_t>& data);
|
||||
|
||||
static HBITMAP read_png_file(const wstring &filename, int &width, int &height, uint64_t &hash, ImageMethod method);
|
||||
static HBITMAP read_png_resource(LPCTSTR lpName, LPCTSTR lpType, int &width, int &height, ImageMethod method);
|
||||
static HBITMAP read_png(vector<uint8_t> &data, int &width, int &height, ImageMethod method);
|
||||
|
||||
|
||||
static HBITMAP read_png(vector<uint8_t> &&data, int &width, int &height, ImageMethod method);
|
||||
|
||||
struct Bmp {
|
||||
HBITMAP image;
|
||||
int width;
|
||||
int height;
|
||||
HBITMAP image = nullptr;
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
wstring fileName;
|
||||
vector<uint8_t> rawData;
|
||||
~Bmp();
|
||||
void destroy();
|
||||
};
|
||||
|
||||
map<int, Bmp> images;
|
||||
map<uint64_t, Bmp> images;
|
||||
public:
|
||||
|
||||
HBITMAP loadImage(int resource, ImageMethod method);
|
||||
HBITMAP loadImage(uint64_t resource, ImageMethod method);
|
||||
|
||||
static vector<uint8_t> loadResourceToMemory(LPCTSTR lpName, LPCTSTR lpType);
|
||||
|
||||
int getWidth(int resource);
|
||||
int getHeight(int resource);
|
||||
void drawImage(int resource, ImageMethod method, HDC hDC, int x, int y, int width, int height);
|
||||
int getWidth(uint64_t resource);
|
||||
int getHeight(uint64_t resource);
|
||||
void drawImage(uint64_t resource, ImageMethod method, HDC hDC, int x, int y, int width, int height);
|
||||
|
||||
uint64_t loadFromFile(const wstring& path, ImageMethod method);
|
||||
uint64_t loadFromMemory(const wstring& fileName, const vector<uint8_t> &bytes, ImageMethod method);
|
||||
void provideFromMemory(uint64_t id, const wstring& fileName, const vector<uint8_t>& bytes);
|
||||
void addImage(uint64_t id, const wstring& fileName);
|
||||
|
||||
void clearLoaded();
|
||||
|
||||
void enumerateImages(vector<pair<wstring, size_t>>& img) const;
|
||||
uint64_t getIdFromEnumeration(int enumerationIx) const;
|
||||
int getEnumerationIxFromId(uint64_t imgId) const;
|
||||
|
||||
bool hasImage(uint64_t imgId) const;
|
||||
void reloadImage(uint64_t imgId, ImageMethod method);
|
||||
|
||||
const wstring& getFileName(uint64_t imgId) const;
|
||||
const vector<uint8_t> &getRawData(uint64_t imgId) const;
|
||||
Image();
|
||||
~Image();
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
BIN
code/info24.png
Normal file
BIN
code/info24.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 874 B |
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -501,9 +501,9 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
|
||||
ch = true;
|
||||
}
|
||||
|
||||
RunnerStatus s = bc.getStatusComputed();
|
||||
RunnerStatus s = bc.getStatusComputed(true);
|
||||
|
||||
int rt = bc.getRunningTime(true) * 10;
|
||||
int rt = bc.getRunningTime(true) * (10/timeConstSecond);
|
||||
if (rt > 0) {
|
||||
if (s == RunnerStatus::StatusUnknown)
|
||||
s = RunnerStatus::StatusOK;
|
||||
@ -521,7 +521,7 @@ bool InfoBaseCompetitor::synchronizeBase(oAbstractRunner &bc) {
|
||||
|
||||
int st = -1;
|
||||
if (bc.startTimeAvailable())
|
||||
st = convertRelativeTime(bc, bc.getStartTime()) * 10;
|
||||
st = convertRelativeTime(bc, bc.getStartTime()) * (10 / timeConstSecond);
|
||||
|
||||
if (st != startTime) {
|
||||
startTime = st;
|
||||
@ -564,7 +564,7 @@ bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &
|
||||
|
||||
pTeam t = r.getTeam();
|
||||
if (useTotalResults) {
|
||||
legInput = r.getTotalTimeInput() * 10;
|
||||
legInput = r.getTotalTimeInput() * (10 / timeConstSecond);
|
||||
s = r.getTotalStatusInput();
|
||||
}
|
||||
else if (t && !isQF && r.getLegNumber() > 0) {
|
||||
@ -578,7 +578,7 @@ bool InfoCompetitor::synchronize(bool useTotalResults, bool useCourse, oRunner &
|
||||
}
|
||||
}
|
||||
if (ltu > 0) {
|
||||
legInput = t->getLegRunningTime(ltu - 1, true, false) * 10;
|
||||
legInput = t->getLegRunningTime(ltu - 1, true, false) * (10 / timeConstSecond);
|
||||
s = t->getLegStatus(ltu - 1, true, false);
|
||||
}
|
||||
}
|
||||
@ -625,7 +625,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
|
||||
}
|
||||
|
||||
vector<RadioTime> newRT;
|
||||
if (r.getClassId(false) > 0 && r.getStatusComputed() != RunnerStatus::StatusNoTiming) {
|
||||
if (r.getClassId(false) > 0 && r.getStatusComputed(true) != RunnerStatus::StatusNoTiming) {
|
||||
const vector<int> &radios = cmp.getControls(r.getClassId(true), r.getLegNumber());
|
||||
for (size_t k = 0; k < radios.size(); k++) {
|
||||
RadioTime radioTime;
|
||||
@ -634,7 +634,7 @@ bool InfoCompetitor::synchronize(const InfoCompetition &cmp, oRunner &r) {
|
||||
r.getSplitTime(radioTime.radioId, s_split, radioTime.runningTime);
|
||||
|
||||
if (radioTime.runningTime > 0) {
|
||||
radioTime.runningTime*=10;
|
||||
radioTime.runningTime *= (10 / timeConstSecond);
|
||||
newRT.push_back(radioTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -224,8 +224,8 @@ private:
|
||||
protected:
|
||||
bool forceComplete;
|
||||
|
||||
bool includeTotal;
|
||||
bool withCourse;
|
||||
bool includeTotal = false;
|
||||
bool withCourse = false;
|
||||
|
||||
list<InfoBase *> toCommit;
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -54,9 +54,9 @@ vector<int> parseSGTimes(const oEvent &oe, const wstring &name) {
|
||||
return times;
|
||||
}
|
||||
|
||||
IOF30Interface::IOF30Interface(oEvent *oe, bool forceSplitFee) : oe(*oe), useGMT(false), teamsAsIndividual(false),
|
||||
IOF30Interface::IOF30Interface(oEvent *oe, bool forceSplitFee, bool useEventorQuirks) : oe(*oe), useGMT(false), teamsAsIndividual(false),
|
||||
entrySourceId(1), unrollLoops(true),
|
||||
includeStageRaceInfo(true) {
|
||||
includeStageRaceInfo(true), useEventorQuirks(useEventorQuirks) {
|
||||
cachedStageNumber = -1;
|
||||
splitLateFee = forceSplitFee || oe->getPropertyInt("SplitLateFees", false) == 1;
|
||||
}
|
||||
@ -705,7 +705,7 @@ void IOF30Interface::assignTeamCourse(gdioutput &gdi, oTeam *team, int iClass, i
|
||||
if (team) {
|
||||
pRunner r = team->getRunner(legId);
|
||||
if (r == 0) {
|
||||
r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(false), 0, 0, false);
|
||||
r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(false), 0, L"", false);
|
||||
if (r) {
|
||||
r->setEntrySource(entrySourceId);
|
||||
r->flagEntryTouched(true);
|
||||
@ -959,7 +959,8 @@ void IOF30Interface::prescanCompetitorList(xmlobject &xo) {
|
||||
}
|
||||
}
|
||||
|
||||
void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount) {
|
||||
void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo,
|
||||
bool onlyWithClub, int &personCount, int &duplicateCount) {
|
||||
if (!xo)
|
||||
return;
|
||||
|
||||
@ -971,11 +972,10 @@ void IOF30Interface::readCompetitorList(gdioutput &gdi, const xmlobject &xo, int
|
||||
xmlList xl;
|
||||
xo.getObjects(xl);
|
||||
|
||||
xmlList::const_iterator it;
|
||||
|
||||
for (it = xl.begin(); it != xl.end(); ++it) {
|
||||
if (it->is("Competitor")) {
|
||||
if (readXMLCompetitorDB(*it))
|
||||
unordered_multimap<size_t, int> duplicateCheck;
|
||||
for (auto &it : xl) {
|
||||
if (it.is("Competitor")) {
|
||||
if (readXMLCompetitorDB(it, onlyWithClub, duplicateCheck, duplicateCount))
|
||||
personCount++;
|
||||
}
|
||||
}
|
||||
@ -1409,12 +1409,17 @@ void IOF30Interface::readStartList(gdioutput &gdi, xmlobject &xo, int &entRead,
|
||||
if (raceToInfo.size() == 1) {
|
||||
RaceInfo &raceInfo = raceToInfo.begin()->second;
|
||||
if (raceInfo.courseId > 0) {
|
||||
if (pc->getCourse() == 0) {
|
||||
pCourse crs = oe.addCourse(pc->getName(), raceInfo.length, raceInfo.courseId);
|
||||
crs->setStart(raceInfo.startName, false);
|
||||
crs->getDI().setInt("Climb", raceInfo.climb);
|
||||
pc->setCourse(crs);
|
||||
crs->synchronize();
|
||||
if (pc->getCourse() == nullptr) {
|
||||
pCourse crs = raceInfo.courseId > 0 ? oe.getCourse(raceInfo.courseId) : nullptr;
|
||||
if (crs == nullptr)
|
||||
crs = oe.addCourse(pc->getName(), raceInfo.length, raceInfo.courseId);
|
||||
|
||||
if (crs != nullptr) {
|
||||
crs->setStart(raceInfo.startName, false);
|
||||
crs->getDI().setInt("Climb", raceInfo.climb);
|
||||
pc->setCourse(crs);
|
||||
crs->synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1639,12 +1644,12 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo,
|
||||
timeStr.swap(tTime);
|
||||
int t = convertAbsoluteTimeISO(timeStr);
|
||||
if (t >= 0 && oe.getNumRunners() == 0) {
|
||||
int zt = t - 3600;
|
||||
int zt = t - timeConstHour;
|
||||
if (zt < 0)
|
||||
zt += 3600*24;
|
||||
zt += timeConstHour *24;
|
||||
|
||||
if (!oe.hasFlag(oEvent::TransferFlags::FlagManualDateTime))
|
||||
oe.setZeroTime(formatTimeHMS(zt), false);
|
||||
oe.setZeroTime(formatTimeHMS(zt, SubSecond::Auto), false);
|
||||
}
|
||||
}
|
||||
if (!oe.hasFlag(oEvent::TransferFlags::FlagManualDateTime))
|
||||
@ -1762,7 +1767,7 @@ void IOF30Interface::readEvent(gdioutput &gdi, const xmlobject &xo,
|
||||
xmlList nameList;
|
||||
s.getObjects("Name", nameList);
|
||||
for (auto s : nameList) {
|
||||
services.emplace_back(id, s.getw());
|
||||
services.emplace_back(id, s.getWStr());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2079,7 +2084,7 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
|
||||
|
||||
if (cardNo > 0 && r == 0 && team) {
|
||||
// We got no person, but a card number. Add the runner anonymously.
|
||||
r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(false), cardNo, 0, false);
|
||||
r = oe.addRunner(lang.tl(L"N.N."), team->getClubId(), team->getClassId(false), cardNo, L"", false);
|
||||
r->flagEntryTouched(true);
|
||||
r->setEntrySource(entrySourceId);
|
||||
r->synchronize();
|
||||
@ -2197,7 +2202,7 @@ pRunner IOF30Interface::readPersonEntry(gdioutput &gdi, xmlobject &xo, pTeam tea
|
||||
if (ts >= 2 && times[ts - 2] < times[ts - 1])
|
||||
oe.setStartGroup(groupId, times[ts - 2], times[ts - 1], groupName);
|
||||
else
|
||||
oe.setStartGroup(groupId, 3600, 3600 * 2, groupName);
|
||||
oe.setStartGroup(groupId, timeConstHour, timeConstHour * 2, groupName);
|
||||
}
|
||||
r->setStartGroup(groupId);
|
||||
}
|
||||
@ -2415,14 +2420,14 @@ pRunner IOF30Interface::readPersonResult(gdioutput &gdi, pClass pc, xmlobject &x
|
||||
int time = split.getObjectInt("Time");
|
||||
split.getObjectString("status", s);
|
||||
if (s != L"missing")
|
||||
card->addPunch(code, st + time, 0);
|
||||
card->addPunch(code, st + time, 0, 0);
|
||||
|
||||
if (s != L"additional")
|
||||
controls.push_back(code);
|
||||
}
|
||||
|
||||
if (ft > 0)
|
||||
card->addPunch(oPunch::PunchFinish, ft, 0);
|
||||
card->addPunch(oPunch::PunchFinish, ft, 0, 0);
|
||||
|
||||
//Update to SQL-source
|
||||
card->synchronize();
|
||||
@ -2469,11 +2474,11 @@ void IOF30Interface::readId(const xmlobject &person, int &pid, __int64 &extId) c
|
||||
person.getObjects("Id", sids);
|
||||
for (auto &x : sids) {
|
||||
auto type = x.getAttrib("type");
|
||||
if (type && type.get() == preferredIdProvider) {
|
||||
sid = x.getw();
|
||||
if (type && type.getPtr() == preferredIdProvider) {
|
||||
sid = x.getWStr();
|
||||
}
|
||||
else if (bsid.empty())
|
||||
bsid = x.getw();
|
||||
bsid = x.getWStr();
|
||||
}
|
||||
if (sid.empty())
|
||||
pid = oBase::idFromExtId(oBase::converExtIdentifierString(bsid));
|
||||
@ -2583,9 +2588,8 @@ pRunner IOF30Interface::readPerson(gdioutput &gdi, const xmlobject &person) {
|
||||
if (s != sUnknown)
|
||||
r->setSex(s);
|
||||
person.getObjectString("BirthDate", tmp);
|
||||
if (tmp.length()>=4) {
|
||||
tmp = tmp.substr(0, 4);
|
||||
r->setBirthYear(_wtoi(tmp.c_str()));
|
||||
if (tmp.length()>=4) {
|
||||
r->setBirthDate(tmp);
|
||||
}
|
||||
|
||||
getNationality(person.getObject("Nationality"), DI);
|
||||
@ -2884,9 +2888,9 @@ void IOF30Interface::FeeInfo::add(IOF30Interface::FeeInfo &fi) {
|
||||
if (!fi.toTime.empty()) {
|
||||
SYSTEMTIME st;
|
||||
convertDateYMS(fi.toTime, st, false);
|
||||
__int64 sec = SystemTimeToInt64Second(st);
|
||||
sec -= 3600;
|
||||
fi.toTime = convertSystemDate(Int64SecondToSystemTime(sec));
|
||||
__int64 sec = SystemTimeToInt64TenthSecond(st);
|
||||
sec -= timeConstHour;
|
||||
fi.toTime = convertSystemDate(Int64TenthSecondToSystemTime(sec));
|
||||
}
|
||||
}
|
||||
//if (fi.fromTime.empty() || (fi.fromTime < toTime && !toTime.empty()))
|
||||
@ -3069,7 +3073,7 @@ void IOF30Interface::setupRelayClass(pClass pc, const vector<LegInfo> &legs) {
|
||||
|
||||
pc->setNumStages(nStage);
|
||||
pc->setStartType(0, STTime, false);
|
||||
pc->setStartData(0, oe.getAbsTime(3600));
|
||||
pc->setStartData(0, oe.getAbsTime(timeConstHour));
|
||||
|
||||
int ix = 0;
|
||||
for (size_t k = 0; k < legs.size(); k++) {
|
||||
@ -3097,10 +3101,24 @@ wstring IOF30Interface::getCurrentTime() const {
|
||||
return getLocalDate() + L"T" + getLocalTimeOnly();
|
||||
}
|
||||
|
||||
|
||||
wstring IOF30Interface::formatRelTime(int rt) {
|
||||
wchar_t bf[32];
|
||||
if (oe.useSubSecond())
|
||||
swprintf_s(bf, L"%d.%d", rt / timeConstSecond, rt % timeConstSecond);
|
||||
else
|
||||
swprintf_s(bf, L"%d", rt / timeConstSecond);
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
|
||||
int IOF30Interface::parseISO8601Time(const xmlobject &xo) {
|
||||
if (!xo)
|
||||
return 0;
|
||||
const char *t = xo.getRaw();
|
||||
const char *t = xo.getRawPtr();
|
||||
if (!t)
|
||||
return 0;
|
||||
int tIx = -1;
|
||||
int zIx = -1;
|
||||
for (int k = 0; t[k] != 0; k++) {
|
||||
@ -3160,9 +3178,9 @@ void IOF30Interface::getLocalDateTime(const string &date, const string &time,
|
||||
int idate = convertDateYMS(date, st, true);
|
||||
if (idate != -1) {
|
||||
if (zone == "Z" || zone == "z") {
|
||||
st.wHour = atime / 3600;
|
||||
st.wMinute = (atime / 60) % 60;
|
||||
st.wSecond = atime % 60;
|
||||
st.wHour = atime / timeConstHour;
|
||||
st.wMinute = (atime / timeConstMinute) % 60;
|
||||
st.wSecond = (atime / timeConstSecond) % 60;
|
||||
|
||||
SYSTEMTIME localTime;
|
||||
memset(&localTime, 0, sizeof(SYSTEMTIME));
|
||||
@ -3219,26 +3237,24 @@ void IOF30Interface::getLocalDateTime(const wstring &date, const wstring &time,
|
||||
SYSTEMTIME st;
|
||||
memset(&st, 0, sizeof(SYSTEMTIME));
|
||||
|
||||
int atime = convertAbsoluteTimeISO(wTime);
|
||||
const int atime = convertAbsoluteTimeISO(wTime);
|
||||
int idate = convertDateYMS(date, st, true);
|
||||
if (idate != -1) {
|
||||
if (zone == L"Z" || zone == L"z") {
|
||||
st.wHour = atime / 3600;
|
||||
st.wMinute = (atime / 60) % 60;
|
||||
st.wSecond = atime % 60;
|
||||
st.wHour = atime / timeConstHour;
|
||||
st.wMinute = (atime / timeConstMinute) % 60;
|
||||
st.wSecond = (atime / timeConstSecond) % 60;
|
||||
|
||||
SYSTEMTIME localTime;
|
||||
memset(&localTime, 0, sizeof(SYSTEMTIME));
|
||||
SystemTimeToTzSpecificLocalTime(0, &st, &localTime);
|
||||
|
||||
atime = localTime.wHour * 3600 + localTime.wMinute * 60 + localTime.wSecond;
|
||||
//atime = localTime.wHour * 3600 + localTime.wMinute * 60 + localTime.wSecond;
|
||||
wchar_t bf[64];
|
||||
wsprintf(bf, L"%02d:%02d:%02d", localTime.wHour, localTime.wMinute, localTime.wSecond);
|
||||
timeOut = bf;
|
||||
wsprintf(bf, L"%d-%02d-%02d", localTime.wYear, localTime.wMonth, localTime.wDay);
|
||||
dateOut = bf;
|
||||
//dateOut = itow(localTime.wYear) + L"-" + itow(localTime.wMonth) + L"-" + itow(localTime.wDay);
|
||||
//timeOut = itow(localTime.wHour) + L":" + itow(localTime.wMinute) + L":" + itow(localTime.wSecond);
|
||||
}
|
||||
else {
|
||||
dateOut = date;
|
||||
@ -3460,16 +3476,16 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.write("StartTime", oe.getAbsDateTimeISO(r.getStartTime(), true, useGMT));
|
||||
|
||||
bool hasTiming = (!r.getClassRef(false) || r.getClassRef(true)->getNoTiming() == false) &&
|
||||
r.getStatusComputed() != RunnerStatus::StatusNoTiming && !r.noTiming();
|
||||
r.getStatusComputed(true) != RunnerStatus::StatusNoTiming && !r.noTiming();
|
||||
|
||||
int finishTime, runningTime, place, after;
|
||||
RunnerStatus status;
|
||||
if (!patrolResult) {
|
||||
place = r.getPlace();
|
||||
finishTime = r.getFinishTimeAdjusted();
|
||||
finishTime = r.getFinishTimeAdjusted(false);
|
||||
runningTime = r.getRunningTime(true);
|
||||
after = r.getTimeAfter();
|
||||
status = r.getStatusComputed();
|
||||
status = r.getStatusComputed(true);
|
||||
}
|
||||
else {
|
||||
int pl = r.getParResultLeg();
|
||||
@ -3480,7 +3496,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
else
|
||||
finishTime = 0;
|
||||
|
||||
after = r.getTeam()->getTimeAfter(pl);
|
||||
after = r.getTeam()->getTimeAfter(pl, true);
|
||||
status = r.getTeam()->getLegStatus(pl, true, false);
|
||||
}
|
||||
|
||||
@ -3494,23 +3510,23 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.write("FinishTime", oe.getAbsDateTimeISO(finishTime, true, useGMT));
|
||||
|
||||
if (runningTime > 0)
|
||||
xml.write("Time", runningTime);
|
||||
xml.write("Time", formatRelTime(runningTime));
|
||||
|
||||
if (after >= 0) {
|
||||
if (teamMember) {
|
||||
xml.write("TimeBehind", "type", L"Leg", itow(after));
|
||||
xml.write("TimeBehind", "type", L"Leg", formatRelTime(after));
|
||||
|
||||
int afterCourse = r.getTimeAfterCourse();
|
||||
if (afterCourse >= 0)
|
||||
xml.write("TimeBehind", "type", L"Course", itow(afterCourse));
|
||||
xml.write("TimeBehind", "type", L"Course", formatRelTime(afterCourse));
|
||||
}
|
||||
else
|
||||
xml.write("TimeBehind", after);
|
||||
xml.write("TimeBehind", formatRelTime(after));
|
||||
}
|
||||
|
||||
if (r.getClassRef(false)) {
|
||||
|
||||
if (r.statusOK(true) && hasTiming) {
|
||||
if (r.statusOK(true, true) && hasTiming) {
|
||||
if (!teamMember && place > 0 && place < 50000) {
|
||||
xml.write("Position", place);
|
||||
}
|
||||
@ -3536,7 +3552,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
|
||||
int rt = r.getTotalRunningTime();
|
||||
if (rt > 0 && hasTiming)
|
||||
xml.write("Time", rt);
|
||||
xml.write("Time", formatRelTime(rt));
|
||||
|
||||
RunnerStatus stat = r.getTotalStatus();
|
||||
|
||||
@ -3546,7 +3562,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
int after = r.getTotalRunningTime() -
|
||||
r.getClassRef(true)->getTotalLegLeaderTime(oClass::AllowRecompute::Yes, tleg, true, true);
|
||||
if (after >= 0)
|
||||
xml.write("TimeBehind", after);
|
||||
xml.write("TimeBehind", formatRelTime(after));
|
||||
}
|
||||
|
||||
if (stat == StatusOK && hasTiming)
|
||||
@ -3563,7 +3579,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
writeCourse(xml, *crs);
|
||||
|
||||
const vector<SplitData> &sp = r.getSplitTimes(doUnroll);
|
||||
RunnerStatus st = r.getStatusComputed();
|
||||
RunnerStatus st = r.getStatusComputed(true);
|
||||
if (r.getStatus()>0 && st != StatusDNS &&
|
||||
st != StatusCANCEL &&
|
||||
st != StatusNotCompetiting) {
|
||||
@ -3579,7 +3595,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
break;
|
||||
if (crs->getControl(k)->isRogaining(hasRogaining)) {
|
||||
if (sp[k].hasTime()) {
|
||||
int time = sp[k].time - r.getStartTime();
|
||||
int time = sp[k].getTime(false) - r.getStartTime();
|
||||
int control = crs->getControl(k)->getFirstNumber();
|
||||
rogaining.insert(make_pair(time, control));
|
||||
}
|
||||
@ -3596,7 +3612,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.startTag("SplitTime");
|
||||
xml.write("ControlCode", crs->getControl(k)->getFirstNumber());
|
||||
if (sp[k].hasTime() && hasTiming)
|
||||
xml.write("Time", sp[k].time - r.getStartTime());
|
||||
xml.write("Time", formatRelTime(sp[k].getTime(false) - r.getStartTime()));
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
@ -3604,7 +3620,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.startTag("SplitTime", "status", "Additional");
|
||||
xml.write("ControlCode", it->second);
|
||||
if (it->first != -1)
|
||||
xml.write("Time", it->first);
|
||||
xml.write("Time", formatRelTime(it->first));
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
@ -3617,7 +3633,7 @@ void IOF30Interface::writeResult(xmlparser &xml, const oRunner &rPerson, const o
|
||||
xml.startTag("SplitTime", "status", "Additional");
|
||||
xml.write("ControlCode", p->getTypeCode());
|
||||
if (p->getTimeInt() > r.getStartTime())
|
||||
xml.write("Time", p->getTimeInt() - r.getStartTime());
|
||||
xml.write("Time", formatRelTime(p->getTimeInt() - r.getStartTime()));
|
||||
xml.endTag();
|
||||
}
|
||||
}
|
||||
@ -3653,7 +3669,8 @@ void IOF30Interface::writeFees(xmlparser &xml, const oRunner &r) const {
|
||||
void IOF30Interface::writeTeamResult(xmlparser &xml, const oTeam &t, bool hasInputTime) {
|
||||
xml.startTag("TeamResult");
|
||||
|
||||
xml.write("EntryId", t.getId());
|
||||
writeTeamEntryId(t, xml);
|
||||
|
||||
xml.write("Name", t.getName());
|
||||
|
||||
if (t.getClubRef())
|
||||
@ -3672,6 +3689,24 @@ void IOF30Interface::writeTeamResult(xmlparser &xml, const oTeam &t, bool hasInp
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
void IOF30Interface::writeTeamEntryId(const oTeam& t, xmlparser& xml)
|
||||
{
|
||||
bool isImported = t.getEntrySource() != 0;
|
||||
wstring id;
|
||||
if (t.getExtIdentifier() != 0) {
|
||||
id = t.getExtIdentifierString();
|
||||
isImported = true;
|
||||
}
|
||||
else
|
||||
id = itow(t.getId());
|
||||
|
||||
if (isImported)
|
||||
xml.write("EntryId", id);
|
||||
else if (!useEventorQuirks) {
|
||||
xml.write("EntryId", "type", L"MeOS", id);
|
||||
}
|
||||
}
|
||||
|
||||
int IOF30Interface::getStageNumber() {
|
||||
if (cachedStageNumber >= 0)
|
||||
return cachedStageNumber;
|
||||
@ -4002,7 +4037,8 @@ void IOF30Interface::writeTeamNoPersonStart(xmlparser &xml, const oTeam &t, int
|
||||
void IOF30Interface::writeTeamStart(xmlparser &xml, const oTeam &t) {
|
||||
xml.startTag("TeamStart");
|
||||
|
||||
xml.write("EntryId", t.getId());
|
||||
writeTeamEntryId(t, xml);
|
||||
|
||||
xml.write("Name", t.getName());
|
||||
|
||||
if (t.getClubRef())
|
||||
@ -4072,7 +4108,25 @@ void IOF30Interface::writeLegOrder(xmlparser &xml, const oClass *pc, int legNo)
|
||||
}
|
||||
}
|
||||
|
||||
bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
size_t hash_entry(const wstring& name, int clubId, int card, const wstring &birth) {
|
||||
size_t h = 0;
|
||||
for (int j = 0; j < name.size(); j++) {
|
||||
h = h * 37 + name[j];
|
||||
}
|
||||
|
||||
h = h * 997 + clubId;
|
||||
h = h * 997 + card;
|
||||
for (int j = 0; j < birth.size(); j++) {
|
||||
if (birth[j] >= '0' && birth[j] <= '9')
|
||||
h = h * 997 + birth[j];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor,
|
||||
bool onlyWithClub,
|
||||
unordered_multimap<size_t, int>& duplicateCheck,
|
||||
int &duplicateCount) {
|
||||
|
||||
if (!xCompetitor) return false;
|
||||
|
||||
@ -4083,10 +4137,7 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
int pidI;
|
||||
long long pid;
|
||||
readId(person, pidI, pid);
|
||||
/*
|
||||
wstring pidS;
|
||||
person.getObjectString("Id", pidS);xxx
|
||||
long long pid = oBase::converExtIdentifierString(pidS);*/
|
||||
|
||||
xmlobject pname = person.getObject("Name");
|
||||
if (!pname) return false;
|
||||
|
||||
@ -4100,7 +4151,7 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
xmlobject &card = cards[k];
|
||||
if (card) {
|
||||
xmlattrib pSystem = card.getAttrib("punchingSystem");
|
||||
if (!pSystem || _stricmp(pSystem.get(), "SI") == 0) {
|
||||
if (!pSystem || _stricmp(pSystem.getPtr(), "SI") == 0) {
|
||||
cardno = card.getObjectInt(0);
|
||||
break;
|
||||
}
|
||||
@ -4116,13 +4167,13 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
if (given.empty() || family.empty())
|
||||
return false;
|
||||
|
||||
//string name(given+" "+family);
|
||||
wstring name(family + L", " + given);
|
||||
|
||||
char sex[2];
|
||||
person.getObjectString("sex", sex, 2);
|
||||
|
||||
int birth = person.getObjectInt("BirthDate");
|
||||
wstring birth;
|
||||
person.getObjectString("BirthDate", birth);
|
||||
|
||||
xmlobject nat=person.getObject("Nationality");
|
||||
|
||||
@ -4137,8 +4188,26 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
clubId = xClub.getObjectInt("Id");
|
||||
}
|
||||
|
||||
if (onlyWithClub && clubId == 0)
|
||||
return false;
|
||||
|
||||
size_t eHash = hash_entry(name, clubId, cardno, birth);
|
||||
|
||||
RunnerDB &runnerDB = oe.getRunnerDatabase();
|
||||
|
||||
|
||||
auto dupCheck = duplicateCheck.equal_range(eHash);
|
||||
wstring dupName;
|
||||
for (auto it = dupCheck.first; it != dupCheck.second; ++it) {
|
||||
int ix = it->second;
|
||||
RunnerWDBEntry* dupCand = runnerDB.getRunnerByIndex(ix);
|
||||
dupCand->getName(dupName);
|
||||
if (dupName == name && clubId == dupCand->dbe().clubNo && cardno == dupCand->dbe().cardNo) {
|
||||
duplicateCount++;
|
||||
return false; // Duplicate person
|
||||
}
|
||||
}
|
||||
|
||||
RunnerWDBEntry *rde = runnerDB.getRunnerById(pid);
|
||||
|
||||
if (!rde) {
|
||||
@ -4152,10 +4221,12 @@ bool IOF30Interface::readXMLCompetitorDB(const xmlobject &xCompetitor) {
|
||||
}
|
||||
|
||||
if (rde) {
|
||||
duplicateCheck.emplace(eHash, rde->getIndex());
|
||||
rde->setExtId(pid);
|
||||
rde->setName(name.c_str());
|
||||
rde->dbe().cardNo = cardno;
|
||||
rde->dbe().clubNo = clubId;
|
||||
rde->dbe().birthYear = extendYear(birth);
|
||||
rde->dbe().setBirthDate(birth);
|
||||
rde->dbe().sex = sex[0];
|
||||
memcpy(rde->dbe().national, national, 3);
|
||||
}
|
||||
@ -4276,14 +4347,14 @@ bool IOF30Interface::readControl(const xmlobject &xControl) {
|
||||
pControl pc = 0;
|
||||
|
||||
if (type == 0) {
|
||||
pc = oe.getControl(code, true);
|
||||
pc = oe.getControl(code, true, false);
|
||||
}
|
||||
else if (type == 1) {
|
||||
wstring start = getStartName(trim(idStr));
|
||||
pc = oe.getControl(getStartIndex(idStr), true);
|
||||
pc = oe.getControl(getStartIndex(idStr), true, false);
|
||||
pc->setNumbers(L"");
|
||||
pc->setName(start);
|
||||
pc->setStatus(oControl::StatusStart);
|
||||
pc->setStatus(oControl::ControlStatus::StatusStart);
|
||||
}
|
||||
else if (type == 2) {
|
||||
wstring finish = trim(idStr);
|
||||
@ -4294,10 +4365,10 @@ bool IOF30Interface::readControl(const xmlobject &xControl) {
|
||||
finish = lang.tl(L"Mål ") + itow(num);
|
||||
else
|
||||
finish = lang.tl(L"Mål");
|
||||
pc = oe.getControl(getFinishIndex(num), true);
|
||||
pc = oe.getControl(getFinishIndex(num), true, false);
|
||||
pc->setNumbers(L"");
|
||||
pc->setName(finish);
|
||||
pc->setStatus(oControl::StatusFinish);
|
||||
pc->setStatus(oControl::ControlStatus::StatusFinish);
|
||||
}
|
||||
|
||||
if (pc) {
|
||||
@ -4395,7 +4466,7 @@ pCourse IOF30Interface::readCourse(const xmlobject &xcrs) {
|
||||
if (type == "Start" && startName.empty()) {
|
||||
wstring idStr;
|
||||
xControls[k].getObjectString("Control", idStr);
|
||||
pControl pStart = oe.getControl(getStartIndex(idStr), false);
|
||||
pControl pStart = oe.getControl(getStartIndex(idStr), false, false);
|
||||
if (pStart)
|
||||
startName = pStart->getName();
|
||||
}
|
||||
@ -4407,14 +4478,14 @@ pCourse IOF30Interface::readCourse(const xmlobject &xcrs) {
|
||||
xControls[k].getObjects("Control", xPunchControls);
|
||||
pControl pCtrl = 0;
|
||||
if (xPunchControls.size() == 1) {
|
||||
pCtrl = oe.getControl(xPunchControls[0].getInt(), true);
|
||||
pCtrl = oe.getControl(xPunchControls[0].getInt(), true, false);
|
||||
}
|
||||
else if (xPunchControls.size()>1) {
|
||||
pCtrl = oe.addControl(1000*cid + xPunchControls[0].getInt(),xPunchControls[0].getInt(), L"");
|
||||
if (pCtrl) {
|
||||
wstring cc;
|
||||
for (size_t j = 0; j < xPunchControls.size(); j++)
|
||||
cc += wstring(xPunchControls[j].getw()) + L" ";
|
||||
cc += xPunchControls[j].getWStr() + L" ";
|
||||
|
||||
pCtrl->setNumbers(cc);
|
||||
}
|
||||
@ -4426,7 +4497,7 @@ pCourse IOF30Interface::readCourse(const xmlobject &xcrs) {
|
||||
int score = xControls[k].getObjectInt("Score");
|
||||
if (score > 0) {
|
||||
pCtrl->getDI().setInt("Rogaining", score);
|
||||
pCtrl->setStatus(oControl::StatusRogaining);
|
||||
pCtrl->setStatus(oControl::ControlStatus::StatusRogaining);
|
||||
hasRogaining = true;
|
||||
}
|
||||
}
|
||||
@ -4459,7 +4530,7 @@ pCourse IOF30Interface::readCourse(const xmlobject &xcrs) {
|
||||
if (hasRogaining) {
|
||||
int mt = oe.getMaximalTime();
|
||||
if (mt == 0)
|
||||
mt = 3600;
|
||||
mt = timeConstHour;
|
||||
pc->setMaximumRogainingTime(mt);
|
||||
}
|
||||
|
||||
@ -4508,7 +4579,7 @@ void IOF30Interface::writeCourses(xmlparser &xml) {
|
||||
xml.endTag();
|
||||
set<wstring> ids;
|
||||
for (size_t k = 0; k < ctrl.size(); k++) {
|
||||
if (ctrl[k]->getStatus() != oControl::StatusFinish && ctrl[k]->getStatus() != oControl::StatusStart) {
|
||||
if (!oControl::isSpecialControl(ctrl[k]->getStatus())) {
|
||||
wstring id = writeControl(xml, *ctrl[k], ids);
|
||||
ctrlId2ExportId[ctrl[k]->getId()] = id;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -25,6 +25,7 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
class oEvent;
|
||||
class xmlobject;
|
||||
@ -72,7 +73,8 @@ class IOF30Interface {
|
||||
bool unrollLoops;
|
||||
// Include data on stage number
|
||||
bool includeStageRaceInfo;
|
||||
void operator=(const IOF30Interface &);
|
||||
|
||||
const IOF30Interface &operator=(const IOF30Interface &) = delete;
|
||||
|
||||
set<wstring> matchedClasses;
|
||||
|
||||
@ -193,6 +195,7 @@ class IOF30Interface {
|
||||
|
||||
int parseISO8601Time(const xmlobject &xo);
|
||||
wstring getCurrentTime() const;
|
||||
wstring formatRelTime(int rt);
|
||||
|
||||
static void getNationality(const xmlobject &xCountry, oDataInterface &di);
|
||||
|
||||
@ -220,6 +223,8 @@ class IOF30Interface {
|
||||
|
||||
void writeTeamResult(xmlparser &xml, const oTeam &t, bool hasInputTime);
|
||||
|
||||
void writeTeamEntryId(const oTeam& t, xmlparser& xml);
|
||||
|
||||
void writeResult(xmlparser &xml, const oRunner &rPerson, const oRunner &rResultCarrier,
|
||||
bool includeCourse, bool includeRaceNumber, bool teamMember, bool hasInputTime);
|
||||
|
||||
@ -249,7 +254,10 @@ class IOF30Interface {
|
||||
// Returns zero if no stage number
|
||||
int getStageNumber();
|
||||
|
||||
bool readXMLCompetitorDB(const xmlobject &xCompetitor);
|
||||
bool readXMLCompetitorDB(const xmlobject &xCompetitor,
|
||||
bool onlyWithClub,
|
||||
unordered_multimap<size_t, int> &duplicateCheck,
|
||||
int &duplicateCount);
|
||||
void writeXMLCompetitorDB(xmlparser &xml, const RunnerDB &db, const RunnerWDBEntry &rde) const;
|
||||
|
||||
int getStartIndex(const wstring &startId);
|
||||
@ -258,7 +266,7 @@ class IOF30Interface {
|
||||
pCourse readCourse(const xmlobject &xcrs);
|
||||
|
||||
void readCourseGroups(xmlobject xClassCourse, vector< vector<pCourse> > &crs);
|
||||
void bindClassCourse(oClass &pc, const vector< vector<pCourse> > &crs);
|
||||
void bindClassCourse(oClass &pc, const vector<vector<pCourse>> &crs);
|
||||
|
||||
static wstring constructCourseName(const xmlobject &xcrs);
|
||||
static wstring constructCourseName(const wstring &family, const wstring &name);
|
||||
@ -290,8 +298,10 @@ class IOF30Interface {
|
||||
|
||||
set<int> readCrsIds;
|
||||
|
||||
bool useEventorQuirks;
|
||||
|
||||
public:
|
||||
IOF30Interface(oEvent *oe, bool forceSplitFee);
|
||||
IOF30Interface(oEvent *oe, bool forceSplitFee, bool useEventorQuirks);
|
||||
virtual ~IOF30Interface() {}
|
||||
|
||||
static void getLocalDateTime(const wstring &datetime, wstring &dateOut, wstring &timeOut);
|
||||
@ -321,7 +331,8 @@ public:
|
||||
void readClassList(gdioutput &gdi, xmlobject &xo, int &entRead, int &entFail);
|
||||
|
||||
void prescanCompetitorList(xmlobject &xo);
|
||||
void readCompetitorList(gdioutput &gdi, const xmlobject &xo, int &personCount);
|
||||
void readCompetitorList(gdioutput &gdi, const xmlobject &xo,
|
||||
bool onlyWithClub, int &personCount, int& duplicateCount);
|
||||
|
||||
void readClubList(gdioutput &gdi, const xmlobject &xo, int &clubCount);
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ Third Party Code. Additional copyright notices and license terms applicable to p
|
||||
All trademarks and registered trademarks mentioned herein are the property of their respective owners.
|
||||
|
||||
------------------------------------
|
||||
Copyright 2007-2020 Melin Software HB.
|
||||
Copyright 2007-2023 Melin Software HB.
|
||||
|
||||
------------------------------------
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -37,6 +37,9 @@
|
||||
#include "generalresult.h"
|
||||
#include "gdiconstants.h"
|
||||
#include "autocomplete.h"
|
||||
#include "image.h"
|
||||
|
||||
extern Image image;
|
||||
|
||||
ListEditor::ListEditor(oEvent *oe_) {
|
||||
oe = oe_;
|
||||
@ -62,13 +65,6 @@ void ListEditor::setCurrentList(MetaList *lst) {
|
||||
delete currentList;
|
||||
currentList = lst;
|
||||
}
|
||||
/*
|
||||
void ListEditor::load(MetaList *list) {
|
||||
currentList = list;
|
||||
currentIndex = -1;
|
||||
dirtyInt = true;
|
||||
dirtyExt = true;
|
||||
}*/
|
||||
|
||||
void ListEditor::load(const MetaListContainer &mlc, int index) {
|
||||
const MetaList &mc = mlc.getList(index);
|
||||
@ -117,6 +113,8 @@ void ListEditor::show(gdioutput &gdi) {
|
||||
gdi.fillRight();
|
||||
|
||||
gdi.addButton("EditList", "Egenskaper", editListCB);
|
||||
gdi.addButton("SplitPrint", "Sträcktidslista", editListCB);
|
||||
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(32));
|
||||
gdi.addButton("OpenFile", "Öppna fil", editListCB);
|
||||
gdi.addButton("OpenInside", "Öppna från aktuell tävling", editListCB);
|
||||
@ -137,6 +135,21 @@ void ListEditor::show(gdioutput &gdi) {
|
||||
gdi.dropLine(2);
|
||||
|
||||
int dx = gdi.getCX();
|
||||
|
||||
if (currentList && currentList->isSplitPrintList()) {
|
||||
gdi.setCX(bx);
|
||||
gdi.addString("", 0, "Välj deltagare för förhandsgranskning:");
|
||||
gdi.addSelection("Runner", 300, 300, editListCB);
|
||||
oe->fillRunners(gdi, "Runner", false, 0);
|
||||
if (currentRunnerId > 0 && oe->getRunner(currentRunnerId, 0))
|
||||
gdi.selectItemByData("Runner", currentRunnerId);
|
||||
else {
|
||||
gdi.selectFirstItem("Runner");
|
||||
currentRunnerId = gdi.getSelectedItem("Runner").first;
|
||||
}
|
||||
gdi.dropLine(2);
|
||||
}
|
||||
|
||||
int dy = gdi.getCY();
|
||||
|
||||
RECT rc;
|
||||
@ -156,6 +169,7 @@ void ListEditor::show(gdioutput &gdi) {
|
||||
makeDirty(gdi, NoTouch, NoTouch);
|
||||
if (!currentList) {
|
||||
gdi.disableInput("EditList");
|
||||
gdi.disableInput("SplitPrint");
|
||||
gdi.disableInput("SaveFile");
|
||||
gdi.disableInput("SaveFileCopy", true);
|
||||
gdi.disableInput("SaveInside");
|
||||
@ -223,8 +237,17 @@ void ListEditor::show(gdioutput &gdi) {
|
||||
gdi.addButton("AddLine3", "Lägg till rad", editListCB);
|
||||
|
||||
gdi.setRestorePoint("EditList");
|
||||
renderListPreview(gdi);
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void ListEditor::renderListPreview(gdioutput &gdi) {
|
||||
gdi.dropLine(2);
|
||||
gdi.fillDown();
|
||||
RECT rc;
|
||||
pRunner splitPrintR = nullptr;
|
||||
if (currentList->isSplitPrintList() && currentRunnerId)
|
||||
splitPrintR = oe->getRunner(currentRunnerId, 0);
|
||||
|
||||
oListInfo li;
|
||||
oListParam par;
|
||||
@ -232,30 +255,59 @@ void ListEditor::show(gdioutput &gdi) {
|
||||
par.splitAnalysis = true;
|
||||
par.setLegNumberCoded(-1);
|
||||
par.inputNumber = 0;
|
||||
gdi.fillDown();
|
||||
|
||||
if (splitPrintR) {
|
||||
par.selection.insert(splitPrintR->getClassId(true));
|
||||
par.showInterTimes = false;
|
||||
par.setLegNumberCoded(splitPrintR->getLegNumber());
|
||||
par.filterMaxPer = 3;
|
||||
par.alwaysInclude = splitPrintR;
|
||||
par.showHeader = false;
|
||||
}
|
||||
double originalScale = 0;
|
||||
try {
|
||||
currentList->interpret(oe, gdi, par, li);
|
||||
rc.left = gdi.getCX();
|
||||
rc.right = gdi.getCX() + gdi.getWidth() - 20;
|
||||
rc.right = gdi.getCX() + gdi.getWidth() - gdi.scaleLength(20);
|
||||
rc.top = gdi.getCY();
|
||||
rc.bottom = rc.top + 4;
|
||||
|
||||
gdi.addRectangle(rc, colorDarkGreen, false, false);
|
||||
gdi.dropLine();
|
||||
|
||||
oe->generateList(gdi, false, li, true);
|
||||
currentList->interpret(oe, gdi, par, li);
|
||||
|
||||
if (splitPrintR) {
|
||||
auto& sp = *li.getSplitPrintInfo();
|
||||
li.getParam().filterMaxPer = sp.numClassResults;
|
||||
|
||||
const bool wideFormat = oe->getPropertyInt("WideSplitFormat", 0) == 1;
|
||||
if (!wideFormat)
|
||||
li.shrinkSize();
|
||||
|
||||
rc.left = gdi.getCX();
|
||||
rc.top = gdi.getCY();
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(10));
|
||||
gdi.dropLine();
|
||||
|
||||
splitPrintR->printSplits(gdi, &li);
|
||||
|
||||
gdi.dropLine();
|
||||
rc.right = rc.left + gdi.scaleLength(250);
|
||||
rc.bottom = gdi.getHeight();
|
||||
gdi.addRectangle(rc, GDICOLOR::colorLightYellow);
|
||||
gdi.refresh();
|
||||
}
|
||||
else {
|
||||
oe->generateList(gdi, false, li, true);
|
||||
}
|
||||
}
|
||||
catch (meosException &ex) {
|
||||
catch (meosException& ex) {
|
||||
gdi.addString("", 1, "Listan kan inte visas").setColor(colorRed);
|
||||
gdi.addString("", 0, ex.wwhat());
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
catch (std::exception& ex) {
|
||||
gdi.addString("", 1, "Listan kan inte visas").setColor(colorRed);
|
||||
gdi.addString("", 0, ex.what());
|
||||
}
|
||||
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
int editListCB(gdioutput *gdi, int type, void *data)
|
||||
@ -274,7 +326,8 @@ void ListEditor::showLine(gdioutput &gdi, const vector<MetaListPost> &line, int
|
||||
addButton(gdi, line[k], gdi.getCX(), gdi.getCY(), ix, k);
|
||||
}
|
||||
|
||||
gdi.addButton("AddPost" + itos(ix), "Lägg till ny", editListCB);
|
||||
gdi.addButton("AddPost", "Lägg till ny", editListCB).setExtra(ix);
|
||||
gdi.addButton("AddImage", "Lägg till bild", editListCB).setExtra(ix);
|
||||
}
|
||||
|
||||
ButtonInfo &ListEditor::addButton(gdioutput &gdi, const MetaListPost &mlp, int x, int y, int lineIx, int ix) const {
|
||||
@ -282,6 +335,17 @@ ButtonInfo &ListEditor::addButton(gdioutput &gdi, const MetaListPost &mlp, int x
|
||||
if (mlp.getType() == L"String") {
|
||||
cap = L"Text: X#" + mlp.getText();
|
||||
}
|
||||
else if (mlp.getType() == L"Image") {
|
||||
if (mlp.getText().empty())
|
||||
cap = L"Image";
|
||||
else {
|
||||
uint64_t imgId = mlp.getImageId();
|
||||
if (!image.hasImage(imgId))
|
||||
cap = L"Error";
|
||||
else
|
||||
cap = image.getFileName(imgId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const wstring &text = mlp.getText();
|
||||
if (text.length() > 0) {
|
||||
@ -364,6 +428,26 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
if (ii.id == "Text" && ii.text != lastShownExampleText) {
|
||||
showExample(gdi);
|
||||
}
|
||||
else if (ii.id == "ImgWidth" || ii.id == "ImgHeight") {
|
||||
if (gdi.isChecked("PreserveAspectRatio")) {
|
||||
auto sel = gdi.getSelectedItem("Image");
|
||||
if (sel.second && sel.first >= 0) {
|
||||
auto imgId = image.getIdFromEnumeration(sel.first);
|
||||
int h = image.getHeight(imgId);
|
||||
int w = image.getWidth(imgId);
|
||||
int ww, hh;
|
||||
if (ii.id == "ImgWidth") {
|
||||
ww = _wtoi(ii.text.c_str());
|
||||
hh = (ww * h + w/2) / w;
|
||||
gdi.setText("ImgHeight", hh);
|
||||
} else {
|
||||
hh = _wtoi(ii.text.c_str());
|
||||
ww = (hh * w + h / 2) / h;
|
||||
gdi.setText("ImgWidth", ww);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == GUI_BUTTON) {
|
||||
ButtonInfo bi = dynamic_cast<ButtonInfo &>(data);
|
||||
@ -376,66 +460,64 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
biSrc.setExtra(res);
|
||||
oe->setProperty("Colors", c);
|
||||
}
|
||||
/*CHOOSECOLOR cc;
|
||||
memset(&cc, 0, sizeof(cc));
|
||||
cc.lStructSize = sizeof(cc);
|
||||
cc.hwndOwner = gdi.getHWND();
|
||||
cc.rgbResult = COLORREF(bi.getExtra());
|
||||
if (GDICOLOR((int)bi.getExtra()) != colorDefault)
|
||||
cc.Flags |= CC_RGBINIT;
|
||||
|
||||
COLORREF staticColor[16];
|
||||
memset(staticColor, 0, 16*sizeof(COLORREF));
|
||||
|
||||
const string &c = oe->getPropertyString("Colors", "");
|
||||
const char *end = c.c_str() + c.length();
|
||||
const char * pEnd = c.c_str();
|
||||
int pix = 0;
|
||||
while(pEnd < end && pix < 16) {
|
||||
staticColor[pix++] = strtol(pEnd,(char **)&pEnd,16);
|
||||
}
|
||||
|
||||
cc.lpCustColors = staticColor;
|
||||
if (ChooseColor(&cc)) {
|
||||
data.setExtra((int)cc.rgbResult);
|
||||
|
||||
wstring co;
|
||||
for (ix = 0; ix < 16; ix++) {
|
||||
wchar_t bf[16];
|
||||
swprintf_s(bf, L"%x ", staticColor[ix]);
|
||||
co += bf;
|
||||
}
|
||||
oe->setProperty("Colors", co);
|
||||
}*/
|
||||
}
|
||||
if ( bi.id.substr(0, 8) == "EditPost" ) {
|
||||
else if (bi.id == "NewImage") {
|
||||
vector<pair<wstring, wstring>> ext = { make_pair(L">Bilder", L"*.png") };
|
||||
wstring fn = gdi.browseForOpen(ext, L"png");
|
||||
if (!fn.empty()) {
|
||||
bool transparent = gdi.isChecked("TransparentWhite");
|
||||
|
||||
uint64_t imgId = image.loadFromFile(fn, transparent ? Image::ImageMethod::WhiteTransparent : Image::ImageMethod::Default);
|
||||
int selIx = selectImage(gdi, imgId);
|
||||
previewImage(gdi, selIx);
|
||||
updateImageStatus(gdi, selIx);
|
||||
|
||||
}
|
||||
}
|
||||
else if (bi.id == "TransparentWhite") {
|
||||
bool transparent = gdi.isChecked("TransparentWhite");
|
||||
int data = gdi.getSelectedItem("Image").first;
|
||||
|
||||
if (data >= 0) {
|
||||
uint64_t imgId = image.getIdFromEnumeration(data);
|
||||
image.reloadImage(imgId, transparent ? Image::ImageMethod::WhiteTransparent : Image::ImageMethod::Default);
|
||||
gdi.refresh();
|
||||
}
|
||||
}
|
||||
else if ( bi.id.substr(0, 8) == "EditPost" ) {
|
||||
if (gdi.hasData("CurrentId")) {
|
||||
DWORD id;
|
||||
gdi.getData("CurrentId", id);
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
saveListPost(gdi, mlp);
|
||||
checkUnsaved(gdi);
|
||||
}
|
||||
int id = atoi(bi.id.substr(8).c_str());
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
editListPost(gdi, mlp, id);
|
||||
if (mlp.getTypeRaw() == EPostType::lImage)
|
||||
editImage(gdi, mlp, id);
|
||||
else
|
||||
editListPost(gdi, mlp, id);
|
||||
}
|
||||
else if ( bi.id.substr(0, 7) == "AddPost" ) {
|
||||
else if (bi.id == "AddPost" || bi.id == "AddImage") {
|
||||
checkUnsaved(gdi);
|
||||
gdi.restore("EditList", true);
|
||||
gdi.pushX();
|
||||
lineIx = atoi(bi.id.substr(7).c_str());
|
||||
lineIx = bi.getExtraInt();
|
||||
groupIx = (lineIx / 100) - 1;
|
||||
int ixOutput = 0;
|
||||
MetaListPost &mlp = currentList->addNew(groupIx, lineIx % 100, ixOutput);
|
||||
int xp = bi.xp;
|
||||
int yp = bi.yp;
|
||||
if (bi.id == "AddImage")
|
||||
mlp.setType(EPostType::lImage);
|
||||
|
||||
auto& post = dynamic_cast<ButtonInfo&>(gdi.getBaseInfo("AddPost", lineIx));
|
||||
|
||||
int xp = post.xp;
|
||||
int yp = post.yp;
|
||||
ButtonInfo &nb = addButton(gdi, mlp, xp, yp, lineIx, ixOutput);
|
||||
//gdi.addButton(xp, yp, string("Foo"), string("FoooBar"), 0);
|
||||
int w, h;
|
||||
nb.getDimension(gdi, w, h);
|
||||
biSrc.moveButton(gdi, xp+w, yp);
|
||||
post.moveButton(gdi, xp + w, yp);
|
||||
int w2, h2;
|
||||
post.getDimension(gdi, w2, h2);
|
||||
dynamic_cast<ButtonInfo&>(gdi.getBaseInfo("AddImage", lineIx)).moveButton(gdi, xp + w + w2, yp);
|
||||
gdi.popX();
|
||||
gdi.setRestorePoint("EditList");
|
||||
makeDirty(gdi, MakeDirty, MakeDirty);
|
||||
@ -463,9 +545,13 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
else if (bi.id == "UseLeg") {
|
||||
gdi.setInputStatus("Leg", gdi.isChecked(bi.id));
|
||||
}
|
||||
else if (bi.id == "UseForSplit") {
|
||||
statusSplitPrint(gdi, gdi.isChecked(bi.id));
|
||||
}
|
||||
else if (bi.id == "Cancel") {
|
||||
gdi.restore("EditList");
|
||||
gdi.enableInput("EditList");
|
||||
gdi.enableInput("SplitPrint");
|
||||
}
|
||||
else if (bi.id == "CancelNew") {
|
||||
gdi.clearPage(false);
|
||||
@ -473,26 +559,35 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
show(gdi);
|
||||
}
|
||||
else if (bi.id == "Apply" || bi.id == "MoveLeft" || bi.id == "MoveRight") {
|
||||
bool image = gdi.hasData("IsEditingImage");
|
||||
DWORD id;
|
||||
gdi.getData("CurrentId", id);
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
|
||||
if (bi.id == "MoveLeft")
|
||||
if (bi.id == "MoveLeft") {
|
||||
currentList->moveOnRow(groupIx, lineIx, ix, -1);
|
||||
else if (bi.id == "MoveRight")
|
||||
id--;
|
||||
}
|
||||
else if (bi.id == "MoveRight") {
|
||||
currentList->moveOnRow(groupIx, lineIx, ix, 1);
|
||||
|
||||
id++;
|
||||
}
|
||||
gdi.setData("CurrentId", id);
|
||||
MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
|
||||
bool force = saveListPost(gdi, mlp);
|
||||
bool force = checkUnsaved(gdi);//saveListPost(gdi, mlp);
|
||||
|
||||
if (!gdi.hasData("NoRedraw") || force) {
|
||||
gdi.restore("BeginListEdit", false);
|
||||
show(gdi);
|
||||
}
|
||||
|
||||
if (bi.id != "Apply")
|
||||
editListPost(gdi, mlp, bi.getExtraInt());
|
||||
if (bi.id != "Apply") {
|
||||
if (image)
|
||||
editImage(gdi, mlp, bi.getExtraInt());
|
||||
else
|
||||
editListPost(gdi, mlp, bi.getExtraInt());
|
||||
}
|
||||
}
|
||||
else if (bi.id == "ApplyListProp") {
|
||||
wstring name = gdi.getText("Name");
|
||||
@ -532,7 +627,6 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
|
||||
list.setSubFilters(subFiltersOut);
|
||||
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
list.setFontFace(k, gdi.getText("Font" + itos(k)),
|
||||
gdi.getTextNo("FontFactor" + itos(k)));
|
||||
@ -541,7 +635,6 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
list.setExtraSpace(k, f);
|
||||
}
|
||||
|
||||
|
||||
list.setSupportFromTo(gdi.isChecked("SupportFrom"), gdi.isChecked("SupportTo"));
|
||||
list.setSupportLegSelection(gdi.isChecked("SupportLegSelection"));
|
||||
|
||||
@ -552,9 +645,32 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
show(gdi);
|
||||
}
|
||||
}
|
||||
else if (bi.id == "ApplySplitList") {
|
||||
MetaList& list = *currentList;
|
||||
if (!gdi.isChecked("UseForSplit"))
|
||||
list.setSplitPrintInfo(nullptr);
|
||||
else {
|
||||
auto spInfo = make_shared<SplitPrintListInfo>();
|
||||
spInfo->includeSplitTimes = gdi.isChecked("Split");
|
||||
spInfo->withSpeed = gdi.isChecked("Speed");
|
||||
spInfo->withResult = gdi.isChecked("Result");
|
||||
spInfo->withAnalysis = gdi.isChecked("Analysis");
|
||||
list.setSplitPrintInfo(spInfo);
|
||||
}
|
||||
|
||||
makeDirty(gdi, MakeDirty, MakeDirty);
|
||||
|
||||
if (!gdi.hasData("NoRedraw")) {
|
||||
gdi.clearPage(false);
|
||||
show(gdi);
|
||||
}
|
||||
}
|
||||
else if (bi.id == "EditList") {
|
||||
editListProp(gdi, false);
|
||||
}
|
||||
else if (bi.id == "SplitPrint") {
|
||||
splitPrintList(gdi);
|
||||
}
|
||||
else if (bi.id == "NewList") {
|
||||
if (!checkSave(gdi))
|
||||
return 0;
|
||||
@ -645,7 +761,7 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
|
||||
gdi.pushX();
|
||||
vector< pair<wstring, size_t> > lists;
|
||||
oe->getListContainer().getLists(lists, true, false, false);
|
||||
oe->getListContainer().getLists(lists, true, false, false, false);
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.addSelection("OpenList", 250, 400, editListCB, L"Välj lista:");
|
||||
@ -691,6 +807,11 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
savedFileName.clear();
|
||||
oe->synchronize(false);
|
||||
|
||||
set<uint64_t> imgUsed;
|
||||
currentList->getUsedImages(imgUsed);
|
||||
for (uint64_t id : imgUsed)
|
||||
oe->saveImage(id);
|
||||
|
||||
if (currentIndex != -1) {
|
||||
oe->getListContainer().saveList(currentIndex, *currentList);
|
||||
}
|
||||
@ -733,15 +854,6 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*else if (bi.id == "BrowseFont") {
|
||||
InitCommonControls();
|
||||
CHOOSEFONT cf;
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
cf.lStructSize = sizeof(cf);
|
||||
cf.hwndOwner = gdi.getHWND();
|
||||
ChooseFont(&cf);
|
||||
EnumFontFamilies(
|
||||
}*/
|
||||
}
|
||||
else if (type == GUI_LISTBOX) {
|
||||
ListBoxInfo &lbi = dynamic_cast<ListBoxInfo &>(data);
|
||||
@ -758,6 +870,10 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
else
|
||||
gdi.setText("AlignText", L"");
|
||||
}
|
||||
else if (lbi.id == "Image") {
|
||||
previewImage(gdi, lbi.data);
|
||||
updateImageStatus(gdi, lbi.data);
|
||||
}
|
||||
else if (lbi.id == "Type") {
|
||||
updateType(lbi.data, gdi);
|
||||
}
|
||||
@ -784,6 +900,12 @@ int ListEditor::editList(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
else if (lbi.id == "OpenList") {
|
||||
enableOpen(gdi);
|
||||
}
|
||||
else if (lbi.id == "Runner") {
|
||||
currentRunnerId = lbi.getDataInt();
|
||||
gdi.restore("EditList", false);
|
||||
renderListPreview(gdi);
|
||||
gdi.refresh();
|
||||
}
|
||||
}
|
||||
else if (type==GUI_CLEAR) {
|
||||
return checkSave(gdi);
|
||||
@ -845,6 +967,26 @@ bool ListEditor::saveListPost(gdioutput &gdi, MetaListPost &mlp) {
|
||||
return force;
|
||||
}
|
||||
|
||||
bool ListEditor::saveImage(gdioutput& gdi, MetaListPost& mlp) {
|
||||
ListBoxInfo lbi;
|
||||
int selIx = gdi.getSelectedItem("Image").first;
|
||||
|
||||
if (selIx >= 0) {
|
||||
auto imgId = image.getIdFromEnumeration(selIx);
|
||||
mlp.setText(itow(imgId));
|
||||
mlp.setImageDimension(gdi.getTextNo("ImgWidth"), gdi.getTextNo("ImgHeight"));
|
||||
mlp.setImageOffset(gdi.getTextNo("ImgOffsetX"), gdi.getTextNo("ImgOffsetY"));
|
||||
mlp.setImageStyle(gdi.isChecked("TransparentWhite") ? 1 : 0);
|
||||
mlp.imageUnderText(gdi.isChecked("ImageUnderText"));
|
||||
}
|
||||
else {
|
||||
mlp.setText(L"");
|
||||
}
|
||||
makeDirty(gdi, MakeDirty, MakeDirty);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ListEditor::readLeg(gdioutput &gdi, EPostType newType, bool checkError) const {
|
||||
if (MetaList::isResultModuleOutput(newType)) {
|
||||
int leg = gdi.getTextNo("Leg");
|
||||
@ -863,6 +1005,13 @@ int ListEditor::readLeg(gdioutput &gdi, EPostType newType, bool checkError) cons
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (MetaList::isAllLegType(newType)) {
|
||||
int leg = gdi.getSelectedItem("LegSel").first;
|
||||
if (leg >= 0)
|
||||
return leg - 1; // -1 -> automatic
|
||||
else
|
||||
return -2; // All legs
|
||||
}
|
||||
else {
|
||||
if (gdi.isChecked("UseLeg")) {
|
||||
int leg = gdi.getTextNo("Leg");
|
||||
@ -899,7 +1048,7 @@ void ListEditor::updateType(int iType, gdioutput & gdi) {
|
||||
if (gdi.getText("Leg").empty())
|
||||
gdi.setText("Leg", L"0");
|
||||
}
|
||||
else if (MetaList::isAllStageType(type)) {
|
||||
else if (MetaList::isAllStageType(type) || MetaList::isAllLegType(type)) {
|
||||
|
||||
}
|
||||
else {
|
||||
@ -915,23 +1064,36 @@ void ListEditor::updateType(int iType, gdioutput & gdi) {
|
||||
showExample(gdi, type);
|
||||
}
|
||||
|
||||
void ListEditor::checkUnsaved(gdioutput &gdi) {
|
||||
if (gdi.hasData("IsEditing")) {
|
||||
if (gdi.hasData("CurrentId")) {
|
||||
DWORD id;
|
||||
gdi.getData("CurrentId", id);
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
MetaListPost &mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
saveListPost(gdi, mlp);
|
||||
}
|
||||
bool ListEditor::checkUnsaved(gdioutput& gdi) {
|
||||
if (gdi.hasData("IsEditing")) {
|
||||
DWORD id;
|
||||
gdi.getData("CurrentId", id);
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
MetaListPost& mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
return saveListPost(gdi, mlp);
|
||||
}
|
||||
if (gdi.hasData("IsEditingList")) {
|
||||
else if (gdi.hasData("IsEditingImage")) {
|
||||
DWORD id;
|
||||
gdi.getData("CurrentId", id);
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
MetaListPost& mlp = currentList->getMLP(groupIx, lineIx, ix);
|
||||
return saveImage(gdi, mlp);
|
||||
}
|
||||
else if (gdi.hasData("IsEditingList")) {
|
||||
if (gdi.isInputChanged("")) {
|
||||
gdi.setData("NoRedraw", 1);
|
||||
gdi.sendCtrlMessage("ApplyListProp");
|
||||
}
|
||||
}
|
||||
else if (gdi.hasData("IsSplitListEdit")) {
|
||||
if (gdi.isInputChanged("")) {
|
||||
gdi.setData("NoRedraw", 1);
|
||||
gdi.sendCtrlMessage("ApplySplitList");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ListEditor::updateAlign(gdioutput &gdi, int val) {
|
||||
@ -949,38 +1111,17 @@ void ListEditor::updateAlign(gdioutput &gdi, int val) {
|
||||
}
|
||||
|
||||
void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
checkUnsaved(gdi);
|
||||
gdi.restore("EditList", false);
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.enableInput("EditList");
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
const bool hasResultModule = currentList && !currentList->getResultModule().empty();
|
||||
int x1 = gdi.getCX();
|
||||
int y1 = gdi.getCY();
|
||||
int margin = gdi.scaleLength(10);
|
||||
gdi.setCX(x1+margin);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
gdi.addString("", boldLarge, "Listpost").setColor(colorDarkGrey);
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
|
||||
int x1, y1, boxY;
|
||||
editDlgStart(gdi, id, "Listpost", x1, y1, boxY);
|
||||
|
||||
gdi.addButton("MoveLeft", "<< Flytta vänster", editListCB).setExtra(id-1);
|
||||
if (ix == 0)
|
||||
gdi.setInputStatus("MoveLeft", false);
|
||||
|
||||
gdi.addButton("MoveRight", "Flytta höger >>", editListCB).setExtra(id+1);
|
||||
if (ix + 1 == currentList->getNumPostsOnLine(groupIx, lineIx))
|
||||
gdi.setInputStatus("MoveRight", false);
|
||||
|
||||
gdi.dropLine(1);
|
||||
int boxY = gdi.getCY();
|
||||
gdi.dropLine(2);
|
||||
int maxX = gdi.getCX();
|
||||
|
||||
gdi.popX();
|
||||
const bool hasResultModule = currentList && !currentList->getResultModule().empty();
|
||||
|
||||
vector< pair<wstring, size_t> > types;
|
||||
int currentType;
|
||||
mlp.getTypes(types, currentType);
|
||||
@ -1039,22 +1180,7 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
int leg = mlp.getLeg();
|
||||
|
||||
legStageTypeIndex(gdi, storedType, leg);
|
||||
/*gdi.addCheckbox(xpUseLeg, ypUseLeg, "UseLeg", getIndexDescription(storedType), editListCB, leg != -1);
|
||||
//gdi.dropLine(-0.2);
|
||||
int dx = gdi.scaleLength(250);
|
||||
int dy = -gdi.getLineHeight() / 5;
|
||||
|
||||
//gdi.setCX(gdi.getCX() + gdi.scaleLength(100));
|
||||
if (MetaList::isResultModuleOutput(storedType))
|
||||
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", leg >= 0 ? itow(leg) : L"0", 4);
|
||||
else
|
||||
gdi.addInput(xpUseLeg + dx, ypUseLeg + dy, "Leg", leg >= 0 ? itow(leg + 1) : L"", 4);
|
||||
|
||||
gdi.setInputStatus("Leg", leg != -1);
|
||||
*/
|
||||
if (MetaList::isResultModuleOutput(storedType)) {
|
||||
//gdi.check("UseLeg", true);
|
||||
//gdi.disableInput("UseLeg");
|
||||
if (gdi.hasWidget("UseResultModule")) {
|
||||
gdi.check("UseResultModule", true);
|
||||
gdi.disableInput("UseResultModule");
|
||||
@ -1083,9 +1209,6 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
gdi.dropLine(1.9);
|
||||
gdi.popX();
|
||||
gdi.fillRight();
|
||||
|
||||
|
||||
|
||||
gdi.dropLine(2);
|
||||
|
||||
int maxY = gdi.getCY();
|
||||
@ -1115,7 +1238,7 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
|
||||
|
||||
gdi.addInput("MinIndent", itow(mlp.getMinimalIndent()), 7, 0, L"Justering i sidled:");
|
||||
int maxX = gdi.getCX();
|
||||
maxX = max(maxX, gdi.getCX());
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
vector< pair<wstring, size_t> > fonts;
|
||||
@ -1136,8 +1259,6 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
gdi.addItem("TextAdjust", lang.tl("Centrera"), textCenter);
|
||||
gdi.selectItemByData("TextAdjust", mlp.getTextAdjustNum());
|
||||
|
||||
//gdi.popX();
|
||||
//gdi.dropLine(2);
|
||||
gdi.dropLine();
|
||||
gdi.addButton("Color", "Färg...", editListCB).setExtra(mlp.getColorValue());
|
||||
|
||||
@ -1190,6 +1311,166 @@ void ListEditor::editListPost(gdioutput &gdi, const MetaListPost &mlp, int id) {
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void ListEditor::editDlgStart(gdioutput& gdi, int id, const char *title, int &x1, int &y1, int &boxY) {
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
|
||||
checkUnsaved(gdi);
|
||||
gdi.restore("EditList", false);
|
||||
gdi.dropLine();
|
||||
gdi.enableInput("EditList");
|
||||
gdi.enableInput("SplitPrint");
|
||||
|
||||
x1 = gdi.getCX();
|
||||
y1 = gdi.getCY();
|
||||
int margin = gdi.scaleLength(10);
|
||||
gdi.setCX(x1 + margin);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.pushX();
|
||||
gdi.fillRight();
|
||||
gdi.addString("", boldLarge, title).setColor(colorDarkGrey);
|
||||
gdi.setCX(gdi.getCX() + gdi.scaleLength(20));
|
||||
|
||||
gdi.addButton("MoveLeft", "<< Flytta vänster", editListCB).setExtra(id - 1);
|
||||
if (ix == 0)
|
||||
gdi.setInputStatus("MoveLeft", false);
|
||||
|
||||
gdi.addButton("MoveRight", "Flytta höger >>", editListCB).setExtra(id + 1);
|
||||
if (ix + 1 == currentList->getNumPostsOnLine(groupIx, lineIx))
|
||||
gdi.setInputStatus("MoveRight", false);
|
||||
|
||||
gdi.dropLine(1);
|
||||
boxY = gdi.getCY();
|
||||
gdi.dropLine(2);
|
||||
}
|
||||
|
||||
void ListEditor::editImage(gdioutput& gdi, const MetaListPost& mlp, int id) {
|
||||
int groupIx, lineIx, ix;
|
||||
getPosFromId(id, groupIx, lineIx, ix);
|
||||
|
||||
uint64_t imgId = mlp.getImageId();
|
||||
|
||||
int x1, y1, boxY;
|
||||
editDlgStart(gdi, id, "Bild", x1, y1, boxY);
|
||||
|
||||
int maxX = gdi.getCX();
|
||||
gdi.popX();
|
||||
gdi.fillRight();
|
||||
gdi.dropLine(1);
|
||||
|
||||
gdi.addSelection("Image", 200, 200, editListCB, L"Välj bild:", L"Välj bland befintliga bilder");
|
||||
|
||||
int selIx = selectImage(gdi, imgId);
|
||||
|
||||
gdi.dropLine(1);
|
||||
gdi.addButton("NewImage", "Ny bild...", editListCB);
|
||||
|
||||
int maxY = 0;
|
||||
maxX = max(maxX, gdi.getCX());
|
||||
int innerBoxLowerCX = maxX + gdi.scaleLength(6);
|
||||
maxX += gdi.scaleLength(12);
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
wstring wh, ww, xoff, yoff;
|
||||
bool keepRatio = true;
|
||||
if (imgId) {
|
||||
int h = mlp.getImageHeight();
|
||||
int w = mlp.getImageWidth();
|
||||
wh = itow(h);
|
||||
ww = itow(w);
|
||||
|
||||
int hImg = image.getHeight(imgId);
|
||||
int wImg = image.getWidth(imgId);
|
||||
|
||||
int hComputed = (w * hImg + wImg / 2) / wImg;
|
||||
int wComputed = (h * wImg + hImg / 2) / hImg;
|
||||
|
||||
keepRatio = std::abs(h - hComputed) <= 1 || std::abs(w - wComputed) <= 1;
|
||||
|
||||
xoff = itow(mlp.getImageOffsetX());
|
||||
yoff = itow(mlp.getImageOffsetY());
|
||||
}
|
||||
|
||||
gdi.addInput("ImgWidth", ww, 5, editListCB, L"Bredd:");
|
||||
gdi.addInput("ImgHeight", wh, 5, editListCB, L"Höjd:");
|
||||
gdi.dropLine();
|
||||
gdi.addCheckbox("PreserveAspectRatio", "Bevara höjd/bredd-relationen", nullptr, keepRatio);
|
||||
gdi.popX();
|
||||
gdi.dropLine(2);
|
||||
|
||||
gdi.dropLine(1);
|
||||
gdi.addString("", 0, "Förskjutning:");
|
||||
gdi.dropLine(-1);
|
||||
|
||||
gdi.addInput("ImgOffsetX", xoff, 5, editListCB, L"Horizontell:");
|
||||
gdi.addInput("ImgOffsetY", yoff, 5, editListCB, L"Vertikal:");
|
||||
|
||||
gdi.popX();
|
||||
gdi.dropLine(3);
|
||||
|
||||
gdi.addCheckbox("TransparentWhite", "Tolka vitt som genomskinligt", editListCB, mlp.getImageStyle() == 1);
|
||||
gdi.addCheckbox("ImageUnderText", "Bild under text", editListCB, mlp.imageUnderText());
|
||||
|
||||
bool hasImg = imgId != 0;
|
||||
gdi.setInputStatus("ImgWidth", hasImg);
|
||||
gdi.setInputStatus("ImgHeight", hasImg);
|
||||
gdi.setInputStatus("ImgOffsetX", hasImg);
|
||||
gdi.setInputStatus("ImgOffsetY", hasImg);
|
||||
|
||||
gdi.setInputStatus("PreserveAspectRatio", hasImg);
|
||||
|
||||
gdi.dropLine(3);
|
||||
gdi.setData("CurrentId", id);
|
||||
gdi.addButton("Remove", "Radera", editListCB, "Ta bort listposten");
|
||||
gdi.addButton("Cancel", "Avbryt", editListCB).setCancel();
|
||||
|
||||
gdi.updatePos(gdi.getCX(), gdi.getCY(), gdi.scaleLength(20), 0);
|
||||
gdi.addButton("Apply", "OK", editListCB).setDefault();
|
||||
|
||||
gdi.dropLine(1);
|
||||
maxY = max(maxY, gdi.getCY());
|
||||
maxX = max(gdi.getCX(), maxX);
|
||||
|
||||
RECT rc;
|
||||
|
||||
rc.top = y1;
|
||||
rc.left = x1;
|
||||
rc.right = maxX + gdi.scaleLength(6);
|
||||
rc.bottom = maxY + gdi.scaleLength(6) + gdi.getLineHeight();
|
||||
|
||||
gdi.addRectangle(rc, colorLightBlue, true, false);
|
||||
|
||||
gdi.setData("IsEditingImage", 1);
|
||||
|
||||
gdi.scrollToBottom();
|
||||
gdi.setCX(rc.right + gdi.scaleLength(10));
|
||||
gdi.setCY(boxY);
|
||||
|
||||
if (imgId != 0) {
|
||||
previewImage(gdi, selIx);
|
||||
}
|
||||
else
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
int ListEditor::selectImage(gdioutput &gdi, uint64_t imgId) {
|
||||
vector<pair<wstring, size_t>> img;
|
||||
image.enumerateImages(img);
|
||||
img.emplace(img.begin(), lang.tl("Ingen[bild]"), -2);
|
||||
gdi.addItem("Image", img);
|
||||
|
||||
int ix = image.getEnumerationIxFromId(imgId);
|
||||
if (ix >= 0)
|
||||
gdi.selectItemByData("Image", ix);
|
||||
else
|
||||
gdi.selectFirstItem("Image");
|
||||
|
||||
return ix;
|
||||
}
|
||||
|
||||
void ListEditor::showExample(gdioutput &gdi, EPostType type) {
|
||||
if (type == EPostType::lLastItem) {
|
||||
type = EPostType(gdi.getSelectedItem("Type").first);
|
||||
@ -1275,6 +1556,46 @@ void ListEditor::showExample(gdioutput &gdi, const MetaListPost &mlp) {
|
||||
gdi.addRectangle(rrInner, color, true);
|
||||
}
|
||||
|
||||
void ListEditor::previewImage(gdioutput& gdi, int data) const {
|
||||
gdi.restoreNoUpdate("image_preview");
|
||||
gdi.setRestorePoint("image_preview");
|
||||
if (data >= 0) {
|
||||
auto imgId = image.getIdFromEnumeration(data);
|
||||
oe->loadImage(imgId);
|
||||
bool transparent = gdi.isChecked("TransparentWhite");
|
||||
image.reloadImage(imgId, transparent ? Image::ImageMethod::WhiteTransparent : Image::ImageMethod::Default);
|
||||
gdi.addImage("", gdi.getCY(), gdi.getCX(), 0, itow(imgId));
|
||||
}
|
||||
gdi.refreshFast();
|
||||
}
|
||||
|
||||
void ListEditor::updateImageStatus(gdioutput& gdi, int data) {
|
||||
bool hasImg = int(data) >= 0;
|
||||
gdi.setInputStatus("ImgWidth", hasImg);
|
||||
gdi.setInputStatus("ImgHeight", hasImg);
|
||||
gdi.setInputStatus("PreserveAspectRatio", hasImg);
|
||||
gdi.setInputStatus("ImgOffsetX", hasImg);
|
||||
gdi.setInputStatus("ImgOffsetY", hasImg);
|
||||
|
||||
if (hasImg) {
|
||||
auto imgId = image.getIdFromEnumeration(data);
|
||||
int h = image.getHeight(imgId);
|
||||
int w = image.getWidth(imgId);
|
||||
gdi.setText("ImgWidth", w);
|
||||
gdi.setText("ImgHeight", h);
|
||||
|
||||
if (gdi.getTextNo("ImgOffsetX") == 0 && gdi.getTextNo("ImgOffsetY") == 0) {
|
||||
// Change from blank to "0"
|
||||
gdi.setText("ImgOffsetX", 0);
|
||||
gdi.setText("ImgOffsetY", 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gdi.setText("ImgWidth", L"");
|
||||
gdi.setText("ImgHeight", L"");
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *ListEditor::getIndexDescription(EPostType type) {
|
||||
if (type == lResultModuleTime || type == lResultModuleTimeTeam)
|
||||
return L"Index in X[index]#OutputTimes";
|
||||
@ -1310,7 +1631,7 @@ bool ListEditor::legStageTypeIndex(gdioutput &gdi, EPostType type, int leg) {
|
||||
gdi.setText("Leg", legW);
|
||||
}
|
||||
}
|
||||
else if (MetaList::isAllStageType(type)) {
|
||||
else if (MetaList::isAllStageType(type) || MetaList::isAllLegType(type)) {
|
||||
if (gdi.hasWidget("UseLeg"))
|
||||
gdi.removeWidget("UseLeg");
|
||||
|
||||
@ -1322,9 +1643,22 @@ bool ListEditor::legStageTypeIndex(gdioutput &gdi, EPostType type, int leg) {
|
||||
else
|
||||
gdi.addString("TUseLeg", ypUseLeg, xpUseLeg, 0, getIndexDescription(type));
|
||||
|
||||
if (!gdi.hasWidget("LegSel")) {
|
||||
if (!gdi.hasWidget("LegSel"))
|
||||
gdi.addSelection(xpUseLeg + dx, ypUseLeg + dy, "LegSel", 160, gdi.scaleLength(300), editListCB);
|
||||
vector<pair<wstring, size_t>> items;
|
||||
vector<pair<wstring, size_t>> items;
|
||||
if (MetaList::isAllLegType(type)) {
|
||||
items.emplace_back(lang.tl("Automatisk"), 0);
|
||||
items.emplace_back(lang.tl("Alla sträckor"), -2);
|
||||
for (int j = 1; j <= 50; j++) {
|
||||
items.emplace_back(lang.tl("Sträcka X#" + itos(j)), j);
|
||||
}
|
||||
gdi.addItem("LegSel", items);
|
||||
if (leg >= -1)
|
||||
gdi.selectItemByData("LegSel", leg + 1);
|
||||
else if (leg == -2)
|
||||
gdi.selectItemByData("LegSel", -2);
|
||||
}
|
||||
else {
|
||||
items.emplace_back(lang.tl("Alla tidigare etapper"), -2);
|
||||
for (int j = 1; j < 20; j++) {
|
||||
items.emplace_back(lang.tl("Etapp X#" + itos(j)), j);
|
||||
@ -1373,6 +1707,7 @@ void ListEditor::editListProp(gdioutput &gdi, bool newList) {
|
||||
if (!newList) {
|
||||
gdi.restore("EditList", false);
|
||||
gdi.disableInput("EditList");
|
||||
gdi.disableInput("SplitPrint");
|
||||
}
|
||||
|
||||
gdi.dropLine(0.8);
|
||||
@ -1552,6 +1887,80 @@ void ListEditor::editListProp(gdioutput &gdi, bool newList) {
|
||||
gdi.setInputFocus("Name");
|
||||
}
|
||||
|
||||
void ListEditor::statusSplitPrint(gdioutput& gdi, bool status) {
|
||||
gdi.setInputStatus("Split", status);
|
||||
gdi.setInputStatus("Speed", status);
|
||||
gdi.setInputStatus("Result", status);
|
||||
gdi.setInputStatus("Analysis", status);
|
||||
}
|
||||
|
||||
void ListEditor::splitPrintList(gdioutput& gdi) {
|
||||
checkUnsaved(gdi);
|
||||
|
||||
if (!currentList)
|
||||
return;
|
||||
|
||||
MetaList& list = *currentList;
|
||||
|
||||
gdi.restore("EditList", false);
|
||||
gdi.disableInput("EditList");
|
||||
gdi.disableInput("SplitPrint");
|
||||
|
||||
gdi.dropLine(0.8);
|
||||
|
||||
int x1 = gdi.getCX();
|
||||
int y1 = gdi.getCY();
|
||||
int margin = gdi.scaleLength(10);
|
||||
gdi.setCX(x1 + margin);
|
||||
|
||||
gdi.dropLine();
|
||||
gdi.fillDown();
|
||||
gdi.addString("", boldLarge, "Sträcktidsutskrift").setColor(colorDarkGrey);
|
||||
gdi.dropLine();
|
||||
|
||||
gdi.fillRight();
|
||||
gdi.pushX();
|
||||
|
||||
bool isSP = list.isSplitPrintList();
|
||||
auto sp = list.getSplitPrintInfo();
|
||||
gdi.fillDown();
|
||||
|
||||
gdi.addCheckbox("UseForSplit", "Använd listan för sträcktidsutskrift", editListCB, isSP);
|
||||
|
||||
gdi.dropLine(0.5);
|
||||
gdi.fillRight();
|
||||
gdi.addCheckbox("Split", "Inkludera sträcktider", nullptr, isSP ? sp->includeSplitTimes : true);
|
||||
gdi.addCheckbox("Speed", "Inkludera tempo", nullptr, isSP ? sp->withSpeed : true);
|
||||
gdi.addCheckbox("Result", "Inkludera individuellt resultat", nullptr, isSP ? sp->withResult : true);
|
||||
gdi.addCheckbox("Analysis", "Inkludera bomanalys", nullptr, isSP ? sp->withAnalysis : true);
|
||||
|
||||
statusSplitPrint(gdi, isSP);
|
||||
|
||||
gdi.dropLine(0.8);
|
||||
gdi.setCX(gdi.getCX() + 20);
|
||||
gdi.addButton("ApplySplitList", "OK", editListCB);
|
||||
gdi.addButton("Cancel", "Avbryt", editListCB);
|
||||
|
||||
gdi.dropLine(3);
|
||||
int maxY = gdi.getCY();
|
||||
int maxX = gdi.getCX();
|
||||
|
||||
gdi.fillDown();
|
||||
gdi.popX();
|
||||
gdi.setData("IsSplitListEdit", 1);
|
||||
|
||||
RECT rc;
|
||||
rc.top = y1;
|
||||
rc.left = x1;
|
||||
rc.right = maxX + gdi.scaleLength(6);
|
||||
rc.bottom = maxY;
|
||||
|
||||
gdi.addRectangle(rc, colorLightBlue, true);
|
||||
|
||||
gdi.scrollToBottom();
|
||||
gdi.refresh();
|
||||
}
|
||||
|
||||
void ListEditor::makeDirty(gdioutput &gdi, DirtyFlag inside, DirtyFlag outside) {
|
||||
if (inside == MakeDirty)
|
||||
dirtyInt = true;
|
||||
@ -1575,10 +1984,10 @@ void ListEditor::makeDirty(gdioutput &gdi, DirtyFlag inside, DirtyFlag outside)
|
||||
bool ListEditor::checkSave(gdioutput &gdi) {
|
||||
if (dirtyInt || dirtyExt) {
|
||||
gdioutput::AskAnswer answer = gdi.askCancel(L"Vill du spara ändringar?");
|
||||
if (answer == gdioutput::AnswerCancel)
|
||||
if (answer == gdioutput::AskAnswer::AnswerCancel)
|
||||
return false;
|
||||
|
||||
if (answer == gdioutput::AnswerYes) {
|
||||
if (answer == gdioutput::AskAnswer::AnswerYes) {
|
||||
if (currentIndex >= 0)
|
||||
gdi.sendCtrlMessage("SaveInside");
|
||||
else if (gdi.sendCtrlMessage("SaveFile") == 0)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -43,6 +43,7 @@ private:
|
||||
MetaList *currentList;
|
||||
void setCurrentList(MetaList *lst);
|
||||
int currentIndex;
|
||||
int currentRunnerId = 0;
|
||||
wstring savedFileName;
|
||||
bool dirtyExt;
|
||||
bool dirtyInt;
|
||||
@ -54,12 +55,22 @@ private:
|
||||
void updateType(int iType, gdioutput &gdi);
|
||||
|
||||
bool saveListPost(gdioutput &gdi, MetaListPost &mlp);
|
||||
bool saveImage(gdioutput& gdi, MetaListPost& mlp);
|
||||
|
||||
static int selectImage(gdioutput& gdi, uint64_t imgId);
|
||||
|
||||
void updateImageStatus(gdioutput& gdi, int data);
|
||||
|
||||
ButtonInfo &addButton(gdioutput &gdi, const MetaListPost &mlp, int x, int y,
|
||||
int lineIx, int ix) const;
|
||||
|
||||
|
||||
void ListEditor::editDlgStart(gdioutput& gdi, int id, const char* title, int& x1, int& y1, int& boxY);
|
||||
|
||||
void editListPost(gdioutput &gdi, const MetaListPost &mlp, int id);
|
||||
|
||||
void editImage(gdioutput& gdi, const MetaListPost& mlp, int id);
|
||||
void previewImage(gdioutput &gdi, int data) const;
|
||||
|
||||
void showExample(gdioutput &gdi, EPostType type = EPostType::lLastItem);
|
||||
|
||||
void showExample(gdioutput &gdi, const MetaListPost &mlp);
|
||||
@ -68,10 +79,14 @@ private:
|
||||
|
||||
void editListProp(gdioutput &gdi, bool newList);
|
||||
|
||||
void statusSplitPrint(gdioutput& gdi, bool status);
|
||||
|
||||
void splitPrintList(gdioutput& gdi);
|
||||
|
||||
enum DirtyFlag {MakeDirty, ClearDirty, NoTouch};
|
||||
|
||||
/// Check (and autosave) if there are unsaved changes in a dialog box
|
||||
void checkUnsaved(gdioutput &gdi);
|
||||
/// Check (and autosave) if there are unsaved changes in a dialog box. Return force flag
|
||||
bool checkUnsaved(gdioutput &gdi);
|
||||
|
||||
/// Check and ask if there are changes to save
|
||||
bool checkSave(gdioutput &gdi);
|
||||
@ -91,6 +106,7 @@ private:
|
||||
|
||||
bool legStageTypeIndex(gdioutput &gdi, EPostType type, int leg);
|
||||
|
||||
void renderListPreview(gdioutput& gdi);
|
||||
|
||||
public:
|
||||
ListEditor(oEvent *oe);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/********************i****************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -89,10 +89,21 @@ void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) {
|
||||
gdi.setData("PunchSync", 1);
|
||||
gdi.setRestorePoint("LiveResult");
|
||||
|
||||
readoutResult();
|
||||
|
||||
resYPos = h/3;
|
||||
|
||||
calculateResults();
|
||||
showResultList = 0;
|
||||
gdi.addTimeoutMilli(1000, "res", 0).setHandler(this);
|
||||
gdi.refreshFast();
|
||||
}
|
||||
|
||||
void LiveResult::readoutResult() {
|
||||
lastTime = 0;
|
||||
vector<const oFreePunch *> pp;
|
||||
vector<const oFreePunch*> pp;
|
||||
oe->synchronizeList({ oListId::oLRunnerId, oListId::oLPunchId });
|
||||
|
||||
|
||||
oe->getLatestPunches(lastTime, pp);
|
||||
processedPunches.clear();
|
||||
|
||||
@ -103,14 +114,14 @@ void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) {
|
||||
fromPunch = oPunch::PunchStart;
|
||||
if (toPunch == 0)
|
||||
toPunch = oPunch::PunchFinish;
|
||||
|
||||
|
||||
for (size_t k = 0; k < pp.size(); k++) {
|
||||
lastTime = max(pp[k]->getModificationTime(), lastTime);
|
||||
pRunner r = pp[k]->getTiedRunner();
|
||||
if (r) {
|
||||
pair<int, int> key = make_pair(r->getId(), pp[k]->getControlId());
|
||||
processedPunches[key] = max(processedPunches[key], pp[k]->getAdjustedTime());
|
||||
|
||||
|
||||
if (!li.getParam().selection.empty() && !li.getParam().selection.count(r->getClassId(true)))
|
||||
continue; // Filter class
|
||||
|
||||
@ -125,9 +136,9 @@ void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) {
|
||||
startFinishTime.clear();
|
||||
results.clear();
|
||||
for (map<int, pair<vector<int>, vector<int> > >::iterator it = storedPunches.begin();
|
||||
it != storedPunches.end(); ++it) {
|
||||
vector<int> &froms = it->second.first;
|
||||
vector<int> &tos = it->second.second;
|
||||
it != storedPunches.end(); ++it) {
|
||||
vector<int>& froms = it->second.first;
|
||||
vector<int>& tos = it->second.second;
|
||||
pRunner r = oe->getRunner(it->first, 0);
|
||||
for (size_t j = 0; j < tos.size(); j++) {
|
||||
int fin = pp[tos[j]]->getAdjustedTime();
|
||||
@ -141,22 +152,15 @@ void LiveResult::showTimer(gdioutput &gdi, const oListInfo &liIn) {
|
||||
}
|
||||
}
|
||||
if (time < 100000000 && r->getStatus() <= StatusOK) {
|
||||
// results.push_back(Result());
|
||||
// results.back().r = r;
|
||||
// results.back().time = time;
|
||||
// results.push_back(Result());
|
||||
// results.back().r = r;
|
||||
// results.back().time = time;
|
||||
startFinishTime[r->getId()].first = sta;
|
||||
startFinishTime[r->getId()].second = fin;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resYPos = h/3;
|
||||
|
||||
calculateResults();
|
||||
showResultList = 0;
|
||||
gdi.addTimeoutMilli(1000, "res", 0).setHandler(this);
|
||||
gdi.refreshFast();
|
||||
}
|
||||
|
||||
|
||||
@ -352,20 +356,41 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
|
||||
|
||||
if (doRefresh)
|
||||
gdi.refreshFast();
|
||||
else {
|
||||
auto resCopy = results;
|
||||
calculateResults();
|
||||
bool reshow = false;
|
||||
if (resCopy.size() != results.size())
|
||||
reshow = true;
|
||||
else {
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
if (resCopy[i].name.empty())
|
||||
break;
|
||||
if (resCopy[i].runnerId != results[i].runnerId) {
|
||||
reshow = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (resCopy[i].time != results[i].time) {
|
||||
reshow = true;
|
||||
break;
|
||||
}
|
||||
|
||||
pRunner r = oe->getRunner(results[i].runnerId, 0);
|
||||
if (!r || resCopy[i].name != r->getName()) {
|
||||
reshow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reshow) {
|
||||
showResults(gdi);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == GUI_TIMEOUT) {
|
||||
gdi.restore("LiveResult", false);
|
||||
int h,w;
|
||||
gdi.getTargetDimension(w, h);
|
||||
gdi.fillDown();
|
||||
BaseInfo *bi = gdi.setTextTranslate("timing", L"MeOS Timing", false);
|
||||
TextInfo &ti = dynamic_cast<TextInfo &>(*bi);
|
||||
ti.changeFont(getFont(gdi, 0.7));
|
||||
gdi.refreshFast();
|
||||
resYPos = ti.textRect.bottom + gdi.scaleLength(20);
|
||||
calculateResults();
|
||||
showResultList = 0;
|
||||
gdi.addTimeoutMilli(300, "res", 0).setHandler(this);
|
||||
showResults(gdi);
|
||||
}
|
||||
else if (type == GUI_TIMER) {
|
||||
if (size_t(showResultList) >= results.size())
|
||||
@ -379,9 +404,10 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
|
||||
gdi.addTimeoutMilli(10, "res" + itos(showResultList), 0).setHandler(this);
|
||||
}
|
||||
else if (res.place > 0) {
|
||||
res.name = r->getName();
|
||||
int h,w;
|
||||
gdi.getTargetDimension(w, h);
|
||||
|
||||
|
||||
gdi.takeShownStringsSnapshot();
|
||||
TextInfo &ti = gdi.addStringUT(y, 30, fontLarge, itow(res.place) + L".", 0, 0, font.c_str());
|
||||
int ht = ti.textRect.bottom - ti.textRect.top;
|
||||
@ -400,6 +426,22 @@ void LiveResult::handle(gdioutput &gdi, BaseInfo &bu, GuiEventType type) {
|
||||
}
|
||||
}
|
||||
|
||||
void LiveResult::showResults(gdioutput &gdi) {
|
||||
gdi.restore("LiveResult", false);
|
||||
int h, w;
|
||||
gdi.getTargetDimension(w, h);
|
||||
gdi.fillDown();
|
||||
BaseInfo* bi = gdi.setTextTranslate("timing", L"MeOS Timing", false);
|
||||
TextInfo& ti = dynamic_cast<TextInfo&>(*bi);
|
||||
ti.changeFont(getFont(gdi, 0.7));
|
||||
gdi.refreshFast();
|
||||
resYPos = ti.textRect.bottom + gdi.scaleLength(20);
|
||||
calculateResults();
|
||||
showResultList = 0;
|
||||
gdi.addTimeoutMilli(300, "res", 0).setHandler(this);
|
||||
|
||||
}
|
||||
|
||||
void LiveResult::calculateResults() {
|
||||
rToWatch.clear();
|
||||
results.clear();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -49,14 +49,17 @@ class LiveResult : public GuiHandler {
|
||||
int place;
|
||||
int runnerId;
|
||||
int time;
|
||||
wstring name;
|
||||
bool operator<(const Result &b) const {
|
||||
return time < b.time;
|
||||
}
|
||||
};
|
||||
|
||||
vector< Result > results;
|
||||
vector<Result> results;
|
||||
|
||||
void calculateResults();
|
||||
void readoutResult();
|
||||
void showResults(gdioutput& gdi);
|
||||
|
||||
public:
|
||||
LiveResult(oEvent *oe);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -54,7 +54,7 @@ void MachineContainer::AbstractMachine::load(const xmlobject &data) {
|
||||
xmlList out;
|
||||
data.getObjects(out);
|
||||
for (auto &x : out) {
|
||||
props[x.getName()] = x.getw();
|
||||
props[x.getName()] = x.getWStr();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1832,14 +1832,13 @@ bool getMeOSFile(wchar_t *FileNamePath, const wchar_t *FileName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getUserFile(wchar_t *FileNamePath, const wchar_t *FileName)
|
||||
{
|
||||
bool getUserFile(wchar_t* FileNamePath, const wchar_t* FileName) {
|
||||
wchar_t Path[MAX_PATH];
|
||||
wchar_t AppPath[MAX_PATH];
|
||||
|
||||
if (SHGetSpecialFolderPath(hWndMain, Path, CSIDL_APPDATA, 1)!=NOERROR) {
|
||||
int i=wcslen(Path);
|
||||
if (Path[i-1]!='\\')
|
||||
if (SHGetSpecialFolderPath(hWndMain, Path, CSIDL_APPDATA, 1) != NOERROR) {
|
||||
int i = wcslen(Path);
|
||||
if (Path[i - 1] != '\\')
|
||||
wcscat_s(Path, MAX_PATH, L"\\");
|
||||
|
||||
wcscpy_s(AppPath, MAX_PATH, Path);
|
||||
|
||||
@ -52,6 +52,7 @@ IDB_ECO BITMAP "bmp00001.bmp"
|
||||
|
||||
IDI_SPLASHIMAGE PNG "meos.png"
|
||||
IDI_MEOSIMAGE PNG "title.png"
|
||||
IDI_MEOSINFO PNG "info24.png"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -152,7 +152,7 @@ int getRelativeDay() {
|
||||
return int(qp);
|
||||
}
|
||||
|
||||
__int64 SystemTimeToInt64Second(const SYSTEMTIME &st) {
|
||||
__int64 SystemTimeToInt64TenthSecond(const SYSTEMTIME &st) {
|
||||
FILETIME ft;
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
|
||||
@ -160,16 +160,16 @@ __int64 SystemTimeToInt64Second(const SYSTEMTIME &st) {
|
||||
u.HighPart = ft.dwHighDateTime;
|
||||
u.LowPart = ft.dwLowDateTime;
|
||||
__int64 qp = u.QuadPart;
|
||||
qp /= __int64(10) * 1000 * 1000;
|
||||
qp /= __int64(1000 * 1000 * timeUnitsPerSecond);
|
||||
return qp;
|
||||
}
|
||||
|
||||
SYSTEMTIME Int64SecondToSystemTime(__int64 time) {
|
||||
SYSTEMTIME Int64TenthSecondToSystemTime(__int64 time) {
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
|
||||
ULARGE_INTEGER u;
|
||||
u.QuadPart = time * __int64(10) * 1000 * 1000;
|
||||
u.QuadPart = time * __int64(1000 * 1000 * timeUnitsPerSecond);
|
||||
ft.dwHighDateTime = u.HighPart;
|
||||
ft.dwLowDateTime = u.LowPart;
|
||||
|
||||
@ -257,44 +257,87 @@ int convertDateYMS(const wstring &m, SYSTEMTIME &st, bool checkValid) {
|
||||
return convertDateYMS(ms, st, checkValid);
|
||||
}
|
||||
//Absolute time string to SYSTEM TIME
|
||||
int convertDateYMS(const string &m, SYSTEMTIME &st, bool checkValid) {
|
||||
int convertDateYMS(const string& m, SYSTEMTIME& st, bool checkValid) {
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
if (m.length()==0)
|
||||
if (m.length() == 0)
|
||||
return -1;
|
||||
|
||||
int len=m.length();
|
||||
for (int k=0;k<len;k++) {
|
||||
BYTE b=m[k];
|
||||
int len = m.length();
|
||||
int dashCount = 0;
|
||||
for (int k = 0; k < len; k++) {
|
||||
BYTE b = m[k];
|
||||
if (b == 'T')
|
||||
break;
|
||||
if ( !(b=='-' || b==' ' || (b>='0' && b<='9')) )
|
||||
if (!(b == '-' || b == ' ' || (b >= '0' && b <= '9')))
|
||||
return -1;
|
||||
|
||||
if (b == '-')
|
||||
dashCount++;
|
||||
}
|
||||
|
||||
int year=atoi(m.c_str());
|
||||
if (year<1900 || year>3000)
|
||||
return -1;
|
||||
int year = atoi(m.c_str());
|
||||
|
||||
int month=0;
|
||||
int day=0;
|
||||
int kp=m.find_first_of('-');
|
||||
if (dashCount == 0) {
|
||||
int day = year % 100;
|
||||
year /= 100;
|
||||
int month = year % 100;
|
||||
year /= 100;
|
||||
|
||||
if (kp!=string::npos) {
|
||||
string mtext=m.substr(kp+1);
|
||||
month=atoi(mtext.c_str());
|
||||
if ((year > 0 && year < 100) || (year == 0 && m.size() > 2 && m[0] == '0' && m[1] == '0'))
|
||||
year = extendYear(year);
|
||||
|
||||
if (month<1 || month>12) {
|
||||
if (year < 1900 || year>3000)
|
||||
return -1;
|
||||
|
||||
if (month < 1 || month>12) {
|
||||
if (checkValid)
|
||||
return -1;
|
||||
month = 1;
|
||||
}
|
||||
|
||||
kp=mtext.find_last_of('-');
|
||||
if (day < 1 || day>31) {
|
||||
if (checkValid)
|
||||
return -1;
|
||||
day = 1;
|
||||
}
|
||||
|
||||
if (kp!=string::npos) {
|
||||
day=atoi(mtext.substr(kp+1).c_str());
|
||||
if (day<1 || day>31) {
|
||||
st.wYear = year;
|
||||
st.wMonth = month;
|
||||
st.wDay = day;
|
||||
|
||||
int t = year * 100 * 100 + month * 100 + day;
|
||||
if (t < 0)
|
||||
return -1;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
if ((year > 0 && year < 100) || (year == 0 && m.size() > 2 && m[0] == '0' && m[1] == '0'))
|
||||
year = extendYear(year);
|
||||
|
||||
if (year < 1900 || year>3000)
|
||||
return -1;
|
||||
|
||||
int month = 0;
|
||||
int day = 0;
|
||||
int kp = m.find_first_of('-');
|
||||
|
||||
if (kp != string::npos) {
|
||||
string mtext = m.substr(kp + 1);
|
||||
month = atoi(mtext.c_str());
|
||||
|
||||
if (month < 1 || month>12) {
|
||||
if (checkValid)
|
||||
return -1;
|
||||
month = 1;
|
||||
}
|
||||
|
||||
kp = mtext.find_last_of('-');
|
||||
|
||||
if (kp != string::npos) {
|
||||
day = atoi(mtext.substr(kp + 1).c_str());
|
||||
if (day < 1 || day>31) {
|
||||
if (checkValid)
|
||||
return -1;
|
||||
day = 1;
|
||||
@ -306,8 +349,8 @@ int convertDateYMS(const string &m, SYSTEMTIME &st, bool checkValid) {
|
||||
st.wDay = day;
|
||||
|
||||
|
||||
int t = year*100*100+month*100+day;
|
||||
if (t<0) return -1;
|
||||
int t = year * 100 * 100 + month * 100 + day;
|
||||
if (t < 0) return -1;
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -356,7 +399,7 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
|
||||
return -1;
|
||||
if (tpart < daysZeroTime)
|
||||
days--;
|
||||
return days * 3600 * 24 + tpart;
|
||||
return days * timeConstHour * 24 + tpart;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -364,7 +407,7 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
|
||||
int plusIndex = -1;
|
||||
for (int k=0;k<len;k++) {
|
||||
BYTE b=m[k];
|
||||
if ( !(isspace(b) || b==':' || (b>='0' && b<='9')) ) {
|
||||
if ( !(isspace(b) || b==':' || (b>='0' && b<='9') || b == '.' || b == ',') ) {
|
||||
if (b=='+' && plusIndex ==-1 && k>0)
|
||||
plusIndex = k;
|
||||
else
|
||||
@ -377,7 +420,7 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
|
||||
int d = atoi(m.c_str());
|
||||
|
||||
if (d>0 && t>=0)
|
||||
return d*24*3600 + t;
|
||||
return d*24* timeConstHour + t;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
@ -389,6 +432,7 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
|
||||
|
||||
int minute=0;
|
||||
int second=0;
|
||||
int tenth = 0;
|
||||
int kp=m.find_first_of(':');
|
||||
|
||||
if (kp!=string::npos) {
|
||||
@ -401,13 +445,27 @@ int convertAbsoluteTimeHMS(const string &m, int daysZeroTime) {
|
||||
kp=mtext.find_last_of(':');
|
||||
|
||||
if (kp!=string::npos) {
|
||||
second=atoi(mtext.substr(kp+1).c_str());
|
||||
second=atoi(mtext.c_str() + kp+1);
|
||||
if (second<0 || second>60)
|
||||
second=0;
|
||||
|
||||
if (timeConstSecond > 1) {
|
||||
kp = mtext.find_last_of('.');
|
||||
if (kp == string::npos)
|
||||
kp = mtext.find_last_of(',');
|
||||
if (kp != string::npos) {
|
||||
tenth = atoi(mtext.c_str() + kp + 1);
|
||||
if (tenth < 0 || tenth >= 10)
|
||||
tenth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int t=hour*3600+minute*60+second;
|
||||
if (t<0) return 0;
|
||||
|
||||
int t = hour * timeConstHour + minute * timeConstMinute + second * timeConstSecond + tenth;
|
||||
|
||||
if (t<0)
|
||||
return 0;
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -477,7 +535,7 @@ int convertAbsoluteTimeISO(const string &m)
|
||||
if (second<0 || second>60)
|
||||
return -1;
|
||||
|
||||
int t = hour*3600 + minute*60 + second;
|
||||
int t = hour * timeConstHour + minute * timeConstMinute + second;
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -509,31 +567,50 @@ int convertAbsoluteTimeMS(const string &m)
|
||||
mtext=m;
|
||||
|
||||
minute=atoi(mtext.c_str());
|
||||
|
||||
int hour = 0;
|
||||
if (minute<0 || minute>60*24)
|
||||
minute=0;
|
||||
|
||||
int kp=mtext.find_first_of(':');
|
||||
|
||||
bool gotSecond = false;
|
||||
if (kp!=string::npos) {
|
||||
mtext = mtext.substr(kp+1);
|
||||
second = atoi(mtext.c_str());
|
||||
gotSecond = true;
|
||||
if (second<0 || second>60)
|
||||
second=0;
|
||||
}
|
||||
|
||||
int t=minute*60+second;
|
||||
|
||||
kp=mtext.find_first_of(':');
|
||||
if (kp!=string::npos) {
|
||||
int t;
|
||||
kp = mtext.find_first_of(':');
|
||||
if (kp != string::npos) {
|
||||
//Allow also for format +-HH:MM:SS
|
||||
mtext = mtext.substr(kp+1);
|
||||
second=atoi(mtext.c_str());
|
||||
if (second<0 || second>60)
|
||||
second=0;
|
||||
else
|
||||
t = t*60 + second;
|
||||
hour = minute;
|
||||
minute = second;
|
||||
|
||||
mtext = mtext.substr(kp + 1);
|
||||
second = atoi(mtext.c_str());
|
||||
if (second < 0 || second>60)
|
||||
second = 0;
|
||||
}
|
||||
|
||||
int tenth = 0;
|
||||
if (timeConstSecond > 1) {
|
||||
kp = mtext.find_first_of('.');
|
||||
if (kp == string::npos)
|
||||
kp = mtext.find_last_of(',');
|
||||
if (kp != string::npos) {
|
||||
tenth = atoi(mtext.c_str() + kp + 1);
|
||||
if (!gotSecond) { // Reinterpret minute as second (no minute was specified)
|
||||
second = minute;
|
||||
minute = 0;
|
||||
}
|
||||
if (tenth < 0 || tenth >= 10)
|
||||
tenth = 0;
|
||||
}
|
||||
}
|
||||
t = hour * timeConstHour + minute * timeConstMinute + second * timeConstSecond + tenth;
|
||||
|
||||
return sign*t;
|
||||
}
|
||||
|
||||
@ -543,13 +620,37 @@ int convertAbsoluteTimeMS(const wstring &m) {
|
||||
}
|
||||
|
||||
//Generate +-MM:SS or +-HH:MM:SS
|
||||
const wstring &getTimeMS(int m) {
|
||||
const wstring &formatTimeMS(int m, bool force2digit, SubSecond mode) {
|
||||
wchar_t bf[32];
|
||||
int am = abs(m);
|
||||
if (am < 3600 || !MeOSUtil::useHourFormat)
|
||||
swprintf_s(bf, L"-%02d:%02d", am/60, am%60);
|
||||
else if (am < 3600*48)
|
||||
swprintf_s(bf, L"-%02d:%02d:%02d", am/3600, (am/60)%60, am%60);
|
||||
if (am < timeConstHour || !MeOSUtil::useHourFormat) {
|
||||
if (force2digit) {
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && m % 10 == 0))
|
||||
swprintf_s(bf, L"-%02d:%02d", am / timeConstMinute, (am / timeConstSecond) % 60);
|
||||
else
|
||||
swprintf_s(bf, L"-%02d:%02d.%d", am / timeConstMinute, (am / timeConstSecond) % 60, am % timeConstSecond);
|
||||
}
|
||||
else {
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && m % 10 == 0))
|
||||
swprintf_s(bf, L"-%d:%02d", am / timeConstMinute, (am / timeConstSecond) % 60);
|
||||
else
|
||||
swprintf_s(bf, L"-%d:%02d.%d", am / timeConstMinute, (am / timeConstSecond) % 60, am % timeConstSecond);
|
||||
}
|
||||
}
|
||||
else if (am < timeConstHour * 48) {
|
||||
if (force2digit) {
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && m % 10 == 0))
|
||||
swprintf_s(bf, L"-%02d:%02d:%02d", am / timeConstHour, (am / timeConstMinute) % 60, (am / timeConstSecond) % 60);
|
||||
else
|
||||
swprintf_s(bf, L"-%02d:%02d:%02d.%d", am / timeConstHour, (am / timeConstMinute) % 60, (am / timeConstSecond) % 60, am % timeConstSecond);
|
||||
}
|
||||
else {
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && m % 10 == 0))
|
||||
swprintf_s(bf, L"-%d:%02d:%02d", am / timeConstHour, (am / timeConstMinute) % 60, (am / timeConstSecond) % 60);
|
||||
else
|
||||
swprintf_s(bf, L"-%d:%02d:%02d.%d", am / timeConstHour, (am / timeConstMinute) % 60, (am / timeConstSecond) % 60, am % timeConstSecond);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m = 0;
|
||||
bf[0] = 0x2013;
|
||||
@ -564,15 +665,25 @@ const wstring &getTimeMS(int m) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const wstring &formatTime(int rt) {
|
||||
const wstring &formatTime(int rt, SubSecond mode) {
|
||||
wstring &res = StringCache::getInstance().wget();
|
||||
if (rt>0 && rt<3600*999) {
|
||||
wchar_t bf[16];
|
||||
if (rt>=3600 && MeOSUtil::useHourFormat)
|
||||
swprintf_s(bf, 16, L"%d:%02d:%02d", rt/3600,(rt/60)%60, rt%60);
|
||||
else
|
||||
swprintf_s(bf, 16, L"%d:%02d", (rt/60), rt%60);
|
||||
if (rt>0 && rt<timeConstHour*999) {
|
||||
wchar_t bf[40];
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && rt % 10 == 0)) {
|
||||
if (rt >= timeConstHour && MeOSUtil::useHourFormat)
|
||||
swprintf_s(bf, L"%d:%02d:%02d", rt / timeConstHour, (rt / timeConstMinute) % 60, (rt / timeConstSecond) % 60);
|
||||
else
|
||||
swprintf_s(bf, L"%d:%02d", (rt / timeConstMinute), (rt / timeConstSecond) % 60);
|
||||
}
|
||||
else {
|
||||
if (rt >= timeConstHour && MeOSUtil::useHourFormat)
|
||||
swprintf_s(bf, L"%d:%02d:%02d.%d", rt / timeConstHour, (rt / timeConstMinute) % 60, (rt / timeConstSecond) % 60, rt%timeConstSecond);
|
||||
else
|
||||
swprintf_s(bf, L"%d:%02d.%d", (rt / timeConstMinute), (rt / timeConstSecond) % 60, rt%timeConstSecond);
|
||||
|
||||
|
||||
|
||||
}
|
||||
res = bf;
|
||||
return res;
|
||||
}
|
||||
@ -583,12 +694,12 @@ const wstring &formatTime(int rt) {
|
||||
|
||||
const string &formatTimeN(int rt) {
|
||||
string &res = StringCache::getInstance().get();
|
||||
if (rt>0 && rt<3600*999) {
|
||||
if (rt>0 && rt<timeConstHour *999) {
|
||||
char bf[16];
|
||||
if (rt>=3600 && MeOSUtil::useHourFormat)
|
||||
sprintf_s(bf, 16, "%d:%02d:%02d", rt/3600,(rt/60)%60, rt%60);
|
||||
if (rt>= timeConstHour && MeOSUtil::useHourFormat)
|
||||
sprintf_s(bf, 16, "%d:%02d:%02d", rt/ timeConstHour,(rt/timeConstMinute)%60, (rt/timeConstSecond)%60);
|
||||
else
|
||||
sprintf_s(bf, 16, "%d:%02d", (rt/60), rt%60);
|
||||
sprintf_s(bf, 16, "%d:%02d", (rt/timeConstMinute), (rt/timeConstSecond)%60);
|
||||
|
||||
res = bf;
|
||||
return res;
|
||||
@ -597,11 +708,15 @@ const string &formatTimeN(int rt) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const wstring &formatTimeHMS(int rt) {
|
||||
const wstring &formatTimeHMS(int rt, SubSecond mode) {
|
||||
wstring &res = StringCache::getInstance().wget();
|
||||
if (rt>=0) {
|
||||
wchar_t bf[32];
|
||||
swprintf_s(bf, 16, L"%02d:%02d:%02d", rt/3600,(rt/60)%60, rt%60);
|
||||
wchar_t bf[40];
|
||||
if (mode == SubSecond::Off || (mode == SubSecond::Auto && rt%10 == 0))
|
||||
swprintf_s(bf, 16, L"%02d:%02d:%02d", rt/timeConstHour,(rt/timeConstMinute)%60, (rt/timeConstSecond)%60);
|
||||
else
|
||||
swprintf_s(bf, 16, L"%02d:%02d:%02d.%d", rt / timeConstHour, (rt / timeConstMinute) % 60, (rt / timeConstSecond) % 60, rt % timeConstSecond);
|
||||
|
||||
res = bf;
|
||||
return res;
|
||||
}
|
||||
@ -612,10 +727,10 @@ const wstring &formatTimeHMS(int rt) {
|
||||
|
||||
wstring formatTimeIOF(int rt, int zeroTime)
|
||||
{
|
||||
if (rt>0 && rt<(3600*24*10)) {
|
||||
rt+=zeroTime;
|
||||
if (rt > 0) {
|
||||
rt += zeroTime;
|
||||
wchar_t bf[16];
|
||||
swprintf_s(bf, 16, L"%02d:%02d:%02d", (rt/3600)%24,(rt/60)%60, rt%60);
|
||||
swprintf_s(bf, 16, L"%02d:%02d:%02d", (rt / timeConstHour) % 24, (rt / timeConstMinute) % 60, (rt / timeConstSecond) % 60);
|
||||
|
||||
return bf;
|
||||
}
|
||||
@ -766,7 +881,7 @@ wstring itow(int64_t i) {
|
||||
|
||||
wstring itow(uint64_t i) {
|
||||
wchar_t bf[32];
|
||||
_i64tow_s(i, bf, 32, 10);
|
||||
_ui64tow_s(i, bf, 32, 10);
|
||||
return bf;
|
||||
}
|
||||
|
||||
@ -819,14 +934,19 @@ bool filterMatchString(const string &c, const char *filt_lc)
|
||||
return strstr(key, filt_lc)!=0;
|
||||
}
|
||||
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc) {
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc, int &score) {
|
||||
score = 0;
|
||||
if (filt_lc[0] == 0)
|
||||
return true;
|
||||
wchar_t key[2048];
|
||||
wcscpy_s(key, c.c_str());
|
||||
CharLowerBuff(key, c.length());
|
||||
|
||||
return wcsstr(key, filt_lc)!=0;
|
||||
bool match = wcsstr(key, filt_lc) != 0;
|
||||
if (match) {
|
||||
while (filt_lc[score] && key[score] && filt_lc[score] == key[score])
|
||||
score++;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
@ -1936,8 +2056,8 @@ int getTimeZoneInfo(const wstring &date) {
|
||||
else if (datecodeUTC < datecode)
|
||||
daydiff = -1;
|
||||
|
||||
int t = st.wHour * 3600;
|
||||
int tUTC = daydiff * 24 * 3600 + utc.wHour * 3600 + utc.wMinute * 60 + utc.wSecond;
|
||||
int t = st.wHour * timeConstSecPerHour;
|
||||
int tUTC = daydiff * 24 * timeConstSecPerHour + utc.wHour * timeConstSecPerHour + utc.wMinute * timeConstSecPerMin + utc.wSecond;
|
||||
|
||||
lastValue = tUTC - t;
|
||||
return lastValue;
|
||||
@ -1949,12 +2069,12 @@ wstring getTimeZoneString(const wstring &date) {
|
||||
return L"+00:00";
|
||||
else if (a>0) {
|
||||
wchar_t bf[12];
|
||||
swprintf_s(bf, L"-%02d:%02d", a/3600, (a/60)%60);
|
||||
swprintf_s(bf, L"-%02d:%02d", a/timeConstSecPerHour, (a/timeConstMinPerHour)%60);
|
||||
return bf;
|
||||
}
|
||||
else {
|
||||
wchar_t bf[12];
|
||||
swprintf_s(bf, L"+%02d:%02d", a/-3600, (a/-60)%60);
|
||||
swprintf_s(bf, L"+%02d:%02d", a/-timeConstSecPerHour, (a/-timeConstMinPerHour)%60);
|
||||
return bf;
|
||||
}
|
||||
}
|
||||
@ -2291,3 +2411,97 @@ const char* meosException::narrow(const wstring& msg) {
|
||||
static string nmsg(msg.begin(), msg.end());
|
||||
return nmsg.c_str();
|
||||
}
|
||||
|
||||
int parseRelativeTime(const char *data) {
|
||||
if (data) {
|
||||
int ret = atoi(data);
|
||||
if (timeConstSecond > 1) {
|
||||
int j = 0;
|
||||
while (data[j]) {
|
||||
if (data[j] == '.') {
|
||||
int t = data[j + 1] - '0';
|
||||
if (t > 0 && t < 10) {
|
||||
if (ret < 0 || data[0] == '-')
|
||||
return ret * timeConstSecond - t;
|
||||
else
|
||||
return ret * timeConstSecond + t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (ret == -1)
|
||||
return ret; // Special value
|
||||
|
||||
return ret * timeConstSecond;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseRelativeTime(const wchar_t *data) {
|
||||
if (data) {
|
||||
int ret = _wtoi(data);
|
||||
if (timeConstSecond > 1) {
|
||||
int j = 0;
|
||||
while (data[j]) {
|
||||
if (data[j] == '.') {
|
||||
int t = data[j + 1] - '0';
|
||||
if (t > 0 && t < 10) {
|
||||
if (ret < 0 || data[0] == '-')
|
||||
return ret * timeConstSecond - t;
|
||||
else
|
||||
return ret * timeConstSecond + t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (ret == -1)
|
||||
return ret; // Special value
|
||||
|
||||
return ret * timeConstSecond;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const wstring &codeRelativeTimeW(int rt) {
|
||||
wchar_t bf[32];
|
||||
int subSec = timeConstSecond == 1 ? 0 : rt % timeConstSecond;
|
||||
|
||||
if (timeConstSecond == 1 || rt == -1)
|
||||
return itow(rt);
|
||||
else if (subSec == 0 && rt != -10)
|
||||
return itow(rt / timeConstSecond);
|
||||
else if (rt > 0) {
|
||||
swprintf_s(bf, L"%d.%d", rt / timeConstSecond, rt % timeConstSecond);
|
||||
}
|
||||
else {
|
||||
rt = -rt;
|
||||
swprintf_s(bf, L"-%d.%d", rt / timeConstSecond, rt % timeConstSecond);
|
||||
}
|
||||
wstring &res = StringCache::getInstance().wget();
|
||||
res = bf;
|
||||
return res;
|
||||
}
|
||||
|
||||
const string &codeRelativeTime(int rt) {
|
||||
char bf[32];
|
||||
int subSec = timeConstSecond == 1 ? 0 : rt % timeConstSecond;
|
||||
|
||||
if (timeConstSecond == 1 || rt == -1)
|
||||
return itos(rt);
|
||||
else if (subSec == 0 && rt != -10)
|
||||
return itos(rt / timeConstSecond);
|
||||
else if (rt > 0) {
|
||||
sprintf_s(bf, "%d.%d", rt / timeConstSecond, rt % timeConstSecond);
|
||||
}
|
||||
else {
|
||||
rt = -rt;
|
||||
sprintf_s(bf, "-%d.%d", rt / timeConstSecond, rt % timeConstSecond);
|
||||
}
|
||||
string &res = StringCache::getInstance().get();
|
||||
res = bf;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -72,9 +72,22 @@ int getRelativeDay();
|
||||
/// Get time and date in a format that forms a part of a filename
|
||||
wstring getLocalTimeFileName();
|
||||
|
||||
const wstring &getTimeMS(int m);
|
||||
const wstring &formatTime(int rt);
|
||||
const wstring &formatTimeHMS(int rt);
|
||||
enum class SubSecond {
|
||||
Off,
|
||||
On,
|
||||
Auto
|
||||
};
|
||||
|
||||
int parseRelativeTime(const char *data);
|
||||
int parseRelativeTime(const wchar_t *data);
|
||||
|
||||
const wstring &codeRelativeTimeW(int rt);
|
||||
const string &codeRelativeTime(int rt);
|
||||
|
||||
// Format time MM:SS.t (force2digit=true) or M:SS.t (force2digit=false)
|
||||
const wstring &formatTimeMS(int m, bool force2digit, SubSecond mode = SubSecond::Auto);
|
||||
const wstring &formatTime(int rt, SubSecond mode = SubSecond::Auto);
|
||||
const wstring &formatTimeHMS(int rt, SubSecond mode = SubSecond::Auto);
|
||||
|
||||
wstring formatTimeIOF(int rt, int zeroTime);
|
||||
|
||||
@ -91,8 +104,8 @@ void processGeneralTime(const wstring &generalTime, wstring &meosTime, wstring &
|
||||
//string formatDate(int m, bool useIsoFormat);
|
||||
wstring formatDate(int m, bool useIsoFormat);
|
||||
|
||||
__int64 SystemTimeToInt64Second(const SYSTEMTIME &st);
|
||||
SYSTEMTIME Int64SecondToSystemTime(__int64 time);
|
||||
__int64 SystemTimeToInt64TenthSecond(const SYSTEMTIME &st);
|
||||
SYSTEMTIME Int64TenthSecondToSystemTime(__int64 time);
|
||||
|
||||
#define NOTIME 0x7FFFFFFF
|
||||
|
||||
@ -141,7 +154,7 @@ wstring itow(uint64_t i);
|
||||
|
||||
///Lower case match (filt_lc must be lc)
|
||||
bool filterMatchString(const string &c, const char *filt_lc);
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc);
|
||||
bool filterMatchString(const wstring &c, const wchar_t *filt_lc, int &score);
|
||||
|
||||
bool matchNumber(int number, const wchar_t *key);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -43,3 +43,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class meosCancel : public meosException {
|
||||
|
||||
};
|
||||
|
||||
@ -462,6 +462,7 @@
|
||||
<ClCompile Include="animationdata.cpp" />
|
||||
<ClCompile Include="autocomplete.cpp" />
|
||||
<ClCompile Include="autotask.cpp" />
|
||||
<ClCompile Include="binencoder.cpp" />
|
||||
<ClCompile Include="classconfiginfo.cpp" />
|
||||
<ClCompile Include="csvparser.cpp">
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@ -669,6 +670,7 @@
|
||||
<ClInclude Include="autocomplete.h" />
|
||||
<ClInclude Include="autocompletehandler.h" />
|
||||
<ClInclude Include="autotask.h" />
|
||||
<ClInclude Include="binencoder.h" />
|
||||
<ClInclude Include="classconfiginfo.h" />
|
||||
<ClInclude Include="gdiconstants.h" />
|
||||
<ClInclude Include="gdifonts.h" />
|
||||
@ -710,6 +712,7 @@
|
||||
<ClInclude Include="speakermonitor.h" />
|
||||
<ClInclude Include="subcommand.h" />
|
||||
<ClInclude Include="testmeos.h" />
|
||||
<ClInclude Include="timeconstants.hpp" />
|
||||
<ClInclude Include="toolbar.h" />
|
||||
<ClInclude Include="csvparser.h" />
|
||||
<ClInclude Include="download.h" />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -23,23 +23,23 @@
|
||||
#include <vector>
|
||||
#include "meos_util.h"
|
||||
|
||||
//ABCDEFGHIJKLMNO
|
||||
//ABCDEFGHIJKLMNOP
|
||||
int getMeosBuild() {
|
||||
string revision("$Rev: 1152 $");
|
||||
string revision("$Rev: 1225 $");
|
||||
return 174 + atoi(revision.substr(5, string::npos).c_str());
|
||||
}
|
||||
|
||||
wstring getMeosDate() {
|
||||
wstring date(L"$Date: 2022-05-04 14:47:48 +0200 (ons, 04 maj 2022) $");
|
||||
wstring date(L"$Date: 2023-02-08 19:30:10 +0100 (ons, 08 feb 2023) $");
|
||||
return date.substr(7,10);
|
||||
}
|
||||
|
||||
wstring getBuildType() {
|
||||
return L"U1"; // No parantheses (...)
|
||||
return L"Beta 1"; // No parantheses (...)
|
||||
}
|
||||
|
||||
wstring getMajorVersion() {
|
||||
return L"3.8";
|
||||
return L"3.9";
|
||||
}
|
||||
|
||||
wstring getMeosFullVersion() {
|
||||
@ -67,31 +67,8 @@ wstring getMeosCompectVersion() {
|
||||
}
|
||||
|
||||
void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
|
||||
{
|
||||
developSupp.emplace_back(L"Almby IK, Örebro");//2019--
|
||||
supp.emplace_back(L"Ligue PACA");
|
||||
supp.emplace_back(L"SC vebr-sport");
|
||||
supp.emplace_back(L"IP Skogen Göteborg");
|
||||
supp.emplace_back(L"Smedjebackens Orientering");
|
||||
supp.emplace_back(L"Gudhems IF");
|
||||
supp.emplace_back(L"Kexholm SK");
|
||||
supp.emplace_back(L"Utby IK");
|
||||
supp.emplace_back(L"JWOC 2019");
|
||||
developSupp.emplace_back(L"OK Nackhe");
|
||||
supp.emplace_back(L"OK Rodhen");
|
||||
developSupp.emplace_back(L"SongTao Wang / Henan Zhixing Exploration Sports Culture Co., Ltd.");
|
||||
developSupp.emplace_back(L"Australian and Oceania Orienteering Championships 2019");
|
||||
supp.emplace_back(L"Järfälla OK");
|
||||
supp.emplace_back(L"TJ Slávia Farmaceut Bratislava");
|
||||
supp.emplace_back(L"Magnus Thornell, Surahammars SOK");
|
||||
supp.emplace_back(L"Mariager Fjord OK");
|
||||
supp.emplace_back(L"Nässjö OK");
|
||||
supp.emplace_back(L"Ringsjö OK");
|
||||
supp.emplace_back(L"Big Foot Orienteers");
|
||||
supp.emplace_back(L"Erik Hulthen, Mölndal Outdoor IF");
|
||||
supp.emplace_back(L"Bay Area Orienteering Club");
|
||||
supp.emplace_back(L"Finspångs SOK");
|
||||
supp.emplace_back(L"OK Gorm, Denmark");
|
||||
{
|
||||
supp.emplace_back(L"OK Gorm, Denmark");//2020-
|
||||
supp.emplace_back(L"Nyköpings OK");
|
||||
supp.emplace_back(L"Thomas Engberg, VK Uvarna");
|
||||
supp.emplace_back(L"LG Axmalm, Sävedalens AIK");
|
||||
@ -113,11 +90,9 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
|
||||
supp.emplace_back(L"Fredrik Magnusson, Laholms IF");
|
||||
supp.emplace_back(L"KOB ATU Košice");
|
||||
supp.emplace_back(L"Alfta-Ösa OK");
|
||||
supp.emplace_back(L"HEYRIES, ACA Aix en Provence");
|
||||
supp.emplace_back(L"IFK Kiruna");
|
||||
supp.emplace_back(L"Smedjebackens OK");
|
||||
supp.emplace_back(L"Gunnar Persson, Svanesunds GIF");
|
||||
supp.emplace_back(L"Kamil Pipek, OK Lokomotiva Pardubice");
|
||||
supp.emplace_back(L"Køge Orienteringsklub");
|
||||
supp.emplace_back(L"Simrishamns OK");
|
||||
supp.emplace_back(L"OK Fryksdalen");
|
||||
@ -137,6 +112,7 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
|
||||
supp.emplace_back(L"Hans Carlstedt, Sävedalens AIK");
|
||||
supp.emplace_back(L"O-Liceo, Spain");
|
||||
developSupp.emplace_back(L"Västerviks OK");
|
||||
supp.emplace_back(L"Aarhus 1900 Orientering");
|
||||
supp.emplace_back(L"Ljusne Ala OK");
|
||||
supp.emplace_back(L"Sävedalens AIK");
|
||||
supp.emplace_back(L"Foothills Wanderers Orienteering Club");
|
||||
@ -144,6 +120,22 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
|
||||
supp.emplace_back(L"Per Ågren, OK Enen");
|
||||
supp.emplace_back(L"OK Roslagen");
|
||||
supp.emplace_back(L"OK Kolmården");
|
||||
|
||||
developSupp.emplace_back(L"Orienteering Queensland Inc.");
|
||||
supp.emplace_back(L"Eksjö SOK");
|
||||
supp.emplace_back(L"Kolding OK");
|
||||
developSupp.emplace_back(L"Alfta-Ösa OK");
|
||||
supp.emplace_back(L"Erik Almséus, IFK Hedemora OK");
|
||||
supp.emplace_back(L"IK Gandvik, Skara");
|
||||
supp.emplace_back(L"Mats Kågeson");
|
||||
supp.emplace_back(L"Lerums SOK");
|
||||
supp.emplace_back(L"OSC Hamburg");
|
||||
supp.emplace_back(L"HEYRIES, ACA Aix en Provence");
|
||||
developSupp.emplace_back(L"IFK Mora OK");
|
||||
supp.emplace_back(L"OK Rodhen");
|
||||
supp.emplace_back(L"Big Foot Orienteers");
|
||||
developSupp.emplace_back(L"OK Måsen");
|
||||
supp.emplace_back(L"Ligue PACA");
|
||||
supp.emplace_back(L"Kamil Pipek, OK Lokomotiva Pardubice");
|
||||
|
||||
reverse(supp.begin(), supp.end());
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -37,8 +37,11 @@
|
||||
#include "localizer.h"
|
||||
#include "gdifonts.h"
|
||||
#include "autocomplete.h"
|
||||
#include "image.h"
|
||||
#include "binencoder.h"
|
||||
|
||||
extern oEvent *gEvent;
|
||||
extern Image image;
|
||||
|
||||
const int MAXLISTPARAMID = 10000000;
|
||||
|
||||
@ -438,9 +441,11 @@ int checksum(const wstring &str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void MetaList::initUniqueIndex() const {
|
||||
__int64 ix = 0;
|
||||
int64_t ix = 0;
|
||||
|
||||
if (splitPrintInfo)
|
||||
ix = splitPrintInfo->checkSum();
|
||||
|
||||
for (int i = 0; i<4; i++) {
|
||||
const vector< vector<MetaListPost> > &lines = data[i];
|
||||
@ -461,6 +466,15 @@ void MetaList::initUniqueIndex() const {
|
||||
value = value * 31 + mp.mergeWithPrevious;
|
||||
value = value * 31 + mp.color;
|
||||
value = value * 31 + mp.textAdjust;
|
||||
if (mp.type == lImage) {
|
||||
value = value * 31 + mp.imageHeight;
|
||||
value = value * 31 + mp.imageWidth;
|
||||
value = value * 31 + mp.imageStyle;
|
||||
value = value * 31 + mp.imageOffsetX;
|
||||
value = value * 31 + mp.imageOffsetY;
|
||||
value = value * 31 + mp.imageStyleUnderText;
|
||||
}
|
||||
|
||||
ix = ix * 997 + value;
|
||||
}
|
||||
}
|
||||
@ -579,12 +593,23 @@ void MetaList::addRow(int ix) {
|
||||
|
||||
static void setFixedWidth(oPrintPost &added,
|
||||
const map<tuple<int,int,int>, int> &indexPosToWidth,
|
||||
int type, int j, int k) {
|
||||
map<tuple<int,int,int>, int>::const_iterator res = indexPosToWidth.find(tuple<int,int,int>(type, j, k));
|
||||
if (res != indexPosToWidth.end())
|
||||
added.fixedWidth = res->second;
|
||||
else
|
||||
added.fixedWidth = 0;
|
||||
int type, int j, int k,
|
||||
const MetaListPost &mlp) {
|
||||
if (added.type == lImage) {
|
||||
added.fixedWidth = mlp.getImageWidth();
|
||||
added.fixedHeight = mlp.getImageHeight();
|
||||
added.dx += mlp.getImageOffsetX();
|
||||
added.dy += mlp.getImageOffsetY();
|
||||
if (mlp.imageUnderText())
|
||||
added.imageNoUpdatePos = true;
|
||||
}
|
||||
else {
|
||||
map<tuple<int, int, int>, int>::const_iterator res = indexPosToWidth.find(tuple<int, int, int>(type, j, k));
|
||||
if (res != indexPosToWidth.end())
|
||||
added.fixedWidth = res->second;
|
||||
else
|
||||
added.fixedWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const {
|
||||
@ -592,6 +617,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
PositionVer2 pos;
|
||||
const bool large = par.useLargeSize;
|
||||
li.lp = par;
|
||||
li.setSplitPrintInfo(getSplitPrintInfo());
|
||||
gdiFonts normal, header, small, italic;
|
||||
double s_factor;
|
||||
oe->calculateResults({}, oEvent::ResultType::ClassResult, false);
|
||||
@ -668,7 +694,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
};
|
||||
|
||||
for (int i = 0; i<4; i++) {
|
||||
const vector< vector<MetaListPost> > &lines = mList.data[i];
|
||||
const vector<vector<MetaListPost>> &lines = mList.data[i];
|
||||
gdiFonts defaultFont = normal;
|
||||
switch (i) {
|
||||
case 0:
|
||||
@ -687,6 +713,10 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
return MetaList::isAllStageType(mp.type) && mp.leg == -1;
|
||||
};
|
||||
|
||||
auto isAllLegType = [](const MetaListPost& mp) {
|
||||
return MetaList::isAllLegType(mp.type) && mp.leg == -2;
|
||||
};
|
||||
|
||||
for (size_t j = 0; j<lines.size(); j++) {
|
||||
if (i == 0 && j == 0)
|
||||
defaultFont = boldLarge;
|
||||
@ -694,8 +724,16 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
dataCopy[i].emplace_back();
|
||||
vector<MetaListPost> &lineCopy = dataCopy[i].back();
|
||||
|
||||
int firstStage = -1;
|
||||
int firstStage = -1, firstLeg = -1;
|
||||
for (size_t k = 0; k < lines[j].size(); k++) {
|
||||
if (lines[j][k].type == lImage) {
|
||||
auto id = lines[j][k].getImageId();
|
||||
if (id > 0) {
|
||||
oe->loadImage(id);
|
||||
image.reloadImage(id, lines[j][k].getImageStyle() ? Image::ImageMethod::WhiteTransparent : Image::ImageMethod::Default);
|
||||
}
|
||||
}
|
||||
|
||||
if (isAllStageType(lines[j][k])) {
|
||||
if (firstStage == -1)
|
||||
firstStage = k;
|
||||
@ -711,6 +749,26 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
firstStage = -1;
|
||||
}
|
||||
}
|
||||
if (isAllLegType(lines[j][k])) {
|
||||
if (firstLeg == -1)
|
||||
firstLeg = k;
|
||||
|
||||
if (k + 1 == lines[j].size() || !isAllLegType(lines[j][k + 1])) {
|
||||
int ns = 0;
|
||||
vector<pClass> allC;
|
||||
oe->getClasses(allC, false);
|
||||
for (pClass c : allC)
|
||||
ns = max<int>(ns, c->getNumStages());
|
||||
|
||||
for (int s = 1; s <= ns; s++) {
|
||||
for (size_t f = firstLeg; f <= k; f++) {
|
||||
lineCopy.push_back(lines[j][f]);
|
||||
lineCopy.back().leg = s - 1;
|
||||
}
|
||||
}
|
||||
firstLeg = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lineCopy.push_back(lines[j][k]);
|
||||
}
|
||||
@ -786,12 +844,18 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
}
|
||||
if (mp.limitWidth && mp.blockWidth > 0)
|
||||
width = gdi.scaleLength(mp.blockWidth);
|
||||
else
|
||||
else if (mp.type == lImage) {
|
||||
if (mp.imageUnderText())
|
||||
width = 1;
|
||||
else
|
||||
width = gdi.scaleLength(mp.getImageWidth());
|
||||
}
|
||||
else {
|
||||
width = li.getMaxCharWidth(oe, gdi, par.selection, typeFormats, font,
|
||||
oPrintPost::encodeFont(fontFaces[i].font,
|
||||
fontFaces[i].scale).c_str(),
|
||||
large, max(mp.blockWidth, extraMinWidth));
|
||||
|
||||
oPrintPost::encodeFont(fontFaces[i].font,
|
||||
fontFaces[i].scale).c_str(),
|
||||
large, max(mp.blockWidth, extraMinWidth));
|
||||
}
|
||||
++linePostCount[make_pair(i, j)]; // Count how many positions on this line
|
||||
indexPosToWidth[tuple<int,int,int>(i, j, k)] = width;
|
||||
}
|
||||
@ -911,10 +975,10 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
fontFaces[MLHead].scale);
|
||||
|
||||
added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
|
||||
setFixedWidth(added, indexPosToWidth, MLHead, j, k);
|
||||
setFixedWidth(added, indexPosToWidth, MLHead, j, k, mp);
|
||||
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLHead, j, k)];
|
||||
added.color = mp.color;
|
||||
if (!mp.mergeWithPrevious)
|
||||
if (!mp.mergeWithPrevious && mp.type != lImage)
|
||||
base = &added;
|
||||
added.useStrictWidth = mp.getLimitBlockWidth();
|
||||
if (added.useStrictWidth)
|
||||
@ -928,9 +992,14 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
added.fixedWidth = 0;
|
||||
}
|
||||
}
|
||||
last = &added;
|
||||
last = mp.type != lImage ? &added : nullptr;
|
||||
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLHead)]);
|
||||
if (mp.type == lImage) {
|
||||
if (!mp.imageUnderText())
|
||||
next_dy = max(next_dy, gdi.scaleLength(mp.getImageHeight()));
|
||||
}
|
||||
else
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLHead)]);
|
||||
}
|
||||
dy += next_dy;
|
||||
next_dy = lineHeight;
|
||||
@ -965,10 +1034,10 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
fontFaces[MLSubHead].scale);
|
||||
|
||||
added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
|
||||
setFixedWidth(added, indexPosToWidth, MLSubHead, j, k);
|
||||
setFixedWidth(added, indexPosToWidth, MLSubHead, j, k, mp);
|
||||
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLSubHead, j, k)];
|
||||
added.color = mp.color;
|
||||
if (!mp.mergeWithPrevious)
|
||||
if (!mp.mergeWithPrevious && mp.type != lImage)
|
||||
base = &added;
|
||||
|
||||
added.useStrictWidth = mp.getLimitBlockWidth();
|
||||
@ -983,9 +1052,14 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
added.fixedWidth = 0;
|
||||
}
|
||||
}
|
||||
last = &added;
|
||||
last = mp.type != lImage ? &added : nullptr;
|
||||
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLSubHead)]);
|
||||
if (mp.type == lImage) {
|
||||
if (!mp.imageUnderText())
|
||||
next_dy = max(next_dy, gdi.scaleLength(mp.getImageHeight()));
|
||||
}
|
||||
else
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLSubHead)]);
|
||||
}
|
||||
dy += next_dy;
|
||||
}
|
||||
@ -1007,7 +1081,13 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
if (mp.font != formatIgnore)
|
||||
font = mp.font;
|
||||
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLList)]);
|
||||
if (mp.type == lImage) {
|
||||
if (!mp.imageUnderText())
|
||||
next_dy = max(next_dy, gdi.scaleLength(mp.getImageHeight()));
|
||||
}
|
||||
else
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLList)]);
|
||||
|
||||
bool dmy;
|
||||
oPrintPost &added = li.addListPost(oPrintPost(mp.type, encode(mp.type, mp.text, dmy), font|mp.textAdjust,
|
||||
pos.get(label, s_factor),
|
||||
@ -1016,14 +1096,14 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
fontFaces[MLList].scale);
|
||||
|
||||
added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
|
||||
setFixedWidth(added, indexPosToWidth, MLList, j, k);
|
||||
setFixedWidth(added, indexPosToWidth, MLList, j, k, mp);
|
||||
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLList, j, k)];
|
||||
added.useStrictWidth = mp.getLimitBlockWidth();
|
||||
if (added.useStrictWidth)
|
||||
added.format |= textLimitEllipsis;
|
||||
|
||||
added.color = mp.color;
|
||||
if (!mp.mergeWithPrevious)
|
||||
if (!mp.mergeWithPrevious && mp.type != lImage)
|
||||
base = &added;
|
||||
|
||||
if (last && mp.mergeWithPrevious) {
|
||||
@ -1033,7 +1113,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
added.fixedWidth = 0;
|
||||
}
|
||||
}
|
||||
last = &added;
|
||||
last = mp.type != lImage ? &added : nullptr;
|
||||
}
|
||||
dy += next_dy;
|
||||
}
|
||||
@ -1062,7 +1142,13 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
else
|
||||
xp = pos.get(label, s_factor);
|
||||
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLSubList)]);
|
||||
if (mp.type == lImage) {
|
||||
if (!mp.imageUnderText())
|
||||
next_dy = max(next_dy, gdi.scaleLength(mp.getImageHeight()));
|
||||
}
|
||||
else
|
||||
next_dy = max(next_dy, fontHeight[make_pair(font, MLSubList)]);
|
||||
|
||||
bool dmy;
|
||||
oPrintPost &added = li.addSubListPost(oPrintPost(mp.type, encode(mp.type, mp.text, dmy), font|mp.textAdjust,
|
||||
xp, dy+sublist_dy, mp.leg == -1 ? parLegNumber : make_pair(mp.leg, true))).
|
||||
@ -1070,11 +1156,11 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
fontFaces[MLSubList].scale);
|
||||
|
||||
added.color = mp.color;
|
||||
if (!mp.mergeWithPrevious)
|
||||
if (!mp.mergeWithPrevious && mp.type != lImage)
|
||||
base = &added;
|
||||
|
||||
added.resultModuleIndex = getResultModuleIndex(oe, li, mp);
|
||||
setFixedWidth(added, indexPosToWidth, MLSubList, j, k);
|
||||
setFixedWidth(added, indexPosToWidth, MLSubList, j, k, mp);
|
||||
added.xlimit = indexPosToWidthSrc[tuple<int, int, int>(MLSubList, j, k)];
|
||||
added.useStrictWidth = mp.getLimitBlockWidth();
|
||||
if (added.useStrictWidth)
|
||||
@ -1087,7 +1173,7 @@ void MetaList::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par
|
||||
added.fixedWidth = 0;
|
||||
}
|
||||
}
|
||||
last = &added;
|
||||
last = mp.type != lImage ? &added : nullptr;
|
||||
}
|
||||
dy += next_dy;
|
||||
}
|
||||
@ -1387,11 +1473,11 @@ bool Position::postAdjust() {
|
||||
void MetaList::save(const wstring &file, const oEvent *oe) const {
|
||||
xmlparser xml;
|
||||
xml.openOutput(file.c_str(), true);
|
||||
save(xml, oe);
|
||||
save(xml, true, oe);
|
||||
xml.closeOut();
|
||||
}
|
||||
|
||||
void MetaList::save(xmlparser &xml, const oEvent *oe) const {
|
||||
void MetaList::save(xmlparser &xml, bool includeImages, const oEvent *oe) const {
|
||||
initSymbols();
|
||||
xml.startTag("MeOSListDefinition", "version", getMajorVersion());
|
||||
// xml.write("Title", defaultTitle);
|
||||
@ -1401,6 +1487,13 @@ void MetaList::save(xmlparser &xml, const oEvent *oe) const {
|
||||
xml.write("ListOrigin", listOrigin);
|
||||
xml.write("Tag", tag);
|
||||
xml.write("UID", getUniqueId());
|
||||
|
||||
if (splitPrintInfo) {
|
||||
xml.startTag("SplitPrint");
|
||||
splitPrintInfo->serialize(xml);
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
xml.write("SortOrder", orderToSymbol[sortOrder]);
|
||||
xml.write("ListType", baseTypeToSymbol[listType]);
|
||||
xml.write("SubListType", baseTypeToSymbol[listSubType]);
|
||||
@ -1454,6 +1547,22 @@ void MetaList::save(xmlparser &xml, const oEvent *oe) const {
|
||||
serialize(xml, "List", getList());
|
||||
serialize(xml, "SubList", getSubList());
|
||||
|
||||
if (includeImages) {
|
||||
set<uint64_t> img;
|
||||
getUsedImages(img);
|
||||
Encoder92 binEncoder;
|
||||
for (auto imgId : img) {
|
||||
wstring fileName = image.getFileName(imgId);
|
||||
auto rawData = image.getRawData(imgId);
|
||||
string encoded;
|
||||
binEncoder.encode92(rawData, encoded);
|
||||
vector<pair<string, wstring>> props;
|
||||
props.emplace_back("filename", fileName);
|
||||
props.emplace_back("id", itow(imgId));
|
||||
xml.writeAscii("Image", props, encoded);
|
||||
}
|
||||
}
|
||||
|
||||
xml.endTag();
|
||||
}
|
||||
|
||||
@ -1475,6 +1584,11 @@ void MetaList::load(const xmlobject &xDef) {
|
||||
xDef.getObjectString("UID", uniqueIndex);
|
||||
xDef.getObjectString("ResultModule", resultModule);
|
||||
|
||||
auto xSplitPrint = xDef.getObject("SplitPrint");
|
||||
if (xSplitPrint) {
|
||||
splitPrintInfo = make_shared<SplitPrintListInfo>();
|
||||
splitPrintInfo->deserialize(xSplitPrint);
|
||||
}
|
||||
// string db = "Specified res mod: " + resultModule + "\n";
|
||||
// OutputDebugString(db.c_str());
|
||||
|
||||
@ -1523,29 +1637,29 @@ void MetaList::load(const xmlobject &xDef) {
|
||||
xmlobject xSubListFont = xDef.getObject("SubListFont");
|
||||
|
||||
if (xHeadFont) {
|
||||
const wchar_t *f = xHeadFont.getw();
|
||||
fontFaces[MLHead].font = f != 0 ? f : L"arial";
|
||||
const wchar_t *f = xHeadFont.getWPtr();
|
||||
fontFaces[MLHead].font = f != nullptr ? f : L"arial";
|
||||
fontFaces[MLHead].scale = xHeadFont.getObjectInt("scale");
|
||||
fontFaces[MLHead].extraSpaceAbove = xHeadFont.getObjectInt("above");
|
||||
}
|
||||
|
||||
if (xSubHeadFont) {
|
||||
const wchar_t *f = xSubHeadFont.getw();
|
||||
fontFaces[MLSubHead].font = f != 0 ? f : L"arial";
|
||||
const wchar_t *f = xSubHeadFont.getWPtr();
|
||||
fontFaces[MLSubHead].font = f != nullptr ? f : L"arial";
|
||||
fontFaces[MLSubHead].scale = xSubHeadFont.getObjectInt("scale");
|
||||
fontFaces[MLSubHead].extraSpaceAbove = xSubHeadFont.getObjectInt("above");
|
||||
}
|
||||
|
||||
if (xListFont) {
|
||||
const wchar_t *f = xListFont.getw();
|
||||
fontFaces[MLList].font = f != 0 ? f : L"arial";
|
||||
const wchar_t *f = xListFont.getWPtr();
|
||||
fontFaces[MLList].font = f != nullptr ? f : L"arial";
|
||||
fontFaces[MLList].scale = xListFont.getObjectInt("scale");
|
||||
fontFaces[MLList].extraSpaceAbove = xListFont.getObjectInt("above");
|
||||
}
|
||||
|
||||
if (xSubListFont) {
|
||||
const wchar_t *f = xSubListFont.getw();
|
||||
fontFaces[MLSubList].font = f != 0 ? f : L"arial";
|
||||
const wchar_t *f = xSubListFont.getWPtr();
|
||||
fontFaces[MLSubList].font = f != nullptr ? f : L"arial";
|
||||
fontFaces[MLSubList].scale = xSubListFont.getObjectInt("scale");
|
||||
fontFaces[MLSubList].extraSpaceAbove = xSubListFont.getObjectInt("above");
|
||||
}
|
||||
@ -1605,7 +1719,7 @@ void MetaList::load(const xmlobject &xDef) {
|
||||
xDef.getObjects("Filter", f);
|
||||
|
||||
for (size_t k = 0; k<f.size(); k++) {
|
||||
string attrib = f[k].getAttrib("name").get();
|
||||
string attrib = f[k].getAttrib("name").getStr();
|
||||
if (symbolToFilter.count(attrib) == 0) {
|
||||
string err = "Invalid filter X#" + attrib;
|
||||
throw std::exception(err.c_str());
|
||||
@ -1620,13 +1734,29 @@ void MetaList::load(const xmlobject &xDef) {
|
||||
xDef.getObjects("SubFilter", f);
|
||||
|
||||
for (size_t k = 0; k<f.size(); k++) {
|
||||
string attrib = f[k].getAttrib("name").get();
|
||||
string attrib = f[k].getAttrib("name").getStr();
|
||||
if (symbolToSubFilter.count(attrib) == 0) {
|
||||
string err = "Invalid filter X#" + attrib;
|
||||
throw std::exception(err.c_str());
|
||||
}
|
||||
addSubFilter(symbolToSubFilter[attrib]);
|
||||
}
|
||||
|
||||
xmlList imgs;
|
||||
xDef.getObjects("Image", imgs);
|
||||
|
||||
Encoder92 binEncoder;
|
||||
vector<uint8_t> bytes;
|
||||
for (auto& img : imgs) {
|
||||
wstring fileName, id;
|
||||
img.getObjectString("filename", fileName);
|
||||
img.getObjectString("id", id);
|
||||
uint64_t imgId = _wcstoui64(id.c_str(), nullptr, 10);
|
||||
string data = img.getRawStr();
|
||||
binEncoder.decode92(data, bytes);
|
||||
image.provideFromMemory(imgId, fileName, bytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MetaList::getDynamicResults(vector<DynamicResultRef> &resultModules) const {
|
||||
@ -1729,6 +1859,14 @@ bool MetaListContainer::updateResultModule(const DynamicResult &dr, bool updateS
|
||||
return changed;
|
||||
}
|
||||
|
||||
void MetaListContainer::getUsedImages(set<uint64_t>& imgId) const {
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
if (data[i].first == ExternalList) {
|
||||
data[i].second.getUsedImages(imgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetaList::serialize(xmlparser &xml, const string &tagp,
|
||||
const vector< vector<MetaListPost> > &lp) const {
|
||||
xml.startTag(tagp.c_str());
|
||||
@ -1802,6 +1940,8 @@ void MetaListPost::getTypes(vector< pair<wstring, size_t> > &types, int ¤t
|
||||
continue;
|
||||
if (it->first == lAlignNext)
|
||||
continue;
|
||||
if (it->first == lImage)
|
||||
continue;
|
||||
|
||||
types.push_back(make_pair(lang.tl(it->second), it->first));
|
||||
}
|
||||
@ -1895,6 +2035,21 @@ void MetaListPost::serialize(xmlparser &xml) const {
|
||||
xml.write("PackPrevious", packPrevious);
|
||||
xml.write("LimitWidth", limitWidth);
|
||||
|
||||
if (imageWidth != 0)
|
||||
xml.write("ImageWidth", imageWidth);
|
||||
if (imageHeight != 0)
|
||||
xml.write("ImageHeight", imageHeight);
|
||||
|
||||
if (imageOffsetX != 0)
|
||||
xml.write("ImageOffsetX", imageOffsetX);
|
||||
if (imageOffsetY != 0)
|
||||
xml.write("ImageOffsetY", imageOffsetY);
|
||||
|
||||
if (imageStyle != 0)
|
||||
xml.write("ImageStyle", imageStyle);
|
||||
|
||||
if (imageStyleUnderText)
|
||||
xml.writeBool("UnderText", imageStyleUnderText);
|
||||
|
||||
if (font != formatIgnore)
|
||||
xml.write("Font", getFont());
|
||||
@ -1914,7 +2069,7 @@ void MetaListPost::deserialize(const xmlobject &xml) {
|
||||
if (!xml)
|
||||
throw meosException("Ogiltigt filformat");
|
||||
|
||||
wstring tp = xml.getAttrib("Type").wget();
|
||||
wstring tp = xml.getAttrib("Type").getWStr();
|
||||
if (MetaList::symbolToType.count(tp) == 0) {
|
||||
wstring err = L"Invalid type X#" + tp;
|
||||
throw meosException(err);
|
||||
@ -1946,6 +2101,15 @@ void MetaListPost::deserialize(const xmlobject &xml) {
|
||||
limitWidth = xml.getObjectBool("LimitWidth");
|
||||
|
||||
mergeWithPrevious = xml.getObjectInt("MergePrevious") != 0;
|
||||
|
||||
imageWidth = xml.getObjectInt("ImageWidth");
|
||||
imageHeight = xml.getObjectInt("ImageHeight");
|
||||
imageOffsetX = xml.getObjectInt("ImageOffsetX");
|
||||
imageOffsetY = xml.getObjectInt("ImageOffsetY");
|
||||
|
||||
imageStyle = xml.getObjectInt("ImageStyle");
|
||||
imageStyleUnderText = xml.getObjectBool("UnderText");
|
||||
|
||||
xml.getObjectString("TextAdjust", at);
|
||||
|
||||
if (at == L"Right")
|
||||
@ -1970,6 +2134,28 @@ void MetaListPost::deserialize(const xmlobject &xml) {
|
||||
}
|
||||
}
|
||||
|
||||
void MetaList::getUsedImages(set<uint64_t>& imgId) const {
|
||||
for (auto& v1 : data) {
|
||||
for (auto& v2 : v1) {
|
||||
for (auto& v3 : v2) {
|
||||
if (v3.type == lImage) {
|
||||
auto id = v3.getImageId();
|
||||
if (id != 0)
|
||||
imgId.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MetaListPost::getImageId() const {
|
||||
if (type == lImage) {
|
||||
uint64_t imgId = _wcstoui64(getText().c_str(), nullptr, 10);
|
||||
return imgId;
|
||||
}
|
||||
throw meosException("Internal error");
|
||||
}
|
||||
|
||||
map<EPostType, wstring> MetaList::typeToSymbol;
|
||||
map<wstring, EPostType> MetaList::symbolToType;
|
||||
map<oListInfo::EBaseType, string> MetaList::baseTypeToSymbol;
|
||||
@ -2006,6 +2192,7 @@ void MetaList::initSymbols() {
|
||||
typeToSymbol[lClassNumEntries] = L"ClassNumEntries";
|
||||
typeToSymbol[lCourseLength] = L"CourseLength";
|
||||
typeToSymbol[lCourseName] = L"CourseName";
|
||||
typeToSymbol[lCourseNumber] = L"CourseNumber";
|
||||
typeToSymbol[lCourseClimb] = L"CourseClimb";
|
||||
typeToSymbol[lCourseUsage] = L"CourseUsage";
|
||||
typeToSymbol[lCourseUsageNoVacant] = L"CourseUsageNoVacant";
|
||||
@ -2066,6 +2253,7 @@ void MetaList::initSymbols() {
|
||||
typeToSymbol[lResultModuleNumberTeam] = L"ResultModuleNumberTeam";
|
||||
|
||||
typeToSymbol[lRunnerBirthYear] = L"RunnerBirthYear";
|
||||
typeToSymbol[lRunnerBirthDate] = L"RunnerBirthDate";
|
||||
typeToSymbol[lRunnerAge] = L"RunnerAge";
|
||||
typeToSymbol[lRunnerSex] = L"RunnerSex";
|
||||
typeToSymbol[lRunnerNationality] = L"RunnerNationality";
|
||||
@ -2080,6 +2268,10 @@ void MetaList::initSymbols() {
|
||||
|
||||
typeToSymbol[lTeamName] = L"TeamName";
|
||||
typeToSymbol[lTeamStart] = L"TeamStart";
|
||||
typeToSymbol[lTeamCourseName] = L"TeamCourseName";
|
||||
typeToSymbol[lTeamCourseNumber] = L"TeamCourseNumber";
|
||||
typeToSymbol[lTeamLegName] = L"TeamLegName";
|
||||
|
||||
typeToSymbol[lTeamStartCond] = L"TeamStartCond";
|
||||
typeToSymbol[lTeamStartZero] = L"TeamStartZero";
|
||||
|
||||
@ -2160,7 +2352,13 @@ void MetaList::initSymbols() {
|
||||
typeToSymbol[lControlRunnersLeft] = L"ControlRunnersLeft";
|
||||
typeToSymbol[lControlCodes] = L"ControlCodes";
|
||||
|
||||
typeToSymbol[lNumEntries] = L"NumEntries";
|
||||
typeToSymbol[lNumStarts] = L"NumStarts";
|
||||
typeToSymbol[lTotalRunLength] = L"TotalRunLength";
|
||||
typeToSymbol[lTotalRunTime] = L"TotalRunTime";
|
||||
|
||||
typeToSymbol[lLineBreak] = L"LineBreak";
|
||||
typeToSymbol[lImage] = L"Image";
|
||||
|
||||
for (map<EPostType, wstring>::iterator it = typeToSymbol.begin();
|
||||
it != typeToSymbol.end(); ++it) {
|
||||
@ -2175,7 +2373,8 @@ void MetaList::initSymbols() {
|
||||
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeRunner] = "Runner";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeTeam] = "Team";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeClub] = "ClubRunner";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeClubRunner] = "ClubRunner";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeClubTeam] = "ClubTeam";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeCoursePunches] = "CoursePunches";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeAllPunches] = "AllPunches";
|
||||
baseTypeToSymbol[oListInfo::EBaseTypeNone] = "None";
|
||||
@ -2199,6 +2398,7 @@ void MetaList::initSymbols() {
|
||||
|
||||
orderToSymbol[ClassStartTime] = "ClassStartTime";
|
||||
orderToSymbol[ClassStartTimeClub] = "ClassStartTimeClub";
|
||||
orderToSymbol[ClubClassStartTime] = "ClubClassStartTime";
|
||||
orderToSymbol[ClassResult] = "ClassResult";
|
||||
orderToSymbol[ClassDefaultResult] = "ClassDefaultResult";
|
||||
orderToSymbol[ClassCourseResult] = "ClassCourseResult";
|
||||
@ -2323,6 +2523,15 @@ MetaList &MetaListContainer::getList(int index) {
|
||||
return data[index].second;
|
||||
}
|
||||
|
||||
const MetaList& MetaListContainer::getList(EStdListType type) const {
|
||||
auto res = globalIndex.find(type);
|
||||
if (res != globalIndex.end())
|
||||
return getList(res->second);
|
||||
|
||||
throw meosException("List Error: X#Unknown type " + itos(type));
|
||||
}
|
||||
|
||||
|
||||
MetaList &MetaListContainer::addExternal(const MetaList &ml) {
|
||||
data.push_back(make_pair(ExternalList, ml));
|
||||
if (owner)
|
||||
@ -2343,7 +2552,7 @@ void MetaListContainer::save(MetaListType type, xmlparser &xml, const oEvent *oe
|
||||
|
||||
for (size_t k = 0; k<data.size(); k++) {
|
||||
if (data[k].first == type)
|
||||
data[k].second.save(xml, oe);
|
||||
data[k].second.save(xml, false, oe);
|
||||
}
|
||||
if (type == ExternalList) {
|
||||
setupIndex(EFirstLoadedList);
|
||||
@ -2385,7 +2594,7 @@ bool MetaListContainer::load(MetaListType type, const xmlobject &xDef, bool igno
|
||||
xmlattrib ver = xList[k].getAttrib("version");
|
||||
bool newVersion = false;
|
||||
if (ver) {
|
||||
wstring vers = ver.wget();
|
||||
wstring vers = ver.getWStr();
|
||||
if (vers > majVer) {
|
||||
newVersion = true;
|
||||
}
|
||||
@ -2451,6 +2660,7 @@ bool MetaListContainer::load(MetaListType type, const xmlobject &xDef, bool igno
|
||||
it->second.nextList = 0; // Clear relation
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushLevel) {
|
||||
xDef.getObjects("MeOSResultCalculationSet", xList);
|
||||
decltype(freeResultModules) copy;
|
||||
@ -2467,7 +2677,7 @@ bool MetaListContainer::load(MetaListType type, const xmlobject &xDef, bool igno
|
||||
|
||||
freeResultModules.emplace(dr->getTag(), GeneralResultCtr(dr->getTag().c_str(), dr->getName(false), dr));
|
||||
}
|
||||
|
||||
|
||||
if (owner)
|
||||
owner->updateChanged();
|
||||
}
|
||||
@ -2661,7 +2871,7 @@ EStdListType MetaListContainer::getType(const int index) const {
|
||||
}
|
||||
|
||||
void MetaListContainer::getLists(vector<pair<wstring, size_t> > &lists, bool markBuiltIn,
|
||||
bool resultListOnly, bool noTeamList) const {
|
||||
bool resultListOnly, bool noTeamList, bool onlyForSplitPrint) const {
|
||||
lists.clear();
|
||||
size_t currentIx = 0;
|
||||
for (bool i : {false, true}) {
|
||||
@ -2677,6 +2887,9 @@ void MetaListContainer::getLists(vector<pair<wstring, size_t> > &lists, bool mar
|
||||
if ((data[k].first == InternalList) == (i != markBuiltIn))
|
||||
continue;
|
||||
|
||||
if (onlyForSplitPrint && !data[k].second.isSplitPrintList())
|
||||
continue;
|
||||
|
||||
if (data[k].first == InternalList) {
|
||||
if (markBuiltIn)
|
||||
lists.push_back(make_pair(L"[" + lang.tl(data[k].second.getListName()) + L"]", k));
|
||||
@ -2790,11 +3003,15 @@ void MetaListContainer::saveList(int index, const MetaList &ml) {
|
||||
if (data[index].first == InternalList)
|
||||
throw meosException("Invalid list type");
|
||||
|
||||
string oldId = data[index].second.getUniqueId();
|
||||
|
||||
data[index].first = ExternalList;
|
||||
data[index].second = ml;
|
||||
data[index].second.initUniqueIndex();
|
||||
if (owner)
|
||||
if (owner) {
|
||||
owner->updateListReferences(oldId, data[index].second.getUniqueId());
|
||||
owner->updateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MetaList::getFilters(vector< pair<wstring, bool> > &filters) const {
|
||||
@ -2894,6 +3111,7 @@ void MetaList::getSortOrder(bool forceIncludeCustom, vector< pair<wstring, size_
|
||||
if (it->first != Custom || forceIncludeCustom || !resultModule.empty() || currentOrder == Custom)
|
||||
orders.push_back(make_pair(lang.tl(it->second), it->first));
|
||||
}
|
||||
sort(orders.begin(), orders.end());
|
||||
currentOrder = sortOrder;
|
||||
}
|
||||
|
||||
@ -2906,7 +3124,7 @@ void MetaList::getBaseType(vector< pair<wstring, size_t> > &types, int ¤tT
|
||||
continue;
|
||||
types.push_back(make_pair(lang.tl(it->second), it->first));
|
||||
}
|
||||
|
||||
sort(types.begin(), types.end());
|
||||
currentType = listType;
|
||||
}
|
||||
|
||||
@ -2937,6 +3155,7 @@ void MetaList::getSubType(vector< pair<wstring, size_t> > &types, int ¤tTy
|
||||
types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t));
|
||||
}
|
||||
|
||||
sort(types.begin()+1, types.end());
|
||||
currentType = listSubType;
|
||||
}
|
||||
|
||||
@ -3098,7 +3317,8 @@ EPostType MetaList::getTypeFromSymbol(wstring &symb) noexcept {
|
||||
|
||||
void MetaList::fillSymbols(vector < pair<wstring, size_t>> &symb) {
|
||||
for (auto s : symbolToType) {
|
||||
if (s.second == lAlignNext || s.second == lNone || s.second == lLineBreak)
|
||||
if (s.second == lAlignNext || s.second == lNone
|
||||
|| s.second == lLineBreak || s.second == lImage)
|
||||
continue;
|
||||
wstring desc = L"[" + s.first + L"]\t" + lang.tl(s.first);
|
||||
symb.emplace_back(desc, size_t(s.second));
|
||||
@ -3224,19 +3444,44 @@ void MetaListContainer::updateGeneralResult(string tag, const shared_ptr<Dynamic
|
||||
owner->updateChanged();
|
||||
}
|
||||
|
||||
void MetaList::getAutoComplete(const wstring &w, vector<AutoCompleteRecord> &records) {
|
||||
void MetaList::getAutoComplete(const wstring& w, vector<AutoCompleteRecord>& records) {
|
||||
records.clear();
|
||||
wchar_t s_lc[1024];
|
||||
wcscpy_s(s_lc, w.c_str());
|
||||
CharLowerBuff(s_lc, w.length());
|
||||
vector<wstring> ws, ws2;
|
||||
split(w, L" ", ws);
|
||||
|
||||
vector<vector<wchar_t>> s_lc(ws.size());
|
||||
|
||||
for (int j = 0; j < ws.size(); j++) {
|
||||
s_lc[j].resize(ws[j].size() + 1);
|
||||
ws[j] = trim(ws[j]);
|
||||
wcscpy_s(s_lc[j].data(), s_lc[j].size(), ws[j].c_str());
|
||||
CharLowerBuff(s_lc[j].data(), ws[j].length());
|
||||
}
|
||||
|
||||
wstring tl;
|
||||
for (auto &ts : typeToSymbol) {
|
||||
if (ts.first == lNone || ts.first == lAlignNext)
|
||||
for (auto& ts : typeToSymbol) {
|
||||
if (ts.first == lNone || ts.first == lAlignNext || ts.first == lImage)
|
||||
continue;
|
||||
|
||||
|
||||
tl = lang.tl(ts.second);
|
||||
if (filterMatchString(ts.second, s_lc) || filterMatchString(tl, s_lc)) {
|
||||
records.emplace_back(tl, ts.second, ts.first);
|
||||
int score = 0;
|
||||
int fScore;
|
||||
for (int j = 0; j < ws.size(); j++) {
|
||||
if (filterMatchString(ts.second, s_lc[j].data(), fScore))
|
||||
score += 1 + fScore * (ws.size() == 1) ? 2 : 0;
|
||||
|
||||
if (filterMatchString(tl, s_lc[j].data(), fScore)) {
|
||||
score++;
|
||||
split(tl, L" ", ws2);
|
||||
for (int i = 0; i < ws2.size(); i++) {
|
||||
if (filterMatchString(ws2[i], s_lc[j].data(), fScore)) {
|
||||
int diff = std::abs(int(ws2[i].length() - ws[j].length()));
|
||||
score += max(5 - diff, 0) + fScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (score > 0)
|
||||
records.emplace_back(tl, score, ts.second, ts.first);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -94,6 +94,15 @@ private:
|
||||
gdiFonts font;
|
||||
int textAdjust; // 0, textRight, textCenter
|
||||
GDICOLOR color;
|
||||
|
||||
// Image
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
int imageStyle = 0;
|
||||
int imageOffsetX = 0;
|
||||
int imageOffsetY = 0;
|
||||
bool imageStyleUnderText = false;
|
||||
|
||||
public:
|
||||
|
||||
MetaListPost(EPostType type_, EPostType align_ = lNone, int leg_ = -1);
|
||||
@ -109,11 +118,47 @@ public:
|
||||
MetaListPost &limitBlockWidth(bool lim = true) { limitWidth = lim; return *this; }
|
||||
MetaListPost &packWithPrevious(bool pack = true) { packPrevious = pack; return *this; }
|
||||
|
||||
|
||||
MetaListPost &indent(int ind) {minimalIndent = ind; return *this;}
|
||||
|
||||
void getTypes(vector< pair<wstring, size_t> > &types, int ¤tType) const;
|
||||
|
||||
uint64_t getImageId() const;
|
||||
void setImageDimension(int x, int y) {
|
||||
imageWidth = x;
|
||||
imageHeight = y;
|
||||
}
|
||||
int getImageWidth() const {
|
||||
return imageWidth;
|
||||
}
|
||||
int getImageHeight() const {
|
||||
return imageHeight;
|
||||
}
|
||||
void setImageOffset(int x, int y) {
|
||||
imageOffsetX = x;
|
||||
imageOffsetY = y;
|
||||
}
|
||||
int getImageOffsetX() const {
|
||||
return imageOffsetX;
|
||||
}
|
||||
int getImageOffsetY() const {
|
||||
return imageOffsetY;
|
||||
}
|
||||
int getImageStyle() const {
|
||||
return imageStyle;
|
||||
}
|
||||
|
||||
void setImageStyle(int style) {
|
||||
imageStyle = style;
|
||||
}
|
||||
|
||||
bool imageUnderText() const {
|
||||
return imageStyleUnderText;
|
||||
}
|
||||
|
||||
void imageUnderText(bool ut) {
|
||||
imageStyleUnderText = ut;
|
||||
}
|
||||
|
||||
const wstring &getType() const;
|
||||
MetaListPost &setType(EPostType type_) {type = type_; return *this;}
|
||||
EPostType getTypeRaw() const { return type; }
|
||||
@ -236,8 +281,20 @@ private:
|
||||
|
||||
static bool isBreak(int x);
|
||||
|
||||
shared_ptr<SplitPrintListInfo> splitPrintInfo;
|
||||
|
||||
public:
|
||||
|
||||
bool isSplitPrintList() const { return splitPrintInfo != nullptr; }
|
||||
|
||||
const shared_ptr<SplitPrintListInfo>& getSplitPrintInfo() const {
|
||||
return splitPrintInfo;
|
||||
}
|
||||
|
||||
void setSplitPrintInfo(const shared_ptr<SplitPrintListInfo>& info) {
|
||||
splitPrintInfo = info;
|
||||
}
|
||||
|
||||
static wstring encode(EPostType type, const wstring &input, bool &foundSymbol);
|
||||
static const wstring &fromResultModuleNumber(const wstring &in, int nr, wstring &out);
|
||||
|
||||
@ -246,12 +303,21 @@ public:
|
||||
MetaList();
|
||||
virtual ~MetaList() {}
|
||||
|
||||
void getUsedImages(set<uint64_t>& imgId) const;
|
||||
|
||||
static constexpr bool isAllStageType(EPostType type) {
|
||||
return type == lRunnerStagePlace || type == lRunnerStageStatus ||
|
||||
type == lRunnerStageTime || type == lRunnerStageTimeStatus ||
|
||||
type == lRunnerStagePoints || type == lRunnerStageNumber;
|
||||
}
|
||||
|
||||
static constexpr bool isAllLegType(EPostType type) {
|
||||
return type == lTeamCourseName || type == lTeamCourseNumber ||
|
||||
type == lTeamLegName || type == lTeamRunner || type == lTeamRunnerCard ||
|
||||
type == lTeamLegTimeStatus || type == lTeamLegTimeAfter ||
|
||||
type == lTeamPlace || type ==lTeamStart;
|
||||
}
|
||||
|
||||
static constexpr bool isResultModuleOutput(EPostType type) {
|
||||
return type == lResultModuleNumber || type == lResultModuleTime ||
|
||||
type == lResultModuleTimeTeam || type == lResultModuleNumberTeam;
|
||||
@ -329,7 +395,7 @@ public:
|
||||
|
||||
bool isValidIx(size_t gIx, size_t lIx, size_t ix) const;
|
||||
|
||||
void save(xmlparser &xml, const oEvent *oe) const;
|
||||
void save(xmlparser &xml, bool includeImages, const oEvent *oe) const;
|
||||
void load(const xmlobject &xDef);
|
||||
|
||||
void interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, oListInfo &li) const;
|
||||
@ -371,6 +437,8 @@ public:
|
||||
friend class MetaListPost;
|
||||
};
|
||||
|
||||
class Image;
|
||||
|
||||
class MetaListContainer {
|
||||
public:
|
||||
enum MetaListType {InternalList, ExternalList, RemovedList};
|
||||
@ -391,7 +459,6 @@ public:
|
||||
|
||||
virtual ~MetaListContainer();
|
||||
|
||||
|
||||
void getFreeResultModules(vector<pair<string, shared_ptr<DynamicResult>>> &res) const;
|
||||
|
||||
string getUniqueId(EStdListType code) const;
|
||||
@ -400,6 +467,8 @@ public:
|
||||
|
||||
bool updateResultModule(const DynamicResult &res, bool updateSimilar);
|
||||
|
||||
void getUsedImages(set<uint64_t>& imgId) const;
|
||||
|
||||
int getNumParam() const {return listParam.size();}
|
||||
int getNumLists() const {return data.size();}
|
||||
int getNumLists(MetaListType) const;
|
||||
@ -409,6 +478,7 @@ public:
|
||||
|
||||
const MetaList &getList(int index) const;
|
||||
MetaList &getList(int index);
|
||||
const MetaList& getList(EStdListType type) const;
|
||||
|
||||
const oListParam &getParam(int index) const;
|
||||
oListParam &getParam(int index);
|
||||
@ -421,7 +491,8 @@ public:
|
||||
void getLists(vector< pair<wstring, size_t> > &lists,
|
||||
bool markBuiltIn,
|
||||
bool resultListOnly,
|
||||
bool noTeamList) const;
|
||||
bool noTeamList,
|
||||
bool onlyForSplitPrint) const;
|
||||
|
||||
const string &getTag(int index) const;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -563,14 +563,14 @@ int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
w[i] = gdi.scaleLength(w[i]);
|
||||
|
||||
set<wstring> errors;
|
||||
currentResult->prepareCalculations(*oe, false, {}, rr, tr, inputNumber);
|
||||
currentResult->prepareCalculations(*oe, true, {}, rr, tr, inputNumber);
|
||||
|
||||
for (size_t k = 0; k < rr.size(); k++) {
|
||||
int txp = xp;
|
||||
int wi = 0;
|
||||
gdi.addStringUT(yp, txp, 0, rr[k]->getCompleteIdentification(), w[wi]-diff);
|
||||
txp += w[wi++];
|
||||
currentResult->prepareCalculations(*rr[k], false);
|
||||
currentResult->prepareCalculations(*rr[k], true);
|
||||
int rt = 0, pt = 0;
|
||||
RunnerStatus st = StatusUnknown;
|
||||
|
||||
@ -674,7 +674,7 @@ int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) {
|
||||
int wi = 0;
|
||||
gdi.addStringUT(yp, txp, 0, tr[k]->getName(), w[wi]-diff);
|
||||
txp += w[wi++];
|
||||
currentResult->prepareCalculations(*tr[k], false);
|
||||
currentResult->prepareCalculations(*tr[k], true);
|
||||
int rt = 0, pt = 0;
|
||||
RunnerStatus st = StatusUnknown;
|
||||
{
|
||||
@ -920,10 +920,10 @@ void MethodEditor::makeDirty(gdioutput &gdi, DirtyFlag inside) {
|
||||
bool MethodEditor::checkSave(gdioutput &gdi) {
|
||||
if (dirtyInt) {
|
||||
gdioutput::AskAnswer answer = gdi.askCancel(L"Vill du spara ändringar?");
|
||||
if (answer == gdioutput::AnswerCancel)
|
||||
if (answer == gdioutput::AskAnswer::AnswerCancel)
|
||||
return false;
|
||||
|
||||
if (answer == gdioutput::AnswerYes) {
|
||||
if (answer == gdioutput::AskAnswer::AnswerYes) {
|
||||
gdi.sendCtrlMessage("SaveInside");
|
||||
}
|
||||
makeDirty(gdi, ClearDirty);
|
||||
@ -1004,11 +1004,11 @@ void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {
|
||||
if (isTeam)
|
||||
oe->getTeams(art->getClassId(true), tt, false);
|
||||
|
||||
currentResult->prepareCalculations(*oe, false, {art->getClassId(true)}, rr, tt, inputNumber);
|
||||
currentResult->prepareCalculations(*oe, true, {art->getClassId(true)}, rr, tt, inputNumber);
|
||||
gdi_new->addString("", fontMediumPlus, "Debug Output");
|
||||
if (!isTeam) {
|
||||
oRunner &r = *pRunner(art);
|
||||
currentResult->prepareCalculations(r, false);
|
||||
currentResult->prepareCalculations(r, true);
|
||||
int rt = 0, pt = 0;
|
||||
RunnerStatus st = StatusUnknown;
|
||||
gdi.dropLine();
|
||||
@ -1065,7 +1065,7 @@ void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {
|
||||
}
|
||||
else {
|
||||
oTeam &t = *pTeam(art);
|
||||
currentResult->prepareCalculations(t, false);
|
||||
currentResult->prepareCalculations(t, true);
|
||||
int rt = 0, pt = 0;
|
||||
RunnerStatus st = StatusUnknown;
|
||||
gdi.dropLine();
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/************************************************************************
|
||||
MeOS - Orienteering Software
|
||||
Copyright (C) 2009-2022 Melin Software HB
|
||||
Copyright (C) 2009-2023 Melin Software HB
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -29,7 +29,7 @@
|
||||
#include "MeosSQL.h"
|
||||
#include <process.h>
|
||||
|
||||
MySQLReconnect::MySQLReconnect(const wstring &errorIn) : AutoMachine("MySQL-daemon", Machines::mMySQLReconnect), error(errorIn) {
|
||||
MySQLReconnect::MySQLReconnect(const wstring &errorIn) : AutoMachine("MySQL-service", Machines::mMySQLReconnect), error(errorIn) {
|
||||
timeError = getLocalTime();
|
||||
hThread=0;
|
||||
}
|
||||
@ -43,7 +43,7 @@ bool MySQLReconnect::stop() {
|
||||
if (interval==0)
|
||||
return true;
|
||||
|
||||
return MessageBox(0, L"If this daemon is stopped, then MeOS will not reconnect to the network. Continue?",
|
||||
return MessageBox(0, L"If this service is stopped, MeOS will not reconnect to the network. Continue?",
|
||||
L"Warning", MB_YESNO|MB_ICONWARNING)==IDYES;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user