StateGroupDocGenerator.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 #include "StateGroupDocGenerator.h"
25 
26 #include <fstream>
27 
28 #include <filesystem>
29 
32 
33 #include <SimoxUtility/algorithm/string/string_tools.h>
34 
35 #include <boost/format.hpp>
36 
37 namespace armarx
38 {
39 
41  { }
42 
43 
44 
45  std::set<std::string> StatechartGroupDocGenerator::getUsedProfiles(const RapidXmlReaderNode& stateNode) const
46  {
47  std::set<std::string> usedProfiles;
48 
49  for (RapidXmlReaderNode defaultNode : stateNode.nodes("InputParameters", "Parameter", "DefaultValue"))
50  {
51  usedProfiles.insert(defaultNode.attribute_value_or_default("profile", "Root"));
52  }
53 
54  for (RapidXmlReaderNode defaultNode : stateNode.nodes("OutputParameters", "Parameter", "DefaultValue"))
55  {
56  usedProfiles.insert(defaultNode.attribute_value_or_default("profile", "Root"));
57  }
58 
59  for (RapidXmlReaderNode defaultNode : stateNode.nodes("LocalParameters", "Parameter", "DefaultValue"))
60  {
61  usedProfiles.insert(defaultNode.attribute_value_or_default("profile", "Root"));
62  }
63 
64  return usedProfiles;
65  }
66 
67  std::string StatechartGroupDocGenerator::unescapeString(std::string str) const
68  {
69  std::string res;
70  std::string::const_iterator it = str.begin();
71 
72  while (it != str.end())
73  {
74  char c = *it++;
75 
76  if (c == '\\' && it != str.end())
77  {
78  switch (*it++)
79  {
80  case '\\':
81  c = '\\';
82  break;
83 
84  case 'r':
85  c = '\r';
86  break;
87 
88  case 'n':
89  c = '\n';
90  break;
91 
92  case 't':
93  c = '\t';
94  break;
95 
96  // all other escapes
97  default:
98  // invalid escape sequence - skip it. alternatively you can copy it as is, throw an exception...
99  continue;
100  }
101  }
102 
103  res += c;
104  }
105 
106  return res;
107  }
108 
109  std::string StatechartGroupDocGenerator::nToBr(std::string str) const
110  {
111  return simox::alg::replace_all(str, "\n", "<br />\n");
112  }
113 
114  DoxTablePtr StatechartGroupDocGenerator::buildParameterTable(RapidXmlReaderNode parametersNode) const
115  {
116  std::set<std::string> usedProfiles;
117 
118  for (RapidXmlReaderNode defaultNode : parametersNode.nodes("Parameter", "DefaultValue"))
119  {
120  usedProfiles.insert(defaultNode.attribute_value_or_default("profile", "Root"));
121  }
122 
123  std::vector<std::string> header;
124 
125  header.push_back("Name");
126  header.push_back("Type");
127  header.push_back("Description");
128  std::copy(usedProfiles.begin(), usedProfiles.end(), std::back_inserter(header));
129  DoxTablePtr table(new DoxTable(header));
130 
131  for (RapidXmlReaderNode parameterNode : parametersNode.nodes("Parameter"))
132  {
133  std::vector<std::string> row(header.size());
134  row.at(0) = parameterNode.attribute_value("name");
135  row.at(1) = parameterNode.has_attribute("docType") ? parameterNode.attribute_value("docType") : parameterNode.attribute_value("type");
136  row.at(2) = nToBr(parameterNode.first_node_value_or_default("Description", ""));
137 
138  for (RapidXmlReaderNode defaultNode : parameterNode.nodes("DefaultValue"))
139  {
140  int index = std::find(header.begin(), header.end(), defaultNode.attribute_value_or_default("profile", "Root")) - header.begin();
141  std::string defaultValue = defaultNode.has_attribute("docValue") ? defaultNode.attribute_value("docValue") : defaultNode.attribute_value("value");
142  row.at(index) = nToBr(unescapeString(defaultValue));
143  }
144 
145  table->addRow(row);
146  }
147 
148  return table;
149  }
150  void StatechartGroupDocGenerator::addParameterTable(const DoxDocPtr& doc, const RapidXmlReaderNode& stateNode, std::string name, const char* nodeName) const
151  {
152  DoxTablePtr table = buildParameterTable(stateNode.first_node(nodeName));
153 
154  if (table->rows() == 0)
155  {
156  doc->addLine("No " + name + ".<br />");
157  }
158  else
159  {
160  doc->addLine(name + ":");
161  doc->addEntry(table);
162  }
163  }
164 
165  std::string StatechartGroupDocGenerator::getNodeAttrsFromStateType(const std::string& nodeType) const
166  {
167  if (nodeType == "EndState")
168  {
169  return "shape=box,style=filled,fillcolor=\"#FFFF96\"";
170  }
171 
172  if (nodeType == "RemoteState")
173  {
174  return "shape=box,style=filled,fillcolor=\"#96FFFA\"";
175  }
176 
177  if (nodeType == "DynamicRemoteState")
178  {
179  return "shape=box,style=filled,fillcolor=\"#B147EA\"";
180  }
181 
182  return "shape=box,style=filled,fillcolor=\"#B3D7FF\"";
183  }
184 
186  {
187  DoxDocPtr doc(new DoxDoc);
188  std::string packageName = reader->getPackageName();
189  std::string groupName = reader->getGroupName();
190  doc->addLine(fmt("@defgroup %s-%s %s", packageName, groupName, groupName));
191  doc->addLine(fmt("@ingroup Statecharts %s-Statecharts", packageName));
192  doc->addLine(nToBr(reader->getDescription()));
193 
194 
195  bool anyPrivateStateFound = false;
196 
197  for (std::string statefile : reader->getStateFilepaths())
198  {
199  if (reader->getStateVisibility(statefile) == StatechartGroupXmlReader::ePrivate)
200  {
201  anyPrivateStateFound = true;
202  }
203 
204  }
205 
206  if (anyPrivateStateFound)
207  {
208  doc->addLine();
209  doc->addLine(fmt("@defgroup %s-%s-PrivateStates %s Private States", packageName, groupName, groupName));
210  doc->addLine(fmt("@ingroup %s-%s", packageName, groupName));
211  }
212 
213  for (std::string statefile : reader->getStateFilepaths())
214  {
215  RapidXmlReaderPtr stateReader = RapidXmlReader::FromFile(statefile);
216  RapidXmlReaderNode stateNode = stateReader->getRoot("State");
217  std::string stateName = stateNode.attribute_value("name");
218  std::string stateUuid = stateNode.attribute_value("uuid");
219 
220  doc->addLine();
221  //doc->addLine(fmt("@defgroup %s-%s-%s %s", packageName, groupName, stateName, stateName));
222  doc->addLine(fmt("@defgroup State-%s %s", stateUuid, stateName));
223  doc->addLine(fmt("@ingroup %s-%s%s", packageName, groupName, reader->getStateVisibility(statefile) == StatechartGroupXmlReader::ePublic ? "" : "-PrivateStates"));
224  doc->addLine("@brief " + stateNode.first_node_value_or_default("Description", "This state has no description."));
225  doc->addLine();
226 
227  addParameterTable(doc, stateNode, "\\b Input \\b Parameters", "InputParameters");
228  addParameterTable(doc, stateNode, "\\b Local \\b Parameters", "LocalParameters");
229  addParameterTable(doc, stateNode, "\\b Output \\b Parameters", "OutputParameters");
230 
231  doc->addLine("<br/>\\b State \\b used by:<br />");
232 
233  if (usageMap.count(stateUuid) > 0)
234  {
235  std::set<std::string> users = usageMap.find(stateUuid)->second;
236 
237  for (std::string uuid : users)
238  {
239  doc->addLine(fmt("@ref State-%s <br />", uuid));
240  }
241  }
242 
243  doc->addLine("<br/>\\b Substates:<br />");
244 
245  for (RapidXmlReaderNode substateNode : stateNode.nodes("Substates", nullptr))
246  {
247  if (substateNode.name() == "LocalState" || substateNode.name() == "RemoteState" || substateNode.name() == "DynamicRemoteState")
248  {
249  std::string name = substateNode.attribute_value("name");
250  std::string refuuid = substateNode.attribute_value("refuuid");
251  std::map<std::string, StateInfo>::const_iterator it = uuidToStateInfoMap.find(refuuid);
252 
253  if (it == uuidToStateInfoMap.end())
254  {
255  doc->addLine(fmt("@ref State-%s \"%s (External Package)\"<br />", refuuid, name));
256  }
257  else
258  {
259  StateInfo stateInfo = it->second;
260 
261  if (stateInfo.group == groupName && stateInfo.state == name)
262  {
263  doc->addLine(fmt("@ref State-%s<br />", refuuid));
264  }
265  else if (stateInfo.group == groupName)
266  {
267  doc->addLine(fmt("%s -> @ref State-%s \"%s\"<br />", name, refuuid, stateInfo.state));
268  }
269  else
270  {
271  doc->addLine(fmt("%s -> @ref State-%s \"%s-%s\"<br />", name, refuuid, stateInfo.group, stateInfo.state));
272  }
273  }
274  }
275  }
276 
277  doc->addLine("<br/>\\b Statechart \\b layout:");
279  graph->addNode("", "shape=point");
280  RapidXmlReaderNode startStateNode = stateNode.first_node("StartState");
281 
282  if (startStateNode.is_valid())
283  {
284  graph->addTransition("", startStateNode.attribute_value("substateName"), "");
285  }
286 
287  for (RapidXmlReaderNode substateNode : stateNode.nodes("Substates", nullptr))
288  {
289  std::string shape = getNodeAttrsFromStateType(substateNode.name());
290  graph->addNode(substateNode.attribute_value("name"), shape);
291  }
292 
293  for (RapidXmlReaderNode transition : stateNode.nodes("Transitions", "Transition"))
294  {
295  if (transition.has_attribute("from") && transition.has_attribute("to") && transition.has_attribute("eventName"))
296  {
297  std::string from = transition.attribute_value_or_default("from", "");
298  std::string to = transition.attribute_value_or_default("to", "");
299  std::string eventName = transition.attribute_value_or_default("eventName", "");
300 
301  graph->addTransition(from, to, eventName);
302  }
303  }
304 
305  if (graph->transitionCount() > 0)
306  {
307  doc->addEntry(graph);
308  }
309 
310 
311  /*std::vector<std::string> header;
312 
313  header.push_back("Name");
314  header.push_back("Type");
315  header.push_back("Description");
316  std::copy(usedProfiles.begin(), usedProfiles.end(), std::back_inserter(header));
317  DoxTablePtr table(new DoxTable(header));
318 
319  for(RapidXmlReaderNode parameterNode : stateNode.nodes("InputParameters", "Parameter"))
320  {
321  std::vector<std::string> row(header.size());
322  row.at(0) = parameterNode.attribute_value("name");
323  row.at(1) = parameterNode.attribute_value("type");
324  row.at(2) = parameterNode.first_node_value_or_default("Description", "");
325  for(RapidXmlReaderNode defaultNode : parameterNode.nodes("DefaultValue"))
326  {
327  int index = std::find(header.begin(), header.end(), defaultNode.attribute_value_or_default("profile", "Root")) - header.begin();
328  row.at(index) = defaultNode.has_attribute("docValue") ? defaultNode.attribute_value("docValue") : defaultNode.attribute_value("value");
329  }
330  table->addRow(row);
331  }
332 
333  doc->addEntry(table);*/
334  }
335 
336 
337  CppWriterPtr writer(new CppWriter(true));
338  doc->writeDoc(writer);
339  return writer->getString();
340  }
341 
342  std::string StatechartGroupDocGenerator::fmt(const std::string& fmt, const std::string& arg1) const
343  {
344  return boost::str(boost::format(fmt) % arg1);
345  }
346 
347  std::string StatechartGroupDocGenerator::fmt(const std::string& fmt, const std::string& arg1, const std::string& arg2) const
348  {
349  return boost::str(boost::format(fmt) % arg1 % arg2);
350  }
351 
352  std::string StatechartGroupDocGenerator::fmt(const std::string& fmt, const std::string& arg1, const std::string& arg2, const std::string& arg3) const
353  {
354  return boost::str(boost::format(fmt) % arg1 % arg2 % arg3);
355  }
356 
357  std::string StatechartGroupDocGenerator::fmt(const std::string& fmt, const std::string& arg1, const std::string& arg2, const std::string& arg3, const std::string& arg4) const
358  {
359  return boost::str(boost::format(fmt) % arg1 % arg2 % arg3 % arg4);
360  }
361 
362  void StatechartGroupDocGenerator::generateDoxygenFile(const std::string& groupDefinitionFilePath)
363  {
365  reader->readXml(std::filesystem::path(groupDefinitionFilePath));
366  CMakePackageFinder finder = getFinder(reader);
367 
368  std::filesystem::path doxyFile = finder.getBuildDir();
369 
370  if (!outputPath.empty())
371  {
372  doxyFile = outputPath;
373  }
374 
375  if (!doxyFile.string().empty())
376  {
377  doxyFile /= "doxygen";
378  }
379  else
380  {
381  doxyFile = ".";
382  }
383 
384  doxyFile /= reader->getGroupName() + ".dox";
385 
386  std::ofstream file;
387  file.open(doxyFile.string().c_str());
388 
389  if (!file.is_open())
390  {
391  throw armarx::exceptions::local::FileOpenException(doxyFile.string());
392  }
393 
394  std::string docstr = generateDocString(reader);
395  file << docstr;
396 
397  ARMARX_INFO_S << "wrote " << docstr.size() << " bytes to " << doxyFile.string();
398 
399  }
400 
401  void StatechartGroupDocGenerator::buildReferenceIndex(const std::vector<std::string>& groups)
402  {
403  for (std::string groupDefinitionFilePath : groups)
404  {
406  reader->readXml(std::filesystem::path(groupDefinitionFilePath));
407 
408  for (std::string statefile : reader->getStateFilepaths())
409  {
410  RapidXmlReaderPtr stateReader = RapidXmlReader::FromFile(statefile);
411  RapidXmlReaderNode stateNode = stateReader->getRoot("State");
412  std::string stateName = stateNode.attribute_value("name");
413  std::string stateUuid = stateNode.attribute_value("uuid");
414  uuidToStateInfoMap.insert(std::make_pair(stateUuid, StateInfo(reader->getPackageName(), reader->getGroupName(), stateName)));
415 
416  for (RapidXmlReaderNode substateNode : stateNode.nodes("Substates", nullptr))
417  {
418  if (substateNode.name() == "LocalState" || substateNode.name() == "RemoteState" || substateNode.name() == "DynamicRemoteState")
419  {
420  //std::string name = substateNode.attribute_value("name");
421  std::string refuuid = substateNode.attribute_value("refuuid");
422 
423  if (usageMap.count(refuuid) == 0)
424  {
425  usageMap.insert(std::make_pair(refuuid, std::set<std::string>()));
426  }
427 
428  usageMap[refuuid].insert(stateUuid);
429  }
430  }
431  }
432  }
433  }
434 
435  void StatechartGroupDocGenerator::generateDoxygenFiles(const std::vector<std::string>& groups)
436  {
437  for (std::string groupDefinitionFilePath : groups)
438  {
439  generateDoxygenFile(groupDefinitionFilePath);
440  }
441  }
442 
443  void StatechartGroupDocGenerator::setOutputpath(const std::string& outputPath)
444  {
445  this->outputPath = outputPath;
446  }
447 
448  std::vector<std::string> StatechartGroupDocGenerator::FindAllStatechartGroupDefinitions(const std::filesystem::path& path)
449  {
450  std::vector<std::string> result;
451 
452  try
453  {
454  int i = 0;
455 
456  for (std::filesystem::recursive_directory_iterator end, dir(path);
457  dir != end ; ++dir, i++)
458  {
459  if (dir->path().extension() == ".scgxml" && dir->path().string().find("deprecated") == std::string::npos)
460  {
461  result.push_back(dir->path().c_str());
462  }
463 
464  if (i % 100 == 0)
465  {
466  ARMARX_INFO_S << "Scanning file " << i << ": " << dir->path().c_str();
467  }
468  }
469  }
470  catch (std::exception& e)
471  {
472  ARMARX_WARNING_S << "Invalid filepath: " << e.what();
473  }
474 
475  return result;
476  }
477 
479  {
480  auto itFinders = finders.find(reader->getPackageName());
481 
482  if (itFinders == finders.end())
483  {
484  itFinders = finders.insert(std::make_pair(reader->getPackageName(), CMakePackageFinder(reader->getPackageName()))).first;
485  }
486 
487  return itFinders->second;
488  }
489 
490 
491 } // namespace armarx
armarx::StatechartGroupDocGenerator::FindAllStatechartGroupDefinitions
static std::vector< std::string > FindAllStatechartGroupDefinitions(const std::filesystem::path &path)
Definition: StateGroupDocGenerator.cpp:448
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:66
armarx::RapidXmlReader::FromFile
static RapidXmlReaderPtr FromFile(const std::string &path)
Definition: RapidXmlReader.h:497
StateGroupDocGenerator.h
armarx::StatechartGroupDocGenerator::usageMap
std::map< std::string, std::set< std::string > > usageMap
Definition: StateGroupDocGenerator.h:67
armarx::DoxTransitionGraphPtr
std::shared_ptr< DoxTransitionGraph > DoxTransitionGraphPtr
Definition: DoxTransitiongraph.h:63
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:42
armarx::StatechartGroupDocGenerator::buildReferenceIndex
void buildReferenceIndex(const std::vector< std::string > &groups)
Definition: StateGroupDocGenerator.cpp:401
armarx::StatechartGroupXmlReader::ePublic
@ ePublic
Definition: GroupXmlReader.h:44
index
uint8_t index
Definition: EtherCATFrame.h:59
FileIOException.h
armarx::StatechartGroupDocGenerator::generateDocString
std::string generateDocString(const StatechartGroupXmlReaderPtr &reader) const
Definition: StateGroupDocGenerator.cpp:185
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:198
DoxTransitiongraph.h
armarx::CMakePackageFinder
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
Definition: CMakePackageFinder.h:53
armarx::StatechartProfilePtr
std::shared_ptr< class StatechartProfile > StatechartProfilePtr
Definition: StatechartContext.h:52
armarx::StatechartGroupXmlReader::ePrivate
@ ePrivate
Definition: GroupXmlReader.h:43
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
armarx::StatechartGroupDocGenerator::StatechartGroupDocGenerator
StatechartGroupDocGenerator()
Definition: StateGroupDocGenerator.cpp:40
armarx::StatechartGroupDocGenerator::getFinder
CMakePackageFinder getFinder(const StatechartGroupXmlReaderPtr &reader)
Definition: StateGroupDocGenerator.cpp:478
armarx::DoxDocPtr
std::shared_ptr< DoxDoc > DoxDocPtr
Definition: DoxDoc.h:38
armarx::StatechartGroupDocGenerator::generateDoxygenFiles
void generateDoxygenFiles(const std::vector< std::string > &groups)
Definition: StateGroupDocGenerator.cpp:435
armarx::DoxTablePtr
std::shared_ptr< DoxTable > DoxTablePtr
Definition: DoxTable.h:35
armarx::StatechartGroupDocGenerator::setOutputpath
void setOutputpath(const std::string &outputPath)
Definition: StateGroupDocGenerator.cpp:443
armarx::StatechartGroupDocGenerator::getUsedProfiles
std::set< std::string > getUsedProfiles(const RapidXmlReaderNode &stateNode) const
Definition: StateGroupDocGenerator.cpp:45
armarx::StatechartGroupXmlReaderPtr
std::shared_ptr< StatechartGroupXmlReader > StatechartGroupXmlReaderPtr
Definition: GroupXmlReader.h:89
armarx::exceptions::local::FileOpenException
Definition: FileIOException.h:58
copy
Use of this software is granted under one of the following two to be chosen freely by the user Boost Software License Version Marcin Kalicinski Permission is hereby free of to any person or organization obtaining a copy of the software and accompanying documentation covered by this and transmit the and to prepare derivative works of the and to permit third parties to whom the Software is furnished to do all subject to the including the above license this restriction and the following must be included in all copies of the in whole or in and all derivative works of the unless such copies or derivative works are solely in the form of machine executable object code generated by a source language processor THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR TITLE AND NON INFRINGEMENT IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN TORT OR ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE The MIT Marcin Kalicinski Permission is hereby free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to copy
Definition: license.txt:39
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:68
armarx::StatechartGroupDocGenerator::finders
std::map< std::string, CMakePackageFinder > finders
Definition: StateGroupDocGenerator.h:64
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:206
armarx::StatechartGroupXmlReader
Definition: GroupXmlReader.h:38
armarx::DoxTransitionGraph
Definition: DoxTransitiongraph.h:65
armarx::StatechartGroupDocGenerator::uuidToStateInfoMap
std::map< std::string, StateInfo > uuidToStateInfoMap
Definition: StateGroupDocGenerator.h:66
armarx::CppWriter
Definition: CppWriter.h:37
armarx::RapidXmlReaderNode::first_node_value_or_default
std::string first_node_value_or_default(const char *name, const std::string &defaultValue) const
Definition: RapidXmlReader.h:374
armarx::RapidXmlReaderNode::nodes
std::vector< RapidXmlReaderNode > nodes(const char *name=nullptr) const
Definition: RapidXmlReader.h:158
armarx::CMakePackageFinder::getBuildDir
std::string getBuildDir() const
Definition: CMakePackageFinder.h:136
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:392
armarx::CppWriterPtr
std::shared_ptr< CppWriter > CppWriterPtr
Definition: CppWriter.h:35
ARMARX_INFO_S
#define ARMARX_INFO_S
Definition: Logging.h:195
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:140
armarx::DoxDoc
Definition: DoxDoc.h:40
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::StatechartGroupDocGenerator::outputPath
std::string outputPath
Definition: StateGroupDocGenerator.h:65
armarx::StatechartGroupDocGenerator::generateDoxygenFile
void generateDoxygenFile(const std::string &groupDefinitionFilePath)
Definition: StateGroupDocGenerator.cpp:362