Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
algorithminformationparser.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
21 
22 #include <limits>
23 #include <locale>
24 
25 #include "../system/eptexception.h"
26 #include "../system/log.h"
27 #include "../settings.h"
28 #include "../adapters/filemanager.h"
29 
30 using tinyxml2::XMLDocument;
31 using tinyxml2::XMLElement;
32 
33 std::shared_ptr<const AlgorithmInformation> AlgorithmInformationParser::parse(const std::string &algorithmId) const {
34  XMLDocument document;
35 
36  std::string fileContent(FileManager::getSingleton().getAlgorithmInformationFileContent(algorithmId));
37 
38  document.Parse(fileContent.c_str(), fileContent.size());
39 
40  if (document.Error()) {
41  EPT_EXCEPT(EptException::ERR_CANNOT_READ_FROM_FILE, "Error while parsing algorithm information from file '" + fileContent + "'");
42  }
43 
44  const XMLElement *root = document.FirstChildElement();
45 
46  if (!root) {
47  EPT_EXCEPT(EptException::ERR_CANNOT_READ_FROM_FILE, "No root element found.");
48  }
49 
50  const int year = root->IntAttribute("year");
51  std::string author = root->Attribute("author");
52  std::string name;
53  std::string description;
55 
56  for (const XMLElement *child = root->FirstChildElement(); child; child = child->NextSiblingElement()) {
57  if (strcmp(child->Name(), "name") == 0) {
58  // name element
59  name = parseLanguageString(child);
60  } else if (strcmp(child->Name(), "description") == 0) {
61  // description
62  description = parseLanguageString(child);
63  } else if (strcmp(child->Name(), "param") == 0) {
64  // param
65  params.push_back(parseAlgorithmParameter(child));
66  }
67 
68  }
69 
70  return std::shared_ptr<const AlgorithmInformation>(
71  new AlgorithmInformation(algorithmId, name, description, year, author, params));
72 }
73 
74 std::string AlgorithmInformationParser::parseLanguageString(const tinyxml2::XMLElement *element) const {
75  EptAssert(element, "XMLElement has to exist");
76 
77  std::string languageId = Settings::getSingleton().getUserLanguageId();
78 
79  std::string defaultLanguageString;
80 
81  for (const XMLElement *child = element->FirstChildElement(); child; child = child->NextSiblingElement()) {
82  if (strcmp(child->Name(), "string") != 0) {
83  EPT_EXCEPT(EptException::ERR_INVALIDPARAMS, "Only string names are expecten when parsing elements of type '"
84  + std::string(element->Name()) + "', but element with name '"
85  + std::string(child->Name()) + "' was given.");
86 
87  }
88  if (child->Attribute("lang")) {
89  if (languageId == child->Attribute("lang")) {
90  return child->GetText();
91  }
92  } else {
93  // default
94  defaultLanguageString = child->GetText();
95 
96  if (languageId == "en") {
97  // default language is en
98  return defaultLanguageString;
99  }
100  }
101 
102  // not the desired string
103  }
104 
105  // language string not found. Check if default string exist, then return this one
106  if (defaultLanguageString.size() > 0) {
107  LogD("Element '%s' has missing translation for '%s'", element->Value(), languageId.c_str());
108  return defaultLanguageString;
109  }
110 
111  EPT_EXCEPT(EptException::ERR_INVALIDPARAMS, "Element '" + std::string(element->Name()) + "' has no child elements with name 'string'");
112 }
113 
115  EptAssert(element, "XMLElement has to exist");
116 
117  const std::string id = element->Attribute("id");
118  const std::string type = element->Attribute("type");
119 
120  std::string label, description;
121 
122  const XMLElement *labelElement = element->FirstChildElement("label");
123  const XMLElement *descriptionElement = element->FirstChildElement("description");
124 
125  if (labelElement) {
126  label = parseLanguageString(labelElement);
127  } else {
128  EPT_EXCEPT(EptException::ERR_INVALIDPARAMS, "XMLElement 'label' missing while parsing a parameter element");
129  }
130 
131  if (descriptionElement) {
132  description = parseLanguageString(descriptionElement);
133  } else {
134  LogD("Desciption of parameter not set.");
135  }
136 
137  if (type == "double") {
138  const double defaultValue = element->DoubleAttribute("default");
139  double minValue = std::numeric_limits<double>::min();
140  double maxValue = std::numeric_limits<double>::max();
141  int precision = -1;
142 
143  element->QueryDoubleAttribute("min", &minValue);
144  element->QueryDoubleAttribute("max", &maxValue);
145  element->QueryIntAttribute("precision", &precision);
146  return AlgorithmParameter(id, label, description, defaultValue, minValue, maxValue, precision);
147  } else if (type == "int") {
148  const int defaultValue = element->IntAttribute("default");
149  int minValue = std::numeric_limits<int>::min();
150  int maxValue = std::numeric_limits<int>::max();
151 
152  element->QueryIntAttribute("min", &minValue);
153  element->QueryIntAttribute("max", &maxValue);
154  return AlgorithmParameter(id, label, description, defaultValue, minValue, maxValue);
155  } else if (type == "list") {
156  const std::string defaultValue = element->Attribute("default");
158 
159  for (const XMLElement *entry = element->FirstChildElement("entry"); entry;
160  entry = entry->NextSiblingElement("entry")) {
161  EptAssert(entry->Attribute("value"), "Value entry is required for string list parameter.");
162  std::string value = entry->Attribute("value");
163  std::string label = parseLanguageString(entry);
164  list.push_back(std::make_pair(value, label));
165  }
166 
167  return AlgorithmParameter(id, label, description, defaultValue, list);
168  } else {
169  EPT_EXCEPT(EptException::ERR_INVALIDPARAMS, "Parameter type '" + type + "' is not supported.");
170  }
171 }
static Settings & getSingleton()
Get a pointer to the singleton instance.
Definition: settings.cpp:46
std::string parseLanguageString(const tinyxml2::XMLElement *element) const
static FileManager & getSingleton()
FileManager::getSingleton: Get a reference to the singleton.
Definition: filemanager.cpp:47
#define LogD(...)
Definition: log.h:44
std::vector< ParameterType > ParameterListType
#define EPT_EXCEPT(num, desc)
Definition: eptexception.h:119
std::shared_ptr< const AlgorithmInformation > parse(const std::string &algorithmId) const
virtual std::string getUserLanguageId() const
Settings::getUserLanguageId.
Definition: settings.cpp:62
AlgorithmParameter parseAlgorithmParameter(const tinyxml2::XMLElement *element) const
#define EptAssert(a, b)
Definition: eptexception.h:47
std::vector< std::pair< std::string, std::string > > StringParameterList