diff options
Diffstat (limited to 'src/uscxml/debug/SCXMLDotWriter.cpp')
-rw-r--r-- | src/uscxml/debug/SCXMLDotWriter.cpp | 888 |
1 files changed, 0 insertions, 888 deletions
diff --git a/src/uscxml/debug/SCXMLDotWriter.cpp b/src/uscxml/debug/SCXMLDotWriter.cpp deleted file mode 100644 index 56de37a..0000000 --- a/src/uscxml/debug/SCXMLDotWriter.cpp +++ /dev/null @@ -1,888 +0,0 @@ -/** - * @file - * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * 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. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -#include "uscxml/Common.h" -#include "uscxml/UUID.h" -#include "SCXMLDotWriter.h" -#include "../transform/FlatStateIdentifier.h" -#include "uscxml/dom/DOMUtils.h" -#include <boost/algorithm/string.hpp> // replace_all -#include <iomanip> - -namespace uscxml { - -using namespace Arabica::DOM; -using namespace Arabica::XPath; - -SCXMLDotWriter::SCXMLDotWriter() { - _iteration = 0; - _indentation = 0; -} - -SCXMLDotWriter::SCXMLDotWriter(Interpreter interpreter, - const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors, - const Element<std::string>& transition) { - _interpreter = interpreter; - _xmlNSPrefix = _interpreter.getNameSpaceInfo().xmlNSPrefix; - _transition = transition; - _anchors = stateAnchors; - - NodeList<std::string > scxmlElems = interpreter.getDocument().getElementsByTagName("scxml"); - _scxml = (Element<std::string>)scxmlElems.item(0); - _isFlat = HAS_ATTR(_scxml, "flat") && stringIsTrue(ATTR(_scxml, "flat")); - - if (_anchors.size() == 0) { - StateAnchor anchor; - anchor.element = _scxml; - _anchors.push_back(anchor); - } - - for (std::list<StateAnchor>::iterator anchIter = _anchors.begin(); anchIter != _anchors.end(); anchIter++) { - if (!anchIter->element) - anchIter->element = _scxml; - if (anchIter->childDepth >= 0 && anchIter->transDepth == -1) - anchIter->transDepth = anchIter->childDepth; - - _portType = anchIter->type; - assembleGraph(anchIter->element, anchIter->childDepth, anchIter->transDepth + 1); - } - - _iteration = 0; - _indentation = 0; -} - -SCXMLDotWriter::~SCXMLDotWriter() { - -} - -void SCXMLDotWriter::onStableConfiguration(Interpreter interpreter) { - std::ostringstream fileSS; - fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot"; - toDot(fileSS.str(), interpreter); -} - -void SCXMLDotWriter::afterCompletion(Interpreter interpreter) { - std::ostringstream fileSS; - fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot"; - toDot(fileSS.str(), interpreter); -} - -void SCXMLDotWriter::beforeMicroStep(Interpreter interpreter) { -// std::ostringstream fileSS; -// fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot"; -// toDot(fileSS.str(), interpreter); -} - -void SCXMLDotWriter::beforeTakingTransition(Interpreter interpreter, - const Element<std::string>& transition, - bool moreComing) { - std::ostringstream fileSS; - fileSS << interpreter.getName() << "." << std::setw(6) << std::setfill('0') << _iteration++ << ".dot"; - toDot(fileSS.str(), interpreter, transition); -} - -std::string SCXMLDotWriter::getPrefix() { - std::string prefix = ""; - for (size_t i = 0; i < _indentation; i++) - prefix += " "; - return prefix; -} - -void SCXMLDotWriter::writeTo(std::ostream& os) { - os << "digraph {" << std::endl; - os << " rankdir=LR;" << std::endl; - os << " fontsize=10;" << std::endl; - // outfile << " splines=ortho;" << std::endl; - // outfile << " splines=false;" << std::endl; - // outfile << " nodesep=1.0;" << std::endl; - - _indentation++; - writeStateElement(os, _scxml); - - // write edges at end of file - for(std::set<DotEdge>::iterator edgeIter = _edges.begin(); edgeIter != _edges.end(); edgeIter++) { - if (edgeIter->from == edgeIter->to) - continue; - if (_histories.find(edgeIter->to) != _histories.end()) { - if (_histories.find(edgeIter->to)->second.from == _histories.find(edgeIter->to)->second.to) - continue; - } - - os << getPrefix() << "\"" << portEscape(edgeIter->from) << "\""; - if (edgeIter->fromPort.size() > 0) { - os << std::string(":\"") + portEscape(edgeIter->fromPort) + "\":e"; - } else { - os << ":__name"; - } - os << " -> "; - - if (_histories.find(edgeIter->to) != _histories.end()) { - os << getPrefix() << "\"" << portEscape(_histories.find(edgeIter->to)->second.to) << "\""; - if (_histories.find(edgeIter->to)->second.toPort.size() > 0) { - os << std::string(":\"") + portEscape(_histories.find(edgeIter->to)->second.toPort) + "\""; - } else { - os << ":__name"; - } - - } else { - os << getPrefix() << "\"" << portEscape(edgeIter->to) << "\""; - if (edgeIter->toPort.size() > 0) { - os << std::string(":\"") + portEscape(edgeIter->toPort) + "\""; - } else { - os << ":__name"; - } - } - - if (edgeIter->type == EDGE_INITAL) { - os << ":nw [style=\"dashed\", color=\"black\"]"; - } else { - os << " [color=\"black\"]"; - } - os << std::endl; - - } - - _indentation--; - - os << "}" << std::endl; - -} - -void SCXMLDotWriter::toDot(const std::string& filename, - Interpreter interpreter, - const std::list<SCXMLDotWriter::StateAnchor>& stateAnchors, - const Element<std::string>& transition) { - - std::ofstream outfile(filename.c_str()); - SCXMLDotWriter writer(interpreter, stateAnchors, transition); - writer.writeTo(outfile); - -} - -/** - * Walk the subset of the graph that is reachable and remember the nodes - */ -void SCXMLDotWriter::assembleGraph(const Element<std::string>& state, int32_t childDepth, int32_t transDepth) { - std::string nodeId = idForNode(state); - - // this node is neither included per child, nor per transition - if (childDepth <= 0 && transDepth <= 0) { - return; - } - - // been here - if (_graph.find(nodeId) != _graph.end()) - return; - - _graph[nodeId].node = state; - _graph[nodeId].portType = _portType; - - - if (childDepth == 0 && transDepth == 0) { - _graph[nodeId].isBorder = true; - } - - - NodeSet<std::string> childElems = DOMUtils::filterChildType(Node_base::ELEMENT_NODE, state); - for (size_t i = 0; i < childElems.size(); i++) { - Element<std::string> childElem(childElems[i]); - - // remember histories we passed - if (iequals(TAGNAME(childElem), "history")) { - _histories[ATTR(childElem, "id")].to = ATTR(state, "id"); - _histories[ATTR(childElem, "id")].toPort = ATTR(childElem, "id"); - } - - // follow transitions - if (iequals(TAGNAME(childElem), "transition")) { - _graph[nodeId].transitions.push_back(childElem); - NodeSet<std::string> targetStates = _interpreter.getImpl()->getTargetStates(childElem); - for (size_t j = 0; j < targetStates.size(); j++) { - std::string remoteNodeId = idForNode(targetStates[j]); - _graph[nodeId].targets.insert(std::make_pair(remoteNodeId, childElem)); - - // recurse along the transition targets, no weight from child depth - assembleGraph((Element<std::string>)targetStates[j], 0, transDepth - 1); - } - if (targetStates.size() == 0) - _graph[nodeId].targets.insert(std::make_pair(nodeId, childElem)); - - std::list<std::string> eventNames; - if (HAS_ATTR(childElem, "event")) - eventNames = tokenize(ATTR(childElem, "event")); - if (eventNames.size() == 0) - _graph[nodeId].events.insert(std::make_pair("", childElem)); - for (std::list<std::string>::iterator evIter = eventNames.begin(); evIter != eventNames.end(); evIter++) { - _graph[nodeId].events.insert(std::make_pair(*evIter, childElem)); - } - } - - // follow childs - if (InterpreterImpl::isState(Element<std::string>(childElem))) { - if (_interpreter.getImpl()->isInitial(Element<std::string>(childElem))) { - // add to initial states if it is initial - _graph[nodeId].initialchilds.insert(idForNode(childElem)); - } else if (_interpreter.getImpl()->isParallel(Element<std::string>(state))) { - // add to initial states if we are parallel - _graph[nodeId].initialchilds.insert(idForNode(childElem)); - } - // in any case, it is a child state - _graph[nodeId].childs.insert(idForNode(childElem)); - - // recurse (do we really need to?) - assembleGraph(childElem, childDepth - 1, transDepth); - } - - } -} - - -/** - * Walk the complete graph and draw reachable subset - */ -void SCXMLDotWriter::writeStateElement(std::ostream& os, const Element<std::string>& stateElem) { - std::string stateId = idForNode(stateElem); - - if (_knownIds.find(stateId) != _knownIds.end()) - return; - _knownIds.insert(stateId); - - std::list<Node<std::string> > invisParents; - bool isVisible = (_graph.find(stateId) != _graph.end()); - - bool subgraph = InterpreterImpl::isCompound(stateElem) || InterpreterImpl::isParallel(stateElem); - bool fatherIsParallel = (stateElem.getParentNode() && - stateElem.getParentNode().getNodeType() == Node_base::ELEMENT_NODE && - InterpreterImpl::isParallel(Element<std::string>(stateElem.getParentNode()))); - - if (subgraph) { - _indentation++; - os << std::endl; - os << getPrefix() << "subgraph \"cluster_" << portEscape(stateId) << "\" {" << std::endl; - _indentation++; - os << getPrefix() << "fontsize=14" << std::endl; - os << getPrefix() << "label=<" << nameForNode(stateElem) << ">" << std::endl; - // os << getPrefix() << "rank=\"same\"" << std::endl; - os << getPrefix() << "labeljust=l" << std::endl; - - os << getPrefix() << (fatherIsParallel ? "style=dashed" : "style=solid") << std::endl; - - // os << getPrefix() << "ranksep=\"equally\"" << std::endl; - - } - - if (isVisible) { - // this state is visible! - const DotState& dotState = _graph.find(stateId)->second; - - // is this a subgraph? - - os << std::endl; - os << getPrefix() << "\"" << portEscape(stateId) << "\" [" << std::endl; - _indentation++; - - os << getPrefix() << "fontsize=10," << std::endl; - os << getPrefix() << "shape=plaintext," << std::endl; - os << getPrefix() << (fatherIsParallel ? "style=dashed," : "style=solid,") << std::endl; - - // is the current state in the basic configuration? - if (InterpreterImpl::isMember(stateElem, _interpreter.getBasicConfiguration())) - os << getPrefix() << "color=red, penwidth=3," << std::endl; - - // is the current state in the basic configuration? - if (dotState.isBorder) - os << getPrefix() << "color=blue," << std::endl; - - // is this state final? - if (_interpreter.getImpl()->isFinal(stateElem)) { - os << getPrefix() << "shape=doublecircle," << std::endl; - os << getPrefix() << "color=black," << std::endl; - os << getPrefix() << "penwidth=2," << std::endl; - os << getPrefix() << "label=< <table cellborder=\"0\" border=\"0\"><tr><td balign=\"left\">" << nameForNode(stateElem) << "</td></tr></table>>" << std::endl; - _indentation--; - os << getPrefix() << "];" << std::endl; - - return; - } - - // is the state initial? - bool isInitial = _interpreter.getImpl()->isInitial(stateElem); - // if (isInitial) - // os << getPrefix() << "style=filled, fillcolor=lightgrey, " << std::endl; - - DotState::mmap_s_e_t::const_iterator destIterF, destIterB; - //std::list<std::string> outPorts; // count unique keys - - int nrOutPorts = 0; - - switch (dotState.portType) { - case PORT_TARGET: // outports are per target - for(DotState::mmap_s_e_t::const_iterator it = dotState.targets.begin(), end = dotState.targets.end(); - it != end; - it = dotState.targets.upper_bound(it->first)) { - nrOutPorts++; - } - break; - case PORT_EVENT: // outports are per event - for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end(); - it != end; - it = dotState.events.upper_bound(it->first)) { - nrOutPorts++; - } - break; - case PORT_TRANSITION: - nrOutPorts = dotState.transitions.size(); -// for (size_t i = 0; i < dotState.transitions.size(); i++) { -// outPorts.push_back(idForNode(dotState.transitions[i])); -// } - break; - } - - os << getPrefix() << "label = < " << std::endl; - - /* - <table cellborder="1" border="0" cellspacing="0" cellpadding="2" style="rounded"> - <tr><td port="name" rowspan="4"><b>step</b></td></tr> - <tr><td port="foo.error.port" align="right">foo.error.port</td></tr> - <tr><td port="bar" align="right">bar</td></tr> - <tr><td port="baz" align="right">baz</td></tr> - </table> - */ - - std::string details = getDetailedLabel(stateElem); - std::string stateLabel = nameForNode(stateElem); - int stateLines = 0; - - std::string::size_type start = 0; - while ((start = stateLabel.find("<br", start)) != std::string::npos) { - ++stateLines; - start += 3; - } - - os << "<table " << (isInitial ? "bgcolor=\"orange\" " : "") << "valign=\"top\" align=\"left\" cellborder=\"1\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\" >" << std::endl; - os << " <tr><td port=\"__name\" balign=\"left\" valign=\"top\" align=\"left\" rowspan=\"" << nrOutPorts + 1 << "\">" << stateLabel << "</td></tr>" << std::endl; - - switch (dotState.portType) { - case PORT_TARGET: // outports are per target - writePerTargetPorts(os, dotState, stateLines); - break; - case PORT_EVENT: // outports are per event - writePerEventPorts(os, dotState, stateLines); - break; - case PORT_TRANSITION: - writePerTransitionPorts(os, dotState, stateLines); - break; - } - - - // write details of the state - if (details.size() > 0) { - os << " <tr><td balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\">" << std::endl; - os << details << std::endl; - os << " </td></tr>" << std::endl; - } - - // write history states - NodeSet<std::string> histories = DOMUtils::filterChildElements(_xmlNSPrefix + "history", stateElem); - for (size_t i = 0; i < histories.size(); i++) { - os << " <tr><td port=\"" << portEscape(ATTR_CAST(histories[i], "id")) << "\" balign=\"left\" colspan=\"" << (nrOutPorts == 0 ? 1 : 2) << "\"><b>history: </b>" << ATTR_CAST(histories[i], "id") << "</td></tr>" << std::endl; - - } - - os << "</table>" << std::endl << getPrefix() << ">" << std::endl; - - _indentation--; - os << getPrefix() << "];" << std::endl; - - for (std::set<std::string>::iterator initIter = dotState.initialchilds.begin(); initIter != dotState.initialchilds.end(); initIter++) { - std::string destId = *initIter; - DotEdge edge(stateId, destId); - edge.type = EDGE_INITAL; - if (_graph.find(destId) != _graph.end()) - _edges.insert(edge); - } - - } - - // recurse into children and search others to draw - NodeSet<std::string> childElems = DOMUtils::filterChildType(Node_base::ELEMENT_NODE, stateElem); - for (size_t i = 0; i < childElems.size(); i++) { - Element<std::string> childElem(childElems[i]); - if (InterpreterImpl::isState(Element<std::string>(childElem))) { - writeStateElement(os, childElem); - } - } - - if (subgraph) { - _indentation--; - os << getPrefix() << "} #" << stateId << std::endl; - _indentation--; - } -} - -void SCXMLDotWriter::writePerTransitionPorts(std::ostream& os, const DotState& dotState, int stateLines) { - // TODO: Not implemented -} - -void SCXMLDotWriter::writePerEventPorts(std::ostream& os, const DotState& dotState, int stateLines) { - // std::multimap<std::string, Arabica::DOM::Element<std::string> > events; // key is event name, value is transitions that react - - std::string stateId = idForNode(dotState.node); - DotState::mmap_s_e_t::const_iterator destIterF, destIterB; - - for(DotState::mmap_s_e_t::const_iterator it = dotState.events.begin(), end = dotState.events.end(); - it != end; - it = dotState.events.upper_bound(it->first)) { - os << " <tr><td port=\"" << portEscape(it->first) << "\" align=\"right\">" << it->first << "</td></tr>" << std::endl; - } - -} - -std::string SCXMLDotWriter::htmlLabelForId(const std::string& stateId, int minRows) { - FlatStateIdentifier flatId(stateId); - - std::list<std::string>::const_iterator listIter; - std::stringstream labelSS; - std::string seperator; - - labelSS << "<b>active: </b>"; - labelSS << "{"; - for (listIter = flatId.getActive().begin(); listIter != flatId.getActive().end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; - } - labelSS << "}"; - - if (flatId.getVisited().size() > 0) { - minRows--; - - labelSS << "<br /><b>init: </b>"; - - labelSS << "{"; - seperator = ""; - for (listIter = flatId.getVisited().begin(); listIter != flatId.getVisited().end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; - } - labelSS << "}"; - } - - if (flatId.getHistory().size() > 0) { - minRows--; - - seperator = ""; - std::string histSeperator = "<br /> "; - - labelSS << "<br /><b>history: </b>"; - - std::map<std::string, std::list<std::string> >::const_iterator histIter; - for (histIter = flatId.getHistory().begin(); histIter != flatId.getHistory().end(); histIter++) { - labelSS << histSeperator << histIter->first << ": {"; - - for (listIter = histIter->second.begin(); listIter != histIter->second.end(); listIter++) { - labelSS << seperator << *listIter; - seperator = ", "; - } - labelSS << "}"; - seperator = ""; - } - } - return labelSS.str(); -} - - -void SCXMLDotWriter::writePerTargetPorts(std::ostream& os, const DotState& dotState, int stateLines) { - // std::multimap<std::string, Arabica::DOM::Element<std::string> > targets; // key is remote node, transition is element - - int nrOutports = 0; - std::string stateId = idForNode(dotState.node); - - typedef DotState::mmap_s_e_t iter_t; - - // we need to count outports first for vertical padding - for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end(); - targetIter != end; - targetIter = dotState.targets.upper_bound(targetIter->first)) { - nrOutports++; - } - - for(iter_t::const_iterator targetIter = dotState.targets.begin(), end = dotState.targets.end(); - targetIter != end; - targetIter = dotState.targets.upper_bound(targetIter->first)) { - - // gather all events that activate the transition - std::string targetId = targetIter->first; - - std::set<std::string> eventNames; - - DotEdge edge(stateId, targetId); - edge.fromPort = targetId; - - std::pair <iter_t::const_iterator, iter_t::const_iterator> targetKeyRange = dotState.targets.equal_range(targetId); - for (iter_t::const_iterator transIter = targetKeyRange.first; transIter != targetKeyRange.second; ++transIter) { - const Element<std::string>& transElem = transIter->second; - - std::list<std::string> events = tokenize(ATTR(transElem, "event")); - eventNames.insert(events.begin(), events.end()); - - if (events.size() == 0) { - // spontaneous transition - eventNames.insert("#"); - edge.type = EDGE_SPONTANEOUS; - } - } - - if (_graph.find(targetId) != _graph.end()) - _edges.insert(edge); - - std::stringstream outPortSS; - outPortSS << (_isFlat ? htmlLabelForId(targetId) : "<b>" + targetId + "</b>" ); - - if (_isFlat) { - outPortSS << "<br /><b>events: </b>{"; - } else { - outPortSS << "<br />{"; - } - - std::string seperator; - for (std::set<std::string>::const_iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) { - outPortSS << seperator << *eventIter << std::endl; - seperator = ", "; - } - outPortSS << "}"; - - if (nrOutports == 1) { - int missing = stateLines - nrOutports; - while (_isFlat && missing-- >= 1) { - outPortSS << "<br /> "; - } - } - - os << " <tr><td port=\"" << portEscape(targetId) << "\" balign=\"left\" align=\"left\">" << outPortSS.str() << "</td></tr>" << std::endl; - - } -} - -std::string SCXMLDotWriter::getDetailedLabel(const Element<std::string>& elem, int indentation) { - - /* - <table> - <tr> - <td colspan="2">onEntry</td> - </tr> - <tr> - <td>Details</td> - <td bgcolor="#eee"> - Nested Content - </td> - </tr> - </table> - */ - - std::list<struct ElemDetails> content; - - NodeList<std::string > childElems = elem.getChildNodes(); - for (size_t i = 0; i < childElems.getLength(); i++) { - if (childElems.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Element<std::string> elem = Element<std::string>(childElems.item(i)); - - if (InterpreterImpl::isState(elem) || - iequals(TAGNAME(elem), "transition") || - iequals(TAGNAME(elem), "initial") || - false) - continue; - - struct ElemDetails details; - details.name = "<b>" + TAGNAME(elem) + ":</b>"; - - if (iequals(TAGNAME(elem), "history")) { - continue; - } - - // provide details for special elements here - - // param --------- - if (iequals(TAGNAME(elem), "param")) { - if (HAS_ATTR(elem, "name")) - details.name += " " + ATTR(elem, "name") + " = "; - if (HAS_ATTR(elem, "expr")) - details.name += ATTR(elem, "expr"); - if (HAS_ATTR(elem, "location")) - details.name += ATTR(elem, "location"); - } - - // data --------- - if (iequals(TAGNAME(elem), "data")) { - if (HAS_ATTR(elem, "id")) - details.name += " " + ATTR(elem, "id"); - if (HAS_ATTR(elem, "src")) - details.name += ATTR(elem, "src"); - if (HAS_ATTR(elem, "expr")) - details.name += " = " + ATTR(elem, "expr"); - NodeList<std::string > grandChildElems = elem.getChildNodes(); - for (size_t j = 0; j < grandChildElems.getLength(); j++) { - if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) { - details.name += dotEscape(grandChildElems.item(j).getNodeValue()); - } - } - } - - // invoke --------- - if (iequals(TAGNAME(elem), "invoke")) { - if (HAS_ATTR(elem, "type")) - details.name += "<br />type = " + ATTR(elem, "type"); - if (HAS_ATTR(elem, "typeexpr")) - details.name += "<br />type = " + ATTR(elem, "typeexpr"); - if (HAS_ATTR(elem, "src")) - details.name += "<br />src = " + ATTR(elem, "src"); - if (HAS_ATTR(elem, "srcexpr")) - details.name += "<br />src = " + ATTR(elem, "srcexpr"); - if (HAS_ATTR(elem, "id")) - details.name += "<br />id = " + ATTR(elem, "id"); - if (HAS_ATTR(elem, "idlocation")) - details.name += "<br />id = " + ATTR(elem, "idlocation"); - } - - // send --------- - if (iequals(TAGNAME(elem), "raise")) { - if (HAS_ATTR(elem, "event ")) - details.name += "<br />event = " + ATTR(elem, "event"); - } - - // send --------- - if (iequals(TAGNAME(elem), "send")) { - if (HAS_ATTR(elem, "id")) - details.name += "<br />id = " + ATTR(elem, "id"); - if (HAS_ATTR(elem, "type")) - details.name += "<br />type = " + ATTR(elem, "type"); - if (HAS_ATTR(elem, "typeexpr")) - details.name += "<br />type = " + ATTR(elem, "typeexpr"); - if (HAS_ATTR(elem, "event")) - details.name += "<br />event = " + ATTR(elem, "event"); - if (HAS_ATTR(elem, "eventexpr")) - details.name += "<br />event = " + ATTR(elem, "eventexpr"); - if (HAS_ATTR(elem, "target")) - details.name += "<br />target = " + ATTR(elem, "target"); - if (HAS_ATTR(elem, "targetexpr")) - details.name += "<br />target = " + ATTR(elem, "targetexpr"); - if (HAS_ATTR(elem, "delay")) - details.name += "<br />delay = " + ATTR(elem, "delay"); - if (HAS_ATTR(elem, "delayexpr")) - details.name += "<br />delay = " + ATTR(elem, "delayexpr"); - } - - // cancel --------- - if (iequals(TAGNAME(elem), "cancel")) { - if (HAS_ATTR(elem, "sendid")) - details.name += " " + ATTR(elem, "sendid"); - } - - // script --------- - if (iequals(TAGNAME(elem), "script")) { - details.name += " "; - if (HAS_ATTR(elem, "src")) - details.name += ATTR(elem, "src"); - NodeList<std::string > grandChildElems = childElems.item(i).getChildNodes(); - for (size_t j = 0; j < grandChildElems.getLength(); j++) { - if (grandChildElems.item(j).getNodeType() == Node_base::TEXT_NODE) { - details.name += dotEscape(grandChildElems.item(j).getNodeValue()); - } - } - } - - // if --------- - if (iequals(TAGNAME(elem), "if")) { - if (HAS_ATTR(elem, "cond")) - details.name += " cond = " + dotEscape(ATTR(elem, "cond")); - } - - // elseif --------- - if (iequals(TAGNAME(elem), "elseif")) { - if (HAS_ATTR(elem, "cond")) - details.name += " cond = " + dotEscape(ATTR(elem, "cond")); - } - - // log --------- - if (iequals(TAGNAME(elem), "log")) { - details.name += " "; - if (HAS_ATTR(elem, "label")) - details.name += ATTR(elem, "label") + " = "; - if (HAS_ATTR(elem, "expr")) - details.name += ATTR(elem, "expr"); - } - - // foreach --------- - if (iequals(TAGNAME(elem), "foreach")) { - if (HAS_ATTR(elem, "item")) - details.name += "<br /> item = " + ATTR(elem, "item"); - if (HAS_ATTR(elem, "array")) - details.name += "<br /> array = " + ATTR(elem, "array"); - if (HAS_ATTR(elem, "index")) - details.name += "<br /> index = " + ATTR(elem, "index"); - } - - // recurse - details.content = getDetailedLabel((Element<std::string>)childElems.item(i), indentation + 1); - content.push_back(details); - } - - std::stringstream ssContent; - - if (content.size() > 0) { - ssContent << "<table cellspacing=\"2\" cellpadding=\"0\" border=\"0\" bgcolor=\"#" << colorForIndent(indentation + 1) << "\">"; - - std::list<struct ElemDetails>::iterator contentIter = content.begin(); - while(contentIter != content.end()) { - ssContent << "<tr>"; -// ssContent << "<td align=\"left\" colspan=\"2\">" << contentIter->name << "</td>"; - ssContent << "<td balign=\"left\" align=\"left\">" << contentIter->name << "</td>"; - ssContent << "</tr>"; - - if (contentIter->content.size() > 0) { - ssContent << "<tr>"; -// ssContent << "<td>" << contentIter->details << "</td>"; - ssContent << "<td bgcolor=\"#" << colorForIndent(indentation + 1) << "\">" << contentIter->content << "</td>"; - ssContent << "</tr>"; - } - contentIter++; - - } - ssContent << "</table>"; - } - return ssContent.str(); -} - -std::string SCXMLDotWriter::portEscape(const std::string& text) { - std::string escaped(text); - boost::replace_all(escaped, ".", "-"); - boost::replace_all(escaped, "{", "-"); - boost::replace_all(escaped, "}", "-"); - boost::replace_all(escaped, ":", "-"); - return escaped; -} - -std::string SCXMLDotWriter::dotEscape(const std::string& text) { - std::string escaped(text); - boost::replace_all(escaped, " ", " "); - boost::replace_all(escaped, "\t", " "); - boost::replace_all(escaped, "<", "<"); - boost::replace_all(escaped, ">", ">"); - boost::replace_all(escaped, "\"", """); - boost::replace_all(escaped, "\n", "<br />"); - - return escaped; -} - -std::string SCXMLDotWriter::colorForIndent(int indent) { - int color = 255 - (16 * indent); - std::stringstream ss; - ss << std::hex << color; - ss << std::hex << color; - ss << std::hex << color; - return ss.str(); -} - -std::string SCXMLDotWriter::nameForNode(const Node<std::string>& node) { - std::string elemName; - if (node.getNodeType() == Node_base::ELEMENT_NODE) { - Element<std::string> elem = (Element<std::string>)node; - - if (InterpreterImpl::isFinal(elem) && _isFlat) { - // ignore visited and history with final elements - FlatStateIdentifier flatId(elem.getAttribute("id")); - return "<b>" + flatId.getActive().front() + "</b>"; - } - - if (elem.hasAttribute("id") && _isFlat) { - elemName = htmlLabelForId(elem.getAttribute("id")); - if (elemName.size() > 0) - return elemName; - } else if (elem.getTagName() == "scxml") { - if (elem.hasAttribute("name") && !UUID::isUUID(elem.getAttribute("name"))) { - elemName += elem.getAttribute("name"); - } else if (elem.hasAttribute("id") && !UUID::isUUID(elem.getAttribute("id"))) { - elemName += elem.getAttribute("id"); - } - } else if (InterpreterImpl::isCompound(elem)) { - elemName = "<i>Compound: </i>" + elem.getAttribute("id"); - } else if (InterpreterImpl::isParallel(elem)) { - elemName = "<i>Parallel: </i>" + elem.getAttribute("id"); - } else if (elem.hasAttribute("id")) { - elemName += elem.getAttribute("id"); - } - } - - if (elemName.size() == 0) - elemName = boost::lexical_cast<std::string>(node.getLocalName()); - - return "<b>" + elemName + "</b>"; - -} - -std::string SCXMLDotWriter::idForNode(const Node<std::string>& node) { - std::string elemId; - - // try to get the id as the name or id attribute - if (node.getNodeType() == Node_base::ELEMENT_NODE) { - Element<std::string> elem = (Element<std::string>)node; - -// if (InterpreterImpl::isFinal(elem) && _isFlat) { -// // ignore visited and history with final elements -// FlatStateIdentifier flatId(elem.getAttribute("id")); -// -// std::stringstream activeSS; -// activeSS << "active-"; -// for (std::list<std::string>::const_iterator activeIter = flatId.getActive().begin(); activeIter != flatId.getActive().end(); activeIter++) { -// activeSS << *activeIter << "-"; -// } -// return activeSS.str(); -// } - - if (elem.hasAttribute("name")) { - elemId = elem.getAttribute("name"); - } else if (elem.hasAttribute("id")) { - elemId = elem.getAttribute("id"); - } - } - - // no luck, create id from position in tree - if (elemId.size() == 0) { - Node<std::string> tmpParent = node; - Node<std::string> tmpIndex; - do { - if (tmpParent.getNodeType() != Node_base::ELEMENT_NODE) - continue; - - tmpIndex = tmpParent; - int index = 0; - - while((tmpIndex = tmpIndex.getPreviousSibling())) - index++; - - std::stringstream ssElemId; - ssElemId << TAGNAME_CAST(tmpParent) << index << "."; - elemId = ssElemId.str() + elemId; - } while ((tmpParent = tmpParent.getParentNode())); -// elemId = ssElemId.str(); - } - return elemId; -} - -}
\ No newline at end of file |