/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2018 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 #include #include #include "oEvent.h" #include "listeditor.h" #include "generalresult.h" #include "metalist.h" #include "gdioutput.h" #include "meosexception.h" #include "meos_util.h" #include "localizer.h" #include "gdifonts.h" extern oEvent *gEvent; const int MAXLISTPARAMID = 10000000; using namespace tr1; oListParam::oListParam() { lockUpdate = false; listCode = EStdResultList; //Just need a default cb = 0; legNumber = 0; useControlIdResultTo = 0; useControlIdResultFrom = 0; filterMaxPer = 0; pageBreak = false; showInterTimes = false; showSplitTimes = false; splitAnalysis = false; useLargeSize = false; saved = false; inputNumber = 0; nextList = 0; // No linked list previousList = 0; relayLegIndex = -1; bgColor = -1; fgColor = -1; bgColor2 = -1; nColumns = 0; animate = true; timePerPage = 8000; margin = 5; screenMode = 0; } void oListParam::serialize(xmlparser &xml, const MetaListContainer &container, const map &idToIndex) const { xml.startTag("ListParam", "Name", name); xml.write("ListId", container.getUniqueId(listCode)); string sel; for (set::const_iterator it = selection.begin(); it != selection.end(); ++it) { if (!sel.empty()) sel += ";"; sel += itos(*it); } xml.write("ClassId", sel); xml.write("LegNumber", legNumber); xml.write("FromControl", useControlIdResultFrom); xml.write("ToControl", useControlIdResultTo); xml.write("MaxFilter", filterMaxPer); xml.write("Title", title); xml.writeBool("Large", useLargeSize); xml.writeBool("PageBreak", pageBreak); xml.writeBool("ShowNamedSplits", showInterTimes); xml.writeBool("ShowInterTitle", showInterTitle); xml.writeBool("ShowSplits", showSplitTimes); xml.writeBool("ShowAnalysis", splitAnalysis); xml.write("InputNumber", inputNumber); if (nextList != 0) { map::const_iterator res = idToIndex.find(nextList); if (res != idToIndex.end()) xml.write("NextList", res->second); } if (bgColor != -1) xml.write("BGColor", itos(bgColor)); if (bgColor2 != -1) xml.write("BGColor2", itos(bgColor2)); if (fgColor != -1) xml.write("FGColor", itos(fgColor)); xml.write("Image", bgImage); xml.write("ScreenMode", screenMode); if (nColumns != 0) { xml.write("NumColumns", itos(nColumns)); xml.writeBool("Animate", animate); xml.write("TimePerPage", timePerPage); xml.write("Margin", margin); } xml.endTag(); } void oListParam::deserialize(const xmlobject &xml, const MetaListContainer &container) { xml.getObjectString("Name", name); string id; xml.getObjectString("ListId", id); listCode = container.getCodeFromUnqiueId(id); string sel; xml.getObjectString("ClassId", sel); vector selVec; split(sel, ";", selVec); for (size_t k = 0; k < selVec.size(); k++) { selection.insert(atoi(selVec[k].c_str())); } legNumber = xml.getObjectInt("LegNumber"); useControlIdResultFrom = xml.getObjectInt("FromControl"); useControlIdResultTo = xml.getObjectInt("ToControl"); filterMaxPer = xml.getObjectInt("MaxFilter"); xml.getObjectString("Title", title); useLargeSize = xml.getObjectBool("Large"); pageBreak = xml.getObjectBool("PageBreak"); showInterTimes = xml.getObjectBool("ShowNamedSplits"); showSplitTimes = xml.getObjectBool("ShowSplits"); splitAnalysis = xml.getObjectBool("ShowAnalysis"); showInterTitle = xml.getObjectBool("ShowInterTitle"); inputNumber = xml.getObjectInt("InputNumber"); nextList = xml.getObjectInt("NextList"); xmlobject bg = xml.getObject("BGColor"); if (bg) bgColor = bg.getInt(); xmlobject bg2 = xml.getObject("BGColor2"); if (bg2) bgColor2 = bg2.getInt(); xmlobject fg = xml.getObject("FGColor"); if (fg) fgColor = fg.getInt(); xml.getObjectString("Image", bgImage); int nColumns = xml.getObjectInt("NumColumns"); screenMode = xml.getObjectInt("ScreenMode"); animate = xml.getObjectBool("Animate"); if (xml.got("TimePerPage")) timePerPage = xml.getObjectInt("TimePerPage"); if (xml.got("Margin")) timePerPage = xml.getObjectInt("Margin"); saved = true; } void oListParam::getCustomTitle(wchar_t *t) const { if (!title.empty()) wcscpy_s(t, 256, makeDash(title).c_str()); } const wstring &oListParam::getCustomTitle(const wstring &t) const { if (!title.empty()) return title; else return t; } MetaList::MetaList() { data.resize(4); fontFaces.resize(4); hasResults_ = false; initSymbols(); listType = oListInfo::EBaseTypeRunner; listSubType = oListInfo::EBaseTypeNone; sortOrder = SortByName; supportFromControl = false; supportToControl = false; hideLegSelection = false; } MetaListPost::MetaListPost(EPostType type_, EPostType align_, int leg_) : type(type_), alignType(align_), leg(leg_), minimalIndent(0), alignBlock(true), blockWidth(0), font(formatIgnore), mergeWithPrevious(false), textAdjust(0), color(colorDefault) {} int checksum(const string &str) { int ret = 0; for (size_t k = 0; k > &lines = data[i]; for (size_t j = 0; j &cline = lines[j]; for (size_t k = 0; k::const_iterator it = filter.begin(); it != filter.end(); ++it) yx = yx * 31 + *it; for (set::const_iterator it = subFilter.begin(); it != subFilter.end(); ++it) yx = yx * 29 + *it; uniqueIndex = "A" + itos(ix) + "B" + itos(yx); } bool MetaList::isBreak(int x) const { return isspace(x) || x == '.' || x == ',' || x == '-' || x == ':' || x == ';' || x == '(' || x == ')' || x=='/' || (x>30 && x < 127 && !isalnum(x)); } wstring MetaList::encode(const wstring &input_) const { wstring out; wstring input = lang.tl(input_); out.reserve(input.length() + 5); for (size_t k = 0; k 0 ? input[k-1] : ' '; int n = k+1 < input.length() ? input[k+1] : ' '; if (c == '%') { out.push_back('%'); out.push_back('%'); } else if (c == 'X' && isBreak(n) && isBreak(p) ) { out.push_back('%'); out.push_back('s'); } else out.push_back(c); } return out; } MetaListPost &MetaList::add(ListIndex ix, const MetaListPost &post) { if (data[ix].empty()) addRow(ix); // data[ix].resize(1); vector &d = data[ix].back(); d.push_back(post); return d.back(); } void MetaList::addRow(int ix) { data[ix].push_back(vector()); } static void setFixedWidth(oPrintPost &added, const map, int> &indexPosToWidth, int type, int j, int k) { map, int>::const_iterator res = indexPosToWidth.find(tuple(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, int lineHeight, oListInfo &li) const { const MetaList &mList = *this; Position pos; const bool large = par.useLargeSize; li.lp = par; gdiFonts normal, header, small, italic; double s_factor; map, int> fontHeight; for (size_t k = 0; k < fontFaces.size(); k++) { for (map::const_iterator it = fontToSymbol.begin(); it != fontToSymbol.end(); ++it) { wstring face = fontFaces[k].font; if (fontFaces[k].scale > 0 && fontFaces[k].scale != 100) { face += L";" + itow(fontFaces[k].scale/100) + L"." + itow(fontFaces[k].scale%100); } fontHeight[make_pair(it->first, int(k))] = gdi.getLineHeight(it->first, face.c_str()); } } if (large) { s_factor = 0.9; normal = fontLarge; header = boldLarge; small = normalText; lineHeight = int(lineHeight *1.6); italic = italicMediumPlus; } else { s_factor = 1.0; normal = normalText; header = boldText; small = italicSmall; italic = italicText; } map labelMap; map stringLabelMap; set skip; li.calcResults = false; li.calcTotalResults = false; li.rogainingResults = false; li.calcCourseClassResults = false; if (par.useControlIdResultFrom > 0 || par.useControlIdResultTo > 0) li.needPunches = true; const bool isPunchList = mList.listSubType == oListInfo::EBaseTypePunches; map, int> indexPosToWidth; map< pair, int> linePostCount; for (int i = 0; i<4; i++) { const vector< vector > &lines = mList.data[i]; gdiFonts defaultFont = normal; switch (i) { case 0: case 1: defaultFont = header; break; case 3: { if (isPunchList) defaultFont = small; else defaultFont = italic; } } for (size_t j = 0; j &cline = lines[j]; for (size_t k = 0; kcalculateResults(oEvent::RTClassResult); oe->calculateTeamResults(false); } li.calcResults = true; } if (mp.type == lRunnerTotalPlace || mp.type == lRunnerPlaceDiff || mp.type == lTeamTotalPlace || mp.type == lTeamPlaceDiff || mp.type == lRunnerGeneralPlace) { if (!li.calcTotalResults) { oe->calculateResults(oEvent::RTTotalResult); oe->calculateTeamResults(true); } li.calcTotalResults = true; } else if (mp.type == lRunnerRogainingPoint || mp.type == lRunnerRogainingPointTotal || mp.type == lTeamRogainingPoint || mp.type == lTeamRogainingPointTotal) { li.rogainingResults = true; } else if (mp.type == lRunnerClassCoursePlace || mp.type == lRunnerClassCourseTimeAfter) { if (!li.calcCourseClassResults) oe->calculateResults(oEvent::RTClassCourseResult); li.calcCourseClassResults = true; } else if (mp.type == lRunnerTempTimeAfter || mp.type == lRunnerTempTimeStatus) { li.needPunches = true; } string label = "P" + itos(i*1000 + j*100 + k); if (mp.type == lRunnerBib || mp.type == lTeamBib) { if (!oe->hasBib(mp.type == lRunnerBib, mp.type == lTeamBib)) skip.insert(mp.type); } int width = 0; if (skip.count(mp.type) == 0 && (k==0 || !mp.mergeWithPrevious)) { gdiFonts font = defaultFont; if (mp.font != formatIgnore) font = mp.font; vector< pair > typeFormats; typeFormats.push_back(make_pair(mp.type, encode(mp.text))); size_t kk = k+1; //Add merged entities while (kk < cline.size() && cline[kk].mergeWithPrevious) { typeFormats.push_back(make_pair(cline[kk].type, encode(cline[kk].text))); kk++; } width = li.getMaxCharWidth(oe, gdi, par.selection, typeFormats, font, 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(i, j, k)] = width; } if (mp.alignType == lNone) { pos.add(label, width, width); pos.indent(mp.minimalIndent); } else { if (mp.alignType == lAlignNext) pos.alignNext(label, width, mp.alignBlock); else if (mp.alignType == lString) { if (stringLabelMap.count(mp.alignWithText) == 0) { throw meosException(L"Don't know how to align with 'X'#" + mp.alignWithText); } pos.update(stringLabelMap[mp.alignWithText], label, width, mp.alignBlock, true); } else { if (labelMap.count(mp.alignType) == 0) { throw meosException(L"Don't know how to align with 'X'#" + typeToSymbol[mp.alignType]); } pos.update(labelMap[mp.alignType], label, width, mp.alignBlock, true); } pos.indent(mp.minimalIndent); } labelMap[mp.type] = label; if (!mp.text.empty()) stringLabelMap[mp.text] = label; } pos.newRow(); } pos.newRow(); } bool c = true; while (c) { c = pos.postAdjust(); } int dy = 0, next_dy = 0; oPrintPost *last = 0; oPrintPost *base = 0; int totalWidth = pos.getWidth(); for (map, int>::iterator it = linePostCount.begin(); it != linePostCount.end(); ++it) { if (it->second == 1) { int base = it->first.first; if (base == MLSubList && listSubType == oListInfo::EBaseTypePunches) continue; // This type of list requires actual width indexPosToWidth[tuple(base, it->first.second, 0)] = totalWidth; } } pClass sampleClass = 0; if (!par.selection.empty()) sampleClass = oe->getClass(*par.selection.begin()); if (!sampleClass) { vector cls; oe->getClasses(cls, false); if (!cls.empty()) sampleClass = cls[0]; } pair parLegNumber = par.getLegInfo(sampleClass); bool capitalizeTitle = lang.capitalizeWords(); resultToIndex.clear(); /*if (large == false && par.pageBreak == false) {*/ { int head_dy = gdi.scaleLength(mList.getExtraSpace(MLHead)); for (size_t j = 0; j &cline = mList.getHead()[j]; next_dy = 0; for (size_t k = 0; kmergeWith = &added; last->doMergeNext = true; if (base) { base->fixedWidth += added.fixedWidth; added.fixedWidth = 0; } } last = &added; next_dy = max(next_dy, fontHeight[make_pair(font, MLHead)]); } dy += next_dy; next_dy = lineHeight; } } dy = lineHeight; int subhead_dy = gdi.scaleLength(mList.getExtraSpace(MLSubHead)); last = 0; base = 0; for (size_t j = 0; j &cline = mList.getSubHead()[j]; for (size_t k = 0; kmergeWith = &added; last->doMergeNext = true; if (base) { base->fixedWidth += added.fixedWidth; added.fixedWidth = 0; } } last = &added; next_dy = max(next_dy, fontHeight[make_pair(font, MLSubHead)]); } dy += next_dy; } last = 0; base = 0; int list_dy = gdi.scaleLength(mList.getExtraSpace(MLList));//mList.getSubList().size() > 0 ? lineHeight/2 : 0; dy = 0; for (size_t j = 0; j &cline = mList.getList()[j]; next_dy = 0; for (size_t k = 0; kdoMergeNext = true; if (base) { base->fixedWidth += added.fixedWidth; added.fixedWidth = 0; } } last = &added; } dy += next_dy; } int sublist_dy = gdi.scaleLength(mList.getExtraSpace(MLSubList)); last = 0; base = 0; dy = 0; for (size_t j = 0; j &cline = mList.getSubList()[j]; next_dy = 0; for (size_t k = 0; kdoMergeNext = true; if (base) { base->fixedWidth += added.fixedWidth; added.fixedWidth = 0; } } last = &added; } dy += next_dy; } li.listType = getListType(); li.listSubType = listSubType; li.sortOrder = sortOrder; for (set::const_iterator it = filter.begin(); it != filter.end(); ++it) { li.setFilter(*it); } for (set::const_iterator it = subFilter.begin(); it != subFilter.end(); ++it) { li.setSubFilter(*it); } li.setResultModule(resultModule); li.supportFrom = supportFromControl; li.supportTo = supportToControl; li.resType = getResultType(); if (!resultModule.empty() || li.calcResults || li.calcCourseClassResults || li.calcTotalResults) hasResults_ = true; } void Position::indent(int ind) { int end = pos.size() - 1; if (end < 1) return; if (pos[end-1].first < ind) { int dx = ind - pos[end-1].first; pos[end-1].first += dx; pos[end].first += dx; } } void Position::newRow() { if (!pos.empty()) pos.pop_back(); pos.push_back(PosInfo(0, 0)); } void Position::alignNext(const string &newname, const int width, bool alignBlock) { if (pos.empty()) return; int p = pos.empty() ? 0 : pos.back().first; const int backAlign = 20; const int fwdAlign = max(width/2, 40); if (p==0) p = backAlign; int next = 0, prev = 0; int next_p = 100000, prev_p = -100000; int last = pos.size()-1; for (int k = pos.size()-2; k >= 0; k--) { last = k; if (pos[k+1].first < pos[k].first) break; } for (int k = 0; k <= last; k++) { if ( pos[k].first >= p && pos[k].first < next_p ) { next = k; next_p = pos[k].first; } if ( pos[k].first < p && pos[k].first > prev_p ) { prev = k; prev_p = pos[k].first; } } if ( p - prev_p < backAlign) { int delta = p - prev_p; for (size_t k = 0; k + 1 < pos.size(); k++) { if (pos[k].first >= prev_p) pos[k].first += delta; } update(prev, newname, width, alignBlock, false); } else { if (next > 0 && (next_p - p) < fwdAlign) update(next, newname, width, alignBlock, false); else add(newname, width, width); } } void Position::update(const string &oldname, const string &newname, const int width, bool alignBlock, bool alignLock) { if (pmap.count(oldname) == 0) throw std::exception("Invalid position"); int ix = pmap[oldname]; update(ix, newname, width, alignBlock, alignLock); } void Position::update(int ix, const string &newname, const int width, bool alignBlock, bool alignLock) { int last = pos.size()-1; if (alignLock) { pos[last].aligned = true; pos[ix].aligned = true; } int xlimit = pos[ix].first; if (xlimit < pos[last].first) { int delta = pos[last].first - xlimit; // Find last entry to update (higher row) int lastud = last; while (lastud>1 && pos[lastud].first >= pos[lastud-1].first) lastud--; for (int k = 0; k= xlimit) pos[k].first += delta; } } else pos[last].first = pos[ix].first; int ow = pos[ix+1].first - pos[ix].first; int nw = width; if (alignBlock && ow>0) { nw = max(ow, nw); if (nw > ow) { int delta = nw - ow; for (size_t k = 0; k pos[ix].first) pos[k].first += delta; } } } add(newname, nw, width); } int Position::getWidth() const { int w = 0; for (size_t k = 0; k < pos.size(); k++) { w = max(w, pos[k].first + pos[k].width); } return w; } void Position::add(const string &name, int width, int blockWidth) { if (pos.empty()) { pos.push_back(PosInfo(0, blockWidth)); pmap[name] = 0; pos.push_back(PosInfo(width, 0)); } else { pmap[name] = pos.size() - 1; pos.back().width = blockWidth; pos.push_back(PosInfo(width + pos.back().first, 0)); } } int Position::get(const string &name) { return pos[pmap[name]].first; } int Position::get(const string &name, double scale) { return int(pos[pmap[name]].first * scale); } int Position::getOriginalPos(const string &name) { return pos[pmap[name]].originalPos; } int Position::getOriginalPos(const string &name, double scale) { return int(pos[pmap[name]].originalPos * scale); } struct PosOrderIndex { int pos; int index; int width; int row; bool aligned; bool operator<(const PosOrderIndex &x) const {return pos < x.pos;} }; bool Position::postAdjust() { vector x; int row = 0; vector aligned(1, -1); for (size_t k = 0; k < pos.size(); k++) { PosOrderIndex poi; poi.pos = pos[k].first; poi.index = k; poi.row = row; if (pos[k].aligned) aligned[row] = k; if (k + 1 == pos.size() || pos[k+1].first == 0) { poi.width = 100000; row++; aligned.push_back(-1); } else poi.width = pos[k].width;//pos[k+1].first - pos[k].first;//XXX// x.push_back(poi); } sort(x.begin(), x.end()); // Transfer aligned blocks to x for (size_t k = 0; k=x[k].index) x[k].aligned = true; else x[k].aligned = false; } pair smallDiff(100000, -1); for (size_t k = 0; k0 && x[k-1].pos == x[k].pos || x[k].pos == 0) continue; int diff = 0; for (size_t j = k + 1; j < x.size(); j++) { if (x[j].pos > x[k].pos) { if (x[j].row == x[k].row) break; else { diff = x[j].pos - x[k].pos; bool skipRow = x[j].aligned || x[k].aligned; if (skipRow) break; for (size_t i = 0; i x[k].width / 2) break; if (diff < smallDiff.first) { smallDiff.first = diff; smallDiff.second = k; } } } } } if (smallDiff.second != -1) { int minK = smallDiff.second; int diff = smallDiff.first; int basePos = x[minK].pos; set keepRow; for (size_t k = 0; k= basePos && keepRow.count(x[k].row) == 0) { pos[x[k].index].first += diff; changed = true; } } return changed; } return false; } void MetaList::save(const wstring &file, const oEvent *oe) const { xmlparser xml; xml.openOutput(file.c_str(), true); save(xml, oe); xml.closeOut(); } void MetaList::save(xmlparser &xml, const oEvent *oe) const { initSymbols(); xml.startTag("MeOSListDefinition", "version", getMajorVersion()); // xml.write("Title", defaultTitle); xml.write("ListName", listName); if (listOrigin.empty()) listOrigin = gEvent->getName() + L" (" + getLocalDate() + L")"; xml.write("ListOrigin", listOrigin); xml.write("Tag", tag); xml.write("UID", getUniqueId()); xml.write("SortOrder", orderToSymbol[sortOrder]); xml.write("ListType", baseTypeToSymbol[listType]); xml.write("SubListType", baseTypeToSymbol[listSubType]); if (!resultModule.empty()) { string ttw = DynamicResult::undecorateTag(resultModule); xml.write("ResultModule", ttw); try { wstring srcFile; GeneralResult &gr = oe->getGeneralResult(resultModule, srcFile); DynamicResult &dr = dynamic_cast(gr); if (!dr.isBuiltIn()) { string ot = dr.getTag(); dr.setTag(ttw); try { dr.save(xml); } catch (...) { dr.setTag(ot); throw; } dr.setTag(ot); // string db = "Saved res mod: " + ttw + " (" + resultModule + ") h=" + itos(dr.getHashCode())+ "\n"; // OutputDebugString(db.c_str()); } } catch (std::exception &) { // Not available } } if (supportFromControl) xml.write("SupportFrom", supportFromControl); if (supportToControl) xml.write("SupportTo", supportToControl); if (hideLegSelection) xml.write("HideLegSelection", hideLegSelection); for (set::const_iterator it = filter.begin(); it != filter.end(); ++it) xml.write("Filter", "name", filterToSymbol[*it]); for (set::const_iterator it = subFilter.begin(); it != subFilter.end(); ++it) xml.write("SubFilter", "name", subFilterToSymbol[*it]); vector< pair > props(2); xml.write("HeadFont", fontFaces[MLHead].serialize(props), fontFaces[MLHead].font); xml.write("SubHeadFont", fontFaces[MLSubHead].serialize(props), fontFaces[MLSubHead].font); xml.write("ListFont", fontFaces[MLList].serialize(props), fontFaces[MLList].font); xml.write("SubListFont", fontFaces[MLSubList].serialize(props), fontFaces[MLSubList].font); serialize(xml, "Head", getHead()); serialize(xml, "SubHead", getSubHead()); serialize(xml, "List", getList()); serialize(xml, "SubList", getSubList()); xml.endTag(); } void MetaList::load(const wstring &file) { xmlparser xml; xml.read(file); filter.clear(); xmlobject xDef = xml.getObject("MeOSListDefinition"); load(xDef); } void MetaList::load(const xmlobject &xDef) { if (!xDef) throw meosException("Ogiltigt filformat"); xDef.getObjectString("ListName", listName); xDef.getObjectString("ListOrigin", listOrigin); xDef.getObjectString("Tag", tag); xDef.getObjectString("UID", uniqueIndex); xDef.getObjectString("ResultModule", resultModule); // string db = "Specified res mod: " + resultModule + "\n"; // OutputDebugString(db.c_str()); vector rs; xDef.getObjects("MeOSResultCalculationSet", rs); dynamicResults.resize(rs.size()); for (size_t k = 0; k < rs.size(); k++) { DynamicResult dr; dr.load(rs[k]); // string db = "Loaded res mod: " + dr.getTag() + ", h=" + itos(dr.getHashCode())+ "\n"; // OutputDebugString(db.c_str()); wstring file = L"*"; dynamicResults[k] = GeneralResultCtr(file, new DynamicResult(dr)); } supportFromControl = xDef.getObjectBool("SupportFrom"); supportToControl = xDef.getObjectBool("SupportTo"); hideLegSelection =xDef.getObjectBool("HideLegSelection"); string tmp; xDef.getObjectString("SortOrder", tmp); if (symbolToOrder.count(tmp) == 0) { string err = "Invalid sort order X#" + tmp; throw std::exception(err.c_str()); } sortOrder = symbolToOrder[tmp]; xDef.getObjectString("ListType", tmp); if (symbolToBaseType.count(tmp) == 0) { string err = "Invalid type X#" + tmp; throw std::exception(err.c_str()); } listType = symbolToBaseType[tmp]; xDef.getObjectString("SubListType", tmp); if (!tmp.empty()) { if (symbolToBaseType.count(tmp) == 0) { string err = "Invalid type X#" + tmp; throw std::exception(err.c_str()); } listSubType = symbolToBaseType[tmp]; } xmlobject xHeadFont = xDef.getObject("HeadFont"); xmlobject xSubHeadFont = xDef.getObject("SubHeadFont"); xmlobject xListFont = xDef.getObject("ListFont"); xmlobject xSubListFont = xDef.getObject("SubListFont"); if (xHeadFont) { const wchar_t *f = xHeadFont.getw(); fontFaces[MLHead].font = f != 0 ? 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"; 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"; 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"; fontFaces[MLSubList].scale = xSubListFont.getObjectInt("scale"); fontFaces[MLSubList].extraSpaceAbove = xSubListFont.getObjectInt("above"); } xmlobject xHead = xDef.getObject("Head"); xmlobject xSubHead = xDef.getObject("SubHead"); xmlobject xList = xDef.getObject("List"); xmlobject xSubList = xDef.getObject("SubList"); deserialize(xHead, data[MLHead]); deserialize(xSubHead, data[MLSubHead]); deserialize(xList, data[MLList]); deserialize(xSubList, data[MLSubList]); // Check if result list for (int i = 0; i<4; i++) { const vector< vector > &lines = data[i]; for (size_t j = 0; j &cline = lines[j]; for (size_t k = 0; k &resultModules) const { resultModules.resize(dynamicResults.size()); for (size_t k = 0; k < dynamicResults.size(); k++) { resultModules[k].res = dynamic_cast(dynamicResults[k].ptr); resultModules[k].ctr = const_cast(this); } } extern gdioutput *gdi_main; const wstring &MetaList::getListInfo(const oEvent &oe) const { vector resultModules; getDynamicResults(resultModules); for (size_t k = 0; k < resultModules.size(); k++) { if (resultModules[k].res) { return resultModules[k].res->getDescription(); } } if (!resultModule.empty()) { wstring f; try { GeneralResult &res = oe.getGeneralResult(resultModule, f); DynamicResult &dres = dynamic_cast(res); return dres.getDescription(); } catch (...) { } } return _EmptyWString; } void MetaList::retagResultModule(const string &newTag, bool retagStoredModule) { if (newTag == resultModule) return; string oldTag = resultModule; resultModule = newTag; for (size_t k = 0; k < data.size(); k++) { for (size_t i = 0; i < data[k].size(); i++) { for (size_t j = 0; j < data[k][i].size(); j++) { MetaListPost &mlp = data[k][i][j]; if (mlp.getResultModule() == oldTag) mlp.setResultModule(newTag); } } } if (retagStoredModule) { for (size_t k = 0; k < dynamicResults.size(); k++) { DynamicResult *res = dynamic_cast(dynamicResults[k].ptr); if (res && res->getTag() == oldTag) { res->setTag(newTag); } } } } bool MetaList::updateResultModule(const DynamicResult &dr, bool updateSimilar) { for (size_t k = 0; k < dynamicResults.size(); k++) { DynamicResult *res = dynamic_cast(dynamicResults[k].ptr); if (res) { const string &tag1 = res->getTag(); const string &tag2 = dr.getTag(); if (tag1 == tag2 || (updateSimilar && DynamicResult::undecorateTag(tag1) == DynamicResult::undecorateTag(tag2)) ) { long long oldCS = res->getHashCode(); *res = dr; retagResultModule(res->getTag(), false); return res->getHashCode() != oldCS; } } if (dr.getTag() == resultModule) { return true; } } return false; } bool MetaListContainer::updateResultModule(const DynamicResult &dr, bool updateSimilar) { bool changed = false; for (size_t i = 0; i < data.size(); i++) { if (data[i].first == ExternalList) { if (data[i].second.updateResultModule(dr, updateSimilar)) changed = true; } } if (changed && owner) owner->updateChanged(); return changed; } void MetaList::serialize(xmlparser &xml, const string &tagp, const vector< vector > &lp) const { xml.startTag(tagp.c_str()); for (size_t k = 0; k > &lp) { if (!xml) throw meosException("Ogiltigt filformat"); xmlList xLines; xml.getObjects(xLines); for (size_t k = 0; k()); xmlList xBlocks; xLines[k].getObjects(xBlocks); for (size_t j = 0; j > &types, int ¤tType) const { currentType = type; types.clear(); types.reserve(MetaList::typeToSymbol.size()); for (map::const_iterator it = MetaList::typeToSymbol.begin(); it != MetaList::typeToSymbol.end(); ++it) { if (it->first == lNone) continue; if (it->first == lAlignNext) continue; types.push_back(make_pair(lang.tl(it->second), it->first)); } } const string &MetaListPost::getFont() const { return MetaList::fontToSymbol[font]; } void MetaListPost::getFonts(vector< pair > &fonts, int ¤tFont) const { currentFont = font; fonts.clear(); fonts.reserve(MetaList::fontToSymbol.size()); for (map::const_iterator it = MetaList::fontToSymbol.begin(); it != MetaList::fontToSymbol.end(); ++it) { fonts.push_back(make_pair(lang.tl(it->second), it->first)); } } void MetaListPost::getAllFonts(vector< pair > &fonts) { fonts.clear(); fonts.reserve(MetaList::fontToSymbol.size()); for (map::const_iterator it = MetaList::fontToSymbol.begin(); it != MetaList::fontToSymbol.end(); ++it) { fonts.push_back(make_pair(lang.tl(it->second), it->first)); } } void MetaList::getAlignTypes(const MetaListPost &mlp, vector< pair > &types, int ¤tType) const { currentType = mlp.alignType; types.clear(); int gix, lix, ix; getIndex(mlp, gix, lix, ix); set< pair > atypes; bool q = false; for (size_t k = 0; k < data.size(); k++) { for (size_t j = 0; j < data[k].size(); j++) { if ( k == gix && j == lix) { q = true; break; } for (size_t i = 0; i < data[k][j].size(); i++) { if (data[k][j][i].type != lString) atypes.insert(make_pair(data[k][j][i].type, L"")); else atypes.insert(make_pair(data[k][j][i].type, data[k][j][i].text)); } } if (q) break; } if (currentType != lString) atypes.insert(make_pair(EPostType(currentType), L"")); atypes.insert(make_pair(lNone, L"")); for (set< pair >::iterator it = atypes.begin(); it != atypes.end(); ++it) { wstring type = lang.tl(typeToSymbol[it->first]); if (it->first == lString) type += L":" + it->second; types.push_back(make_pair(type, it->first)); } } void MetaList::getIndex(const MetaListPost &mlp, int &gix, int &lix, int &ix) const { for (size_t k = 0; k < data.size(); k++) { for (size_t j = 0; j < data[k].size(); j++) { for (size_t i = 0; i < data[k][j].size(); i++) { if (&data[k][j][i] == &mlp) { gix = k, lix = j, ix = i; return; } } } } throw meosException("Invalid object"); } void MetaListPost::serialize(xmlparser &xml) const { xml.startTag("Block", "Type", MetaList::typeToSymbol[type]); xml.write("Text", text); if (!resultModule.empty()) xml.write("ResultModule", DynamicResult::undecorateTag(resultModule)); if (leg != -1) xml.write("Leg", itos(leg)); if (alignType == lString) xml.writeBool("Align", "BlockAlign", alignBlock, alignWithText); else xml.writeBool("Align", "BlockAlign", alignBlock, MetaList::typeToSymbol[alignType]); xml.write("BlockWidth", blockWidth); xml.write("IndentMin", minimalIndent); if (font != formatIgnore) xml.write("Font", getFont()); if (mergeWithPrevious) xml.write("MergePrevious", "1"); if (textAdjust != 0) xml.write("TextAdjust", getTextAdjust()); if (color != colorDefault) { char bf[16]; sprintf_s(bf, "%x", color); xml.write("Color", bf); } xml.endTag(); } void MetaListPost::deserialize(const xmlobject &xml) { if (!xml) throw meosException("Ogiltigt filformat"); wstring tp = xml.getAttrib("Type").wget(); if (MetaList::symbolToType.count(tp) == 0) { wstring err = L"Invalid type X#" + tp; throw meosException(err); } type = MetaList::symbolToType[tp]; xml.getObjectString("Text", text); xml.getObjectString("ResultModule", resultModule); if (xml.getObject("Leg")) leg = xml.getObjectInt("Leg"); else leg = -1; xmlobject xAlignBlock = xml.getObject("Align"); alignBlock = xAlignBlock && xAlignBlock.getObjectBool("BlockAlign"); blockWidth = xml.getObjectInt("BlockWidth"); minimalIndent = xml.getObjectInt("IndentMin"); wstring at; xml.getObjectString("Align", at); if (!at.empty()) { if (MetaList::symbolToType.count(at) == 0) { alignType = lString; alignWithText = at; } else alignType = MetaList::symbolToType[at]; } mergeWithPrevious = xml.getObjectInt("MergePrevious") != 0; xml.getObjectString("TextAdjust", at); if (at == L"Right") textAdjust = textRight; else if (at == L"Center") textAdjust = textCenter; xml.getObjectString("Color", at); if (!at.empty()) { color = (GDICOLOR)(wcstol(at.c_str(), 0, 16)&0xFFFFFF); //color = GDICOLOR(atoi(at.c_str())); } string f; xml.getObjectString("Font", f); if (!f.empty()) { if (MetaList::symbolToFont.count(f) == 0) { string err = "Invalid font X#" + f; throw meosException(err); } else font = MetaList::symbolToFont[f]; } } map MetaList::typeToSymbol; map MetaList::symbolToType; map MetaList::baseTypeToSymbol; map MetaList::symbolToBaseType; map MetaList::orderToSymbol; map MetaList::symbolToOrder; map MetaList::filterToSymbol; map MetaList::symbolToFilter; map MetaList::fontToSymbol; map MetaList::symbolToFont; map MetaList::subFilterToSymbol; map MetaList::symbolToSubFilter; void MetaList::initSymbols() { if (typeToSymbol.empty()) { typeToSymbol[lAlignNext] = L"AlignNext"; typeToSymbol[lNone] = L"None"; typeToSymbol[lString] = L"String"; typeToSymbol[lResultDescription] = L"ResultDescription"; typeToSymbol[lTimingFromName] = L"TimingFrom"; typeToSymbol[lTimingToName] = L"TimingTo"; typeToSymbol[lCmpName] = L"CmpName"; typeToSymbol[lCmpDate] = L"CmpDate"; typeToSymbol[lCurrentTime] = L"CurrentTime"; typeToSymbol[lClubName] = L"ClubName"; typeToSymbol[lClassName] = L"ClassName"; typeToSymbol[lClassStartName] = L"ClassStartName"; typeToSymbol[lClassStartTime] = L"StartTimeForClass"; typeToSymbol[lClassStartTimeRange] = L"StartTimeForClassRange"; typeToSymbol[lClassLength] = L"ClassLength"; typeToSymbol[lClassResultFraction] = L"ClassResultFraction"; typeToSymbol[lCourseLength] = L"CourseLength"; typeToSymbol[lCourseName] = L"CourseName"; typeToSymbol[lCourseClimb] = L"CourseClimb"; typeToSymbol[lCourseUsage] = L"CourseUsage"; typeToSymbol[lCourseUsageNoVacant] = L"CourseUsageNoVacant"; typeToSymbol[lCourseClasses] = L"CourseClasses"; typeToSymbol[lCourseShortening] = L"CourseShortening"; typeToSymbol[lRunnerName] = L"RunnerName"; typeToSymbol[lRunnerGivenName] = L"RunnerGivenName"; typeToSymbol[lRunnerFamilyName] = L"RunnerFamilyName"; typeToSymbol[lRunnerCompleteName] = L"RunnerCompleteName"; typeToSymbol[lPatrolNameNames] = L"PatrolNameNames"; typeToSymbol[lPatrolClubNameNames] = L"PatrolClubNameNames"; typeToSymbol[lRunnerFinish] = L"RunnerFinish"; typeToSymbol[lRunnerTime] = L"RunnerTime"; typeToSymbol[lRunnerTimeStatus] = L"RunnerTimeStatus"; typeToSymbol[lRunnerTempTimeStatus] = L"RunnerTempTimeStatus"; typeToSymbol[lRunnerTempTimeAfter] = L"RunnerTempTimeAfter"; typeToSymbol[lRunnerTimeAfter] = L"RunnerTimeAfter"; typeToSymbol[lRunnerClassCourseTimeAfter] = L"RunnerClassCourseTimeAfter"; typeToSymbol[lRunnerMissedTime] = L"RunnerTimeLost"; typeToSymbol[lRunnerPlace] = L"RunnerPlace"; typeToSymbol[lRunnerClassCoursePlace] = L"RunnerClassCoursePlace"; typeToSymbol[lRunnerStart] = L"RunnerStart"; typeToSymbol[lRunnerStartCond] = L"RunnerStartCond"; typeToSymbol[lRunnerStartZero] = L"RunnerStartZero"; typeToSymbol[lRunnerClub] = L"RunnerClub"; typeToSymbol[lRunnerCard] = L"RunnerCard"; typeToSymbol[lRunnerBib] = L"RunnerBib"; typeToSymbol[lRunnerStartNo] = L"RunnerStartNo"; typeToSymbol[lRunnerRank] = L"RunnerRank"; typeToSymbol[lRunnerCourse] = L"RunnerCourse"; typeToSymbol[lRunnerRogainingPoint] = L"RunnerRogainingPoint"; typeToSymbol[lRunnerRogainingPointTotal] = L"RunnerRogainingPointTotal"; typeToSymbol[lRunnerRogainingPointReduction] = L"RunnerRogainingReduction"; typeToSymbol[lRunnerRogainingPointOvertime] = L"RunnerRogainingOvertime"; typeToSymbol[lRunnerTimeAdjustment] = L"RunnerTimeAdjustment"; typeToSymbol[lRunnerPointAdjustment] = L"RunnerPointAdjustment"; typeToSymbol[lRunnerRogainingPointGross] = L"RunnerRogainingPointGross"; typeToSymbol[lRunnerUMMasterPoint] = L"RunnerUMMasterPoint"; typeToSymbol[lRunnerTimePlaceFixed] = L"RunnerTimePlaceFixed"; typeToSymbol[lRunnerLegNumberAlpha] = L"RunnerLegNumberAlpha"; typeToSymbol[lRunnerLegNumber] = L"RunnerLegNumber"; typeToSymbol[lResultModuleTime] = L"ResultModuleTime"; typeToSymbol[lResultModuleNumber] = L"ResultModuleNumber"; typeToSymbol[lResultModuleTimeTeam] = L"ResultModuleTimeTeam"; typeToSymbol[lResultModuleNumberTeam] = L"ResultModuleNumberTeam"; typeToSymbol[lRunnerBirthYear] = L"RunnerBirthYear"; typeToSymbol[lRunnerAge] = L"RunnerAge"; typeToSymbol[lRunnerSex] = L"RunnerSex"; typeToSymbol[lRunnerNationality] = L"RunnerNationality"; typeToSymbol[lRunnerPhone] = L"RunnerPhone"; typeToSymbol[lRunnerFee] = L"RunnerFee"; typeToSymbol[lRunnerPaid] = L"RunnerPaid"; typeToSymbol[lRunnerPayMethod] = L"RunnerPayMethod"; typeToSymbol[lRunnerEntryDate] = L"RunnerEntryDate"; typeToSymbol[lRunnerEntryTime] = L"RunnerEntryTime"; typeToSymbol[lTeamName] = L"TeamName"; typeToSymbol[lTeamStart] = L"TeamStart"; typeToSymbol[lTeamStartCond] = L"TeamStartCond"; typeToSymbol[lTeamStartZero] = L"TeamStartZero"; typeToSymbol[lTeamTimeStatus] = L"TeamTimeStatus"; typeToSymbol[lTeamTimeAfter] = L"TeamTimeAfter"; typeToSymbol[lTeamPlace] = L"TeamPlace"; typeToSymbol[lTeamLegTimeStatus] = L"TeamLegTimeStatus"; typeToSymbol[lTeamLegTimeAfter] = L"TeamLegTimeAfter"; typeToSymbol[lTeamRogainingPoint] = L"TeamRogainingPoint"; typeToSymbol[lTeamRogainingPointTotal] = L"TeamRogainingPointTotal"; typeToSymbol[lTeamRogainingPointReduction] = L"TeamRogainingReduction"; typeToSymbol[lTeamRogainingPointOvertime] = L"TeamRogainingOvertime"; typeToSymbol[lTeamTimeAdjustment] = L"TeamTimeAdjustment"; typeToSymbol[lTeamPointAdjustment] = L"TeamPointAdjustment"; typeToSymbol[lTeamTime] = L"TeamTime"; typeToSymbol[lTeamStatus] = L"TeamStatus"; typeToSymbol[lTeamClub] = L"TeamClub"; typeToSymbol[lTeamRunner] = L"TeamRunner"; typeToSymbol[lTeamRunnerCard] = L"TeamRunnerCard"; typeToSymbol[lTeamBib] = L"TeamBib"; typeToSymbol[lTeamStartNo] = L"TeamStartNo"; typeToSymbol[lPunchNamedTime] = L"PunchNamedTime"; typeToSymbol[lPunchTime] = L"PunchTime"; typeToSymbol[lPunchControlNumber] = L"PunchControlNumber"; typeToSymbol[lPunchControlCode] = L"PunchControlCode"; typeToSymbol[lPunchLostTime] = L"PunchLostTime"; typeToSymbol[lPunchControlPlace] = L"PunchControlPlace"; typeToSymbol[lPunchControlPlaceAcc] = L"PunchControlPlaceAcc"; typeToSymbol[lRogainingPunch] = L"RogainingPunch"; typeToSymbol[lTotalCounter] = L"TotalCounter"; typeToSymbol[lSubCounter] = L"SubCounter"; typeToSymbol[lSubSubCounter] = L"SubSubCounter"; typeToSymbol[lTeamFee] = L"TeamFee"; typeToSymbol[lRunnerTotalTime] = L"RunnerTotalTime"; typeToSymbol[lRunnerTimePerKM] = L"RunnerTimePerKM"; typeToSymbol[lRunnerTotalTimeStatus] = L"RunnerTotalTimeStatus"; typeToSymbol[lRunnerTotalPlace] = L"RunnerTotalPlace"; typeToSymbol[lRunnerTotalTimeAfter] = L"RunnerTotalTimeAfter"; typeToSymbol[lRunnerTimeAfterDiff] = L"RunnerTimeAfterDiff"; typeToSymbol[lRunnerPlaceDiff] = L"RunnerPlaceDiff"; typeToSymbol[lRunnerGeneralTimeStatus] = L"RunnerGeneralTimeStatus"; typeToSymbol[lRunnerGeneralPlace] = L"RunnerGeneralPlace"; typeToSymbol[lRunnerGeneralTimeAfter] = L"RunnerGeneralTimeAfter"; typeToSymbol[lTeamTotalTime] = L"TeamTotalTime"; typeToSymbol[lTeamTotalTimeStatus] = L"TeamTotalTimeStatus"; typeToSymbol[lTeamTotalPlace] = L"TeamTotalPlace"; typeToSymbol[lTeamTotalTimeAfter] = L"TeamTotalTimeAfter"; typeToSymbol[lTeamTotalTimeDiff] = L"TeamTotalTimeDiff"; typeToSymbol[lTeamPlaceDiff] = L"TeamPlaceDiff"; typeToSymbol[lCountry] = L"Country"; typeToSymbol[lNationality] = L"Nationality"; typeToSymbol[lControlName] = L"ControlName"; typeToSymbol[lControlCourses] = L"ControlCourses"; typeToSymbol[lControlClasses] = L"ControlClasses"; typeToSymbol[lControlVisitors] = L"ControlVisitors"; typeToSymbol[lControlPunches] = L"ControlPunches"; typeToSymbol[lControlMedianLostTime] = L"ControlMedianLostTime"; typeToSymbol[lControlMaxLostTime] = L"ControlMaxLostTime"; typeToSymbol[lControlMistakeQuotient] = L"ControlMistakeQuotient"; typeToSymbol[lControlRunnersLeft] = L"ControlRunnersLeft"; typeToSymbol[lControlCodes] = L"ControlCodes"; for (map::iterator it = typeToSymbol.begin(); it != typeToSymbol.end(); ++it) { symbolToType[it->second] = it->first; } if (typeToSymbol.size() != lLastItem) throw std::exception("Bad symbol setup"); if (symbolToType.size() != lLastItem) throw std::exception("Bad symbol setup"); baseTypeToSymbol[oListInfo::EBaseTypeRunner] = "Runner"; baseTypeToSymbol[oListInfo::EBaseTypeTeam] = "Team"; baseTypeToSymbol[oListInfo::EBaseTypeClub] = "ClubRunner"; baseTypeToSymbol[oListInfo::EBaseTypePunches] = "Punches"; baseTypeToSymbol[oListInfo::EBaseTypeNone] = "None"; baseTypeToSymbol[oListInfo::EBaseTypeRunnerGlobal] = "RunnerGlobal"; baseTypeToSymbol[oListInfo::EBaseTypeRunnerLeg] = "RunnerLeg"; baseTypeToSymbol[oListInfo::EBaseTypeTeamGlobal] = "TeamGlobal"; baseTypeToSymbol[oListInfo::EBaseTypeControl] = "Control"; baseTypeToSymbol[oListInfo::EBaseTypeCourse] = "Course"; for (map::iterator it = baseTypeToSymbol.begin(); it != baseTypeToSymbol.end(); ++it) { symbolToBaseType[it->second] = it->first; } if (baseTypeToSymbol.size() != oListInfo::EBasedTypeLast_) throw std::exception("Bad symbol setup"); if (symbolToBaseType.size() != oListInfo::EBasedTypeLast_) throw std::exception("Bad symbol setup"); orderToSymbol[ClassStartTime] = "ClassStartTime"; orderToSymbol[ClassStartTimeClub] = "ClassStartTimeClub"; orderToSymbol[ClassResult] = "ClassResult"; orderToSymbol[ClassCourseResult] = "ClassCourseResult"; orderToSymbol[SortByName] = "SortNameOnly"; orderToSymbol[SortByLastName] = "SortLastNameOnly"; orderToSymbol[SortByFinishTime] = "FinishTime"; orderToSymbol[SortByFinishTimeReverse] = "FinishTimeReverse"; orderToSymbol[ClassFinishTime] = "ClassFinishTime"; orderToSymbol[SortByStartTime] = "StartTime"; orderToSymbol[SortByEntryTime] = "EntryTime"; orderToSymbol[ClassPoints] = "ClassPoints"; orderToSymbol[ClassTotalResult] = "ClassTotalResult"; orderToSymbol[ClassTeamLegResult] = "ClassTeamLegResult"; orderToSymbol[CourseResult] = "CourseResult"; orderToSymbol[CourseStartTime] = "CourseStartTime"; orderToSymbol[ClassTeamLeg] = "ClassTeamLeg"; orderToSymbol[Custom] = "CustomSort"; for (map::iterator it = orderToSymbol.begin(); it != orderToSymbol.end(); ++it) { symbolToOrder[it->second] = it->first; } if (orderToSymbol.size() != SortEnumLastItem) throw std::exception("Bad symbol setup"); if (symbolToOrder.size() != SortEnumLastItem) throw std::exception("Bad symbol setup"); filterToSymbol[EFilterHasResult] = "FilterResult"; filterToSymbol[EFilterHasPrelResult] = "FilterPrelResult"; filterToSymbol[EFilterRentCard] = "FilterRentCard"; filterToSymbol[EFilterHasCard] = "FilterHasCard"; filterToSymbol[EFilterExcludeDNS] = "FilterStarted"; filterToSymbol[EFilterExcludeCANCEL] = "FilterNoCancel"; filterToSymbol[EFilterVacant] = "FilterNotVacant"; filterToSymbol[EFilterOnlyVacant] = "FilterOnlyVacant"; filterToSymbol[EFilterHasNoCard] = "FilterNoCard"; for (map::iterator it = filterToSymbol.begin(); it != filterToSymbol.end(); ++it) { symbolToFilter[it->second] = it->first; } if (filterToSymbol.size() != _EFilterMax) throw std::exception("Bad symbol setup"); if (symbolToFilter.size() != _EFilterMax) throw std::exception("Bad symbol setup"); subFilterToSymbol[ESubFilterHasResult] = "FilterResult"; subFilterToSymbol[ESubFilterHasPrelResult] = "FilterPrelResult"; subFilterToSymbol[ESubFilterExcludeDNS] = "FilterStarted"; subFilterToSymbol[ESubFilterVacant] = "FilterNotVacant"; subFilterToSymbol[ESubFilterSameParallel] = "FilterSameParallel"; subFilterToSymbol[ESubFilterSameParallelNotFirst] = "FilterSameParallelNotFirst"; for (map::iterator it = subFilterToSymbol.begin(); it != subFilterToSymbol.end(); ++it) { symbolToSubFilter[it->second] = it->first; } if (subFilterToSymbol.size() != _ESubFilterMax) throw std::exception("Bad symbol setup"); if (symbolToSubFilter.size() != _ESubFilterMax) throw std::exception("Bad symbol setup"); fontToSymbol[normalText] = "NormalFont"; fontToSymbol[boldText] = "Bold"; fontToSymbol[boldLarge] = "BoldLarge"; fontToSymbol[boldHuge] = "BoldHuge"; fontToSymbol[boldSmall] = "BoldSmall"; fontToSymbol[fontLarge] = "LargeFont"; fontToSymbol[fontMedium] = "MediumFont"; fontToSymbol[fontMediumPlus] = "MediumPlus"; fontToSymbol[fontSmall] = "SmallFont"; fontToSymbol[italicSmall] = "SmallItalic"; fontToSymbol[italicText] = "Italic"; fontToSymbol[italicMediumPlus] = "ItalicMediumPlus"; fontToSymbol[formatIgnore] = "DefaultFont"; for (map::iterator it = fontToSymbol.begin(); it != fontToSymbol.end(); ++it) { symbolToFont[it->second] = it->first; } if (fontToSymbol.size() != symbolToFont.size()) throw std::exception("Bad symbol setup"); } } MetaListContainer::MetaListContainer(oEvent *ownerIn): owner(ownerIn) {} MetaListContainer::~MetaListContainer() {} const MetaList &MetaListContainer::getList(int index) const { return data[index].second; } MetaList &MetaListContainer::getList(int index) { return data[index].second; } MetaList &MetaListContainer::addExternal(const MetaList &ml) { data.push_back(make_pair(ExternalList, ml)); if (owner) owner->updateChanged(); return data.back().second; } void MetaListContainer::clearExternal() { globalIndex.clear(); uniqueIndex.clear(); while(!data.empty() && (data.back().first == ExternalList || data.back().first == RemovedList) ) data.pop_back(); listParam.clear(); } void MetaListContainer::save(MetaListType type, xmlparser &xml, const oEvent *oe) const { for (size_t k = 0; k id2Ix; int count = 0; for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { id2Ix[it->first+1] = ++count; // One indexed } for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { it->second.serialize(xml, *this, id2Ix); } } } bool MetaListContainer::load(MetaListType type, const xmlobject &xDef, bool ignoreOld) { if (!xDef) return true; xmlList xList; xDef.getObjects("MeOSListDefinition", xList); wstring majVer = getMajorVersion(); bool hasSkipped = false; if (xList.empty() && strcmp(xDef.getName(), "MeOSListDefinition") == 0) xList.push_back(xDef); wstring err; for (size_t k = 0; k majVer) { newVersion = true; } } data.push_back(make_pair(type, MetaList())); try { data.back().second.load(xList[k]); } catch (const meosException &ex) { if (newVersion && ignoreOld) hasSkipped = true; else if (err.empty()) err = ex.wwhat(); data.pop_back(); } catch (const std::exception &ex) { if (newVersion && ignoreOld) hasSkipped = true; else if (err.empty()) { string nw = ex.what(); err.insert(err.begin(), nw.begin(), nw.end()); } data.pop_back(); } } setupIndex(EFirstLoadedList); xmlList xParam; xDef.getObjects("ListParam", xParam); for (size_t k = 0; k::iterator it = listParam.begin(); it != listParam.end(); ++it) { int next = it->second.nextList; if (next>0) { int ix = next - 1; if (listParam.count(ix)) { if (listParam[ix].previousList == 0) listParam[ix].previousList = it->first + 1; else it->second.nextList = 0; // Clear relation } else it->second.nextList = 0; // Clear relation } } if (owner) owner->updateChanged(); if (!err.empty()) throw meosException(err); return !hasSkipped; } bool MetaList::isValidIx(size_t gIx, size_t lIx, size_t ix) const { return gIx < data.size() && lIx < data[gIx].size() && (ix == -1 || ix < data[gIx][lIx].size()); } MetaListPost &MetaList::addNew(int groupIx, int lineIx, int &ix) { if (isValidIx(groupIx, lineIx, -1)) { ix = data[groupIx][lineIx].size(); data[groupIx][lineIx].push_back(MetaListPost(lString)); data[groupIx][lineIx].back().setResultModule(resultModule); return data[groupIx][lineIx].back(); } else if (lineIx == -1 && size_t(groupIx) < data.size()) { lineIx = data[groupIx].size(); addRow(groupIx); return addNew(groupIx, lineIx, ix); } throw meosException("Invalid index"); } MetaListPost &MetaList::getMLP(int groupIx, int lineIx, int ix) { if (isValidIx(groupIx, lineIx, ix)) { return data[groupIx][lineIx][ix]; } else throw meosException("Invalid index"); } void MetaList::removeMLP(int groupIx, int lineIx, int ix) { if (isValidIx(groupIx, lineIx, ix)) { data[groupIx][lineIx].erase(data[groupIx][lineIx].begin() + ix); if (data[groupIx][lineIx].empty() && data[groupIx].size() == lineIx + 1) data[groupIx].pop_back(); } else throw meosException("Invalid index"); } void MetaList::moveOnRow(int groupIx, int lineIx, int &ix, int delta) { if (isValidIx(groupIx, lineIx, ix)) { if (ix > 0 && delta == -1) { ix--; swap(data[groupIx][lineIx][ix], data[groupIx][lineIx][ix+1]); } else if (delta == 1 && size_t(ix + 1) < data[groupIx][lineIx].size()) { ix++; swap(data[groupIx][lineIx][ix], data[groupIx][lineIx][ix-1]); } } else throw meosException("Invalid index"); } string MetaListContainer::getUniqueId(EStdListType code) const { if (int(code) < int(EFirstLoadedList)) return "C" + itos(code); else { size_t ix = int(code) - int(EFirstLoadedList); if (ix < data.size()) { if (!data[ix].second.getTag().empty()) return "T" + data[ix].second.getTag(); else return data[ix].second.getUniqueId(); } else return "C-1"; } } EStdListType MetaListContainer::getCodeFromUnqiueId(const string &id) const { if (id[0] == 'C') return EStdListType(atoi(id.substr(1).c_str())); else if (id[0] == 'T') { string tag = id.substr(1); map::const_iterator res = tagIndex.find(tag); if (res != tagIndex.end()) return res->second; else return EStdNone; } else { map::const_iterator res = uniqueIndex.find(id); if (res != uniqueIndex.end()) return res->second; else return EStdNone; } } void MetaListContainer::setupIndex(int firstIndex) const { globalIndex.clear(); uniqueIndex.clear(); for (size_t k = 0; k &listMap, bool resultsOnly) const { setupIndex(firstIndex); for (size_t k = 0; k::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { if (it->second.name.length() >= len) { if (nameIn == it->second.name) maxValue = max(1, maxValue); else { if (it->second.name.substr(0, len) == nameIn) { int v = _wtoi(it->second.name.substr(len + 1).c_str()); if (v > 0) maxValue = max(v, maxValue); } } } } if (maxValue == -1) return nameIn; else return nameIn + L" " + itow(maxValue + 1); } bool MetaListContainer::interpret(oEvent *oe, const gdioutput &gdi, const oListParam &par, int lineHeight, oListInfo &li) const { map::const_iterator it = globalIndex.find(par.listCode); if (it != globalIndex.end()) { data[it->second].second.interpret(oe, gdi, par, lineHeight, li); return true; } return false; } EStdListType MetaListContainer::getType(const std::string &tag) const { map::iterator it = tagIndex.find(tag); if (it == tagIndex.end()) throw meosException("Could not load list 'X'.#" + tag); return it->second; } EStdListType MetaListContainer::getType(const int index) const { return EStdListType(index + EFirstLoadedList); } void MetaListContainer::getLists(vector > &lists, bool markBuiltIn, bool resultListOnly, bool noTeamList) const { lists.clear(); for (size_t k = 0; k= MAXLISTPARAMID) { toInsertAfter -= MAXLISTPARAMID; swap(toMerge, toInsertAfter); } oListParam &after = getParam(toInsertAfter); oListParam &merge = getParam(toMerge); merge.showInterTitle = showTitleBetween; int oldNext = after.nextList; after.nextList = toMerge + 1; merge.previousList = toInsertAfter + 1; if (oldNext > 0) { oListParam &am = getParam(oldNext - 1); am.previousList = toMerge + 1; merge.nextList = oldNext; } if (owner) owner->updateChanged(); } void MetaListContainer::getMergeCandidates(int toMerge, vector< pair > ¶m) const { param.clear(); for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { if (it->first == toMerge) continue; if (it->second.previousList == 0) { wstring desc = L"Före X#" + it->second.getName(); param.push_back(make_pair(lang.tl(desc), MAXLISTPARAMID + it->first)); } if (it->second.nextList == 0) { wstring desc = L"Efter X#" + it->second.getName(); param.push_back(make_pair(lang.tl(desc), it->first)); } else { const oListParam &next = getParam(it->second.nextList - 1); wstring desc = L"Mellan X och Y#" + it->second.getName() + L"#" + next.getName(); param.push_back(make_pair(lang.tl(desc), it->first)); } } } bool MetaListContainer::canSplit(int index) const { return getParam(index).nextList > 0; } void MetaListContainer::split(int index) { oListParam &par = getParam(index); int n = par.nextList; par.nextList = 0; par.previousList = 0; if (n > 0) { split(n-1); if (owner) owner->updateChanged(); } } const string &MetaListContainer::getTag(int index) const { if (size_t(index) >= data.size()) throw meosException("Invalid index"); if (data[index].first != InternalList) throw meosException("Invalid list type"); return data[index].second.getTag(); } void MetaListContainer::removeList(int index) { if (size_t(index) >= data.size()) throw meosException("Invalid index"); if (data[index].first != ExternalList) throw meosException("Invalid list type"); data[index].first = RemovedList; if (owner) owner->updateChanged(); } void MetaListContainer::saveList(int index, const MetaList &ml) { if (size_t(index) >= data.size()) throw meosException("Invalid index"); if (data[index].first == InternalList) throw meosException("Invalid list type"); data[index].first = ExternalList; data[index].second = ml; data[index].second.initUniqueIndex(); if (owner) owner->updateChanged(); } void MetaList::getFilters(vector< pair > &filters) const { filters.clear(); for (map::const_iterator it = filterToSymbol.begin(); it != filterToSymbol.end(); ++it) { bool has = this->filter.count(it->first) == 1; filters.push_back(make_pair(gdi_main->widen(it->second), has)); } } void MetaList::setFilters(const vector &filters) { int k = 0; filter.clear(); assert(filters.size() == filterToSymbol.size()); for (map::const_iterator it = filterToSymbol.begin(); it != filterToSymbol.end(); ++it) { bool has = filters[k++]; if (has) filter.insert(it->first); } } void MetaList::getSubFilters(vector< pair > &filters) const { filters.clear(); for (map::const_iterator it = subFilterToSymbol.begin(); it != subFilterToSymbol.end(); ++it) { bool has = this->subFilter.count(it->first) == 1; filters.push_back(make_pair(gdi_main->widen(it->second), has)); } } void MetaList::setSubFilters(const vector &filters) { int k = 0; subFilter.clear(); assert(filters.size() == subFilterToSymbol.size()); for (map::const_iterator it = subFilterToSymbol.begin(); it != subFilterToSymbol.end(); ++it) { bool has = filters[k++]; if (has) subFilter.insert(it->first); } } void MetaList::getResultModule(const oEvent &oe, vector< pair > &modules, int ¤tModule) const { modules.clear(); vector< pair > > mol; oe.getGeneralResults(false, mol, true); modules.push_back(make_pair(lang.tl("Standard"), 0)); currentModule = 0; for (size_t k = 0; k < mol.size(); k++) { modules.push_back(make_pair(mol[k].second.second, mol[k].first)); if (resultModule == mol[k].second.first) currentModule = mol[k].first; } } MetaList &MetaList::setResultModule(const oEvent &oe, int moduleIx) { vector< pair > > mol; oe.getGeneralResults(false, mol, false); if (moduleIx == 0) { //resultModule = ""; retagResultModule("", false); return *this; } else { for (size_t k = 0; k < mol.size(); k++) { if (moduleIx == mol[k].first) { retagResultModule(mol[k].second.first, false); return *this; } } } throw meosException("Unknown result module"); } MetaList &MetaList::setSupportLegSelection(bool state) { hideLegSelection = !state; return *this; } bool MetaList::supportLegSelection() const { return !hideLegSelection; } MetaList &MetaList::setSupportFromTo(bool from, bool to) { supportFromControl = from; supportToControl = to; return *this; } void MetaList::getSortOrder(bool forceIncludeCustom, vector< pair > &orders, int ¤tOrder) const { orders.clear(); for(map::const_iterator it = orderToSymbol.begin(); it != orderToSymbol.end(); ++it) { if (it->first != Custom || forceIncludeCustom || !resultModule.empty() || currentOrder == Custom) orders.push_back(make_pair(lang.tl(it->second), it->first)); } currentOrder = sortOrder; } void MetaList::getBaseType(vector< pair > &types, int ¤tType) const { types.clear(); for(map::const_iterator it = baseTypeToSymbol.begin(); it != baseTypeToSymbol.end(); ++it) { if (it->first == oListInfo::EBaseTypeNone || it->first == oListInfo::EBaseTypePunches) continue; types.push_back(make_pair(lang.tl(it->second), it->first)); } currentType = listType; } void MetaList::getSubType(vector< pair > &types, int ¤tType) const { types.clear(); oListInfo::EBaseType t; set tt; t = oListInfo::EBaseTypeNone; tt.insert(t); types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); t = oListInfo::EBaseTypePunches; tt.insert(t); types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); t = oListInfo::EBaseTypeRunner; tt.insert(t); types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); if (tt.count(listSubType) == 0) { t = listSubType; types.push_back(make_pair(lang.tl(baseTypeToSymbol[t]), t)); } currentType = listSubType; } int MetaListContainer::getNumLists(MetaListType t) const { int num = 0; for (size_t k = 0; k > ¶m) const { for (map::const_iterator it = listParam.begin(); it != listParam.end(); ++it) { if (it->second.previousList > 0) continue; param.push_back(make_pair(it->second.getName(), it->first)); } } void MetaListContainer::removeParam(int index) { if (listParam.count(index)) { listParam[index].previousList = 0; if (listParam[index].nextList > 0) { oListParam &next = getParam(listParam[index].nextList - 1); if (next.previousList == index + 1) removeParam(listParam[index].nextList-1); } listParam.erase(index); if (owner) owner->updateChanged(); } else throw meosException("No such parameters exist"); } void MetaListContainer::addListParam(oListParam ¶m) { param.saved = true; int ix = 0; if (!listParam.empty()) ix = listParam.rbegin()->first + 1; listParam[ix] = param; if (owner) owner->updateChanged(); } const oListParam &MetaListContainer::getParam(int index) const { if (!listParam.count(index)) throw meosException("Internal error"); return listParam.find(index)->second; } oListParam &MetaListContainer::getParam(int index) { if (!listParam.count(index)) throw meosException("Internal error"); return listParam.find(index)->second; } extern gdioutput *gdi_main; void MetaListContainer::enumerateLists(vector< pair > > &out) const { out.clear(); wchar_t bf[260]; getUserFile(bf, L""); vector res; expandDirectory(bf, L"*.meoslist", res); for (size_t k = 0; k < res.size(); k++) { xmlparser xml; try { xml.read(res[k], 6); xmlobject xDef = xml.getObject("MeOSListDefinition"); wstring name; xDef.getObjectString("ListName", name); wstring origin; xDef.getObjectString("ListOrigin", origin); string uid; xDef.getObjectString("UID", uid); if (!origin.empty()) name += makeDash(L" - ") + origin; out.push_back(make_pair(name, make_pair(uid, res[k]))); } catch (std::exception &) { // Ignore log?! out.push_back(make_pair(L"Error? " + res[k], make_pair("?", res[k]))); } } sort(out.begin(), out.end()); } int MetaList::getResultModuleIndex(oEvent *oe, oListInfo &li, const MetaListPost &lp) const { if (resultToIndex.empty()) { vector< pair > > tagNameList; oe->getGeneralResults(false, tagNameList, false); resultToIndex[""] = -1; for (size_t k = 0; k < tagNameList.size(); k++) { resultToIndex[tagNameList[k].second.first] = k; } } if (resultToIndex.count(lp.resultModule) == 0) throw meosException("Unknown result module: " + lp.resultModule); if (!lp.resultModule.empty()) li.additionalResultModule(lp.resultModule); return resultToIndex[lp.resultModule]; } void MetaListContainer::getListsByResultModule(const string &tag, vector &listIx) const { listIx.clear(); for (size_t k = 0; k