33 #include <SimoxUtility/algorithm/string/string_tools.h>
35 #include <boost/format.hpp>
47 std::set<std::string> usedProfiles;
51 usedProfiles.insert(defaultNode.attribute_value_or_default(
"profile",
"Root"));
56 usedProfiles.insert(defaultNode.attribute_value_or_default(
"profile",
"Root"));
61 usedProfiles.insert(defaultNode.attribute_value_or_default(
"profile",
"Root"));
67 std::string StatechartGroupDocGenerator::unescapeString(std::string
str)
const
70 std::string::const_iterator it =
str.begin();
72 while (it !=
str.end())
76 if (
c ==
'\\' && it !=
str.end())
109 std::string StatechartGroupDocGenerator::nToBr(std::string
str)
const
111 return simox::alg::replace_all(
str,
"\n",
"<br />\n");
114 DoxTablePtr StatechartGroupDocGenerator::buildParameterTable(RapidXmlReaderNode parametersNode)
const
116 std::set<std::string> usedProfiles;
118 for (RapidXmlReaderNode defaultNode : parametersNode.nodes(
"Parameter",
"DefaultValue"))
120 usedProfiles.insert(defaultNode.attribute_value_or_default(
"profile",
"Root"));
123 std::vector<std::string> header;
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));
131 for (RapidXmlReaderNode parameterNode : parametersNode.nodes(
"Parameter"))
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",
""));
138 for (RapidXmlReaderNode defaultNode : parameterNode.nodes(
"DefaultValue"))
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));
150 void StatechartGroupDocGenerator::addParameterTable(
const DoxDocPtr& doc,
const RapidXmlReaderNode& stateNode, std::string name,
const char* nodeName)
const
152 DoxTablePtr table = buildParameterTable(stateNode.first_node(nodeName));
154 if (table->rows() == 0)
156 doc->addLine(
"No " + name +
".<br />");
160 doc->addLine(name +
":");
161 doc->addEntry(table);
165 std::string StatechartGroupDocGenerator::getNodeAttrsFromStateType(
const std::string& nodeType)
const
167 if (nodeType ==
"EndState")
169 return "shape=box,style=filled,fillcolor=\"#FFFF96\"";
172 if (nodeType ==
"RemoteState")
174 return "shape=box,style=filled,fillcolor=\"#96FFFA\"";
177 if (nodeType ==
"DynamicRemoteState")
179 return "shape=box,style=filled,fillcolor=\"#B147EA\"";
182 return "shape=box,style=filled,fillcolor=\"#B3D7FF\"";
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()));
195 bool anyPrivateStateFound =
false;
197 for (std::string statefile : reader->getStateFilepaths())
201 anyPrivateStateFound =
true;
206 if (anyPrivateStateFound)
209 doc->addLine(fmt(
"@defgroup %s-%s-PrivateStates %s Private States", packageName, groupName, groupName));
210 doc->addLine(fmt(
"@ingroup %s-%s", packageName, groupName));
213 for (std::string statefile : reader->getStateFilepaths())
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"));
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");
231 doc->addLine(
"<br/>\\b State \\b used by:<br />");
235 std::set<std::string> users =
usageMap.find(stateUuid)->second;
237 for (std::string uuid : users)
239 doc->addLine(fmt(
"@ref State-%s <br />", uuid));
243 doc->addLine(
"<br/>\\b Substates:<br />");
247 if (substateNode.name() ==
"LocalState" || substateNode.name() ==
"RemoteState" || substateNode.name() ==
"DynamicRemoteState")
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);
255 doc->addLine(fmt(
"@ref State-%s \"%s (External Package)\"<br />", refuuid, name));
259 StateInfo stateInfo = it->second;
261 if (stateInfo.group == groupName && stateInfo.state == name)
263 doc->addLine(fmt(
"@ref State-%s<br />", refuuid));
265 else if (stateInfo.group == groupName)
267 doc->addLine(fmt(
"%s -> @ref State-%s \"%s\"<br />", name, refuuid, stateInfo.state));
271 doc->addLine(fmt(
"%s -> @ref State-%s \"%s-%s\"<br />", name, refuuid, stateInfo.group, stateInfo.state));
277 doc->addLine(
"<br/>\\b Statechart \\b layout:");
279 graph->addNode(
"",
"shape=point");
284 graph->addTransition(
"", startStateNode.
attribute_value(
"substateName"),
"");
289 std::string shape = getNodeAttrsFromStateType(substateNode.name());
290 graph->addNode(substateNode.attribute_value(
"name"), shape);
295 if (transition.has_attribute(
"from") && transition.has_attribute(
"to") && transition.has_attribute(
"eventName"))
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",
"");
301 graph->addTransition(from, to, eventName);
305 if (graph->transitionCount() > 0)
307 doc->addEntry(graph);
338 doc->writeDoc(writer);
339 return writer->getString();
342 std::string StatechartGroupDocGenerator::fmt(
const std::string& fmt,
const std::string& arg1)
const
347 std::string StatechartGroupDocGenerator::fmt(
const std::string& fmt,
const std::string& arg1,
const std::string& arg2)
const
349 return boost::str(boost::format(fmt) % arg1 % arg2);
352 std::string StatechartGroupDocGenerator::fmt(
const std::string& fmt,
const std::string& arg1,
const std::string& arg2,
const std::string& arg3)
const
354 return boost::str(boost::format(fmt) % arg1 % arg2 % arg3);
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
359 return boost::str(boost::format(fmt) % arg1 % arg2 % arg3 % arg4);
365 reader->readXml(std::filesystem::path(groupDefinitionFilePath));
368 std::filesystem::path doxyFile = finder.
getBuildDir();
375 if (!doxyFile.string().empty())
377 doxyFile /=
"doxygen";
384 doxyFile /= reader->getGroupName() +
".dox";
387 file.open(doxyFile.string().c_str());
397 ARMARX_INFO_S <<
"wrote " << docstr.size() <<
" bytes to " << doxyFile.string();
403 for (std::string groupDefinitionFilePath : groups)
406 reader->readXml(std::filesystem::path(groupDefinitionFilePath));
408 for (std::string statefile : reader->getStateFilepaths())
414 uuidToStateInfoMap.insert(std::make_pair(stateUuid, StateInfo(reader->getPackageName(), reader->getGroupName(), stateName)));
418 if (substateNode.name() ==
"LocalState" || substateNode.name() ==
"RemoteState" || substateNode.name() ==
"DynamicRemoteState")
421 std::string refuuid = substateNode.attribute_value(
"refuuid");
425 usageMap.insert(std::make_pair(refuuid, std::set<std::string>()));
428 usageMap[refuuid].insert(stateUuid);
437 for (std::string groupDefinitionFilePath : groups)
450 std::vector<std::string> result;
456 for (std::filesystem::recursive_directory_iterator end, dir(path);
457 dir != end ; ++dir, i++)
459 if (dir->path().extension() ==
".scgxml" && dir->path().string().find(
"deprecated") == std::string::npos)
461 result.push_back(dir->path().c_str());
466 ARMARX_INFO_S <<
"Scanning file " << i <<
": " << dir->path().c_str();
470 catch (std::exception& e)
480 auto itFinders =
finders.find(reader->getPackageName());
482 if (itFinders ==
finders.end())
484 itFinders =
finders.insert(std::make_pair(reader->getPackageName(),
CMakePackageFinder(reader->getPackageName()))).first;
487 return itFinders->second;