/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2024 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "stdafx.h"
#include "gdioutput.h"
#include "qf_editor.h"
#include "qualification_final.h"
#include "localizer.h"
#include "oClass.h"
#include "meosexception.h"
#include "TabBase.h"
QFEditor::QFEditor() {
emptyScheme();
}
QFEditor::~QFEditor() = default;
void QFEditor::emptyScheme() {
currentQF = make_shared(0, 0);
data.clear();
data.resize(2, { 1, {} });
data[0].second.emplace_back(lang.tl("Kval"));
data[1].second.emplace_back(lang.tl("Final"));
numLevels = 2;
makeDirty(DirtyFlag::ClearDirty, DirtyFlag::ClearDirty);
}
void QFEditor::load(const shared_ptr& qf) {
currentQF = make_shared(*qf);
data.clear();
data.resize(currentQF->getNumLevels());
for (int j = 0; j < currentQF->getNumClasses(); j++) {
int level = currentQF->getLevel(j+1);
data.at(level).second.push_back(currentQF->getInstance(j));
data[level].first++;
}
numLevels = data.size();
}
void QFEditor::makeQF() {
vector linear;
for (int j = 0; j < numLevels; j++) {
for (int i = 0; i < data[j].first; i++) {
linear.push_back(data[j].second[i]);
linear.back().level = j;
}
}
currentQF->setClasses(linear);
}
void QFEditor::show(gdioutput& gdi) {
gdi.clearPage(false);
gdi.pushX();
gdi.fillRight();
gdi.addButton("CloseEditor", "Stäng").setHandler(this);
gdi.addButton("New", "Nytt").setHandler(this);
gdi.addButton("Load", "Ladda").setHandler(this);
gdi.addButton("Save", "Exportera").setHandler(this);
if (cls)
gdi.addButton("Use", L"Use in X#" + cls->getName()).setHandler(this);
gdi.popX();
updateActions(gdi);
gdi.fillDown();
gdi.dropLine(3);
gdi.addSelection("Levels", 100, 100, nullptr, L"Antal nivåer:").setHandler(this);
vector> levels;
for (int i = 2; i <= 10; i++)
levels.emplace_back(itow(i), i);
gdi.setItems("Levels", levels);
gdi.selectItemByData("Levels", numLevels);
gdi.autoGrow("Levels");
gdi.setRestorePoint("LevelView");
showLevels(gdi);
gdi.refresh();
}
void QFEditor::showLevels(gdioutput& gdi) const {
for (int level = 0; level < numLevels; level++) {
showLevel(gdi, level, data[level].first, data[level].second);
}
}
void QFEditor::showLevel(gdioutput& gdi, int level, size_t numRaces, const vector& classes) const {
const int cxBase = gdi.getCX();
int cy = gdi.getCY();
gdi.setRestorePoint("Level" + itos(level));
gdi.fillDown();
RECT rcR = { cxBase, cy, cxBase + gdi.scaleLength(400), cy + gdi.scaleLength(2) };
gdi.addRectangle(rcR, colorDarkBlue);
gdi.addString("", fontMediumPlus, "Nivå X#" + itos(level + 1));
string cKey = "NumCls" + itos(level);
gdi.addSelection(cKey, 100, 100, nullptr, L"Antal klasser:").setHandler(this).setExtra(level);
vector> levels;
for (int i = 1; i <= 32; i++)
levels.emplace_back(itow(i), i);
gdi.setItems(cKey, levels);
gdi.autoGrow(cKey.c_str());
gdi.selectItemByData(cKey, numRaces);
bool rankBased = classes.size() > 0 && classes[0].rankLevel;
if (level > 0) {
gdi.addCheckbox("Rank" + itos(level), "Klass efter ranking", nullptr, rankBased,
"Använd ranking istället för placering i kval för att placera kvalificerade löpare i klasser").setExtra(level).setHandler(this);
}
// auto rc = gdi.getDimensionSince("Level" + itos(level));
gdi.setCX(gdi.scaleLength(230));
const int cxCls = gdi.getCX();
int cx = cxCls;
gdi.fillDown();
cy += gdi.scaleLength(10);
const int w = gdi.scaleLength(24 * 10);
int ww, hh;
gdi.getTargetDimension(ww, hh);
ww = max(ww, gdi.scaleLength(500));
for (int i = 0; i < numRaces; i++) {
gdi.setCY(cy);
gdi.setCX(cx);
string CK = getKeyTag(level, i);
auto& ref = gdi.addInput("Name" + CK, classes[i].name.empty() ? wstring(L"???") : classes[i].name, 24, nullptr,
L"Klass X (namnsuffix):#" + itow(i + 1));
ref.setHandler(this).setExtra(code(level, i));
if (level > 0) {
gdi.addString("QInfo" + CK, 0, classes[i].getQualInfo());
gdi.addButton("Edit", "Redigera...").setHandler(this).setExtra(code(level, i));
}
cx += w;
if (cx + w > ww) {
cx = cxCls;
gdi.dropLine(2);
cy = gdi.getCY();
}
}
gdi.dropLine(3);
gdi.setCX(cxBase);
}
void QFEditor::loadQualificationView(gdioutput& gdi, const QFClass& cls, int cCode) {
gdi.clearPage(false);
gdi.fillDown();
gdi.addString("", boldLarge, L"Kvalificeringsregler för X#" + cls.name);
gdi.pushY();
gdi.setRestorePoint("X");
gdi.addListBox("Rules", 120, 150, nullptr, L"Regler").setExtra(cCode).setHandler(this);
gdi.setItems("Rules", getRules(cls));
gdi.addButton("RemoveRule", "Ta bort").setHandler(this).setExtra(cCode);
gdi.disableInput("RemoveRule");
gdi.popY();
gdi.dropLine();
auto rc = gdi.getDimensionSince("X");
gdi.setCX(rc.right + gdi.scaleLength(10));
rcRuleForm.left = gdi.getCX();
rcRuleForm.top = gdi.getCY();
gdi.dropLine(0.8);
gdi.setCX(rcRuleForm.left + gdi.scaleLength(10));
gdi.pushX();
gdi.fillDown();
gdi.addString("", fontMediumPlus, "Lägg till regler");
gdi.dropLine();
gdi.addSelection("RuleType", 200, 100).setHandler(this).setExtra(cCode);
vector> ruleType;
for (auto* type : { "Klass / placering", "Bästa tid", "Övriga okvalificerade"}) {
ruleType.emplace_back(lang.tl(type), ruleType.size());
}
gdi.setItems("RuleType", ruleType);
gdi.selectFirstItem("RuleType");
gdi.setRestorePoint("RuleType");
//other.emplace_back(lang.tl("Inga"), 0);
//gdi.addString("", gdiFonts::boldText, "Klass / placering");
addRuleClassPlace(cCode, gdi);
/*gdi.dropLine(2.5);
rcE.bottom = gdi.getCY();
rcE.right = gdi.getWidth();
gdi.addRectangle(rcE, GDICOLOR::colorLightCyan);
gdi.dropLine();
gdi.setCX(rcE.right - gdi.scaleLength(75));
gdi.setCY(gdi.getHeight());
gdi.addButton("Close", "Stäng").setHandler(this);
gdi.refresh();*/
}
void QFEditor::addRuleClassPlace(int cCode, gdioutput& gdi) {
pair levelClass = decode(cCode);
gdi.addSelection("Classes", 150, 200, nullptr, L"Kvalklass:");
if (levelClass.first > 0 && levelClass.first < data.size()) {
vector> prevLevel;
for (int i = levelClass.first - 1; i >= 0; i--) {
auto& dLine = data[i];
for (int j = 0; j < dLine.first; j++)
prevLevel.emplace_back(dLine.second[j].name, code(i, j));
}
gdi.setItems("Classes", prevLevel);
gdi.autoGrow("Classes");
gdi.selectFirstItem("Classes");
}
gdi.fillRight();
gdi.addInput("Places", L"", 10, nullptr, L"Placeringar");
gdi.fillDown();
gdi.dropLine(0.9);
gdi.addButton("AddClassPlace", "Lägg till").setHandler(this).setExtra(cCode);
gdi.popX();
endAddRuleForm(gdi);
}
void QFEditor::addRuleTime(int cCode, gdioutput& gdi) {
gdi.dropLine();
gdi.addString("", gdiFonts::boldText, "Bästa tid");
gdi.addButton("AddBestTime", "Lägg till").setHandler(this).setExtra(cCode);
endAddRuleForm(gdi);
}
void QFEditor::addRuleOther(int cCode, gdioutput &gdi) {
// gdi.addString("", gdiFonts::boldText, "Övriga okvalificerade:");
gdi.pushX();
gdi.fillRight();
gdi.addSelection("Other", 100, 200).setExtra(cCode).setHandler(this);
vector> other;
other.emplace_back(lang.tl("Inga"), 0);
other.emplace_back(lang.tl("Alla"), 1);
other.emplace_back(lang.tl("N bästa"), 2);
other.emplace_back(lang.tl("Tidskval"), 3);
gdi.setItems("Other", other);
gdi.autoGrow("Other");
gdi.addButton("AddOther", "Lägg till").setHandler(this).setExtra(cCode);
gdi.popX();
gdi.dropLine(3);
QFClass& cls = getQFClass(cCode);
int toSel = 1;
if (cls.extraQualification == QFClass::ExtraQualType::All)
toSel = 1;
else if (cls.extraQualification == QFClass::ExtraQualType::NBest)
toSel = 2;
else if (cls.extraQualification == QFClass::ExtraQualType::TimeLimit)
toSel = 3;
gdi.selectItemByData("Other", toSel);
extraSelPosX = gdi.getCX();
extraSelPosY = gdi.getCY();
updateExtraField(gdi, cls, cCode);
gdi.setCY(extraSelPosY);
gdi.dropLine(3);
endAddRuleForm(gdi);
}
void QFEditor::endAddRuleForm(gdioutput &gdi) {
gdi.dropLine(2.5);
rcRuleForm.bottom = gdi.getCY();
rcRuleForm.right = gdi.getWidth();
gdi.addRectangle(rcRuleForm, GDICOLOR::colorLightCyan);
gdi.dropLine();
gdi.setCX(rcRuleForm.right - gdi.scaleLength(75));
gdi.setCY(gdi.getHeight());
gdi.addButton("Close", "Stäng").setHandler(this);
gdi.refresh();
}
void QFEditor::updateExtraField(gdioutput& gdi, const QFClass& cls, int code) {
int type = gdi.getSelectedItem("Other").first;
if (type == 2) {
wstring def = cls.extraQualification == QFClass::ExtraQualType::NBest ? itow(cls.extraQualData) : L"0";
if (!gdi.hasWidget("NBest"))
gdi.addInput(extraSelPosX, extraSelPosY, "NBest", def, 6).setHandler(this).setExtra(code);
else
gdi.setText("NBest", def)->setExtra(code);
}
else if (gdi.hasWidget("NBest"))
gdi.removeWidget("NBest");
if (type == 3) {
wstring def = cls.extraQualification == QFClass::ExtraQualType::TimeLimit ?
formatTimeMS(cls.extraQualData, false) : L"0:00";
if (!gdi.hasWidget("TimeLimit"))
gdi.addInput(extraSelPosX, extraSelPosY, "TimeLimit", def , 6).setHandler(this).setExtra(code);
else
gdi.setText("TimeLimit", def)->setExtra(code);
}
else if (gdi.hasWidget("TimeLimit"))
gdi.removeWidget("TimeLimit");
}
vector> QFEditor::getRules(const QFClass& cls) const {
vector> qf;
for (int j = 0; j < cls.qualificationMap.size(); j++) {
auto& q = cls.qualificationMap[j];
int qIx = q.first;
pair ix = getLevelIndexFromLinear(qIx);
if (ix.first == -1)
qf.emplace_back(L"???", -1);
else {
qf.emplace_back(itow(j+1) + L": " + data[ix.first].second[ix.second].name + L" / " + itow(q.second), j);
}
}
int base = cls.qualificationMap.size() + 1;
for (int j = 0; j < cls.numTimeQualifications; j++) {
qf.emplace_back(itow(base++) + lang.tl(" Bästa tid"), 1000 + j);
}
if (cls.extraQualification == QFClass::ExtraQualType::All)
qf.emplace_back(itow(base++) + lang.tl(" Alla övriga"), 10000);
else if(cls.extraQualification == QFClass::ExtraQualType::NBest)
qf.emplace_back(itow(base++) + lang.tl(" X bästa#" + itos(cls.extraQualData) ), 10000);
else if (cls.extraQualification == QFClass::ExtraQualType::TimeLimit)
qf.emplace_back(itow(base++) + lang.tl(L" Tidskval: X#" + formatTimeMS(cls.extraQualData, false)), 10000);
return qf;
}
QFClass& QFEditor::getQFClass(int id) {
auto key = decode(id);
if (key.first < data.size() && key.second < data[key.first].second.size()) {
return data[key.first].second[key.second];
}
throw meosException("Internal error");
}
const QFClass& QFEditor::getQFClass(int id) const {
return const_cast(this)->getQFClass(id);
}
int QFEditor::getLinearIndex(int level, int ix) const {
int lx = 0;
for (int j = 0; j <= level; j++) {
if (j < level)
lx += data[j].first;
else
return lx + ix + 1; // One indexed
}
return -1;
}
pair QFEditor::getLevelIndexFromLinear(int linearIndex) const {
int lx = 0;
for (int j = 0; j <= numLevels; j++) {
if (lx + data[j].first < linearIndex)
lx += data[j].first;
else {
return make_pair(j, linearIndex - lx - 1); // linearIndex is one indexed
}
}
return make_pair(-1, -1);
}
vector> QFEditor::getLevelIndex() const {
vector> out;
out.emplace_back(-1, -1);
for (int j = 0; j < numLevels; j++) {
for (int i = 0; i < data[j].first; i++)
out.emplace_back(j+1, i+1);
}
return out;
}
void QFEditor::updateLevelMap(const vector>& oldIndex) {
auto newIndex = getLevelIndex();
map, int> levelMap;
for (int j = 1; j < newIndex.size(); j++)
levelMap[newIndex[j]] = j;
for (auto& d : data) {
for (auto &dc : d.second) {
for (auto& clpPlace : dc.qualificationMap) {
if (clpPlace.first < oldIndex.size()) {
auto res = levelMap.find(oldIndex[clpPlace.first]);
if (res == levelMap.end())
clpPlace.first = -1;
else
clpPlace.first = res->second;
}
else {
clpPlace.first = -1;
}
}
auto it = remove_if(dc.qualificationMap.begin(), dc.qualificationMap.end(), [](auto v)->bool {return v.first == -1; });
dc.qualificationMap.erase(it, dc.qualificationMap.end());
}
}
}
QFClass& QFEditor::getQFClassFromIndex(int linearIndex) {
auto v = getLevelIndexFromLinear(linearIndex);
return data[v.first].second[v.second];
}
void QFEditor::handle(gdioutput& gdi, BaseInfo& info, GuiEventType type) {
if (type == GUI_TIMER) {
if (info.id == "Reload") {
gdi.restore("LevelView", false);
showLevels(gdi);
gdi.refresh();
}
}
else if (type == GUI_INPUTCHANGE) {
InputInfo& ii = dynamic_cast(info);
if (ii.id.substr(0, 4) == "Name") {
if (trim(ii.text).empty())
ii.setBgColor(GDICOLOR::colorLightRed);
else {
ii.setBgColor(GDICOLOR::colorDefault);
}
ii.refresh();
}
}
else if (type == GUI_INPUT) {
InputInfo& ii = dynamic_cast(info);
if (ii.id.substr(0, 4) == "Name") {
QFClass& cls = getQFClass(ii.getExtraInt());
wstring tt = trim(ii.text);
if (!tt.empty()) {
if (tt != cls.name && !(cls.name.empty() && tt == ii.getPreviousText())) {
cls.name = tt;
edit(gdi);
}
}
else {
gdi.setText(ii.id, ii.getPreviousText());
ii.setBgColor(GDICOLOR::colorDefault);
}
}
}
else if (type == GUI_BUTTON) {
ButtonInfo& bi = dynamic_cast(info);
if (bi.id == "AddClassPlace") {
wstring place = gdi.getText("Places");
vector sPlace;
split(place, L" ;,", sPlace);
vector iPlace;
for (auto& sp : sPlace) {
int p = _wtoi(sp.c_str());
if (p > 0)
iPlace.push_back(p);
}
if (iPlace.empty())
throw meosException("Ange vilka placeringar i kalssen som kvalificerar hit, t.ex. '1,3'");
pair levelCls = decode(bi.getExtraInt());
QFClass& cls = getQFClass(bi.getExtraInt());
int codedTarget = gdi.getSelectedItem("Classes").first;
pair levelClsTgt = decode(codedTarget);
int linearCode = getLinearIndex(levelClsTgt.first, levelClsTgt.second);
int level = levelCls.first;
wstring errInfo;
for (int place : iPlace) {
pair codedClassPlace(linearCode, place);
bool add = true;
for (int j = 0; j < data.size(); j++) {
for (int i = 0; i < data[j].first; i++) {
auto& c = data[j].second[i];
if (count(c.qualificationMap.begin(), c.qualificationMap.end(), codedClassPlace)) {
wstring info = lang.tl(L"Placering X kvalificerar till Y#" + itow(place) + L"#" + c.name);
if (errInfo.empty())
errInfo = info;
else
errInfo = L"\n" + info;
add = false;
break;
}
}
}
if (add)
cls.qualificationMap.push_back(codedClassPlace);
// Clear from unused data
for (int j = 0; j < data.size(); j++) {
for (int i = data[j].first; i < data[j].second.size(); i++) {
auto& c = data[j].second[i];
if (!c.qualificationMap.empty())
c.qualificationMap.erase(remove(c.qualificationMap.begin(), c.qualificationMap.end(), codedClassPlace));
}
}
}
sort(cls.qualificationMap.begin(), cls.qualificationMap.end());
gdi.setItems("Rules", getRules(cls));
updateQInfo(cls);
gdi.setText("Places", L"", true);
if (!errInfo.empty()) {
gdi.alert(errInfo);
}
}
else if (bi.id == "AddBestTime") {
QFClass& cls = getQFClass(bi.getExtraInt());
cls.numTimeQualifications++;
gdi.setItems("Rules", getRules(cls));
updateQInfo(cls);
gdi.setText("Places", L"", true);
}
else if (bi.id == "AddOther") {
QFClass& cls = getQFClass(bi.getExtraInt());
ListBoxInfo lbi;
gdi.getSelectedItem("Other", lbi);
int tp = lbi.data;
if (tp == 0)
cls.extraQualification = QFClass::ExtraQualType::None;
else if (tp == 1)
cls.extraQualification = QFClass::ExtraQualType::All;
else if (tp == 2) {
cls.extraQualification = QFClass::ExtraQualType::NBest;
cls.extraQualData = max(_wtoi(gdi.getText("NBest").c_str()), 0);
}
else if (tp == 3) {
cls.extraQualification = QFClass::ExtraQualType::TimeLimit;
cls.extraQualData = convertAbsoluteTimeMS(gdi.getText("TimeLimit").c_str());
if (cls.extraQualData == NOTIME || cls.extraQualData < 0)
cls.extraQualData = 0;
}
gdi.setItems("Rules", getRules(cls));
updateQInfo(cls);
}
else if (bi.id == "RemoveRule") {
auto sel = gdi.getSelectedItem("Rules");
QFClass& cls = getQFClass(bi.getExtraInt());
if (sel.second) {
int id = sel.first;
if (id < 1000) {
cls.qualificationMap.erase(cls.qualificationMap.begin() + id);
}
else if (id < 10000 && cls.numTimeQualifications > 0)
cls.numTimeQualifications--;
else if (id == 10000)
cls.extraQualification = QFClass::ExtraQualType::None;
gdi.setItems("Rules", getRules(cls));
updateQInfo(getQFClass(bi.getExtraInt()));
gdi.disableInput("RemoveRule");
}
}
else if (bi.id.substr(0, 4) == "Rank") {
int level = bi.getExtraInt();
if (level < data.size()) {
edit(gdi);
bool rnk = gdi.isChecked(bi.id);
for (auto& d : data[level].second)
d.rankLevel = rnk;
}
else
throw meosException("Internal error");
}
else if (bi.id == "Edit") {
QFClass& qfc = getQFClass(bi.getExtraInt());
pair LIX = decode(bi.getExtraInt());
infoTextTag = "QInfo" + getKeyTag(LIX.first, LIX.second);
infoTextGdi = &gdi;
gdioutput* qual_settings = getExtraWindow("qualification", true);
if (!qual_settings) {
qual_settings = createExtraWindow("qualification", L"Qualification", gdi.scaleLength(700), gdi.scaleLength(500), true);
loadQualificationView(*qual_settings, qfc, bi.getExtraInt());
}
}
else if (bi.id == "Close") {
gdioutput* qual_settings = getExtraWindow("qualification", false);
if (qual_settings) {
qual_settings->closeWindow();
infoTextGdi = nullptr;
}
}
else if (bi.id == "New" || bi.id == "CloseEditor") {
if (checkSave(gdi)) {
gdioutput* qual_settings = getExtraWindow("qualification", false);
if (qual_settings) {
qual_settings->closeWindow();
infoTextGdi = nullptr;
}
if (bi.id == "New") {
emptyScheme();
if (cls && cls->getQualificationFinal())
cls = nullptr; // Clear connection to class
show(gdi);
}
else {
gdi.getTabs().get(TClassTab)->loadPage(gdi);
return;
}
}
}
else if (bi.id == "Use") {
if (cls) {
use();
updateActions(gdi);
}
}
else if (bi.id == "Load") {
vector> ext;
ext.push_back(make_pair(L"Qualfication/Final", L"*.xml"));
wstring fileName = gdi.browseForOpen(ext, L"xml");
if (!fileName.empty()) {
auto newQF = make_shared(0, 0);
newQF->importXML(fileName);
load(newQF);
makeDirty(QFEditor::DirtyFlag::MakeDirty, QFEditor::DirtyFlag::ClearDirty);
show(gdi);
}
}
else if (bi.id == "Save") {
if (save(gdi))
updateActions(gdi);
}
}
else if (type == GUI_LISTBOX) {
ListBoxInfo& lbi = dynamic_cast(info);
if (lbi.id == "Levels") {
auto origiIndex = getLevelIndex();
numLevels = lbi.data;
if (numLevels > data.size()) {
data.resize(numLevels);
for (auto& d : data) {
if (d.first == 0) {
d.first = 1;
d.second.emplace_back(lang.tl("Klass"));
}
}
}
edit(gdi);
updateLevelMap(origiIndex);
gdi.addTimeoutMilli(25, "Reload", nullptr).setHandler(this);
gdioutput* qual_settings = getExtraWindow("qualification", false);
if (qual_settings)
qual_settings->closeWindow();
}
else if (lbi.id.substr(0, 6) == "NumCls") {
int numCls = lbi.data;
int level = lbi.getExtraInt();
if (level < data.size()) {
auto origiIndex = getLevelIndex();
wstring bn = lang.tl("Class");
bool rnk = false;
if (!data[level].second.empty()) {
bn = data[level].second.back().name;
rnk = data[level].second.front().rankLevel;
}
while (numCls >= data[level].second.size()) {
data[level].second.emplace_back(bn);
data[level].second.back().rankLevel = rnk;
}
data[level].first = numCls;
updateLevelMap(origiIndex);
}
else
throw meosException("Internal error");
edit(gdi);
gdi.addTimeoutMilli(25, "Reload", nullptr).setHandler(this);
gdioutput* qual_settings = getExtraWindow("qualification", false);
if (qual_settings)
qual_settings->closeWindow();
}
else if (lbi.id == "Rules") {
gdi.setInputStatus("RemoveRule", lbi.data != -1);
}
else if (lbi.id == "RuleType") {
int cCode = lbi.getExtraInt();
gdi.restoreNoUpdate("RuleType");
if (lbi.data == 0)
addRuleClassPlace(cCode, gdi);
else if (lbi.data == 1)
addRuleTime(cCode, gdi);
else if (lbi.data == 2)
addRuleOther(cCode, gdi);
}
else if (lbi.id == "Other") {
QFClass& cls = getQFClass(lbi.getExtraInt());
updateExtraField(gdi, cls, lbi.getExtraInt());
}
}
}
string QFEditor::getKeyTag(int level, int ix) {
return "L" + itos(level) + "C" + itos(ix);
}
void QFEditor::updateQInfo(const QFClass& cls) {
if (infoTextGdi) {
edit(*infoTextGdi);
infoTextGdi->setText(infoTextTag, lang.tl(cls.getQualInfo()), true);
}
}
bool QFEditor::checkSave(gdioutput& gdi) {
if (cls != nullptr && dirtyInt) {
auto ans = gdi.askCancel(L"Vill du uppdatera X med ändringarna?#" + cls->getName());
if (ans == gdioutput::AskAnswer::AnswerCancel)
return false;
else if (ans == gdioutput::AskAnswer::AnswerYes)
use();
}
else if (cls == nullptr && dirtyExt) {
auto ans = gdi.askCancel(L"Vill du spara ändringar?");
if (ans == gdioutput::AskAnswer::AnswerCancel)
return false;
else if (ans == gdioutput::AskAnswer::AnswerYes) {
if (!save(gdi))
return false;
}
}
return true;
}
void QFEditor::makeDirty(DirtyFlag inside, DirtyFlag outside) {
if (inside == DirtyFlag::ClearDirty)
dirtyInt = false;
else if (inside == DirtyFlag::MakeDirty)
dirtyInt = true;
if (outside == DirtyFlag::ClearDirty)
dirtyExt = false;
else if (outside == DirtyFlag::MakeDirty)
dirtyExt = true;
}
void QFEditor::edit(gdioutput& gdi) {
makeDirty(DirtyFlag::MakeDirty, DirtyFlag::MakeDirty);
updateActions(gdi);
}
void QFEditor::updateActions(gdioutput& gdi) {
gdi.setInputStatus("Use", dirtyInt, true);
gdi.setInputStatus("Save", dirtyExt);
}
void QFEditor::use() {
makeQF();
cls->loadQualificationFinalScheme(*currentQF);
cls->updateFinalClasses(0, true);
makeDirty(QFEditor::DirtyFlag::ClearDirty, QFEditor::DirtyFlag::NoTouch);
}
bool QFEditor::save(gdioutput& gdi) {
vector> ext;
ext.push_back(make_pair(L"Qualfication/Final", L"*.xml"));
int fx = 0;
wstring fileName = gdi.browseForSave(ext, L"xml", fx);
if (!fileName.empty()) {
makeQF();
currentQF->exportXML(fileName);
makeDirty(QFEditor::DirtyFlag::NoTouch, QFEditor::DirtyFlag::ClearDirty);
return true;
}
return false;
}