package org.ntlab.deltaViewer; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.geom.Path2D; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.JPanel; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DirectedWeightedPseudograph; import org.ntlab.deltaExtractor.Alias; import org.ntlab.deltaExtractor.IAliasCollector; import org.ntlab.deltaExtractor.Alias.AliasType; import org.ntlab.deltaViewer.Edge.TypeName; import org.ntlab.trace.ArrayUpdate; import org.ntlab.trace.FieldUpdate; import org.ntlab.trace.MethodExecution; import org.ntlab.trace.MethodInvocation; import org.ntlab.trace.Reference; import org.ntlab.trace.Statement; import org.ntlab.trace.TracePoint; import com.mxgraph.canvas.mxGraphics2DCanvas; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxICell; import com.mxgraph.shape.mxConnectorShape; import com.mxgraph.shape.mxIShape; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.swing.view.mxInteractiveCanvas; import com.mxgraph.util.mxConstants; import com.mxgraph.util.mxPoint; import com.mxgraph.util.mxUtils; import com.mxgraph.view.mxCellState; abstract public class MagnetRONViewer extends JPanel { protected static Dimension DEFAULT_SIZE = new Dimension(1300, 700); protected static String WINDOW_TITLE = "Delta Viewer"; protected static Dimension VERTEX_OBJECT_SIZE = new Dimension(70, 70); protected static Dimension VERTEX_METHOD_EXECUTION_SIZE = new Dimension(55, 20); protected IAliasCollector aliasCollector; protected Map<String, ObjectVertex> objectToVertexMap = new HashMap<>(); protected Map<MethodExecution, MethodExecutionVertex> methodExecToVertexMap = new LinkedHashMap<>(); protected Map<String, Edge> edgeMap = new HashMap<>(); protected DeltaGraphAdapter mxgraph; protected mxICell mxDefaultParent; protected mxGraphComponent mxgraphComponent; protected DeltaAnimation deltaAnimation; protected int curFrame = 0; public MagnetRONViewer() { mxgraph = new DeltaGraphAdapter(new DirectedWeightedPseudograph(DefaultEdge.class)); mxDefaultParent = (mxCell)mxgraph.getDefaultParent(); mxgraphComponent = new mxGraphComponent(mxgraph) { public mxInteractiveCanvas createCanvas() { return new CurvedCanvas(this); } }; deltaAnimation = new DeltaAnimation(mxgraph, mxgraphComponent); mxgraphComponent.setPreferredSize(DEFAULT_SIZE); setLayout(new BorderLayout()); add(mxgraphComponent, BorderLayout.CENTER); } public mxGraphComponent getGraphComponent() { return mxgraphComponent; } abstract public void initAnimation(); /** * Step to animation of specified alias. * * @param alias Alias type and occurrence point etc. */ abstract public void stepToAnimation(Alias alias); /** * Parent : Step to animation of specified numFrame. * * @param numFrame Current animation frame. */ abstract public void stepToAnimation(int numFrame); /** * Do animation from fromFrame to toFrame. * * @param fromFrame * @param toFrame */ protected void doAnimation(int fromFrame, int toFrame) { for (int i = fromFrame; i <= toFrame; i++) { List<Alias> aliasList = new ArrayList<>(aliasCollector.getAliasList()); Alias alias = aliasList.get(i); System.out.println("\r\n" + i + ": " + alias.getAliasType().toString()); System.out.println(alias.getObjectId() + ", " + alias.getMethodSignature() + " l." + alias.getLineNo()); switch(alias.getAliasType()) { case RETURN_VALUE: moveObjectVertex(alias); update(); break; case METHOD_INVOCATION: removeMethodExecutionVertex(alias); moveObjectVertex(alias); update(); break; case CONSTRACTOR_INVOCATION: createObjectVertexOnConstractor(alias); createMethodExecutionVertex(alias.getObjectId(), ((MethodInvocation)alias.getOccurrencePoint().getStatement()).getCallerSideMethodName(), ((MethodInvocation)alias.getOccurrencePoint().getStatement()).getCalledMethodExecution()); update(); removeMethodExecutionVertex(alias); update(); break; case FORMAL_PARAMETER: moveObjectVertex(alias); update(); break; case ACTUAL_ARGUMENT: moveObjectVertex(alias); update(); break; case THIS: if (curFrame == 0 || alias.getObjectId().matches("0")) { createMethodExecutionVertex(alias); update(); } break; case RECEIVER: // Make VertexMethodExecution of called method execution. MethodExecution calledMethodExec = ((MethodInvocation) alias.getOccurrencePoint().getStatement()).getCalledMethodExecution(); if (!methodExecToVertexMap.containsKey(calledMethodExec)) { MethodExecution methodExec = alias.getMethodExecution(); if (!methodExecToVertexMap.containsKey(methodExec) && methodExec.getSignature() != calledMethodExec.getSignature() && objectToVertexMap.containsKey(methodExec.getThisObjId())) { createMethodExecutionVertex(methodExec.getThisObjId(), methodExec.getSignature(), methodExec); } createMethodExecutionVertex(alias.getObjectId(), calledMethodExec.getSignature(), calledMethodExec); update(); } break; default: break; } curFrame = i + 1; outputLog(); } } /** * Create ObjectVertex when CONSTRACTOR_INVOCATION. * @param alias */ protected void createObjectVertexOnConstractor(Alias alias) { ObjectVertex objectVertex = objectToVertexMap.get(alias.getObjectId()); String sourceObjId = alias.getMethodExecution().getThisObjId(); mxICell sourceCell = (mxICell)objectToVertexMap.get(sourceObjId).getCell(); double sourceWidth = sourceCell.getGeometry().getWidth(); double sourceHeight = sourceCell.getGeometry().getHeight(); double overlapWidth = sourceWidth * Math.sqrt(2) * 0.1; double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1); MethodInvocation methodInvocation; String fieldName = null; if (!alias.getMethodExecution().isCollectionType() && alias.getOccurrencePoint().getStatement() != null) { methodInvocation = (MethodInvocation)alias.getOccurrencePoint().getStatement(); fieldName = methodInvocation.getCallerSideMethodName(); } Point absPtSrcCell = getAbsolutePointforCell(sourceCell); mxgraph.getModel().beginUpdate(); try { Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, objectVertex.getLabel(), objectVertex.getLabel(), absPtSrcCell.getX() + overlapWidth, absPtSrcCell.getY() + overlapHeight, VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. objectVertex.setCell(vertex); Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, null, sourceCell, vertex); setEdgePoint((mxCell)edge, absPtSrcCell, objectVertex.getInitialPoint()); edgeMap.put(alias.getMethodExecution().getThisClassName() + "." + fieldName, new Edge(fieldName, TypeName.Create, edge)); setCellsStyle(); deltaAnimation.setVertexAnimation((mxICell)vertex, new mxPoint(objectVertex.getInitialX(), objectVertex.getInitialY())); deltaAnimation.startVertexAnimation(); } finally { mxgraph.getModel().endUpdate(); } } /** * Create ObjectVertex when CONSTRACTOR_INVOCATION is preceded by FORMAL_PARAMETER. * @param alias */ protected void createObjectVertexOnConstractorByFormalParameter(Alias alias) { ObjectVertex objectVertex = objectToVertexMap.get(alias.getObjectId()); // Create cell of this object vertex. MethodExecution methodExec = alias.getMethodExecution(); String srcObjId = methodExec.getArguments().get(0).getId(); mxICell srcCell = (mxICell)objectToVertexMap.get(srcObjId).getCell(); double srcWidth = srcCell.getGeometry().getWidth(); double srcHeight = srcCell.getGeometry().getHeight(); double overlapWidth = srcWidth * Math.sqrt(2) * 0.1; double overlapHeight = srcHeight - (srcHeight * Math.sqrt(2) * 0.1); Point absPtSrcCell = getAbsolutePointforCell(srcCell); MethodInvocation methodInv; String fieldName = null; if (!methodExec.isCollectionType() && alias.getOccurrencePoint().getStatement() != null) { methodInv = (MethodInvocation)alias.getOccurrencePoint().getStatement(); fieldName = methodInv.getCallerSideMethodName(); } mxgraph.getModel().beginUpdate(); try { Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, objectVertex.getLabel(), objectVertex.getLabel(), absPtSrcCell.getX() + overlapWidth, absPtSrcCell.getY() + overlapHeight, VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. objectVertex.setCell(vertex); Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, null, srcCell, vertex); setEdgePoint((mxCell)edge, absPtSrcCell, objectVertex.getInitialPoint()); edgeMap.put(methodExec.getThisClassName() + "." + fieldName, new Edge(fieldName, TypeName.Create, edge)); setCellsStyle(); deltaAnimation.setVertexAnimation((mxICell)vertex, new mxPoint(objectVertex.getInitialX(), objectVertex.getInitialY())); deltaAnimation.startVertexAnimation(); } finally { mxgraph.getModel().endUpdate(); } } protected void createObjectRefrence(FieldUpdate fieldUpdateStatement, String fieldName) { String sourceObjectId = fieldUpdateStatement.getContainerObjId(); String targetObjectId = fieldUpdateStatement.getValueObjId(); mxICell sourceCell = (mxICell)objectToVertexMap.get(sourceObjectId).getCell(); mxICell targetCell = (mxICell)objectToVertexMap.get(targetObjectId).getCell(); Point absolutePointTargetCell = getAbsolutePointforCell(targetCell); targetCell.getParent().remove(targetCell); targetCell.setParent(mxDefaultParent); targetCell.getGeometry().setX(absolutePointTargetCell.getX()); targetCell.getGeometry().setY(absolutePointTargetCell.getY()); Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldUpdateStatement.getFieldName(), fieldName, objectToVertexMap.get(sourceObjectId).getCell(), objectToVertexMap.get(targetObjectId).getCell()); // ((mxCell)edge).setStyle("exitX=0;exitY=0.5;exitPerimeter=1;entryX=1;entryY=0.5;entryPerimeter=1;strokeColor=red;"); ((mxCell)edge).setStyle("strokeColor=red;"); // mxgraph.orderCells(true, new Object[] {edge}); edgeMap.put(fieldUpdateStatement.getFieldName(), new Edge(fieldName, TypeName.Reference, edge)); // System.out.println("last" + objectToVertexMap.get(targetObjectId).getInitialX() + ", " + objectToVertexMap.get(targetObjectId).getInitialY()); deltaAnimation.setVertexAnimation(targetCell, new mxPoint(objectToVertexMap.get(targetObjectId).getInitialX(), objectToVertexMap.get(targetObjectId).getInitialY())); deltaAnimation.startVertexAnimation(); targetCell.getGeometry().setX(objectToVertexMap.get(targetObjectId).getInitialX()); targetCell.getGeometry().setY(objectToVertexMap.get(targetObjectId).getInitialY()); } protected void createObjectRefrence(String srcClassName, String srcObjId, String tgtObjId) { mxICell targetCell; // if (objectToVertexMap.containsKey(targetObjId)) { targetCell = (mxICell)objectToVertexMap.get(tgtObjId).getCell(); // } else { // targetObjId = methodExec.getCallerMethodExecution().getArguments().get(0).getId(); // targetCell = (mxICell)objectToVertexMap.get(targetObjId).getCell(); // } Point absolutePointTargetCell = getAbsolutePointforCell(targetCell); // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { targetCell.getParent().remove(targetCell); targetCell.setParent(mxDefaultParent); targetCell.getGeometry().setX(absolutePointTargetCell.getX()); targetCell.getGeometry().setY(absolutePointTargetCell.getY()); Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, tgtObjId, null, objectToVertexMap.get(srcObjId).getCell(), objectToVertexMap.get(tgtObjId).getCell()); // ((mxCell)edge).setStyle("exitX=0;exitY=0.5;exitPerimeter=1;entryX=1;entryY=0.5;entryPerimeter=1;strokeColor=red;"); ((mxCell)edge).setStyle("strokeColor=red;"); // mxgraph.orderCells(true, new Object[] {edge}); edgeMap.put(tgtObjId, new Edge(null, TypeName.Reference, edge)); // System.out.println("last" + objectToVertexMap.get(targetObjectId).getInitialX() + ", " + objectToVertexMap.get(targetObjectId).getInitialY()); deltaAnimation.setVertexAnimation(targetCell, new mxPoint(objectToVertexMap.get(tgtObjId).getInitialX(), objectToVertexMap.get(tgtObjId).getInitialY())); deltaAnimation.startVertexAnimation(); targetCell.getGeometry().setX(objectToVertexMap.get(tgtObjId).getInitialX()); targetCell.getGeometry().setY(objectToVertexMap.get(tgtObjId).getInitialY()); } finally { mxgraph.getModel().endUpdate(); } System.out.println("rTHIS " + srcClassName + ", " + tgtObjId); } /** * SourceVertex move targetVertex. * * @param alias */ protected void moveObjectVertex(Alias alias) { // sourceVertex ObjectVertex sourceObjectVertex = objectToVertexMap.get(alias.getObjectId()); if (alias.getMethodExecution().isStatic() && !methodExecToVertexMap.containsKey(alias.getMethodExecution())) { createMethodExecutionVertex(alias.getObjectId(), alias.getMethodExecution().getSignature(), alias.getMethodExecution()); } // targetVertex MethodExecutionVertex targetMethodExecVertex = methodExecToVertexMap.get(alias.getMethodExecution()); System.out.println("moveObjectVertex: " + targetMethodExecVertex); System.out.println("moveObjectVertex: " + alias.getMethodExecution().isStatic()); moveObjectVertex(alias, sourceObjectVertex, targetMethodExecVertex); updateObjectVertices(); } /** * Parent : Source VertexObject move target VertexMethodExecution. * * @param alias * @param sourceVertexObject Source VertexObject. * @param targetVertexMethodExec Target VertexMethodExecution. */ private void moveObjectVertex(Alias alias, ObjectVertex sourceVertexObject, MethodExecutionVertex targetVertexMethodExec) { MethodExecution methodExec = alias.getMethodExecution(); if (alias.getAliasType().equals(AliasType.RETURN_VALUE) || alias.getAliasType().equals(AliasType.METHOD_INVOCATION)) { if (sourceVertexObject.getCell() == null && methodExec.isCollectionType()) { if (methodExec.getArguments().isEmpty()) { createObjectVertexOnConstractor(alias); } else { createObjectVertexOnConstractorByFormalParameter(alias); } } moveLocalObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec); } else if (alias.getAliasType().equals(AliasType.FORMAL_PARAMETER)) { moveArgumentObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec); } else if (alias.getAliasType().equals(AliasType.ACTUAL_ARGUMENT)) { moveActualArgumentObjectVertex(methodExec, sourceVertexObject, targetVertexMethodExec); } } /** * Source VertexObject move target VertexMethodExecution to Local position from caller MethodExecution. * * @param callerMethodExec Caller MethodExecution. * @param sourceVertexObject * @param targetVertexMethodExec */ private void moveLocalObjectVertex(MethodExecution callerMethodExec, ObjectVertex sourceVertexObject, MethodExecutionVertex targetVertexMethodExec) { mxICell sourceCell = (mxICell)sourceVertexObject.getCell(); mxICell targetCell = (mxICell) targetVertexMethodExec.getCell(); if (sourceCell == targetCell.getParent()) { System.out.println("nothing."); return; } // Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex. if (methodExecToVertexMap.containsKey(callerMethodExec) && methodExecToVertexMap.get(callerMethodExec).getLocals().contains(sourceVertexObject)) { methodExecToVertexMap.get(callerMethodExec).getLocals().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(callerMethodExec).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel()); } if (methodExecToVertexMap.containsKey(callerMethodExec) && methodExecToVertexMap.get(callerMethodExec).getArguments().contains(sourceVertexObject)) { methodExecToVertexMap.get(callerMethodExec).getArguments().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(callerMethodExec).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel()); } // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { int time = targetVertexMethodExec.getLocals().size(); double sourceX = sourceCell.getGeometry().getX(); double sourceY = sourceCell.getGeometry().getY(); // System.out.println(time); if(sourceCell.getParent().getValue() != null) { Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell); sourceX = absolutePointSourceCell.getX(); sourceY = absolutePointSourceCell.getY(); sourceCell.getParent().remove(sourceCell); } mxgraph.orderCells(true, new Object[] {sourceCell}); sourceCell.setParent(targetCell.getParent()); targetCell.getParent().insert(sourceCell); System.out.println("moveLocalObjectVertex: " + sourceCell.getId() + " (" + sourceCell.hashCode() + ")" + ", " + sourceCell.getParent().getId() + " (" + sourceCell.getParent().hashCode() + ")"); System.out.println(" " + targetCell.getId() + " (" + targetCell.hashCode() + ")" + ", " + targetCell.getParent().getId() + " (" + targetCell.getParent().hashCode() + ")"); Point absolutePointTargetCell = getAbsolutePointforCell(sourceCell.getParent()); sourceCell.getGeometry().setX(sourceX - absolutePointTargetCell.getX()); sourceCell.getGeometry().setY(sourceY - absolutePointTargetCell.getY()); double sourceWidth = sourceCell.getGeometry().getWidth(); double sourceHeight = sourceCell.getGeometry().getHeight(); double targetWidth = targetCell.getGeometry().getWidth(); double targetHeight = targetCell.getGeometry().getHeight(); double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1); double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1); // deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time))); // deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth + (sourceWidth * time), targetCell.getGeometry().getY() - overlapHeight + sourceHeight)); deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - (sourceWidth / Math.sqrt(2.5)) + (sourceWidth * time), targetCell.getGeometry().getY() + targetHeight)); deltaAnimation.startVertexAnimation(); sourceCell.setParent(targetCell.getParent()); targetCell.getParent().insert(sourceCell); // sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth); // sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time)); // sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth + (sourceWidth * time)); // sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + sourceHeight); sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - (sourceWidth / Math.sqrt(2.5)) + (sourceWidth * time)); sourceCell.getGeometry().setY(targetCell.getGeometry().getY() + targetHeight); targetVertexMethodExec.getLocals().add(sourceVertexObject); System.out.println("moveLocalObjectVertex: " + targetVertexMethodExec.getLabel() + " :Local: " + sourceVertexObject.getLabel()); } finally { mxgraph.getModel().endUpdate(); } } /** * Source VertexObject move target VertexMethodExecution to Argument position from MethodExecution. * * @param methodExec MethodExecution. * @param sourceVertexObject move * @param targetVertexMethodExec */ private void moveArgumentObjectVertex(MethodExecution methodExec, ObjectVertex sourceVertexObject, MethodExecutionVertex targetVertexMethodExec) { mxICell sourceCell = (mxICell)sourceVertexObject.getCell(); mxICell targetCell = (mxICell) targetVertexMethodExec.getCell(); // mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent(); // Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex. MethodExecution callerMethodExecution = methodExec.getCallerMethodExecution(); if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getLocals().contains(sourceVertexObject)) { methodExecToVertexMap.get(callerMethodExecution).getLocals().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel()); } if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getArguments().contains(sourceVertexObject)) { methodExecToVertexMap.get(callerMethodExecution).getArguments().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel()); } // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { int time = targetVertexMethodExec.getArguments().size(); double sourceX = sourceCell.getGeometry().getX(); double sourceY = sourceCell.getGeometry().getY(); // System.out.println(time); if(sourceCell.getParent().getValue() != null) { Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell); sourceX = absolutePointSourceCell.getX(); sourceY = absolutePointSourceCell.getY(); sourceCell.getParent().remove(sourceCell); } if (!isParent(targetCell, sourceCell)) { mxgraph.orderCells(true, new Object[] {sourceCell}); sourceCell.setParent(targetCell.getParent()); targetCell.getParent().insert(sourceCell); Point absolutePointSourceParentCell = getAbsolutePointforCell(sourceCell.getParent()); sourceCell.getGeometry().setX(sourceX - absolutePointSourceParentCell.getX()); sourceCell.getGeometry().setY(sourceY - absolutePointSourceParentCell.getY()); double sourceWidth = sourceCell.getGeometry().getWidth(); double sourceHeight = sourceCell.getGeometry().getHeight(); double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1); double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1); deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time))); deltaAnimation.startVertexAnimation(); // sourceCell.setParent(targetCell.getParent()); // targetCell.getParent().insert(sourceCell); sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth); sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time)); targetVertexMethodExec.getArguments().add(sourceVertexObject); System.out.println("moveArgumentObejctVertex" + targetVertexMethodExec.getLabel() + " :Argument: " + sourceVertexObject.getLabel()); } else { // 仕様上のバグ, ループが発生 outputLog(); // try { // ObjectVertex(sourceCell)のクローン生成 // mxICell cloneSourceCell = (mxICell) mxgraph.addCell(sourceCell.clone()); // // cloneSourceCell.setStyle("fillColor=#ffffff;opacity=50;shape=ellipse"); // cloneSourceCell.setId("clone" + cloneSourceCell.getId()); // cloneSourceCell.setValue(null); // cloneSourceCell.setParent(sourceCell); // sourceCell.insert(cloneSourceCell); // cloneSourceCell.getGeometry().setX(0); // cloneSourceCell.getGeometry().setX(0); // cloneSourceCell.getGeometry().setY(0); // 元のObjectVertex Point absPtSourceCell = getAbsolutePointforCell(sourceCell); Point absPtTargetParentCell = getAbsolutePointforCell(targetCell.getParent()); sourceCell.remove(targetCell.getParent()); targetCell.getParent().setParent(mxDefaultParent); sourceCell.setParent(targetCell.getParent()); targetCell.getParent().insert(sourceCell); targetCell.getParent().getGeometry().setX(absPtTargetParentCell.getX()); targetCell.getParent().getGeometry().setY(absPtTargetParentCell.getY()); sourceCell.getGeometry().setX(absPtSourceCell.getX() - absPtTargetParentCell.getX()); sourceCell.getGeometry().setY(absPtSourceCell.getY() - absPtTargetParentCell.getY()); sourceCell.setStyle("opacity=50;shape=ellipse"); double sourceWidth = sourceCell.getGeometry().getWidth(); double sourceHeight = sourceCell.getGeometry().getHeight(); // double overlapWidth = targetCell.getGeometry().getWidth() / 2; double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1); double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1); // deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() + overlapWidth, targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time))); deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth + (sourceWidth * time), targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time))); deltaAnimation.startVertexAnimation(); outputLog(); // sourceCell.getGeometry().setX(targetCell.getGeometry().getX() + overlapWidth); sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth + (sourceWidth * time)); sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time)); targetVertexMethodExec.getArguments().add(sourceVertexObject); // } catch (CloneNotSupportedException e) { // e.printStackTrace(); // } } } finally { mxgraph.getModel().endUpdate(); } } /** * Source VertexObject move target VertexMethodExecution to Argument position from MethodExecution. * * @param methodExec MethodExecution. * @param sourceVertexObject * @param targetVertexMethodExec */ private void moveActualArgumentObjectVertex(MethodExecution methodExec, ObjectVertex sourceVertexObject, MethodExecutionVertex targetVertexMethodExec) { mxICell sourceCell = (mxICell)sourceVertexObject.getCell(); mxICell targetCell = (mxICell) targetVertexMethodExec.getCell(); // mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent(); if (sourceCell == targetCell.getParent()) { System.out.println("nothing."); return; } // Remove sourceVertex from Locals and Arguments Vertex of MethodExecution's Vertex. // MethodExecution callerMethodExecution = methodExec.getCallerMethodExecution(); System.out.println(methodExec.getSignature()); System.out.println(sourceVertexObject.getLabel()); // if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getLocals().contains(sourceVertexObject)) { // methodExecToVertexMap.get(callerMethodExecution).getLocals().remove(sourceVertexObject); // System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel()); // } // // if (methodExecToVertexMap.containsKey(callerMethodExecution) && methodExecToVertexMap.get(callerMethodExecution).getArguments().contains(sourceVertexObject)) { // methodExecToVertexMap.get(callerMethodExecution).getArguments().remove(sourceVertexObject); // System.out.println(methodExecToVertexMap.get(callerMethodExecution).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel()); // } if (methodExecToVertexMap.containsKey(methodExec) && methodExecToVertexMap.get(methodExec).getLocals().contains(sourceVertexObject)) { methodExecToVertexMap.get(methodExec).getLocals().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeLocal: " + sourceVertexObject.getLabel()); } if (methodExecToVertexMap.containsKey(methodExec) && methodExecToVertexMap.get(methodExec).getArguments().contains(sourceVertexObject)) { methodExecToVertexMap.get(methodExec).getArguments().remove(sourceVertexObject); System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeArgument: " + sourceVertexObject.getLabel()); } // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { // int time = targetVertexMethodExec.getArguments().size(); // int time = targetVertexMethodExec.getLocals().size() + 1; int time = targetVertexMethodExec.getLocals().size(); double sourceX = sourceCell.getGeometry().getX(); double sourceY = sourceCell.getGeometry().getY(); System.out.println(time + ", " + targetVertexMethodExec.getLocals().size()); // if (time == 0) time = 1; if(sourceCell.getParent().getValue() != null) { Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell); sourceX = absolutePointSourceCell.getX(); sourceY = absolutePointSourceCell.getY(); sourceCell.getParent().remove(sourceCell); } sourceCell.setParent(targetCell.getParent()); targetCell.getParent().insert(sourceCell); Point absolutePointSourceParentCell = getAbsolutePointforCell(sourceCell.getParent()); sourceCell.getGeometry().setX(sourceX - absolutePointSourceParentCell.getX()); sourceCell.getGeometry().setY(sourceY - absolutePointSourceParentCell.getY()); double sourceWidth = sourceCell.getGeometry().getWidth(); double sourceHeight = sourceCell.getGeometry().getHeight(); double targetWidth = targetCell.getGeometry().getWidth(); double targetHeight = targetCell.getGeometry().getHeight(); double overlapWidth = sourceWidth - (sourceWidth * Math.sqrt(2) * 0.1); double overlapHeight = sourceHeight - (sourceHeight * Math.sqrt(2) * 0.1); // deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - overlapWidth, targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time))); deltaAnimation.setVertexAnimation(sourceCell, new mxPoint(targetCell.getGeometry().getX() - (sourceWidth / Math.sqrt(3)) + (sourceWidth * time), targetCell.getGeometry().getY() + targetHeight)); deltaAnimation.startVertexAnimation(); // sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - overlapWidth); // sourceCell.getGeometry().setY(targetCell.getGeometry().getY() - overlapHeight + (sourceHeight * time)); sourceCell.getGeometry().setX(targetCell.getGeometry().getX() - (sourceWidth / Math.sqrt(3)) + (sourceWidth * time)); sourceCell.getGeometry().setY(targetCell.getGeometry().getY() + targetHeight); targetVertexMethodExec.getArguments().add(sourceVertexObject); System.out.println("moveActualArgumentObjectVertex: " + targetVertexMethodExec.getLabel() + " :Argument: " + sourceVertexObject.getLabel()); } finally { mxgraph.getModel().endUpdate(); } } /** Update ObjectVertices size and position. */ protected void updateObjectVertices() { // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology mxgraph.getModel().beginUpdate(); try { for (ObjectVertex objectVertex: objectToVertexMap.values()) { mxCell objectVertexCell = ((mxCell) objectVertex.getCell()); if (objectVertexCell != null) { int time = 0; for (int i = 0; i < objectVertexCell.getChildCount(); i++) { if (!(objectVertexCell.getChildAt(i).getId()).contains("clone")) { time++; } } if (time == 0) { time = 1; } if(objectVertexCell.getGeometry().getWidth() != VERTEX_OBJECT_SIZE.getWidth() * time) { System.out.println("updateVertexObjectSize: " + objectVertexCell.getGeometry().getWidth() + "->" + VERTEX_OBJECT_SIZE.getWidth() * time+ ", " + objectVertexCell.getId()); Dimension targetDimension = new Dimension(); targetDimension.setSize(VERTEX_OBJECT_SIZE.getWidth() * time, VERTEX_OBJECT_SIZE.getHeight() * time); if (objectVertexCell.getParent() != mxDefaultParent && (objectVertexCell.getChildCount() != 0 || objectVertexCell.getGeometry().getWidth() > VERTEX_OBJECT_SIZE.getWidth() * time)) { double overlapX = (targetDimension.getWidth() - objectVertexCell.getGeometry().getWidth()) / 2 / Math.sqrt(2); double overlapY = (targetDimension.getHeight() - objectVertexCell.getGeometry().getHeight()) / 2 / Math.sqrt(2); System.out.println("updateVertexObjectPosition: " + objectVertexCell.getGeometry().getX() + " - " + overlapX); mxPoint targetPoint = new mxPoint(objectVertexCell.getGeometry().getX() - overlapX, objectVertexCell.getGeometry().getY() + overlapY); for (MethodExecutionVertex methodExecVertex: methodExecToVertexMap.values()) { List<ObjectVertex> arguments = methodExecVertex.getArguments(); if (arguments != null && arguments.contains(objectVertex)) { targetPoint.setY(objectVertexCell.getGeometry().getY() - overlapY); break; } } deltaAnimation.setVertexAnimation(objectVertexCell, targetPoint); deltaAnimation.startVertexAnimation(); } deltaAnimation.setResizeVertexAnimation(objectVertexCell, targetDimension); deltaAnimation.startResizeVertexAnimation(); } } } } finally { mxgraph.getModel().endUpdate(); } } abstract protected void createMethodExecutionVertex(Alias alias); /** * Parent : Create MethodExecutionVertex. * * @param objId * @param methodSignature Called or this MethodSignature. * @param methodExec Called or this MethodExecution. */ protected void createMethodExecutionVertex(String objId, String methodSignature, MethodExecution methodExec) { if (methodSignature == null) methodSignature = methodExec.getSignature(); if (methodSignature.matches(".+\\(.*\\)")) { System.out.println(methodSignature); methodSignature = formatMethodSignature(methodSignature, methodExec.getThisClassName()); } // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { if (methodExec.isStatic() && !objId.equals("0")) { objId = methodExec.getCallerMethodExecution().getThisObjId(); } Object object = objectToVertexMap.get(objId).getCell(); // if (object != null) { double xCor = VERTEX_OBJECT_SIZE.getWidth() * 0.1; double yCor = VERTEX_OBJECT_SIZE.getHeight() * 0.5; double standardX = xCor; double standardY = 0; int time = objectToVertexMap.get(objId).getVertexMethodExecutions().size(); System.out.println(time); if (time >= 1) { mxICell standardCell = (mxICell) objectToVertexMap.get(objId).getVertexMethodExecutions().get(0).getCell(); standardX = standardCell.getGeometry().getX(); standardY = standardCell.getGeometry().getY(); time-=1; } Object vertex = mxgraph.insertDeltaVertex(object, methodSignature, methodSignature, "fillColor=white"); //creates a white vertex. System.out.println("makeVertexMethodExecution: " + ((mxICell)vertex).getId() + " in " + objId + " (" + standardX + ", " + yCor * (time + 1) + standardY + ")"); MethodExecutionVertex vertexMethodExecution = new MethodExecutionVertex(methodSignature, vertex, standardX , yCor * (time + 1) + standardY, VERTEX_METHOD_EXECUTION_SIZE.getWidth(), VERTEX_METHOD_EXECUTION_SIZE.getHeight()); // Object vertex = mxgraph.insertVertex(object, methodSignature, methodSignature, 0, 0, 0, 0, "fillColor=white", true); //creates a white vertex. // Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, methodSignature, methodSignature, "fillColor=white"); //creates a white vertex. // VertexMethodExecution vertexMethodExecution = new VertexMethodExecution(methodSignature, vertex, getXForCell(objectId) + (xCor * (time + 1)), getYForCell(objectId) + (yCor * (time + 1)), VERTEX_METHOD_EXECUTION_SIZE.getWidth(), VERTEX_METHOD_EXECUTION_SIZE.getHeight()); methodExecToVertexMap.put(methodExec, vertexMethodExecution); if(methodExecToVertexMap.size() > 1) { ((mxICell)vertex).setVisible(false); createEdgeToMethodExecution(); } objectToVertexMap.get(objId).addMethodExecution(vertexMethodExecution); // } } finally { mxgraph.getModel().endUpdate(); } setCellsStyle(); } /** * Remove VertexMethodExecution on AliasType is MethodInvocation of alias. * * @param alias */ private void removeMethodExecutionVertex(Alias alias) { // sourceVertex ObjectVertex sourceVertexObject = objectToVertexMap.get(alias.getObjectId()); MethodExecution methodExec = alias.getMethodExecution(); if(alias.getAliasType().equals(AliasType.METHOD_INVOCATION) || alias.getAliasType().equals(AliasType.CONSTRACTOR_INVOCATION)) { MethodExecution calledMethodExec = ((MethodInvocation) alias.getOccurrencePoint().getStatement()).getCalledMethodExecution(); // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { List<ObjectVertex> arguments = new ArrayList<>(methodExecToVertexMap.get(calledMethodExec).getArguments()); List<ObjectVertex> locals = new ArrayList<>(methodExecToVertexMap.get(calledMethodExec).getLocals()); if (arguments.size() != 0) { for (ObjectVertex vo: arguments) { if (vo != sourceVertexObject) { System.out.println("argumentRemove"); mxICell cell = (mxICell)vo.getCell(); Point absolutePointCell = getAbsolutePointforCell(cell); cell.getParent().remove(cell); cell.setParent(mxDefaultParent); cell.getGeometry().setX(absolutePointCell.getX()); cell.getGeometry().setY(absolutePointCell.getY()); deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY())); deltaAnimation.startVertexAnimation(); methodExecToVertexMap.get(calledMethodExec).getArguments().remove(vo); } } } if (locals.size() != 0) { for (ObjectVertex vo: locals) { if (vo != sourceVertexObject) { System.out.println("localRemove"); mxICell cell = (mxICell)vo.getCell(); Point absolutePointCell = getAbsolutePointforCell(cell); cell.getParent().remove(cell); cell.setParent(mxDefaultParent); cell.getGeometry().setX(absolutePointCell.getX()); cell.getGeometry().setY(absolutePointCell.getY()); deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY())); deltaAnimation.startVertexAnimation(); methodExecToVertexMap.get(calledMethodExec).getLocals().remove(vo); } } } } finally { mxgraph.getModel().endUpdate(); } removeCalledMethodExecutionVertex(sourceVertexObject, methodExec, calledMethodExec); } else { removeMethodExecutionVertex(sourceVertexObject, methodExec); } } /** * Remove VertexMethodExecution on AliasType is MethodInvocation of alias. * * @param sourceVertexObject * @param methodExec */ private void removeMethodExecutionVertex(ObjectVertex sourceVertexObject, MethodExecution methodExec) { // Remove sourceVertex from Locals and Arguments Vertex of CalledMethodExecution's Vertex. if (methodExecToVertexMap.containsKey(methodExec)) { mxCell targetVertexCell = (mxCell)methodExecToVertexMap.get(methodExec).getCell(); targetVertexCell.getParent().remove(targetVertexCell); targetVertexCell.setParent(mxDefaultParent); mxgraph.removeCells(new Object[] {targetVertexCell}); objectToVertexMap.get(methodExec.getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(methodExec)); methodExecToVertexMap.remove(methodExec); edgeMap.remove(methodExec.getSignature()); updateObjectVertices(); } } /** * Remove CalledVertexMethodExecution on AliasType is MethodInvocation of alias. * * @param sourceVertexObject * @param methodExec * @param calledMethodExec */ protected void removeCalledMethodExecutionVertex(ObjectVertex sourceVertexObject, MethodExecution methodExec, MethodExecution calledMethodExec) { outputLog(); // Remove sourceVertex from Locals and Arguments Vertex of CalledMethodExecution's Vertex. if (methodExecToVertexMap.containsKey(calledMethodExec)) { mxICell sourceVertexCell = null; mxCell targetVertexCell = null; if (methodExec != null) { sourceVertexCell = (mxICell)methodExecToVertexMap.get(methodExec).getCell(); targetVertexCell = (mxCell)methodExecToVertexMap.get(calledMethodExec).getCell(); } // if(!calledMethodExec.isStatic()) { // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology. mxgraph.getModel().beginUpdate(); try { // Dangerous List<ObjectVertex> arguments = new ArrayList<>(methodExecToVertexMap.get(calledMethodExec).getArguments()); List<ObjectVertex> locals = new ArrayList<>(methodExecToVertexMap.get(calledMethodExec).getLocals()); if (arguments.size() != 0) { for (ObjectVertex vo: arguments) { if (vo != sourceVertexObject) { mxICell cell = (mxICell)vo.getCell(); Point absolutePointCell = getAbsolutePointforCell(cell); System.out.println(cell); System.out.println(vo.getInitialX() + ", " + vo.getInitialY()); System.out.println(cell.getGeometry().getX() + ", " + cell.getGeometry().getY()); System.out.println(absolutePointCell); if (cell.getParent() != mxDefaultParent) { cell.getParent().remove(cell); cell.setParent(mxDefaultParent); } if (!absolutePointCell.equals(vo.getInitialPoint())) { cell.getGeometry().setX(absolutePointCell.getX()); cell.getGeometry().setY(absolutePointCell.getY()); deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY())); deltaAnimation.startVertexAnimation(); } methodExecToVertexMap.get(calledMethodExec).getArguments().remove(vo); } } } if (locals.size() != 0) { for (ObjectVertex vo: locals) { if (vo != sourceVertexObject) { mxICell cell = (mxICell)vo.getCell(); Point absolutePointCell = getAbsolutePointforCell(cell); System.out.println(cell); System.out.println(vo.getInitialX() + ", " + vo.getInitialY()); System.out.println(cell.getGeometry().getX() + ", " + cell.getGeometry().getY()); System.out.println(absolutePointCell); if (cell.getParent() != mxDefaultParent) { cell.getParent().remove(cell); cell.setParent(mxDefaultParent); } if (!absolutePointCell.equals(vo.getInitialPoint())) { cell.getGeometry().setX(absolutePointCell.getX()); cell.getGeometry().setY(absolutePointCell.getY()); deltaAnimation.setVertexAnimation(cell, new mxPoint(vo.getInitialX(), vo.getInitialY())); deltaAnimation.startVertexAnimation(); } methodExecToVertexMap.get(calledMethodExec).getLocals().remove(vo); } } } if (sourceVertexCell == null || targetVertexCell == null) return; mxgraph.removeCells(mxgraph.getEdgesBetween(sourceVertexCell, targetVertexCell)); try { mxICell cloneTargetVertexCell = (mxICell) mxgraph.addCell(targetVertexCell.clone()); Point absolutPointSourceVertexCell = getAbsolutePointforCell(sourceVertexCell); Point absolutPointTargetVertexCell = getAbsolutePointforCell(targetVertexCell); cloneTargetVertexCell.getGeometry().setX(absolutPointTargetVertexCell.getX()); cloneTargetVertexCell.getGeometry().setY(absolutPointTargetVertexCell.getY()); cloneTargetVertexCell.setStyle("fillColor=none;strokeColor=none;fontColor=#008000;"); cloneTargetVertexCell.setValue(null); Object tempEdge = mxgraph.insertEdge(mxDefaultParent, null, null, sourceVertexCell, cloneTargetVertexCell); ((mxCell)tempEdge).setStyle("dashed=1;strokeColor=#008000;exitX=0.5;exitY=1;exitPerimeter=1;entryX=0.5;entryY=0;entryPerimeter=1;endArrow=none"); deltaAnimation.setReductionEdgeAnimation(cloneTargetVertexCell, new mxPoint(absolutPointSourceVertexCell.getX(), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight())); deltaAnimation.startReductionEdgeAnimation(); // deltaAnimation.setReductionEdgeAnimation(new mxPoint(absolutPointSourceVertexCell.getX() + (sourceVertexCell.getGeometry().getWidth() / 2), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight()), new mxPoint(absolutPointTargetVertexCell.getX() + (targetVertexCell.getGeometry().getWidth() / 2), absolutPointTargetVertexCell.getY())); // deltaAnimation.startReductionEdgeAnimation(); mxgraph.removeCells(new Object[]{cloneTargetVertexCell}); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } finally { mxgraph.getModel().endUpdate(); } ((mxCell)targetVertexCell.getParent()).remove(targetVertexCell); targetVertexCell.setParent(mxDefaultParent); mxgraph.removeCells(new Object[] {targetVertexCell}); if (!calledMethodExec.isStatic()) { objectToVertexMap.get(calledMethodExec.getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(calledMethodExec)); } else { objectToVertexMap.get(calledMethodExec.getCallerMethodExecution().getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(calledMethodExec)); } methodExecToVertexMap.get(calledMethodExec).getLocals().remove(sourceVertexObject); methodExecToVertexMap.remove(calledMethodExec); edgeMap.remove(methodExec.getSignature()); // moveInitialVertexObject(methodExec); // updateObjectVerticesSize(); // } else { // ((mxCell)targetVertexCell.getParent()).remove(targetVertexCell); // targetVertexCell.setParent(mxDefaultParent); // mxgraph.removeCells(new Object[] {targetVertexCell}); // methodExecToVertexMap.get(calledMethodExec).getLocals().remove(sourceVertexObject); // methodExecToVertexMap.remove(calledMethodExec); // } } outputLog(); } /** Make EdgeMethodExecution. */ private void createEdgeToMethodExecution() { List<MethodExecution> methodExecList = new ArrayList<>(methodExecToVertexMap.keySet()); // BUG : Edge Orientation Reverse. for (int i = 0; i < methodExecList.size() - 1; i++) { MethodExecution sourceMethodExec = methodExecList.get(i); MethodExecution targetMethodExec = methodExecList.get(i + 1); String methodSignature = sourceMethodExec.getSignature(); if (!edgeMap.containsKey(methodSignature)) { mxICell sourceVertexCell = (mxICell)methodExecToVertexMap.get(sourceMethodExec).getCell(); mxICell targetVertexCell = (mxICell)methodExecToVertexMap.get(targetMethodExec).getCell(); // if (!targetMethodExec.isStatic()) { Point absolutPointSourceVertexCell = getAbsolutePointforCell(sourceVertexCell); Point absolutPointTargetVertexCell = getAbsolutePointforCell(targetVertexCell); // Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology mxgraph.getModel().beginUpdate(); try { try { mxICell cloneTargetVertexCell = (mxICell) mxgraph.addCell(targetVertexCell.clone()); cloneTargetVertexCell.getGeometry().setX(absolutPointSourceVertexCell.getX()); cloneTargetVertexCell.getGeometry().setY(absolutPointSourceVertexCell.getY() + targetVertexCell.getGeometry().getHeight()); cloneTargetVertexCell.setStyle("fillColor=none;strokeColor=none;fontColor=#008000;"); cloneTargetVertexCell.setValue(null); cloneTargetVertexCell.setVisible(true); Object tempEdge = mxgraph.insertEdge(mxDefaultParent, null, null, sourceVertexCell, cloneTargetVertexCell); ((mxCell)tempEdge).setStyle("dashed=1;strokeColor=#008000;exitX=0.5;exitY=1;exitPerimeter=1;entryX=0.5;entryY=0;entryPerimeter=1;endArrow=none"); deltaAnimation.setExpandEdgeAnimation(cloneTargetVertexCell, new mxPoint(absolutPointTargetVertexCell.getX(), absolutPointTargetVertexCell.getY())); deltaAnimation.startExpandEdgeAnimation(); targetVertexCell.setVisible(true); // deltaAnimation.setExpandEdgeAnimation(new mxPoint(absolutPointSourceVertexCell.getX() + (sourceVertexCell.getGeometry().getWidth() / 2), absolutPointSourceVertexCell.getY() + sourceVertexCell.getGeometry().getHeight()), new mxPoint(absolutPointTargetVertexCell.getX() + (targetVertexCell.getGeometry().getWidth() / 2), absolutPointTargetVertexCell.getY())); // deltaAnimation.startExpandEdgeAnimation(); Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, methodSignature, null, sourceVertexCell, targetVertexCell); ((mxCell)edge).getParent().remove(((mxCell)edge)); ((mxCell)edge).setParent(mxDefaultParent); mxgraph.orderCells(false, new Object[] {edge}); ((mxCell)edge).setStyle("exitX=0.5;exitY=1;exitPerimeter=1;entryX=0.5;entryY=0;entryPerimeter=1;"); mxgraph.removeCells(new Object[]{cloneTargetVertexCell}); edgeMap.put(methodSignature, new Edge(methodSignature, TypeName.Call, edge)); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } finally { mxgraph.getModel().endUpdate(); } // } else { // targetVertexCell.setVisible(true); // } } } } protected void setEdgePoint(mxICell edge, Point absPtSrcCell, Point absPtTgtCell) { // mxgraph.orderCells(true, new Object[] {edge}); // if(absPtSrcCell.getX() <= absPtTgtCell.getX()) { // // 右下から左上へエッジを引く // edge.setStyle("exitX=0.5;exitY=0.5;exitPerimeter=1;entryX=0;entryY=0.5;entryPerimeter=1;"); // } else { // // 左下から右上へエッジを引く // edge.setStyle("exitX=0.5;exitY=0.5;exitPerimeter=1;entryX=1;entryY=0.5;entryPerimeter=1;"); // } } /** Set style of All cells. */ protected void setCellsStyle() { List<Object> vertexObject = new ArrayList<>(); List<Object> staticVertexObject = new ArrayList<>(); List<Object> alignMiddleVertex = new ArrayList<>(); List<Object> alignTopVertex = new ArrayList<>(); List<Object> edgeObject = new ArrayList<>(); List<Object> edgeObjectCreate = new ArrayList<>(); List<Object> edgeMethodExec = new ArrayList<>(); List<Object> roundEdge = new ArrayList<>(); for (Entry<String, ObjectVertex> objectToVertexEntry: objectToVertexMap.entrySet()) { String key = objectToVertexEntry.getKey(); ObjectVertex objectVertex = objectToVertexEntry.getValue(); if (key.matches("0")) { staticVertexObject.add(objectVertex.getCell()); } else { vertexObject.add(objectVertex.getCell()); } if(objectVertex.getVertexMethodExecutions().size() == 0) { alignMiddleVertex.add(objectVertex.getCell()); } else { alignTopVertex.add(objectVertex.getCell()); } } List<MethodExecutionVertex> vertexMethodExecList = new ArrayList<>(methodExecToVertexMap.values()); Collections.reverse(vertexMethodExecList); for (int i = 0; i < vertexMethodExecList.size(); i++) { switch(i) { case 0: ((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ff7fbf"); break; case 1: ((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ff99cc"); break; case 2: ((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffb2d8"); break; case 3: ((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffcce5"); break; case 4: ((mxICell)vertexMethodExecList.get(i).getCell()).setStyle("fillColor=#ffe0ef"); break; default: break; } } for (Edge edge: edgeMap.values()) { roundEdge.add(edge.getCell()); switch(edge.getTypeName()) { case Reference: edgeObject.add(edge.getCell()); break; case Create: edgeObject.add(edge.getCell()); edgeObjectCreate.add(edge.getCell()); break; case Call: edgeMethodExec.add(edge.getCell()); break; default: break; } } /*Given a cell, we can change it's style attributes, for example the color. NOTE that you have to call the graphComponent.refresh() function, otherwise you won't see the difference! */ mxgraph.setCellStyles(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE, vertexObject.toArray(new Object[vertexObject.size()])); mxgraph.setCellStyles(mxConstants.STYLE_PERIMETER, mxConstants.PERIMETER_ELLIPSE, vertexObject.toArray(new Object[vertexObject.size()])); mxgraph.setCellStyleFlags(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_UNDERLINE, true, vertexObject.toArray(new Object[vertexObject.size()])); mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE, alignMiddleVertex.toArray(new Object[alignMiddleVertex.size()])); mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP, alignTopVertex.toArray(new Object[alignTopVertex.size()])); mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_TOPTOBOTTOM, edgeObject.toArray(new Object[edgeObject.size()])); mxgraph.setCellStyleFlags(mxConstants.STYLE_DASHED, 1, true, edgeObjectCreate.toArray(new Object[edgeObjectCreate.size()])); // mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ENTITY_RELATION, edgeObject.toArray(new Object[edgeObject.size()])); // mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ORTHOGONAL, edgeObject.toArray(new Object[edgeObject.size()])); mxgraph.setCellStyleFlags(mxConstants.STYLE_ROUNDED, 1, true, roundEdge.toArray(new Object[roundEdge.size()])); mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_TOP, roundEdge.toArray(new Object[roundEdge.size()])); mxgraph.setCellStyles(mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_BOTTOM, roundEdge.toArray(new Object[roundEdge.size()])); // mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.SHAPE_CURVE, edgeObject.toArray(new Object[edgeObject.size()])); mxgraph.setCellStyles(mxConstants.STYLE_STROKECOLOR, "#008000", edgeMethodExec.toArray(new Object[edgeMethodExec.size()])); mxgraph.setCellStyleFlags(mxConstants.STYLE_DASHED, 1, true, edgeMethodExec.toArray(new Object[edgeMethodExec.size()])); // mxgraph.setCellStyleFlags(mxConstants.STYLE_AUTOSIZE, 1, true, vertexObject.toArray(new Object[vertexObject.size()])); // mxgraph.setCellStyles(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ORTHOGONAL, edgeMethodExec.toArray(new Object[edgeMethodExec.size()])); // mxgraph.setCellStyles(mxConstants.STYLE_ELBOW, mxConstants.ELBOW_VERTICAL, edgeMethodExec.toArray(new Object[edgeMethodExec.size()])); } private void setFrameSize(int width, int height) { DEFAULT_SIZE.setSize(width, height); } protected Point getAbsolutePointforCell(mxICell cell) { Point p1 = cell.getGeometry().getPoint(); if(cell.getParent().getValue() == null || cell == cell.getParent()) { return p1; } System.out.println(cell.getId() + ", " + cell.getParent().getId()); Point p2 = getAbsolutePointforCell(cell.getParent()); return new Point((int) (p1.getX() + p2.getX()), (int) (p1.getY() + p2.getY())); } /** Update graph on JFrame and set Cell style. */ protected void update() { setCellsStyle(); mxgraphComponent.refresh(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } private int countChildVertex(ObjectVertex vertexObject) { int time = vertexObject.getVertexMethodExecutions().size(); if(time == 0) { return 1; } for(MethodExecutionVertex vertexMethodExecution: vertexObject.getVertexMethodExecutions()) { for(ObjectVertex vo: vertexMethodExecution.getLocals()) { time += countChildVertex(vo); } for(ObjectVertex vo: vertexMethodExecution.getArguments()) { return countChildVertex(vo); } } System.out.println(vertexObject.getLabel() + ": " + time); return time; } protected static String[] formatFieldName(String fieldName) { String fieldNames[] = fieldName.split("\\."); String names[] = new String[] {fieldNames[0], fieldNames[fieldNames.length - 1]}; for(int i = 1; i < fieldNames.length - 1; i++) { names[0] += "." + fieldNames[i]; } return names; } protected String formatMethodSignature(String methodSignature, String thisClassName) { // TODO Modify algorithm formatMethodSignature(). // Step1 : split "(" // String[] methodSignatures = methodSignature.split("\\("); methodSignature = methodSignature.substring(0, methodSignature.lastIndexOf('(')); // Step2 : split " " String[] methodSignatures = methodSignature.split(" "); String tmpMethodSignature = methodSignatures[methodSignatures.length-1]; // Step3 : split "." String[] thisClassNames = thisClassName.split("\\."); methodSignatures = tmpMethodSignature.split("\\."); StringBuffer sb = new StringBuffer(); int i = methodSignatures.length - 2; int count = methodSignature.split("\\(").length - 1; if (count > 0) i -= count; if (i >= 0 && !thisClassNames[thisClassNames.length - 1].equals(methodSignatures[i])) { if (thisClassNames[thisClassNames.length - 1].equals(methodSignatures[i + 1])) i += 1; sb.append(methodSignatures[i]); if (methodSignatures.length - i > 1) sb.append("."); } for (i = i + 1; i < methodSignatures.length; i++) { sb.append(methodSignatures[i]); if (methodSignatures.length - i > 1) sb.append("."); } sb.append("()"); String newMethodSignature = sb.toString(); if (!newMethodSignature.isEmpty()) { return newMethodSignature; } return methodSignature; } protected String formatArrayName(String srcClassName) { // Step1 : remove "[L" StringBuffer sb = new StringBuffer(); sb.append(srcClassName.substring(2, srcClassName.length()-1)); sb.append("[]"); return sb.toString(); } protected String formatArrayIndex(int index) { StringBuffer sb = new StringBuffer(); sb.append("["); sb.append(index); sb.append("]"); return sb.toString(); } protected void outputLog() { for (Object object: mxgraph.getChildCells(mxDefaultParent)) { System.out.println(object + " " + object.hashCode()); for (int i = 0; i < ((mxICell)object).getChildCount(); i++) { System.out.println(" " + ((mxICell)object).getChildAt(i) + " " + object.hashCode()); } } System.out.println("\nObject"); for (Entry<String, ObjectVertex> e: objectToVertexMap.entrySet()) { String objId = e.getKey(); ObjectVertex vo = e.getValue(); if (vo.getCell() != null) { System.out.println(vo.getLabel() + " (" + objId + ")" + " " + vo.getCell().hashCode()); } else { System.out.println(vo.getLabel() + " (" + objId + ")"); } for (MethodExecutionVertex vme: vo.getVertexMethodExecutions()) { System.out.println(" " + vme.getLabel()); for (ObjectVertex vmevo: vme.getArguments()) { System.out.println(" Argument: " + vmevo.getLabel()); } for (ObjectVertex vmevo: vme.getLocals()) { System.out.println(" Local: " + vmevo.getLabel()); } } } System.out.println("\nEdge"); for (Edge e: edgeMap.values()) { System.out.println(e.getLabel() + "(" + ((mxICell)e.getCell()).getId() + ")"); if (((mxICell)e.getCell()).getParent() != null) { System.out.println(" " + ((mxICell)e.getCell()).getParent().getId()); } } } /** * Whether sourceCell parents contain targetCell. * @param sourceCell * @param targetCell * @return */ private boolean isParent(mxICell sourceCell, mxICell targetCell) { mxICell sourceParentCell = sourceCell.getParent(); if (sourceParentCell == null || sourceParentCell.getValue() == null) { return false; } if (sourceParentCell == targetCell) { return true; } System.out.println(sourceCell.getId() + ", " + sourceParentCell.getId()); return isParent(sourceParentCell, targetCell); } protected void reflectCoordinates(DeltaGraphAdapter mxgraph) { // TODO Auto-generated method stub } public static Map.Entry<Reference, String> getRelatedInformation(TracePoint rp) { Statement rpStatement = rp.getStatement(); String rpSrcObjId = null; String rpDstObjId = null; String rpSrcClassName = null; String rpDstClassName = null; String rpFieldName = null; // Search for relatedPoint objectReference srcClassName, fieldName. if(rpStatement instanceof FieldUpdate) { // Format fieldName. FieldUpdate rpFieldUpdateStatement = (FieldUpdate) rpStatement; rpSrcObjId = rpFieldUpdateStatement.getContainerObjId(); rpDstObjId = rpFieldUpdateStatement.getValueObjId(); String rpFieldNames[] = formatFieldName(rpFieldUpdateStatement.getFieldName()); rpSrcClassName = rpFieldNames[0]; rpDstClassName = rpFieldUpdateStatement.getValueClassName(); rpFieldName = rpFieldNames[rpFieldNames.length-1]; } else if (rpStatement instanceof ArrayUpdate) { // container to component ArrayUpdate rpArrayUpdateStatement = (ArrayUpdate) rpStatement; rpSrcObjId = rpArrayUpdateStatement.getArrayObjectId(); rpDstObjId = rpArrayUpdateStatement.getValueObjectId(); rpSrcClassName = rpArrayUpdateStatement.getArrayClassName(); rpDstClassName = rpArrayUpdateStatement.getValueClassName(); rpFieldName = "[" + rpArrayUpdateStatement.getIndex() + "]"; } else if(rpStatement instanceof MethodInvocation) { MethodInvocation rpMethodInvStatement = (MethodInvocation) rpStatement; MethodExecution rpCalledMethodExec = rpMethodInvStatement.getCalledMethodExecution(); String rpMethodSig = rpCalledMethodExec.getSignature(); //ArrayやListのときだけラベルを付ける(確実に分かっているものとき)getSignature->contains("List.get(") || "Map.get(") <ホワイトリスト> // if (rpMethodExec.getSignature().contains("List.add(") || // rpMethodExec.getSignature().contains("Map.put(")) { if (rpCalledMethodExec.isCollectionType() && (rpMethodSig.contains("add(") || rpMethodSig.contains("set(") || rpMethodSig.contains("put(") || rpMethodSig.contains("push(") || rpMethodSig.contains("addElement("))) { rpSrcClassName = rpCalledMethodExec.getThisClassName(); rpDstClassName = rpCalledMethodExec.getArguments().get(0).getActualType(); rpSrcObjId = rpCalledMethodExec.getThisObjId(); rpDstObjId = rpCalledMethodExec.getArguments().get(0).getId(); } else { // this to another rpSrcClassName = rpMethodInvStatement.getThisClassName(); rpDstClassName = rpCalledMethodExec.getReturnValue().getActualType(); rpSrcObjId = rpMethodInvStatement.getThisObjId(); rpDstObjId = rpCalledMethodExec.getReturnValue().getId(); } } return new AbstractMap.SimpleEntry<>(new Reference(rpSrcObjId, rpDstObjId, rpSrcClassName, rpDstClassName), rpFieldName); } protected class CurvedCanvas extends mxInteractiveCanvas { mxIShape shape = new CurvedConnector(); public CurvedCanvas(mxGraphComponent mxGraphComponent) { super(mxGraphComponent); } public Object drawCell(mxCellState state) { if (!(state.getCell() instanceof mxCell) || !((mxCell)state.getCell()).isEdge() || state.getAbsolutePointCount() == 2) { return super.drawCell(state); } Map<String, Object> style = state.getStyle(); if (g != null) { // Creates a temporary graphics instance for drawing this shape float opacity = mxUtils.getFloat(style, mxConstants.STYLE_OPACITY, 100); Graphics2D previousGraphics = g; g = createTemporaryGraphics(style, opacity, state); shape.paintShape(this, state); g.dispose(); g = previousGraphics; } return shape; } } protected class CurvedConnector extends mxConnectorShape { public void paintShape(mxGraphics2DCanvas canvas, mxCellState state) { if (state.getAbsolutePointCount() > 1 && configureGraphics(canvas, state, false)) { List<mxPoint> pts = new ArrayList<mxPoint>( state.getAbsolutePoints()); Map<String, Object> style = state.getStyle(); // Paints the markers and updates the points // Switch off any dash pattern for markers boolean dashed = mxUtils.isTrue(style, mxConstants.STYLE_DASHED); Object dashedValue = style.get(mxConstants.STYLE_DASHED); if (dashed) { style.remove(mxConstants.STYLE_DASHED); canvas.getGraphics().setStroke(canvas.createStroke(style)); } translatePoint(pts, 0, paintMarker(canvas, state, true)); translatePoint( pts, pts.size() - 1, paintMarker(canvas, state, false)); if (dashed) { // Replace the dash pattern style.put(mxConstants.STYLE_DASHED, dashedValue); canvas.getGraphics().setStroke(canvas.createStroke(style)); } // Paints the shape and restores the graphics object if (state.getAbsolutePointCount() == 4) { double sx = state.getAbsolutePoint(0).getX(); double sy = state.getAbsolutePoint(0).getY(); double tx1 = state.getAbsolutePoint(1).getX(); double ty1 = state.getAbsolutePoint(1).getY(); double tx2 = state.getAbsolutePoint(2).getX(); double ty2 = state.getAbsolutePoint(2).getY(); double ex = state.getAbsolutePoint(3).getX(); double ey = state.getAbsolutePoint(3).getY(); Path2D.Double p = new Path2D.Double(); p.moveTo((int) sx, (int) sy); p.quadTo((int) tx2, (int) ty2, (int) ex, (int) ey); // p.curveTo((int) tx1, (int) ty1, (int) tx2, (int) ty2, (int) ex, (int) ey); canvas.getGraphics().draw(p); } else if (state.getAbsolutePointCount() == 3) { double sx = state.getAbsolutePoint(0).getX(); double sy = state.getAbsolutePoint(0).getY(); double tx = state.getAbsolutePoint(1).getX(); double ty = state.getAbsolutePoint(1).getY(); double ex = state.getAbsolutePoint(2).getX(); double ey = state.getAbsolutePoint(2).getY(); Path2D.Double p = new Path2D.Double(); p.moveTo((int) sx, (int) sy); p.quadTo((int) tx, (int) ty, (int) ex, (int) ey); canvas.getGraphics().draw(p); } } } private void translatePoint(List<mxPoint> points, int index, mxPoint offset) { if (offset != null) { mxPoint pt = (mxPoint) points.get(index).clone(); pt.setX(pt.getX() + offset.getX()); pt.setY(pt.getY() + offset.getY()); points.set(index, pt); } } } }