/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2017 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "resource.h" #include #include #include #include "oEvent.h" #include "xmlparser.h" #include "gdioutput.h" #include "csvparser.h" #include "SportIdent.h" #include "meos_util.h" #include "gdifonts.h" #include "table.h" #include #include "MeOSFeatures.h" #include "TabControl.h" TabControl::TabControl(oEvent *poe):TabBase(poe) { clearCompetitionData(); } TabControl::~TabControl(void) { } void TabControl::selectControl(gdioutput &gdi, pControl pc) { if (pc) { pc->synchronize(); if (pc->getStatus() == oControl::StatusStart || pc->getStatus() == oControl::StatusFinish) { gdi.selectItemByData("Controls", pc->getId()); gdi.selectItemByData("Status", oControl::StatusOK); gdi.setText("ControlID", "-", true); gdi.setText("Code", ""); gdi.setText("Name", pc->getName()); gdi.setText("TimeAdjust", "00:00"); gdi.setText("MinTime", "-"); gdi.setText("Point", ""); controlId = pc->getId(); gdi.enableInput("Remove"); gdi.enableInput("Save"); gdi.enableEditControls(false); gdi.enableInput("Name"); } else { gdi.selectItemByData("Controls", pc->getId()); gdi.selectItemByData("Status", pc->getStatus()); const int numVisit = pc->getNumVisitors(true); const int numVisitExp = pc->getNumVisitors(false); string info; if (numVisit > 0) { info = "Antal besökare X, genomsnittlig bomtid Y, största bomtid Z#" + itos(numVisit) + " (" + itos(numVisitExp) + ")#" + getTimeMS(pc->getMissedTimeTotal() / numVisit) + "#" + getTimeMS(pc->getMissedTimeMax()); } else if (numVisitExp > 0) { info = "Förväntat antal besökare: X#" + itos(numVisitExp); } gdi.setText("ControlID", itos(pc->getId()), true); gdi.setText("Info", lang.tl(info), true); gdi.setText("Code", pc->codeNumbers()); gdi.setText("Name", pc->getName()); gdi.setText("TimeAdjust", pc->getTimeAdjustS()); gdi.setText("MinTime", pc->getMinTimeS()); if (gdi.hasField("Point")) gdi.setText("Point", pc->getRogainingPointsS()); controlId = pc->getId(); gdi.enableInput("Remove"); gdi.enableInput("Save"); gdi.enableInput("Visitors"); gdi.enableInput("Courses"); gdi.enableEditControls(true); oControl::ControlStatus st = pc->getStatus(); if (st == oControl::StatusRogaining || st == oControl::StatusNoTiming) gdi.disableInput("MinTime"); if (st == oControl::StatusNoTiming) gdi.disableInput("TimeAdjust"); if (gdi.hasField("Point") && st != oControl::StatusRogaining) gdi.disableInput("Point"); } } else { gdi.selectItemByData("Controls", -1); gdi.selectItemByData("Status", oControl::StatusOK); gdi.setText("Code", ""); gdi.setText("Name", ""); controlId = 0; gdi.setText("ControlID", "-", true); gdi.setText("TimeAdjust", "00:00"); if (gdi.hasField("Point")) gdi.setText("Point", ""); gdi.disableInput("Remove"); gdi.disableInput("Save"); gdi.disableInput("Visitors"); gdi.disableInput("Courses"); gdi.enableEditControls(false); } } int ControlsCB(gdioutput *gdi, int type, void *data) { TabControl &tc = dynamic_cast(*gdi->getTabs().get(TControlTab)); return tc.controlCB(*gdi, type, data); } void TabControl::save(gdioutput &gdi) { if (controlId==0) return; DWORD pcid = controlId; pControl pc; pc = oe->getControl(pcid, false); if (!pc) throw std::exception("Internal error"); if (pc->getStatus() != oControl::StatusFinish && pc->getStatus() != oControl::StatusStart) { if (!pc->setNumbers(gdi.getText("Code"))) gdi.alert("Kodsiffran måste vara ett heltal. Flera kodsiffror måste separeras med komma."); pc->setStatus(oControl::ControlStatus(gdi.getSelectedItem("Status").first)); pc->setTimeAdjust(gdi.getText("TimeAdjust")); if (pc->getStatus() != oControl::StatusRogaining) { if (pc->getStatus() != oControl::StatusNoTiming) pc->setMinTime(gdi.getText("MinTime")); pc->setRogainingPoints(0); } else { if (gdi.hasField("Point")) { pc->setMinTime(0); pc->setRogainingPoints(gdi.getTextNo("Point")); } } } pc->setName(gdi.getText("Name")); pc->synchronize(); vector< pair > d; oe->fillControls(d, oEvent::CTAll); gdi.addItem("Controls", d); oe->reEvaluateAll(set(), true); selectControl(gdi, pc); } static void visitorTable(Table &table, void *ptr) { TabControl *view = (TabControl *)ptr; view->visitorTable(table); } static void courseTable(Table &table, void *ptr) { TabControl *view = (TabControl *)ptr; view->courseTable(table); } void TabControl::courseTable(Table &table) const { vector r; oe->getRunners(0, 0, r, false); map runnersPerCourse; for (size_t k = 0; k < r.size(); k++) { pCourse c = r[k]->getCourse(false); int id = c != 0 ? c->getId() : 0; ++runnersPerCourse[id]; } vector crs; oe->getCourses(crs); int ix = 1; for (size_t k = 0; k < crs.size(); k++) { vector pc; crs[k]->getControls(pc); int used = 0; for (size_t j = 0; j < pc.size(); j++) { if (pc[j]->getId() == controlId) { used++; } } oCourse &it = *crs[k]; if (used > 0) { table.addRow(ix++, &it); int row = 0; table.set(row++, it, TID_ID, itos(it.getId()), false); table.set(row++, it, TID_MODIFIED, it.getTimeStamp(), false); table.set(row++, it, TID_COURSE, crs[k]->getName(), false); table.set(row++, it, TID_INDEX, itos(used), false); table.set(row++, it, TID_RUNNER, itos(runnersPerCourse[crs[k]->getId()]), false); } } } void TabControl::visitorTable(Table &table) const { vector c; oe->getCards(c); pControl pc = oe->getControl(controlId, false); if (!pc) return; vector n; pc->getNumbers(n); struct PI { PI(int c, int type, int t) : card(c), code(type), time(t) {} int card; int code; int time; bool operator<(const PI&c) const { if (card != c.card) return card < c.card; else if (code != c.code) return code < c.code; else return time < c.time; } bool operator==(const PI&c) const { return c.card == card && c.code == code && c.time == time; } }; set registeredPunches; vector p; int ix=1; for (size_t k = 0; k< c.size(); k++) { oCard &it = *c[k]; it.getPunches(p); //oPunch *punch = it.getPunchByType(pc->getFirstNumber()); //XXX for (size_t j = 0; j < p.size(); j++) { vector::iterator res = find(n.begin(), n.end(), p[j]->getTypeCode()); if (res != n.end()) { oPunch *punch = p[j]; registeredPunches.insert(PI(it.getCardNo(), p[j]->getTypeCode(), p[j]->getAdjustedTime())); table.addRow(ix++, &it); int row = 0; table.set(row++, it, TID_ID, itos(it.getId()), false); table.set(row++, it, TID_MODIFIED, it.getTimeStamp(), false); pRunner r = it.getOwner(); if (r) { table.set(row++, it, TID_RUNNER, r->getName(), false); table.set(row++, it, TID_COURSE, r->getCourseName(), false); } else { table.set(row++, it, TID_RUNNER, "-", false); table.set(row++, it, TID_COURSE, "-", false); } table.set(row++, it, TID_FEE, punch->isUsedInCourse() ? 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_CONTROL, punch->getType(), false); table.set(row++, it, TID_CODES, j>0 ? p[j-1]->getType() : "-", true); } } } } int TabControl::controlCB(gdioutput &gdi, int type, void *data) { if (type==GUI_BUTTON) { ButtonInfo bi=*(ButtonInfo *)data; if (bi.id=="Save") save(gdi); else if (bi.id=="Add") { bool rogaining = false; if (controlId>0) { save(gdi); pControl pc = oe->getControl(controlId, false); rogaining = pc && pc->getStatus() == oControl::StatusRogaining; } pControl pc = oe->addControl(0,oe->getNextControlNumber(), ""); if (rogaining) pc->setStatus(oControl::StatusRogaining); vector< pair > d; oe->fillControls(d, oEvent::CTAll); gdi.addItem("Controls", d); selectControl(gdi, pc); } else if (bi.id=="Remove") { DWORD cid = controlId; if (cid==0) { gdi.alert("Ingen kontroll vald vald."); return 0; } if (oe->isControlUsed(cid)) gdi.alert("Kontrollen används och kan inte tas bort."); else oe->removeControl(cid); vector< pair > d; oe->fillControls(d, oEvent::CTAll); gdi.addItem("Controls", d); selectControl(gdi, 0); } else if (bi.id=="SwitchMode") { if (!tableMode) save(gdi); tableMode = !tableMode; loadPage(gdi); } else if (bi.id=="Visitors") { save(gdi); Table *table=new Table(oe, 20, "Kontroll X#" + itos(controlId), "controlvisitor"); table->addColumn("Id", 70, true, true); table->addColumn("Ändrad", 70, false); table->addColumn("Namn", 150, false); table->addColumn("Bana", 70, false); table->addColumn("På banan", 70, false); table->addColumn("Bricka", 70, true, true); table->addColumn("Tidpunkt", 70, false); table->addColumn("Stämpelkod", 70, true); table->addColumn("Föregående kontroll", 70, false); table->setGenerator(::visitorTable, this); table->setTableProp(0); table->update(); gdi.clearPage(false); int xp=gdi.getCX(); gdi.fillDown(); gdi.addButton("Show", "Återgå", ControlsCB); gdi.addTable(table, xp, gdi.getCY()); gdi.refresh(); } else if (bi.id=="Courses") { Table *table=new Table(oe, 20, "Kontroll X#" + itos(controlId), "controlcourse"); table->addColumn("Id", 70, true, true); table->addColumn("Ändrad", 70, false); table->addColumn("Bana", 70, false, true); table->addColumn("Förekomst", 70, true, true); table->addColumn("Antal deltagare", 70, true, true); table->setGenerator(::courseTable, this); table->setTableProp(0); table->update(); gdi.clearPage(false); int xp=gdi.getCX(); gdi.fillDown(); gdi.addButton("Show", "Återgå", ControlsCB); gdi.addTable(table, xp, gdi.getCY()); gdi.refresh(); } else if (bi.id=="Show") { loadPage(gdi); } } else if (type==GUI_LISTBOX){ ListBoxInfo bi=*(ListBoxInfo *)data; if (bi.id=="Controls") { if (gdi.isInputChanged("")) save(gdi); pControl pc=oe->getControl(bi.data, false); 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, true); gdi.setInputStatus("Point", bi.data == oControl::StatusRogaining, true); gdi.setInputStatus("TimeAdjust", bi.data != oControl::StatusNoTiming, true); } } else if (type==GUI_CLEAR) { if (controlId>0) save(gdi); return true; } return 0; } bool TabControl::loadPage(gdioutput &gdi) { oe->checkDB(); gdi.selectTab(tabId); gdi.clearPage(false); int xp=gdi.getCX(); const int button_w=gdi.scaleLength(90); string switchMode; switchMode=tableMode ? "Formulärläge" : "Tabelläge"; gdi.addButton(2, 2, button_w, "SwitchMode", switchMode, ControlsCB, "Välj vy", false, false).fixedCorner(); if (tableMode) { Table *tbl=oe->getControlTB(); gdi.addTable(tbl, xp, 30); return true; } gdi.fillDown(); gdi.addString("", boldLarge, "Kontroller"); gdi.pushY(); gdi.addListBox("Controls", 250, 530, ControlsCB).isEdit(false).ignore(true); gdi.setTabStops("Controls", 40, 160); vector< pair > d; oe->fillControls(d, oEvent::CTAll); gdi.addItem("Controls", d); gdi.newColumn(); gdi.fillDown(); gdi.popY(); gdi.pushX(); gdi.fillRight(); gdi.addString("", 1, "Kontrollens ID-nummer:"); gdi.fillDown(); gdi.addString("ControlID", 1, "#-").setColor(colorGreen); gdi.popX(); gdi.fillRight(); gdi.addInput("Name", "", 16, 0, "Kontrollnamn:"); gdi.addSelection("Status", 150, 100, ControlsCB, "Status:", "Ange om kontrollen fungerar och hur den ska användas."); oe->fillControlStatus(gdi, "Status"); gdi.addInput("TimeAdjust", "", 6, 0, "Tidsjustering:"); gdi.fillDown(); gdi.addInput("MinTime", "", 6, 0, "Minsta sträcktid:"); gdi.popX(); gdi.dropLine(0.5); gdi.addString("", 10, "help:9373"); gdi.fillRight(); gdi.dropLine(0.5); gdi.addInput("Code", "", 16, 0, "Stämpelkod(er):"); if (oe->getMeOSFeatures().hasFeature(MeOSFeatures::Rogaining)) { gdi.addInput("Point", "", 6, 0, "Rogaining-poäng:"); } gdi.popX(); gdi.dropLine(3.5); gdi.fillRight(); gdi.addButton("Save", "Spara", ControlsCB, "help:save"); gdi.disableInput("Save"); gdi.addButton("Remove", "Radera", ControlsCB); gdi.disableInput("Remove"); gdi.addButton("Courses", "Banor...", ControlsCB); gdi.addButton("Visitors", "Besökare...", ControlsCB); gdi.addButton("Add", "Ny kontroll", ControlsCB); gdi.dropLine(2.5); gdi.popX(); gdi.fillDown(); gdi.addString("Info", 0, "").setColor(colorGreen); gdi.dropLine(1.5); gdi.addString("", 10, "help:89064"); selectControl(gdi, oe->getControl(controlId, false)); gdi.setOnClearCb(ControlsCB); gdi.refresh(); return true; } void TabControl::clearCompetitionData() { tableMode = false; controlId = 0; }