use of com.randomnoun.build.javaToGraphviz.dag.DagSubgraph in project java-to-graphviz by randomnoun.
the class AstToDagVisitor method processCommentsToTypeOrMethodNode.
private void processCommentsToTypeOrMethodNode(DagNode pdn, int line, DagNode mn) {
// DagNode lastNode = null;
while (lastIdx < comments.size() && comments.get(lastIdx).line < line) {
CommentText ct = comments.get(lastIdx);
/*
DagNode dn = new DagNode();
dn.keepNode = true; // always keep comments
dn.type = "comment";
dn.line = ct.line;
dn.name = dag.getUniqueName("c_" + ct.line);
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
*/
DagNode dn = null;
if (ct instanceof GvComment) {
mn.classes.addAll(((GvComment) ct).classes);
// last comment wins
mn.label = ct.text;
} else if (ct instanceof GvGraphComment) {
GvGraphComment gc = ((GvGraphComment) ct);
// to remove the class ast node from the 0th root graph
if (rootGraphIdx == 0) {
dag.clear();
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
} else {
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
}
root.name = gc.id;
root.classes.addAll(gc.classes);
// append to existing ?
root.gvAttributes.put("style", gc.inlineStyleString);
rootGraphIdx++;
} else if (ct instanceof GvEndGraphComment) {
if (rootGraphIdx == 0) {
throw new IllegalStateException("gv-endGraph without gv-graph");
} else {
root = null;
}
} else if (ct instanceof GvSubgraphComment) {
GvSubgraphComment gvsc = (GvSubgraphComment) ct;
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
dn.name = gvsc.id;
dn.classes.addAll(gvsc.classes);
dn.classes.add("beginSubgraph");
} else if (ct instanceof GvEndSubgraphComment) {
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
dn.classes.add("endSubgraph");
} else if (ct instanceof GvLiteralComment) {
logger.warn("gv-literal outside of method");
} else if (ct instanceof GvKeepNodeComment) {
GvKeepNodeComment knc = ((GvKeepNodeComment) ct);
boolean defaultKeepNode = "true".equals(options.get("defaultKeepNode"));
keepNodeMatcher = keepNodeMatcher.getModifiedKeepNodeMatcher(defaultKeepNode, knc.text.trim());
} else if (ct instanceof GvOptionComment) {
GvOptionComment oc = ((GvOptionComment) ct);
options = newOptions(oc.text.trim());
}
if (dn != null) {
if (pdn != null) {
if (root == null) {
throw new IllegalStateException("gv comment outside of graph");
}
dag.addNode(root, dn);
pdn.addChild(dn);
} else {
// could add as a root node, but let's see how we go
throw new IllegalStateException("null pdn in processCommentsToTypeOrMethodNode");
}
}
lastIdx++;
}
}
use of com.randomnoun.build.javaToGraphviz.dag.DagSubgraph in project java-to-graphviz by randomnoun.
the class DagStyleApplier method setDagSubgraphLiterals.
// copy any literal elements into their containing subgraphs
private void setDagSubgraphLiterals(Document document, CSSStyleSheet stylesheet) {
Stack<DagSubgraph> subgraphStack = new Stack<>();
final CSSOMParser inlineParser = new CSSOMParser();
inlineParser.setErrorHandler(new ExceptionErrorHandler());
NodeTraversor.traverse(new NodeVisitor() {
@Override
public void head(Node node, int depth) {
if (node instanceof DagElement) {
DagElement dagElement = (DagElement) node;
String tagName = ((Element) node).tagName();
DagSubgraph dagSubgraph = dagElement.dagSubgraph;
DagNode dagNode = dagElement.dagNode;
if (dagSubgraph != null) {
subgraphStack.push(dagSubgraph);
}
if ("literal".equals(tagName)) {
if (subgraphStack.size() == 0) {
// could add to root subgraph instead
throw new IllegalStateException("literal outside of subgraph");
}
subgraphStack.peek().literals.add(dagNode.label);
}
}
}
@Override
public void tail(Node node, int depth) {
if (node instanceof DagElement) {
DagElement dagElement = (DagElement) node;
if (dagElement.dagSubgraph != null) {
subgraphStack.pop();
}
}
}
}, document.body());
}
use of com.randomnoun.build.javaToGraphviz.dag.DagSubgraph in project java-to-graphviz by randomnoun.
the class DagStyleApplier method setDagStyles.
private void setDagStyles(Document document, CSSStyleSheet stylesheet, boolean setIds) {
// copy the calculated styles from the DOM back into the gvStyles field
final CSSOMParser inlineParser = new CSSOMParser();
inlineParser.setErrorHandler(new ExceptionErrorHandler());
NodeTraversor.traverse(new NodeVisitor() {
@Override
public void head(Node node, int depth) {
if (node instanceof DagElement && node.hasAttr("style")) {
// parse the CSS into a CSSStyleDeclaration
InputSource input = new InputSource(new StringReader(node.attr("style")));
CSSStyleDeclaration declaration = null;
try {
declaration = inlineParser.parseStyleDeclaration(input);
} catch (IOException e) {
throw new IllegalStateException("IOException on string", e);
}
DagElement dagElement = (DagElement) node;
String tagName = ((Element) node).tagName();
// Dag dag = dagElement.dag;
DagNode dagNode = dagElement.dagNode;
DagEdge dagEdge = dagElement.dagEdge;
DagSubgraph dagSubgraph = dagElement.dagSubgraph;
if (dagSubgraph != null) {
for (int i = 0; i < declaration.getLength(); i++) {
String prop = declaration.item(i);
if (tagName.equals("graph") || tagName.equals("subgraph")) {
logger.debug("setting graph prop " + prop + " to " + declaration.getPropertyValue(prop));
dagSubgraph.gvStyles.put(prop, declaration.getPropertyValue(prop));
} else if (tagName.equals("graphNode")) {
logger.debug("setting graphNode prop " + prop + " to " + declaration.getPropertyValue(prop));
dagSubgraph.gvNodeStyles.put(prop, declaration.getPropertyValue(prop));
} else if (tagName.equals("graphEdge")) {
logger.debug("setting graphEdge prop " + prop + " to " + declaration.getPropertyValue(prop));
dagSubgraph.gvEdgeStyles.put(prop, declaration.getPropertyValue(prop));
}
}
if ((tagName.equals("graph") || tagName.equals("subgraph")) && setIds) {
setIdLabel(dagSubgraph);
}
} else if (dagNode != null) {
for (int i = 0; i < declaration.getLength(); i++) {
String prop = declaration.item(i);
logger.debug("setting " + dagNode.name + " prop " + prop + " to " + declaration.getPropertyValue(prop));
dagNode.gvStyles.put(prop, declaration.getPropertyValue(prop));
}
if (setIds) {
setIdLabel(dagNode);
}
} else if (dagEdge != null) {
for (int i = 0; i < declaration.getLength(); i++) {
String prop = declaration.item(i);
logger.debug("setting dagEdge prop " + prop + " to " + declaration.getPropertyValue(prop));
dagEdge.gvStyles.put(prop, declaration.getPropertyValue(prop));
}
if (setIds) {
setIdLabel(dagEdge);
}
}
}
}
@Override
public void tail(Node node, int depth) {
}
}, document.body());
}
use of com.randomnoun.build.javaToGraphviz.dag.DagSubgraph in project java-to-graphviz by randomnoun.
the class DagStyleApplier method inlineStyles.
/**
* Apply the rules in the stylesheet to the Dag, and populates the gvStyles
* fields on the Dag, DagEdge and DagNode objects.
*
* @param stylesheet
*
* @throws IOException
*/
public void inlineStyles(CSSStyleSheet stylesheet) throws IOException {
// OK so before we create the subgraphs, create dag edges for things that are enabled by style properties
// applyDomStyles(document, stylesheet);
// List<DagElement> elementsToExpandInExcruciatingDetail = getElementsWithStyleProperty(document, "gv-fluent", "true"); // enable method nodes
// use the gv-newSubgraph CSS properties to add subgraphs into both the Dag and the DOM
resetDomStyles(document);
applyDomStyles(document, stylesheet);
Set<DagElement> elementsToCreateSubgraphsInside = getElementsWithStyleProperty(document, "gv-newSubgraph", "true").keySet();
Map<DagElement, String> elementsTruncateEdges = getElementsWithStyleProperty(document, "gv-truncateEdges", null);
Set<DagElement> elementsToCreateSubgraphsFrom = getElementsWithStyleProperty(document, "gv-beginOuterSubgraph", "true").keySet();
Set<DagElement> elementsToCreateSubgraphsTo = getElementsWithStyleProperty(document, "gv-endOuterSubgraph", "true").keySet();
// DagElement outsideEl = elementsToCreateSubgraphsInside.get(i);
for (DagElement outsideEl : elementsToCreateSubgraphsInside) {
DagNode outsideNode = outsideEl.dagNode;
DagSubgraph newSg;
DagSubgraph sg = dag.dagNodeToSubgraph.get(outsideNode);
if (sg == null) {
throw new IllegalStateException("this shouldn't happen any more");
} else {
newSg = new DagSubgraph(dag, sg);
sg.subgraphs.add(newSg);
}
newSg.lineNumber = outsideNode.lineNumber;
newSg.gvAttributes = new HashMap<>(outsideNode.gvAttributes);
// moves the nodes in the dom
DagElement newSgEl = new DagElement("subgraph", newSg, newSg.gvAttributes);
while (outsideEl.childrenSize() > 0) {
Element c = outsideEl.child(0);
c.remove();
newSgEl.appendChild(c);
}
outsideEl.appendChild(newSgEl);
// moves the nodes in the dag subgraphs
moveToSubgraph(newSg, newSgEl, dag, dagNodesToElements, outsideNode);
String truncateEdges = elementsTruncateEdges.get(outsideEl);
if (truncateEdges != null && !truncateEdges.equals("none")) {
// outsideEl.addClass("red");
// outsideNode.classes.add("red");
boolean truncateIncoming = false;
boolean truncateOutgoing = false;
if (truncateEdges.equals("incoming")) {
truncateIncoming = true;
} else if (truncateEdges.equals("outgoing")) {
truncateOutgoing = true;
} else if (truncateEdges.equals("both")) {
truncateIncoming = true;
truncateOutgoing = true;
} else {
throw new IllegalArgumentException("Invalid 'gv-truncateEdges' property '" + truncateEdges + "'; expected " + "'none', 'incoming', 'outgoing' or 'both'");
}
List<DagEdge> inEdges = new ArrayList<>();
List<DagEdge> outEdges = new ArrayList<>();
// actually maybe I do now
for (DagEdge e : dag.edges) {
if (truncateOutgoing && newSg.nodes.contains(e.n1) && !newSg.nodes.contains(e.n2)) {
outEdges.add(e);
}
if (truncateIncoming && newSg.nodes.contains(e.n2) && !newSg.nodes.contains(e.n1)) {
inEdges.add(e);
}
}
for (DagEdge e : outEdges) {
// e.n1 = newSg; // needs to be node -> node, not subgraph -> node
// instead, outgoing edges need 'ltail' with the name of the source subgraph
// don't know the name of this subgraph yet
e.gvObjectStyles.put("ltail", newSg);
}
for (DagEdge e : inEdges) {
// don't know the name of this subgraph yet
e.gvObjectStyles.put("lhead", newSg);
}
}
}
// DagElement fromEl = elementsToCreateSubgraphsFrom.get(i);
for (DagElement fromEl : elementsToCreateSubgraphsFrom) {
Element fromParentEl = fromEl.parent();
DagNode fromNode = fromEl.dagNode;
DagSubgraph newSg;
DagSubgraph sg = dag.dagNodeToSubgraph.get(fromNode);
if (sg == null) {
throw new IllegalStateException("this shouldn't happen any more");
} else {
newSg = new DagSubgraph(dag, sg);
sg.subgraphs.add(newSg);
}
newSg.lineNumber = fromNode.lineNumber;
newSg.gvAttributes = new HashMap<>(fromNode.gvAttributes);
// moves the nodes in the dom
DagElement newSgEl = new DagElement("subgraph", newSg, newSg.gvAttributes);
int idx = fromEl.elementSiblingIndex();
boolean done = false;
while (idx < fromParentEl.childrenSize() && !done) {
// TODO: could probably remove the from and to nodes completely, but then I'll have to rejig the edges,
// although they should always be straight-through so that should be easy enough
// and then apply the 'from' styles to the newly-created subgraph
DagElement c = (DagElement) fromParentEl.child(idx);
if (elementsToCreateSubgraphsTo.contains(c)) {
elementsToCreateSubgraphsTo.remove(c);
done = true;
}
c.remove();
newSgEl.appendChild(c);
// moves the nodes in the dag subgraphs
if (c.dagNode != null) {
// dag subgraphs don't contain edges
moveToSubgraph(newSg, newSgEl, dag, dagNodesToElements, c.dagNode);
}
}
if (!done) {
logger.warn("gv-subgraph without gv-end, closing subgraph at AST boundary");
}
fromParentEl.insertChildren(idx, newSgEl);
}
if (elementsToCreateSubgraphsTo.size() > 0) {
throw new IllegalStateException("gv-end without gv-subgraph");
}
// reapply styles now the DOM contains CSS-defined subgraph elements
resetDomStyles(document);
applyDomStyles(document, stylesheet);
// true = set IDs
setDagStyles(document, stylesheet, true);
// TODO: arguably now that the node IDs have changed, couple reapply a third time in case there are any
// ID-specific CSS rules
// TODO: also recreate element inNodeId, outNodeId inNodeIds, outNodeIds attributes
// applyStyles(document, stylesheet, dag);
setDagSubgraphLiterals(document, stylesheet);
}
use of com.randomnoun.build.javaToGraphviz.dag.DagSubgraph in project java-to-graphviz by randomnoun.
the class AstToDagVisitor method processCommentsToStatementNode.
private void processCommentsToStatementNode(DagNode pdn, int line, int column, DagNode currentLineDn) {
// DagNode lastNode = null;
while (lastIdx < comments.size() && (comments.get(lastIdx).line < line || (comments.get(lastIdx).line == line && comments.get(lastIdx).column < column))) {
CommentText ct = comments.get(lastIdx);
DagNode dn;
if (currentLineDn == null) {
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
} else {
dn = currentLineDn;
}
if (ct instanceof GvComment) {
GvComment gc = (GvComment) ct;
if (Text.isBlank(gc.direction)) {
DagNode prevDagNode = getStartingDagNodeOnLine(ct.line);
if (prevDagNode == null) {
// no direction
annotateDag(dn, gc);
} else {
annotateDag(prevDagNode, gc);
dn = null;
}
} else if (gc.direction.equals("^")) {
// apply to previous node instead
DagNode prevDagNode = getStartingDagNodeAboveLine(ct.line);
if (prevDagNode == null) {
throw new IllegalStateException("Could not find previous statement to associate with '^' comment on line " + ct.line);
}
annotateDag(prevDagNode, gc);
dn = null;
} else if (gc.direction.equals("<")) {
// apply to previous ast on this line
DagNode prevDagNode = getEndDagNodeBeforeLineColumn(ct.line, ct.column);
if (prevDagNode == null) {
throw new IllegalStateException("Could not find previous statement to associate with '<' comment on line " + ct.line);
}
annotateDag(prevDagNode, gc);
dn = null;
} else if (gc.direction.equals("v")) {
// apply to first node on next line instead
nextLineComments.add(gc);
nextLineFromLine = ct.line;
dn = null;
} else if (gc.direction.equals(">")) {
nextDagComments.add(gc);
dn = null;
} else {
throw new IllegalStateException("Unknown direction '" + gc.direction + "'");
}
} else if (ct instanceof GvGraphComment) {
GvGraphComment gc = ((GvGraphComment) ct);
// to remove the class ast node from the 0th root graph
if (rootGraphIdx == 0) {
dag.clear();
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
} else {
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
}
root.name = gc.id;
root.classes.addAll(gc.classes);
// append to existing ?
root.gvAttributes.put("style", gc.inlineStyleString);
rootGraphIdx++;
dn = null;
} else if (ct instanceof GvEndGraphComment) {
if (rootGraphIdx == 0) {
throw new IllegalStateException("gv-endGraph without gv-graph");
} else {
root = null;
}
dn = null;
} else if (ct instanceof GvSubgraphComment) {
GvSubgraphComment gvsc = (GvSubgraphComment) ct;
dn.name = gvsc.id;
dn.classes.addAll(gvsc.classes);
dn.classes.add("beginSubgraph");
} else if (ct instanceof GvEndSubgraphComment) {
dn.classes.add("endSubgraph");
} else if (ct instanceof GvLiteralComment) {
GvLiteralComment gvlc = (GvLiteralComment) ct;
dn.classes.add("gv-literal");
dn.skipNode = true;
} else if (ct instanceof GvKeepNodeComment) {
GvKeepNodeComment knc = ((GvKeepNodeComment) ct);
boolean defaultKeepNode = "true".equals(options.get("defaultKeepNode"));
keepNodeMatcher = keepNodeMatcher.getModifiedKeepNodeMatcher(defaultKeepNode, knc.text.trim());
dn = null;
} else if (ct instanceof GvOptionComment) {
GvOptionComment oc = ((GvOptionComment) ct);
options = newOptions(oc.text.trim());
dn = null;
}
if (dn != null && dn != currentLineDn) {
if (pdn != null) {
if (root == null) {
throw new IllegalStateException("gv comment outside of graph");
}
dag.addNode(root, dn);
pdn.addChild(dn);
} else {
throw new IllegalStateException("null pdn in createCommentNodesToLine");
// logger.warn("null pdn on " + dn.type + " on line " + dn.line);
}
}
lastIdx++;
}
}
Aggregations