1069 lines
34 KiB
C++
1069 lines
34 KiB
C++
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2019 Melin Software HB
|
|
|
|
This 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 <algorithm>
|
|
|
|
#include "methodeditor.h"
|
|
#include "generalresult.h"
|
|
#include "gdioutput.h"
|
|
#include "meosexception.h"
|
|
#include "gdistructures.h"
|
|
#include "meos_util.h"
|
|
#include "localizer.h"
|
|
#include "gdifonts.h"
|
|
#include "oEvent.h"
|
|
#include "tabbase.h"
|
|
#include "CommDlg.h"
|
|
#include "random.h"
|
|
#include "metalist.h"
|
|
|
|
MethodEditor::MethodEditor(oEvent *oe_) {
|
|
oe = oe_;
|
|
inputNumber = 0;
|
|
currentResult = 0;
|
|
currentIndex = -1;
|
|
dirtyInt = false;
|
|
wasLoadedBuiltIn = false;
|
|
}
|
|
|
|
MethodEditor::~MethodEditor() {
|
|
setCurrentResult(0, L"");
|
|
}
|
|
|
|
void MethodEditor::setCurrentResult(DynamicResult *lst, const wstring &fileSrc) {
|
|
delete currentResult;
|
|
currentResult = lst;
|
|
fileNameSource = fileSrc;
|
|
}
|
|
|
|
int methodCB(gdioutput *gdi, int type, void *data) {
|
|
void *clz = gdi->getData("MethodEditorClz");
|
|
MethodEditor *le = (MethodEditor *)clz;
|
|
BaseInfo *bi = (BaseInfo *)data;
|
|
if (le)
|
|
return le->methodCb(*gdi, type, *bi);
|
|
|
|
throw meosException("Unexpected error");
|
|
}
|
|
|
|
void MethodEditor::show(gdioutput &gdi) {
|
|
oe->loadGeneralResults(true);
|
|
|
|
gdi.setRestorePoint("BeginMethodEdit");
|
|
|
|
gdi.pushX();
|
|
gdi.setCX(gdi.getCX() + gdi.scaleLength(6));
|
|
if (currentResult)
|
|
gdi.addString("", boldLarge, makeDash(L"Result Module - X#") + currentResult->getName(true));
|
|
else
|
|
gdi.addString("", boldLarge, "Edit Result Modules");
|
|
|
|
gdi.setOnClearCb(methodCB);
|
|
gdi.setData("MethodEditorClz", this);
|
|
gdi.dropLine(0.5);
|
|
gdi.fillRight();
|
|
|
|
gdi.addButton("OpenFile", "Importera från fil", methodCB);
|
|
gdi.addButton("OpenInside", "Öppna", methodCB);
|
|
|
|
if (currentResult) {
|
|
gdi.addButton("SaveFile", "Exportera till fil...", methodCB);
|
|
gdi.addButton("SaveInside", "Spara", methodCB);
|
|
gdi.addButton("Remove", "Ta bort", methodCB);
|
|
|
|
makeDirty(gdi, NoTouch);
|
|
}
|
|
|
|
gdi.addButton("NewRules", "New Result Module", methodCB);
|
|
gdi.addButton("Close", "Stäng", methodCB);
|
|
|
|
#ifdef _DEBUG
|
|
gdi.addButton("WriteDoc", "#WriteDoc", methodCB);
|
|
#endif
|
|
gdi.popX();
|
|
gdi.dropLine(2);
|
|
gdi.fillDown();
|
|
|
|
if (currentResult) {
|
|
gdi.dropLine(0.5);
|
|
if (currentResult->getTag().empty())
|
|
currentResult->setTag(uniqueTag("result"));
|
|
|
|
gdi.addInput("Name", currentResult->getName(false), 20, methodCB, L"Name of result module:");
|
|
|
|
string tag = currentResult->getTag();
|
|
vector<int> listIx;
|
|
oe->getListContainer().getListsByResultModule(tag, listIx);
|
|
|
|
string udtag = DynamicResult::undecorateTag(tag);
|
|
gdi.addInput("Tag", gdi.widen(udtag), 20, methodCB, L"Result module identifier:");
|
|
if (!listIx.empty()) {
|
|
gdi.disableInput("Tag");
|
|
gdi.getBaseInfo("Tag").setExtra(1);
|
|
wstring lists = oe->getListContainer().getList(listIx.front()).getListName();
|
|
if (listIx.size() > 1)
|
|
lists += L", ...";
|
|
gdi.addString("", 0, L"Resultatmodulen används i X.#" + lists);
|
|
}
|
|
|
|
wstring desc = currentResult->getDescription();
|
|
if (wasLoadedBuiltIn)
|
|
desc = lang.tl(desc);
|
|
|
|
gdi.addInputBox("Desc", 300, 70, desc, methodCB, L"Description:");
|
|
|
|
gdi.dropLine();
|
|
gdi.fillRight();
|
|
gdi.addSelection("Method", 200, 200, methodCB, L"Edit rule for:");
|
|
vector< pair<DynamicResult::DynamicMethods, string> > mt;
|
|
currentResult->getMethodTypes(mt);
|
|
|
|
for (size_t k = 0; k < mt.size(); k++)
|
|
gdi.addItem("Method", lang.tl(mt[k].second), mt[k].first);
|
|
|
|
gdi.dropLine();
|
|
gdi.addButton("SaveSource", "Save changes", methodCB);
|
|
gdi.addButton("CancelSource", "Cancel", methodCB);
|
|
gdi.addButton("TestRule", "Test Result Module", methodCB);
|
|
gdi.disableInput("SaveSource");
|
|
gdi.disableInput("CancelSource");
|
|
gdi.dropLine(2);
|
|
gdi.popX();
|
|
gdi.fillDown();
|
|
|
|
gdi.setRestorePoint("TestRule");
|
|
}
|
|
|
|
gdi.refresh();
|
|
}
|
|
|
|
bool MethodEditor::checkTag(const string &tag, bool throwError) const {
|
|
vector< pair<int, pair<string, wstring> > > tagNameList;
|
|
oe->getGeneralResults(false, tagNameList, false);
|
|
for (size_t k = 0; k < tag.length(); k++) {
|
|
char c = tag[k];
|
|
if (c == '-' || c == '_' || c == '%')
|
|
continue;
|
|
if (!isalnum(c)) {
|
|
if (throwError)
|
|
throw meosException("Invalid character in tag X.#" + tag);
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
if (tag.empty()) {
|
|
if (throwError)
|
|
throw meosException("Empty tag is invalid");
|
|
else
|
|
return false;
|
|
}
|
|
for (size_t k = 0; k < tagNameList.size(); k++) {
|
|
if (_strcmpi(tagNameList[k].second.first.c_str(), tag.c_str()) == 0) {
|
|
if (throwError)
|
|
throw meosException("The tag X is in use.#" + tag);
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
string MethodEditor::uniqueTag(const string &tag) const {
|
|
vector< pair<int, pair<string, wstring> > > tagNameList;
|
|
oe->getGeneralResults(false, tagNameList, false);
|
|
set<string> tags;
|
|
for (size_t k = 0; k < tagNameList.size(); k++)
|
|
tags.insert(tagNameList[k].second.first);
|
|
|
|
int a = GetRandomNumber(65536);
|
|
srand(GetTickCount());
|
|
int b = rand() % 65536;
|
|
char un[64];
|
|
sprintf_s(un, "-%04X-%04X-", a, b);
|
|
int iter = 0;
|
|
while (tags.count(tag + un + itos(++iter)));
|
|
return tag + un + itos(iter);
|
|
}
|
|
|
|
int MethodEditor::methodCb(gdioutput &gdi, int type, BaseInfo &data) {
|
|
if (type == GUI_BUTTON) {
|
|
ButtonInfo bi = dynamic_cast<ButtonInfo &>(data);
|
|
|
|
if (bi.id == "Cancel") {
|
|
gdi.restore("EditList");
|
|
gdi.enableInput("EditList");
|
|
}
|
|
else if (bi.id == "CloseWindow") {
|
|
gdi.closeWindow();
|
|
}
|
|
else if (bi.id == "WriteDoc") {
|
|
ofstream fout("methoddoc.txt");
|
|
DynamicResult dr;
|
|
dr.declareSymbols(DynamicResult::MRScore, true);
|
|
vector< pair<wstring, size_t> > symbs;
|
|
dr.getSymbols(symbs);
|
|
fout << "#head{" << gdi.toUTF8(lang.tl("Deltagare")) << "}\n#table{2}" << endl;
|
|
for (size_t k = 0; k < symbs.size(); k++) {
|
|
wstring name, desc;
|
|
dr.getSymbolInfo(symbs[k].second, name, desc);
|
|
fout << "{#mono{" << gdi.toUTF8(name) << "}}{" << gdi.toUTF8(lang.tl(desc)) << "}" << endl;
|
|
}
|
|
|
|
dr.declareSymbols(DynamicResult::MTScore, true);
|
|
dr.getSymbols(symbs);
|
|
fout << "#head{" << gdi.toUTF8(lang.tl("Lag")) << "}\n#table{2}" << endl;
|
|
for (size_t k = 0; k < symbs.size(); k++) {
|
|
wstring name, desc;
|
|
dr.getSymbolInfo(symbs[k].second, name, desc);
|
|
fout << "{#mono{" << gdi.toUTF8(name) << "}}{" << gdi.toUTF8(lang.tl(desc)) << "}" << endl;
|
|
}
|
|
}
|
|
else if (bi.id == "NewRules") {
|
|
if (!checkSave(gdi))
|
|
return 0;
|
|
gdi.clearPage(false);
|
|
gdi.setData("MethodEditorClz", this);
|
|
gdi.addString("", boldLarge, "New Set of Result Rules");
|
|
|
|
setCurrentResult(new DynamicResult(), L"");
|
|
wasLoadedBuiltIn = false;
|
|
currentResult->setName(lang.tl("Result Calculation"));
|
|
currentIndex = -1;
|
|
makeDirty(gdi, ClearDirty);
|
|
show(gdi);
|
|
gdi.setInputStatus("Remove", resultIsInstalled());
|
|
}
|
|
else if (bi.id == "SaveFile") {
|
|
if (!currentResult)
|
|
return 0;
|
|
checkChangedSave(gdi);
|
|
|
|
wstring fileName;
|
|
|
|
int ix = 0;
|
|
vector< pair<wstring, wstring> > ext;
|
|
ext.push_back(make_pair(L"xml-data", L"*.rules"));
|
|
fileName = gdi.browseForSave(ext, L"rules", ix);
|
|
if (fileName.empty())
|
|
return 0;
|
|
|
|
saveSettings(gdi);
|
|
wstring path = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource;
|
|
currentResult->save(path);
|
|
fileNameSource = path;
|
|
oe->loadGeneralResults(true);
|
|
makeDirty(gdi, ClearDirty);
|
|
|
|
currentResult->save(fileName);
|
|
//savedFileName = fileName;
|
|
return 1;
|
|
}
|
|
else if (bi.id == "SaveInside") {
|
|
if (!currentResult)
|
|
return 0;
|
|
saveSettings(gdi);
|
|
checkChangedSave(gdi);
|
|
|
|
wstring path = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource;
|
|
currentResult->save(path);
|
|
fileNameSource = path;
|
|
|
|
int nl = oe->getListContainer().getNumLists();
|
|
string utag = DynamicResult::undecorateTag(currentResult->getTag());
|
|
bool doUpdate = false;
|
|
for (int j = 0; j < nl && !doUpdate; j++) {
|
|
if (!oe->getListContainer().isExternal(j))
|
|
continue;
|
|
|
|
const string &mtag = oe->getListContainer().getList(j).getResultModule();
|
|
if (mtag.empty() || currentResult->getTag() == mtag)
|
|
continue;
|
|
|
|
if (utag == DynamicResult::undecorateTag(mtag)) {
|
|
doUpdate = gdi.ask(L"Vill du uppdatera resultatlistorna i den öppande tävlingen?");
|
|
break;
|
|
}
|
|
}
|
|
|
|
oe->synchronize(false);
|
|
oe->getListContainer().updateResultModule(*currentResult, doUpdate);
|
|
|
|
oe->loadGeneralResults(true);
|
|
|
|
oe->synchronize(true);
|
|
|
|
makeDirty(gdi, ClearDirty);
|
|
gdi.setInputStatus("Remove", resultIsInstalled());
|
|
return 1;
|
|
}
|
|
else if (bi.id == "Remove") {
|
|
if (!currentResult)
|
|
return 0;
|
|
if (gdi.ask(L"Vill du ta bort 'X'?#" + currentResult->getName(true))) {
|
|
wstring path = fileNameSource;//getInternalPath(currentResult->getTag());
|
|
wstring rm = path + L".removed";
|
|
DeleteFile(rm.c_str());
|
|
_wrename(path.c_str(), rm.c_str());
|
|
oe->loadGeneralResults(true);
|
|
makeDirty(gdi, ClearDirty);
|
|
setCurrentResult(0, L"");
|
|
gdi.clearPage(false);
|
|
show(gdi);
|
|
}
|
|
return 1;
|
|
}
|
|
else if (bi.id == "OpenFile") {
|
|
if (!checkSave(gdi))
|
|
return 0;
|
|
|
|
vector< pair<wstring, wstring> > ext;
|
|
ext.push_back(make_pair(L"xml-data", L"*.rules"));
|
|
wstring fileName = gdi.browseForOpen(ext, L"rules");
|
|
if (fileName.empty())
|
|
return 0;
|
|
|
|
DynamicResult *tmp = new DynamicResult();
|
|
try {
|
|
tmp->load(fileName);
|
|
}
|
|
catch(...) {
|
|
delete tmp;
|
|
throw;
|
|
}
|
|
|
|
wasLoadedBuiltIn = false;
|
|
setCurrentResult(tmp, L"");
|
|
currentIndex = -1;
|
|
gdi.clearPage(false);
|
|
|
|
//savedFileName = fileName;
|
|
makeDirty(gdi, ClearDirty);
|
|
show(gdi);
|
|
}
|
|
else if (bi.id == "OpenInside") {
|
|
if (!checkSave(gdi))
|
|
return 0;
|
|
|
|
gdi.clearPage(true);
|
|
gdi.setOnClearCb(methodCB);
|
|
gdi.setData("MethodEditorClz", this);
|
|
|
|
gdi.pushX();
|
|
vector< pair<wstring, size_t> > lists;
|
|
//oe->getListContainer().getLists(lists);
|
|
vector< pair<int, pair<string, wstring> > > tagNameList;
|
|
oe->getGeneralResults(true, tagNameList, true);
|
|
for (size_t k = 0; k < tagNameList.size(); k++) {
|
|
string tag = tagNameList[k].second.first;
|
|
string utag = DynamicResult::undecorateTag(tag);
|
|
vector<int> listIx;
|
|
oe->getListContainer().getListsByResultModule(tag, listIx);
|
|
wstring n = tagNameList[k].second.second + L" (" + gdi.widen(utag) + L")";
|
|
|
|
if (listIx.size() > 0) {
|
|
n += L" *";
|
|
}
|
|
|
|
lists.push_back(make_pair(n, tagNameList[k].first));
|
|
}
|
|
sort(lists.begin(), lists.end());
|
|
gdi.fillRight();
|
|
gdi.addSelection("OpenList", 350, 400, methodCB, L"Choose result module:", L"Rader markerade med (*) kommer från en lista i tävlingen.");
|
|
gdi.addItem("OpenList", lists);
|
|
gdi.autoGrow("OpenList");
|
|
gdi.selectFirstItem("OpenList");
|
|
|
|
gdi.dropLine();
|
|
gdi.addButton("DoOpen", "Öppna", methodCB);
|
|
gdi.addButton("DoOpenCopy", "Open a Copy", methodCB);
|
|
|
|
if (!lists.empty()) {
|
|
wstring srcFile;
|
|
|
|
bool ro = dynamic_cast<DynamicResult &>(oe->getGeneralResult(tagNameList.front().second.first, srcFile)).isReadOnly();
|
|
gdi.setInputStatus("DoOpen", !ro);
|
|
}
|
|
else {
|
|
gdi.disableInput("DoOpen");
|
|
gdi.disableInput("DoOpenCopy");
|
|
}
|
|
|
|
gdi.addButton("CancelReload", "Avbryt", methodCB);
|
|
gdi.dropLine(4);
|
|
gdi.popX();
|
|
}
|
|
else if (bi.id == "DoOpen" || bi.id == "DoOpenCopy") {
|
|
ListBoxInfo lbi;
|
|
DynamicResult *dr = 0;
|
|
if (gdi.getSelectedItem("OpenList", lbi)) {
|
|
vector< pair<int, pair<string, wstring> > > tagNameList;
|
|
oe->getGeneralResults(true, tagNameList, false);
|
|
size_t ix = -1;
|
|
for (size_t k = 0; k < tagNameList.size(); k++) {
|
|
if (tagNameList[k].first == lbi.data) {
|
|
ix = k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ix < tagNameList.size()) {
|
|
wstring srcFile;
|
|
DynamicResult &drIn = dynamic_cast<DynamicResult &>(oe->getGeneralResult(tagNameList[ix].second.first, srcFile));
|
|
wasLoadedBuiltIn = drIn.isReadOnly();
|
|
dr = new DynamicResult(drIn);
|
|
if (bi.id == "DoOpenCopy") {
|
|
dr->setTag(uniqueTag("result"));
|
|
dr->setName(lang.tl("Copy of ") + dr->getName(false));
|
|
setCurrentResult(dr, L"");
|
|
}
|
|
else
|
|
setCurrentResult(dr, srcFile);
|
|
}
|
|
|
|
if (bi.id == "DoOpen")
|
|
makeDirty(gdi, ClearDirty);
|
|
else
|
|
makeDirty(gdi, MakeDirty);
|
|
|
|
gdi.clearPage(false);
|
|
show(gdi);
|
|
if (dr) dr->compile(true);
|
|
}
|
|
}
|
|
else if (bi.id == "CancelReload") {
|
|
gdi.clearPage(false);
|
|
show(gdi);
|
|
}
|
|
else if (bi.id == "Close") {
|
|
if (!checkSave(gdi))
|
|
return 0;
|
|
|
|
setCurrentResult(0, L"");
|
|
makeDirty(gdi, ClearDirty);
|
|
currentIndex = -1;
|
|
gdi.getTabs().get(TListTab)->loadPage(gdi);
|
|
return 0;
|
|
}
|
|
else if (bi.id == "SaveSource") {
|
|
DynamicResult::DynamicMethods dm = DynamicResult::DynamicMethods(bi.getExtraInt());
|
|
string src = gdi.narrow(gdi.getText("Source"));
|
|
currentResult->setMethodSource(dm, src);
|
|
gdi.setText("Source", gdi.widen(src));
|
|
}
|
|
else if (bi.id == "CancelSource") {
|
|
checkChangedSave(gdi);
|
|
gdi.restore("NoSourceEdit", true);
|
|
gdi.selectItemByData("Method", -1);
|
|
gdi.disableInput("SaveSource");
|
|
gdi.disableInput("CancelSource");
|
|
}
|
|
else if (bi.id == "TestRule") {
|
|
checkChangedSave(gdi);
|
|
|
|
gdi.restore("TestRule", false);
|
|
gdi.setRestorePoint("TestRule");
|
|
gdi.disableInput("SaveSource");
|
|
gdi.disableInput("CancelSource");
|
|
gdi.selectItemByData("Method", -1);
|
|
|
|
int y = gdi.getCY();
|
|
vector<pRunner> r;
|
|
vector<pTeam> t;
|
|
oe->getRunners(0, 0, r, true);
|
|
oe->getTeams(0, t, true);
|
|
vector<pRunner> rr;
|
|
vector<pTeam> tr;
|
|
for (size_t k = 0; k < r.size(); k++) {
|
|
if (r[k]->getStatus() != StatusUnknown)
|
|
rr.push_back(r[k]);
|
|
}
|
|
for (size_t k = 0; k < t.size(); k++) {
|
|
if (t[k]->getStatus() != StatusUnknown)
|
|
tr.push_back(t[k]);
|
|
else {
|
|
for (int j = 0; j < t[k]->getNumRunners(); j++) {
|
|
if (t[k]->getRunner(j) && t[k]->getRunner(j)->getStatus() != StatusUnknown) {
|
|
tr.push_back(t[k]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
gdi.fillDown();
|
|
if (tr.size() + rr.size() == 0) {
|
|
gdi.addString("", 1, "Tävlingen innehåller inga resultat").setColor(colorRed);
|
|
}
|
|
else
|
|
gdi.addString("", 1, "Applying rules to the current competition");
|
|
gdi.dropLine(0.5);
|
|
int xp = gdi.getCX();
|
|
int yp = gdi.getCY();
|
|
int diff = gdi.scaleLength(3);
|
|
const int w[5] = {200, 70, 70, 70, 85};
|
|
set<wstring> errors;
|
|
currentResult->prepareCalculations(*oe, tr.size()>0, 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]);
|
|
int rt = 0, pt = 0;
|
|
RunnerStatus st = StatusUnknown;
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
st = currentResult->deduceStatus(*rr[k]);
|
|
str = oe->formatStatus(st);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
RECT rc = ti.textRect;
|
|
gdi.addToolTip("", err, 0, &rc);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
rt = currentResult->deduceTime(*rr[k], rr[k]->getStartTime());
|
|
str = formatTime(rt);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
pt = currentResult->deducePoints(*rr[k]);
|
|
str = itow(pt);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
int score = currentResult->score(*rr[k], st, rt, pt, false);
|
|
str = itow(score);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
rr[k]->setTempResultZero(oAbstractRunner::TempResult(st, rr[k]->getStartTime(), rt, pt));
|
|
|
|
gdi.addString("Debug", yp, txp, 0, "Debug...", 0, methodCB).setColor(colorGreen).setExtra(rr[k]->getId());
|
|
yp += gdi.getLineHeight();
|
|
}
|
|
|
|
yp += gdi.getLineHeight();
|
|
|
|
if (tr.size() > 0) {
|
|
gdi.addString("", yp, xp, 1, "Lag");
|
|
yp += gdi.getLineHeight();
|
|
}
|
|
else {
|
|
}
|
|
|
|
for (size_t k = 0; k < tr.size(); k++) {
|
|
int txp = xp;
|
|
int wi = 0;
|
|
gdi.addStringUT(yp, txp, 0, tr[k]->getName(), w[wi]-diff);
|
|
txp += w[wi++];
|
|
currentResult->prepareCalculations(*tr[k]);
|
|
int rt = 0, pt = 0;
|
|
RunnerStatus st = StatusUnknown;
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
st = currentResult->deduceStatus(*tr[k]);
|
|
str = oe->formatStatus(st);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
rt = currentResult->deduceTime(*tr[k]);
|
|
str = formatTime(rt);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
pt = currentResult->deducePoints(*tr[k]);
|
|
str = itow(pt);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
|
|
{
|
|
wstring err;
|
|
wstring str;
|
|
try {
|
|
int score = currentResult->score(*tr[k], st, rt, pt);
|
|
str = itow(score);
|
|
}
|
|
catch (meosException &ex) {
|
|
err = ex.wwhat();
|
|
errors.insert(ex.wwhat());
|
|
str = L"Error";
|
|
}
|
|
TextInfo &ti = gdi.addStringUT(yp, txp, 0, str, w[wi]-diff);
|
|
if (!err.empty()) {
|
|
ti.setColor(colorRed);
|
|
gdi.addToolTip("", err, 0, &ti.textRect);
|
|
}
|
|
txp += w[wi++];
|
|
}
|
|
|
|
gdi.addString("Debug", yp, txp, 0, "Debug...", 0, methodCB).setColor(colorGreen).setExtra(-tr[k]->getId());
|
|
|
|
yp += gdi.getLineHeight();
|
|
}
|
|
|
|
gdi.scrollTo(0, y);
|
|
gdi.refresh();
|
|
}
|
|
}
|
|
else if (type == GUI_LISTBOX) {
|
|
ListBoxInfo &lbi = dynamic_cast<ListBoxInfo &>(data);
|
|
if (lbi.id == "Method") {
|
|
checkChangedSave(gdi);
|
|
|
|
DynamicResult::DynamicMethods m = DynamicResult::DynamicMethods(lbi.data);
|
|
const string &src = currentResult->getMethodSource(m);
|
|
gdi.enableInput("SaveSource");
|
|
gdi.enableInput("CancelSource");
|
|
gdi.getBaseInfo("SaveSource").setExtra(lbi.data);
|
|
|
|
if (!gdi.hasField("Source")) {
|
|
gdi.fillRight();
|
|
gdi.restore("TestRule", false);
|
|
gdi.pushX();
|
|
gdi.setRestorePoint("NoSourceEdit");
|
|
gdi.addInputBox("Source", 450, 300,
|
|
gdi.widen(src),
|
|
methodCB, L"Source code:").setFont(gdi, monoText);
|
|
gdi.fillDown();
|
|
gdi.setCX(gdi.getCX() + gdi.getLineHeight());
|
|
gdi.addListBox("Symbols", 450, 300-20, methodCB, L"Available symbols:");
|
|
gdi.setTabStops("Symbols", 180);
|
|
gdi.addString("SymbInfo", gdi.getCY(), gdi.getCX(), 0, "", 350, 0);
|
|
gdi.popX();
|
|
gdi.setCY(gdi.getHeight());
|
|
gdi.dropLine();
|
|
gdi.scrollToBottom();
|
|
}
|
|
else {
|
|
gdi.setText("Source", gdi.widen(src));
|
|
}
|
|
|
|
currentResult->declareSymbols(m, true);
|
|
vector< pair<wstring, size_t> > symb;
|
|
currentResult->getSymbols(symb);
|
|
gdi.addItem("Symbols", symb);
|
|
}
|
|
else if (lbi.id == "Symbols") {
|
|
wstring name, desc;
|
|
currentResult->getSymbolInfo(lbi.data, name, desc);
|
|
gdi.setText("SymbInfo", name + L":" + lang.tl(desc) + L".", true);
|
|
}
|
|
else if (lbi.id == "OpenList") {
|
|
vector< pair<int, pair<string, wstring> > > tagNameList;
|
|
oe->getGeneralResults(true, tagNameList, false);
|
|
size_t ix = -1;
|
|
for (size_t k = 0; k < tagNameList.size(); k++) {
|
|
if (tagNameList[k].first == lbi.data) {
|
|
ix = k;
|
|
break;
|
|
}
|
|
}
|
|
wstring srcFile;
|
|
if (ix < tagNameList.size()) {
|
|
bool ro = dynamic_cast<DynamicResult &>(oe->getGeneralResult(tagNameList[ix].second.first, srcFile)).isReadOnly();
|
|
gdi.setInputStatus("DoOpen", !ro);
|
|
}
|
|
else
|
|
gdi.setInputStatus("DoOpen", true);
|
|
}
|
|
}
|
|
else if (type == GUI_LISTBOXSELECT) {
|
|
ListBoxInfo &lbi = dynamic_cast<ListBoxInfo &>(data);
|
|
if (lbi.id == "Symbols") {
|
|
wstring name, desc;
|
|
currentResult->getSymbolInfo(lbi.data, name, desc);
|
|
gdi.replaceSelection("Source", name);
|
|
}
|
|
}
|
|
else if (type==GUI_CLEAR) {
|
|
return checkSave(gdi);
|
|
}
|
|
else if (type == GUI_INPUT) {
|
|
InputInfo &ii = dynamic_cast<InputInfo &>(data);
|
|
if (ii.changed())
|
|
makeDirty(gdi, MakeDirty);
|
|
|
|
}
|
|
else if (type == GUI_LINK) {
|
|
TextInfo &ti = dynamic_cast<TextInfo &>(data);
|
|
|
|
if (ti.id == "Debug") {
|
|
int id = ti.getExtraInt();
|
|
if (id > 0) {
|
|
debug(gdi, id, false);
|
|
}
|
|
else if (id < 0) {
|
|
debug(gdi, -id, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void MethodEditor::saveSettings(gdioutput &gdi) {
|
|
wstring name = gdi.getText("Name");
|
|
string tag;
|
|
const bool updateTag = gdi.getBaseInfo("Tag").getExtraInt() == 0;
|
|
if (updateTag)
|
|
tag = gdi.narrow(gdi.getText("Tag"));
|
|
else
|
|
tag = currentResult->getTag();
|
|
|
|
wstring desc = gdi.getText("Desc");
|
|
|
|
if (_strcmpi(currentResult->getTag().c_str(), tag.c_str()) != 0) {
|
|
checkTag(tag, true);
|
|
wstring oldPath = fileNameSource.empty() ? getInternalPath(currentResult->getTag()) : fileNameSource;
|
|
wstring path = getInternalPath(tag);
|
|
_wrename(oldPath.c_str(), path.c_str());
|
|
fileNameSource = path;
|
|
}
|
|
|
|
currentResult->setTag(tag);
|
|
currentResult->setName(name);
|
|
currentResult->setDescription(desc);
|
|
gdi.setText("Name", name);
|
|
gdi.setText("Tag", gdi.widen(tag));
|
|
gdi.setText("Desc", desc);
|
|
}
|
|
|
|
void MethodEditor::checkUnsaved(gdioutput &gdi) {
|
|
/*if (gdi.hasData("IsEditing")) {
|
|
if (gdi.isInputChanged("")) {
|
|
gdi.setData("NoRedraw", 1);
|
|
gdi.sendCtrlMessage("Apply");
|
|
}
|
|
}
|
|
if (gdi.hasData("IsEditingList")) {
|
|
if (gdi.isInputChanged("")) {
|
|
gdi.setData("NoRedraw", 1);
|
|
gdi.sendCtrlMessage("ApplyListProp");
|
|
}
|
|
}*/
|
|
}
|
|
|
|
|
|
void MethodEditor::makeDirty(gdioutput &gdi, DirtyFlag inside) {
|
|
if (inside == MakeDirty)
|
|
dirtyInt = true;
|
|
else if (inside == ClearDirty)
|
|
dirtyInt = false;
|
|
|
|
if (gdi.hasField("SaveInside")) {
|
|
gdi.setInputStatus("SaveInside", dirtyInt);
|
|
gdi.setInputStatus("Remove", resultIsInstalled());
|
|
}
|
|
}
|
|
|
|
bool MethodEditor::checkSave(gdioutput &gdi) {
|
|
if (dirtyInt) {
|
|
gdioutput::AskAnswer answer = gdi.askCancel(L"Vill du spara ändringar?");
|
|
if (answer == gdioutput::AnswerCancel)
|
|
return false;
|
|
|
|
if (answer == gdioutput::AnswerYes) {
|
|
gdi.sendCtrlMessage("SaveInside");
|
|
}
|
|
makeDirty(gdi, ClearDirty);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MethodEditor::checkChangedSave(gdioutput &gdi) {
|
|
if (gdi.hasField("Source")) {
|
|
gdi.getText("Source");
|
|
if (dynamic_cast<InputInfo &>(gdi.getBaseInfo("Source")).changed() &&
|
|
gdi.ask(L"Save changes in rule code?")) {
|
|
DynamicResult::DynamicMethods dm = DynamicResult::DynamicMethods(gdi.getExtraInt("SaveSource"));
|
|
string src = gdi.narrow(gdi.getText("Source"));
|
|
currentResult->setMethodSource(dm, src);
|
|
gdi.setText("Source", gdi.widen(src));
|
|
}
|
|
}
|
|
}
|
|
extern gdioutput *gdi_main;
|
|
|
|
wstring MethodEditor::getInternalPath(const string &tag) {
|
|
string udTag = DynamicResult::undecorateTag(tag);
|
|
wstring resFile;
|
|
if (udTag == tag)
|
|
resFile = gdi_main->widen(tag) + L".rules";
|
|
else
|
|
resFile = L"imp_" + gdi_main->widen(udTag) + L".rules";
|
|
|
|
wchar_t path[260];
|
|
getUserFile(path, resFile.c_str());
|
|
return path;
|
|
}
|
|
|
|
bool MethodEditor::resultIsInstalled() const {
|
|
if (!currentResult || fileNameSource.empty())
|
|
return false;
|
|
|
|
string tag = currentResult->getTag();
|
|
vector<int> listIx;
|
|
oe->getListContainer().getListsByResultModule(tag, listIx);
|
|
|
|
if (!listIx.empty())
|
|
return false; // Used in a list in this competition
|
|
|
|
//string path = getInternalPath(currentResult->getTag());
|
|
return fileExist(fileNameSource.c_str());
|
|
}
|
|
|
|
void MethodEditor::debug(gdioutput &gdi_in, int id, bool isTeam) {
|
|
|
|
oAbstractRunner *art = 0;
|
|
if (isTeam)
|
|
art = oe->getTeam(id);
|
|
else
|
|
art = oe->getRunner(id, 0);
|
|
|
|
if (!art || !currentResult)
|
|
throw meosException("Internal error");
|
|
|
|
gdioutput *gdi_new = getExtraWindow("debug", true);
|
|
wstring title = lang.tl(L"Debug X for Y#" + currentResult->getName(false) + L"#" + art->getName());
|
|
|
|
if (!gdi_new)
|
|
gdi_new = createExtraWindow("debug", title,
|
|
gdi_in.scaleLength(500) );
|
|
else
|
|
gdi_new->setWindowTitle(title);
|
|
|
|
gdi_new->clearPage(false);
|
|
gdi_new->setData("MethodEditorClz", this);
|
|
gdioutput &gdi = *gdi_new;
|
|
currentResult->prepareCalculations(*oe, isTeam, inputNumber);
|
|
gdi_new->addString("", fontMediumPlus, "Debug Output");
|
|
if (!isTeam) {
|
|
oRunner &r = *pRunner(art);
|
|
currentResult->prepareCalculations(r);
|
|
int rt = 0, pt = 0;
|
|
RunnerStatus st = StatusUnknown;
|
|
gdi.dropLine();
|
|
try {
|
|
st = currentResult->deduceStatus(r);
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
|
|
gdi.addStringUT(1, L"ComputedStatus: " + oe->formatStatus(st)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Status Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceRStatus))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
|
|
try {
|
|
rt = currentResult->deduceTime(r, r.getStartTime());
|
|
gdi.addStringUT(1, L"ComputedTime: " + formatTime(rt)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Time Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceRTime))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
|
|
try {
|
|
pt = currentResult->deducePoints(r);
|
|
gdi.addStringUT(1, "ComputedPoints: " + itos(pt)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Points Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceRPoints))
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
|
|
try {
|
|
int score = currentResult->score(r, st, rt, pt, false);
|
|
gdi.addStringUT(1, "ComputedScore: " + itos(score)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Score Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MRScore))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
}
|
|
else {
|
|
oTeam &t = *pTeam(art);
|
|
currentResult->prepareCalculations(t);
|
|
int rt = 0, pt = 0;
|
|
RunnerStatus st = StatusUnknown;
|
|
gdi.dropLine();
|
|
try {
|
|
st = currentResult->deduceStatus(t);
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
|
|
gdi.addStringUT(1, L"ComputedStatus: " + oe->formatStatus(st)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Status Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceTStatus))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
|
|
try {
|
|
rt = currentResult->deduceTime(t);
|
|
gdi.addStringUT(1, L"ComputedTime: " + formatTime(rt)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Time Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceRTime))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
|
|
try {
|
|
pt = currentResult->deducePoints(t);
|
|
gdi.addStringUT(1, "ComputedPoints: " + itos(pt)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Points Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MDeduceTPoints))
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
|
|
try {
|
|
int score = currentResult->score(t, st, rt, pt);
|
|
gdi.addStringUT(1, "ComputedScore:" + itos(score)).setColor(colorGreen);
|
|
}
|
|
catch (meosException &ex) {
|
|
currentResult->debugDumpVariables(gdi, true);
|
|
wstring err = lang.tl(ex.wwhat());
|
|
gdi.addString("", 0, L"Status Calculation Failed: X#" + err).setColor(colorRed);
|
|
}
|
|
if (currentResult->hasMethod(DynamicResult::MTScore))
|
|
currentResult->debugDumpVariables(gdi, false);
|
|
}
|
|
|
|
gdi.addButton("CloseWindow", "Stäng", methodCB);
|
|
gdi.refresh();
|
|
}
|