Newer
Older
MagnetRON / src / org / ntlab / deltaViewer / DeltaViewer.java
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.awt.geom.Point2D;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JFrame;

import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DirectedWeightedPseudograph;
import org.ntlab.deltaExtractor.Alias;
import org.ntlab.deltaExtractor.Delta;
import org.ntlab.deltaExtractor.ExtractedStructure;
import org.ntlab.deltaExtractor.AliasPair;
import org.ntlab.deltaViewer.Edge.TypeName;
import org.ntlab.deltaExtractor.Alias.AliasType;
import org.ntlab.trace.ArrayAccess;
import org.ntlab.trace.ArrayUpdate;
import org.ntlab.trace.FieldAccess;
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 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;
import com.mxgraph.view.mxGraphView;

/**
 * Make and display JGraph of extracted delta.
 * 
 * @author Nitta Lab.
 */
//TASK: bArray O
//Careful: Parent
//BUG: methodExecution Id. O
//BUG: Move ObjectVertex position sometimes. O
//BUG: Resize ObjectVertex sometimes. O
//BUG: finally field reference. O
//BUG: edge drawing order. -> parent
//BUG: methodExecution drawing order. -> parent
//BUG: ObjectVertex position when Resize ObjectVertex. O
public class DeltaViewer {
	private static Dimension DEFAULT_SIZE = new Dimension(1300, 700);
	private static String WINDOW_TITLE = "Delta Viewer";

	private ExtractedStructure eStructure;
	private DeltaAliasCollector deltaAliasCollector;

	private Map<String, ObjectVertex> objectToVertexMap = new HashMap<>();
	private Map<MethodExecution, MethodExecutionVertex> methodExecToVertexMap = new LinkedHashMap<>();
	private Map<String, Edge> edgeMap = new HashMap<>();

	private JFrame frame;
	private DeltaGraphAdapter mxgraph;
	// No clue what this does but it is needed.
	private mxICell mxDefaultParent;

	private mxGraphComponent mxgraphComponent;

	private int curFrame = 0;
	private static Dimension VERTEX_OBJECT_SIZE = new Dimension(70, 70);
	private static Dimension VERTEX_METHOD_EXECUTION_SIZE = new Dimension(55, 20);
	private mxPoint coordinatorPoint = new mxPoint(0, 100);

	private DeltaAnimation deltaAnimation;

	private double scale = 1;

	public DeltaViewer() {
		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);
	}

	public DeltaViewer(ExtractedStructure extractedStructure, DeltaAliasCollector deltaAliasCollector) {
		this();
		this.eStructure = extractedStructure;
		this.deltaAliasCollector = deltaAliasCollector;
//		init();
	}

	/** Initialize JFrame, make vertex object and edge object. */
	public void init() {
		// Build a frame, create a graph, and add the graph to the frame so you can actually see the graph.
		if(eStructure != null) {
			List<Reference> srcSide = eStructure.getDelta().getSrcSide();
			List<Reference> dstSide = eStructure.getDelta().getDstSide();
			if (srcSide.size() >= 1 && dstSide.size() >= 1) {
				WINDOW_TITLE = "extract delta of:" + eStructure.getDelta().getSrcSide().get(0).getDstClassName() + "(" + eStructure.getDelta().getSrcSide().get(0).getDstObjectId() + ")" + " -> " + eStructure.getDelta().getDstSide().get(0).getDstClassName()  + "(" + eStructure.getDelta().getDstSide().get(0).getDstObjectId() + ")";
			}
		}

		frame = new JFrame(WINDOW_TITLE);
		frame.setSize(DEFAULT_SIZE);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.add(mxgraphComponent, BorderLayout.CENTER);
		frame.setVisible(true);

		createObjectVertices(eStructure);
		createEdgeToObject(deltaAliasCollector.getAliasList(), deltaAliasCollector.getAliasPairList());

		// Fit graph size in visible JFrame.
		mxGraphView view = mxgraphComponent.getGraph().getView();
		int componentWidth = mxgraphComponent.getWidth() - 25;
		double viewWidth = (double) view.getGraphBounds().getWidth();

//		Object component = mxgraph.insertDeltaVertex(mxDefaultParent, "component", "component", "fillColor=white"); //creates a white vertex.
//		((mxICell)component).getGeometry().setX(mxgraphComponent.getWidth() - 30);
//		((mxICell)component).getGeometry().setY(10);
//		Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, "view", "view", "fillColor=white"); //creates a white vertex.
//		((mxICell)vertex).getGeometry().setX(view.getGraphBounds().getWidth());
//		((mxICell)vertex).getGeometry().setY(10);

		System.out.print("Scale " + componentWidth + ", " + viewWidth + ", " + coordinatorPoint.getX());
		if (viewWidth < coordinatorPoint.getX()) {
			viewWidth += coordinatorPoint.getX();
		}
//		scale = (double)componentWidth/viewWidth;
		System.out.println(", " + scale);
//		scale = 1.5;
		view.setScale(scale);
		deltaAnimation.setScale(scale);

		update();
	}

	/** Update graph on JFrame and set Cell style. */
	public void update() {
		setCellsStyle();
		mxgraphComponent.refresh();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void setExtractedStructure(ExtractedStructure extractedStructure) {
		this.eStructure = extractedStructure;
	}

	public void setDeltaAliasCollector(DeltaAliasCollector deltaAliasCollector) {
		this.deltaAliasCollector = deltaAliasCollector;
	}

	public void setFrameSize(int width, int height) {
		DEFAULT_SIZE.setSize(width, height);
	}

	public void setCoordinatorPoint(double x, double y) {
		coordinatorPoint.setX(x);
		coordinatorPoint.setY(y);
	}

	/** Set style of All cells. */
	private 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 double getXForCell(String id) {
//		double res = -1;
//		if (objectToVertexMap.containsKey(id)) {
//			Object cell = objectToVertexMap.get(id).getCell();
//			res = mxgraph.getCellGeometry(cell).getX();
//		}
//		return res;
//	}

//	private double getYForCell(String id) {
//		double res = -1;
//		if (objectToVertexMap.containsKey(id)) {
//			Object cell = objectToVertexMap.get(id).getCell();
//			res = mxgraph.getCellGeometry(cell).getY();
//		}
//		return res;
//	}

//	private mxICell getRootParentCell(Object object) {
//		mxICell cell = (mxICell) object;
//		if(cell.getParent().getValue() == null) {
//			return cell;
//		}
//		return getRootParentCell(cell.getParent());
//	}

	/**
	 * 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);
	}

	private 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()));
	}

	/**
	 * Step to animation of specified alias. 
	 * 
	 * @param alias Alias type and occurrence point etc.
	 */
	public void stepToAnimation(Alias alias) {
		try {
			stepToAnimation(deltaAliasCollector.getAliasList().indexOf(alias));
		} catch (IndexOutOfBoundsException e) {
			stepToAnimation(-1);	
		}
	}

	/**
	 * Parent : Step to animation of specified numFrame.
	 * 
	 * @param numFrame Current animation frame.
	 */
	public void stepToAnimation(int numFrame) {
		if (deltaAliasCollector.getAliasList().size() > numFrame) {
			doAnimation(curFrame, numFrame);
		} else if (deltaAliasCollector.getAliasList().size() == numFrame){
			System.out.println("\r\nLast Animation.");
			doLastAnimation(numFrame);	
		} else {
			System.out.println("ERROR : Not exist alias.");
		}
	}

	/**
	 * Do animation from fromFrame to toFrame.
	 * 
	 * @param fromFrame 
	 * @param toFrame
	 */
	private void doAnimation(int fromFrame, int toFrame) {
		for (int i = fromFrame; i <= toFrame; i++) {
			List<Alias> aliasList = new ArrayList<>(deltaAliasCollector.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)) {
					if (curFrame == 0) {
						MethodExecution methodExec = alias.getMethodExecution();
						if (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();
		}
	}

	/**
	 * Make last animation of extracted delta.
	 * 
	 * @param numFrame AliasList size.
	 */
	private void doLastAnimation(int numFrame) {
		outputLog();
		curFrame = numFrame;	    	
		Alias alias = deltaAliasCollector.getAliasList().get(numFrame - 1);

		// Make ObjectEdge and reset position of vertexObject, remove vertexMethodExecution.
//		for(Statement statement: alias.getMethodExecution().getStatements()) 
		{
			Statement statement = eStructure.getRelatedTracePoint().getStatement();
			MethodExecution methodExec = alias.getMethodExecution();
			if(statement instanceof FieldUpdate) {
				// Format fieldName.
				FieldUpdate fieldUpdateStatement = (FieldUpdate) statement;
				String fieldNames[] = formatFieldName(fieldUpdateStatement.getFieldName());
				String fieldName = fieldNames[fieldNames.length-1];
				String sourceObjectId = fieldUpdateStatement.getContainerObjId();

				createObjectRefrence(fieldUpdateStatement, fieldName);

				// Change!
				String targetObjectId = fieldUpdateStatement.getValueObjId();
				ObjectVertex targetObjectVertex = objectToVertexMap.get(targetObjectId);

				if (methodExecToVertexMap.containsKey(methodExec)) {
					if (methodExecToVertexMap.get(methodExec).getLocals().contains(targetObjectVertex)) {
						methodExecToVertexMap.get(methodExec).getLocals().remove(targetObjectVertex);
						System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeLocal: " + targetObjectVertex.getLabel());
					} else if (methodExecToVertexMap.get(methodExec).getArguments().contains(targetObjectVertex)) {
						methodExecToVertexMap.get(methodExec).getArguments().remove(targetObjectVertex);
						System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeArgument: " + targetObjectVertex.getLabel());
					}
				}

				removeCalledMethodExecutionVertex(objectToVertexMap.get(sourceObjectId), methodExec.getCallerMethodExecution(), methodExec);
				updateObjectVertices();
			}

			if(statement instanceof MethodInvocation) {
				MethodInvocation methodInvStatement = (MethodInvocation) statement;
				MethodExecution calledMethodExec = methodInvStatement.getCalledMethodExecution();
				String methodSignature = calledMethodExec.getSignature();
				String srcClassName = null;
				String srcObjId = null;
				String tgtObjId = null;

				//ArrayやListのときだけラベルを付ける(確実に分かっているものとき)getSignature->contains("List.get(") || "Map.get(") <ホワイトリスト>
//				if (methodExec.getSignature().contains("List.add(") ||
//						methodExec.getSignature().contains("Map.put(")) {
				if (calledMethodExec.isCollectionType()
						&& (methodSignature.contains("add(") 
								|| methodSignature.contains("set(") 
								|| methodSignature.contains("put(") 
								|| methodSignature.contains("push(") 
								|| methodSignature.contains("addElement("))) {

					srcClassName = calledMethodExec.getThisClassName();
					srcObjId = calledMethodExec.getThisObjId();
					tgtObjId = calledMethodExec.getArguments().get(0).getId();
				} else {
					// this to another
					srcClassName = methodInvStatement.getThisClassName();
					srcObjId = methodInvStatement.getThisObjId();
					tgtObjId = calledMethodExec.getReturnValue().getId();
				}


				createObjectRefrence(srcClassName, srcObjId, tgtObjId);

				// Change!
				ObjectVertex tgtObjectVertex = objectToVertexMap.get(tgtObjId);

				if (methodExecToVertexMap.containsKey(methodExec)) {
					if (methodExecToVertexMap.get(methodExec).getLocals().contains(tgtObjectVertex)) {
						methodExecToVertexMap.get(methodExec).getLocals().remove(tgtObjectVertex);
						System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeLocal: " + tgtObjectVertex.getLabel());
					} else if (methodExecToVertexMap.get(methodExec).getArguments().contains(tgtObjectVertex)) {
						methodExecToVertexMap.get(methodExec).getArguments().remove(tgtObjectVertex);
						System.out.println(methodExecToVertexMap.get(methodExec).getLabel() + " :removeArgument: " + tgtObjectVertex.getLabel());
					}
				}
				removeCalledMethodExecutionVertex(objectToVertexMap.get(srcObjId), methodExec.getCallerMethodExecution(), methodExec);
				updateObjectVertices();
			}
		}

//		MethodExecution tempMethodExec = alias.getMethodExecution();
//		//ArrayやListのときだけラベルを付ける(確実に分かっているものとき)getSignature->contains("List.get(") || "Map.get(") <ホワイトリスト>
//		if (tempMethodExec.getSignature().contains("List.add(") ||
//				tempMethodExec.getSignature().contains("Map.put(")) {
//			String srcClassName = tempMethodExec.getThisClassName();
//			String fieldName = tempMethodExec.getArguments().get(0).getId();
//			System.out.println("rTHIS " + srcClassName + ", " + fieldName);
//		}

//		Statement tempStatement = alias.getOccurrencePoint().getStatement(); -> MethodInvocation
//		if(tempStatement instanceof FieldAccess) {
//			FieldAccess fieldAccessStatement = (FieldAccess) tempStatement;
//			String fieldNames[] = formatFieldName(fieldAccessStatement.getFieldName());
//			String srcClassName = fieldNames[0];
//			String fieldName = fieldNames[1];
//			String sourceObjectId = fieldAccessStatement.getContainerObjId();
//			System.out.println(fieldName);
//			createObjectRefrence(fieldAccessStatement, fieldName);
//			removeCalledMethodExecutionVertex(objectToVertexMap.get(sourceObjectId), alias.getMethodExecution().getCallerMethodExecution(), alias.getMethodExecution());
//			updateObjectVertices();
//		}

		// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
			List<MethodExecution> methodExecList = new ArrayList<>(methodExecToVertexMap.keySet());
			Collections.reverse(methodExecList);
			System.out.println(methodExecList.size());
			for(int i = 0; i < methodExecList.size(); i++) {
				String objectId = methodExecList.get(i).getThisObjId();
				ObjectVertex sourceVertexObject = objectToVertexMap.get(objectId); // sourceVertex
				MethodExecution methodExec = methodExecList.get(i);
				if (i != methodExecList.size()-1) {
					for(Statement statement: methodExec.getStatements()) {
						if(statement instanceof MethodInvocation) {
							MethodExecution calledMethodExec = ((MethodInvocation) statement).getCalledMethodExecution();
							String calledObjectId = calledMethodExec.getThisObjId();
							System.out.println(calledObjectId);
							if(objectToVertexMap.containsKey(calledObjectId)) {
								mxICell calledCell = (mxICell)objectToVertexMap.get(calledObjectId).getCell();
								Point absolutePointCalledCell = getAbsolutePointforCell(calledCell);
								System.out.println(objectId + ", " + methodExec.getSignature());
								//	    	    		objectToVertexMap.get(calledObjectId).resetCellPosition();
//								if (methodExecToVertexMap.get(methodExec).getArguments().contains(objectToVertexMap.get(calledObjectId)) || methodExecToVertexMap.get(methodExec).getLocals().contains(objectToVertexMap.get(calledObjectId))) {
//									calledCell.getParent().remove(calledCell);
//									calledCell.setParent(mxDefaultParent);
//									calledCell.getGeometry().setX(absolutePointCalledCell.getX());
//									calledCell.getGeometry().setY(absolutePointCalledCell.getY());
//									deltaAnimation.setVertexAnimation(calledCell, new mxPoint(objectToVertexMap.get(calledObjectId).getInitialX(), objectToVertexMap.get(calledObjectId).getInitialY()));
//									deltaAnimation.startVertexAnimation();
//								}
								removeCalledMethodExecutionVertex(sourceVertexObject, methodExec.getCallerMethodExecution(), methodExec);
								updateObjectVertices();
								//			    		removeVertexMethodExecution(sourceVertexObject, methodExec);
								//	    				update();
								break;
							}
						}
					}
				}  else {
					outputLog();

					// Change!
					List<ObjectVertex> arguments = new ArrayList<>(methodExecToVertexMap.get(methodExec).getArguments());
					List<ObjectVertex> locals = new ArrayList<>(methodExecToVertexMap.get(methodExec).getLocals());
					if (arguments.size() != 0) {
						for (ObjectVertex vo: arguments) {
							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(methodExec).getArguments().remove(vo);
						}
					}else if (locals.size() != 0) {
						for (ObjectVertex vo: locals) {
							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(methodExec).getLocals().remove(vo);
						}
					}
					updateObjectVertices();	    			
				}
			}
		} finally {
			mxgraph.getModel().endUpdate();
		}
		update();
	}

	/** Create ObjectVertices. */
	private void createObjectVertices(ExtractedStructure eStructure) {
		Delta delta = eStructure.getDelta();
		double time = 150;
		double padding = 200;
		coordinatorPoint.setX(coordinatorPoint.getX() + (time * delta.getDstSide().size()) + padding);

		// 左上(0, 0)
		double xCor = coordinatorPoint.getX();
		double yCor = coordinatorPoint.getY();

		//Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
		mxgraph.getModel().beginUpdate();
		try {
			// Draw vertex object.
			// srcSide
			int srcSideSize = delta.getSrcSide().size();
			MethodExecution coordinator = eStructure.getCoordinator();
			String coordinatorObjId = coordinator.getThisObjId();
			String coordinatorClassName = coordinator.getThisClassName();
			for (int i = srcSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getSrcSide().get(i);
				if (i == srcSideSize - 1 && !coordinatorObjId.equals(ref.getSrcObjectId()) && !coordinatorClassName.equals(ref.getSrcClassName())) {
					System.out.println("coordinator: " + coordinatorClassName + ", " + coordinatorObjId);
					coordinatorPoint.setX(coordinatorPoint.getX() + time * 2);
					xCor += time * 2;
					Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, coordinatorObjId, coordinatorClassName, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
					objectToVertexMap.put(coordinatorObjId, new ObjectVertex(coordinatorClassName, vertex, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i))));
					srcSideSize++;
				}
				System.out.println("srcSide: " + ref.getSrcClassName() + ", " + ref.isCreation() + ", " + ref.getSrcObjectId());
				if (!ref.isCreation() && !ref.getSrcObjectId().equals(ref.getDstObjectId())) {
					if (!objectToVertexMap.containsKey(ref.getSrcObjectId())) {
						String srcClassName = ref.getSrcClassName();
						if (srcClassName.contains("[L")) {
							srcClassName = formatArrayName(srcClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getSrcObjectId(), srcClassName, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
						objectToVertexMap.put(ref.getSrcObjectId(), new ObjectVertex(ref.getSrcClassName(), vertex, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i))));
					}
					if (!objectToVertexMap.containsKey(ref.getDstObjectId())) {
						System.out.println(ref.getDstClassName() + ", " + ref.isCreation());
						String dstClassName = ref.getDstClassName();
						if (dstClassName.contains("[L")) {
							dstClassName = formatArrayName(dstClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getDstObjectId(), dstClassName, xCor + (time * (srcSideSize - i)), yCor + (time * (srcSideSize - i)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 		
						objectToVertexMap.put(ref.getDstObjectId(), new ObjectVertex(ref.getDstClassName(), vertex, xCor + (time * (srcSideSize - i)), yCor + (time * (srcSideSize - i))));
					}
				} else {
					objectToVertexMap.put(ref.getSrcObjectId(), new ObjectVertex(ref.getSrcClassName(), null, xCor + (time * ((srcSideSize - 1) - i)), yCor + (time * ((srcSideSize - 1) - i))));
				}
			}

			// dstSide
			int dstSideSize = delta.getDstSide().size();
			int cnt = 0;
			for (int i = dstSideSize - 1; i >= 0; i--) {
				Reference ref = delta.getDstSide().get(i);
				if (i == dstSideSize - 1 && srcSideSize == 0 && !coordinatorObjId.equals(ref.getSrcObjectId()) && !coordinatorClassName.equals(ref.getSrcClassName())) {
					System.out.println("coordinator: " + coordinatorClassName + ", " + coordinatorObjId);
					coordinatorPoint.setX(coordinatorPoint.getX() + time * 2);
					xCor += time * 2;
					System.out.println(coordinatorPoint.getX() + ", " + xCor);
					Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, coordinatorObjId, coordinatorClassName, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
					objectToVertexMap.put(coordinatorObjId, new ObjectVertex(coordinatorClassName, vertex, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt))));
					dstSideSize++;
				}
				System.out.println("dstSide: " + ref.getSrcClassName() + ", " + ref.getDstClassName() + ", " + ref.isCreation());
				if (!ref.isCreation() && !ref.getSrcObjectId().equals(ref.getDstObjectId())) {
					if (!objectToVertexMap.containsKey(ref.getSrcObjectId())) {
						String srcClassName = ref.getSrcClassName();
						if (srcClassName.contains("[L")) {
							srcClassName = formatArrayName(srcClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getSrcObjectId(), srcClassName, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
						objectToVertexMap.put(ref.getSrcObjectId(), new ObjectVertex(ref.getSrcClassName(), vertex, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt))));
						cnt++;
					}
					if (!objectToVertexMap.containsKey(ref.getDstObjectId())) {
						String dstClassName = ref.getDstClassName();
						if (dstClassName.contains("[L")) {
							dstClassName = formatArrayName(dstClassName);
						}
						Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, ref.getDstObjectId(), dstClassName, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt)), VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 
						objectToVertexMap.put(ref.getDstObjectId(), new ObjectVertex(ref.getDstClassName(), vertex, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt))));
					}
				} else {
					objectToVertexMap.put(ref.getDstObjectId(), new ObjectVertex(ref.getDstClassName(), null, xCor - (time * (dstSideSize - i + cnt)), yCor + (time * (dstSideSize - i + cnt))));
				}
			}
		} finally {
			mxgraph.getModel().endUpdate();
		}
	}

	/**
	 * Create ObjectVertex when CONSTRACTOR_INVOCATION.
	 * @param alias
	 */
	private void createObjectVertexOnConstractor(Alias alias) {
		ObjectVertex vertexObj = objectToVertexMap.get(alias.getObjectId());
		String souceObjId = alias.getMethodExecution().getThisObjId();
		mxICell sourceCell = (mxICell)objectToVertexMap.get(souceObjId).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 = (MethodInvocation)alias.getOccurrencePoint().getStatement();
		String fieldName = methodInvocation.getCallerSideMethodName();
		List<AliasPair> aliasPairListByAlias = deltaAliasCollector.getAliasPairListByAlias(alias);
		AliasPair aliasPair = null;
		if (aliasPairListByAlias.size() >= 1) {
			aliasPair = aliasPairListByAlias.get(0);
		}
		boolean isSrcSideChanged = aliasPair.getIsSrcSideChanged();
		Point absolutePointSourceCell = getAbsolutePointforCell(sourceCell);
		mxgraph.getModel().beginUpdate();
		try {
			Object vertex = mxgraph.insertDeltaVertex(mxDefaultParent, vertexObj.getLabel(), vertexObj.getLabel(), absolutePointSourceCell.getX() + overlapWidth, absolutePointSourceCell.getY() + overlapHeight, VERTEX_OBJECT_SIZE.getWidth(), VERTEX_OBJECT_SIZE.getHeight(), "fillColor=white"); //creates a white vertex. 		
			vertexObj.setCell(vertex);
			Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, null, sourceCell, vertex);
			if(isSrcSideChanged) {
				((mxCell)edge).setStyle("exitX=1;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;");
			} else {
				((mxCell)edge).setStyle("exitX=0;exitY=1;exitPerimeter=1;entryX=1;entryY=0;entryPerimeter=1;");
			}
			edgeMap.put(alias.getMethodExecution().getThisClassName() + "." + fieldName, new Edge(fieldName, TypeName.Create, edge));
			setCellsStyle();
			deltaAnimation.setVertexAnimation((mxICell)vertex, new mxPoint(vertexObj.getInitialX(), vertexObj.getInitialY()));
			deltaAnimation.startVertexAnimation();
		} finally {
			mxgraph.getModel().endUpdate();
		}
	}

	private 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;");
		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());
	}

	private 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;");
			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
	 */
	private 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)) {
			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);
			}

			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)) {
				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();
		}
	}

	//	private void moveInitialObjectVertex(MethodExecution methodExecution) {
	//		for(Statement statement: methodExecution.getStatements()) {
	//			if(statement instanceof MethodInvocation) {
	//				//				moveInitialVertexObject((MethodInvocation) statement);
	//				MethodExecution calledMethodExec = ((MethodInvocation)statement).getCalledMethodExecution();
	//				String calledObjectId = calledMethodExec.getThisObjId();
	//				mxICell calledCell = (mxICell)objectToVertexMap.get(calledObjectId).getCell();
	//				Point absolutePointCalledCell = getAbsolutePointforCell(calledCell);
	//				//				System.out.println(objectId + ", " + methodExec.getSignature());
	//				//		    	    		objectToVertexMap.get(calledObjectId).resetCellPosition();
	//				if (methodExecToVertexMap.get(methodExecution).getArguments().contains(objectToVertexMap.get(calledObjectId)) || methodExecToVertexMap.get(methodExecution).getLocals().contains(objectToVertexMap.get(calledObjectId))) {
	//					calledCell.getParent().remove(calledCell);
	//					calledCell.setParent(mxDefaultParent);
	//					calledCell.getGeometry().setX(absolutePointCalledCell.getX());
	//					calledCell.getGeometry().setY(absolutePointCalledCell.getY());
	//					deltaAnimation.setVertexAnimation(calledCell, new mxPoint(objectToVertexMap.get(calledObjectId).getInitialX(), objectToVertexMap.get(calledObjectId).getInitialY()));
	//					deltaAnimation.startVertexAnimation();
	//					break;
	//				}
	//			}
	//		}
	//	}

	/** Update ObjectVertices size and position. */
	private 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();
		}
	}

	/**
	 * Update VertexObject of targetMethodExecCell size have sourceObjectCell.
	 * 
	 * @param sourceObjectCell
	 * @param targetMethodExecCell
	 */
	//	private void updateVertexObjectSize(mxICell sourceObjectCell, mxICell targetMethodExecCell) {
	//		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();	    	
	//
	//		//Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
	//		mxgraph.getModel().beginUpdate();
	//		try {
	//			double preX = parentTargetMethodExecCell.getGeometry().getX();
	//			double preY = parentTargetMethodExecCell.getGeometry().getY();
	//			double preCenterX = parentTargetMethodExecCell.getGeometry().getCenterX();
	//			double preCenterY = parentTargetMethodExecCell.getGeometry().getCenterY();
	//			parentTargetMethodExecCell.getGeometry().setWidth(parentTargetMethodExecCell.getGeometry().getWidth() * 1.8);
	//			parentTargetMethodExecCell.getGeometry().setHeight(parentTargetMethodExecCell.getGeometry().getHeight() * 1.8);
	//			parentTargetMethodExecCell.getGeometry().setX(preX - (parentTargetMethodExecCell.getGeometry().getCenterX() - preCenterX));
	//			parentTargetMethodExecCell.getGeometry().setY(preY - (parentTargetMethodExecCell.getGeometry().getCenterY() - preCenterY));
	//		} finally {
	//			mxgraph.getModel().endUpdate();
	//		}
	//	}

	/**
	 * Create MethodExecutionVertex.
	 * 
	 * @param alias
	 */
	private void createMethodExecutionVertex(Alias alias) {
		String objId = alias.getObjectId();
		MethodExecution methodExec = alias.getMethodExecution();
		String methodExecSignature = methodExec.getSignature();

		if (curFrame == 0) {
			MethodExecution callerMethodExec = methodExec.getCallerMethodExecution();
			if (methodExecSignature != callerMethodExec.getSignature() && objectToVertexMap.containsKey(callerMethodExec.getThisObjId())) {
				createMethodExecutionVertex(callerMethodExec.getThisObjId(), callerMethodExec.getSignature(), callerMethodExec);
			}
			createMethodExecutionVertex(objId, methodExecSignature, methodExec);
		} else if (alias.getObjectId().matches("0")) {
			createMethodExecutionVertex(objId, methodExecSignature, methodExec);
		}
	}

	/**
	 * Parent : Create MethodExecutionVertex.
	 * 
	 * @param objId
	 * @param methodSignature Called or this MethodSignature.
	 * @param methodExec Called or this MethodExecution.
	 */
	private void createMethodExecutionVertex(String objId, String methodSignature, MethodExecution methodExec) {

		if (methodSignature.contains(" ")) {
			System.out.println(methodSignature);
			methodSignature = formatMethodSignature(methodSignature);
		}

		// 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
	 */
	private 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 = (mxICell)methodExecToVertexMap.get(methodExec).getCell();
			mxCell 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);
							}
						}
					}

					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});
				objectToVertexMap.get(calledMethodExec.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});
				objectToVertexMap.get(calledMethodExec.getCallerMethodExecution().getThisObjId()).getVertexMethodExecutions().remove(methodExecToVertexMap.get(calledMethodExec));
				methodExecToVertexMap.get(calledMethodExec).getLocals().remove(sourceVertexObject);
				methodExecToVertexMap.remove(calledMethodExec);
			}
		}
		outputLog();
	}


	/**
	 * Update VertexObject of targetMethodExecCell size have sourceObjectCell.
	 * 
	 * @param sourceObjectCell
	 * @param targetMethodExecCell
	 */
	//	private void updateVertexObjectSize(mxICell sourceObjectCell, mxICell targetMethodExecCell) {
	//		mxICell parentTargetMethodExecCell = targetMethodExecCell.getParent();	    	
	//
	//		//Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
	//		mxgraph.getModel().beginUpdate();
	//		try {
	//			double preX = parentTargetMethodExecCell.getGeometry().getX();
	//			double preY = parentTargetMethodExecCell.getGeometry().getY();
	//			double preCenterX = parentTargetMethodExecCell.getGeometry().getCenterX();
	//			double preCenterY = parentTargetMethodExecCell.getGeometry().getCenterY();
	//			parentTargetMethodExecCell.getGeometry().setWidth(parentTargetMethodExecCell.getGeometry().getWidth() * 1.8);
	//			parentTargetMethodExecCell.getGeometry().setHeight(parentTargetMethodExecCell.getGeometry().getHeight() * 1.8);
	//			parentTargetMethodExecCell.getGeometry().setX(preX - (parentTargetMethodExecCell.getGeometry().getCenterX() - preCenterX));
	//			parentTargetMethodExecCell.getGeometry().setY(preY - (parentTargetMethodExecCell.getGeometry().getCenterY() - preCenterY));
	//		} finally {
	//			mxgraph.getModel().endUpdate();
	//		}
	//	}

	/** Make edge object in JGraphT and draw this in JGraphX. 
	 * @param map 
	 * @param collection */
	private void createEdgeToObject(List<Alias> aliasList, List<AliasPair> aliasPairList) {
		for (int i = 0; i < aliasList.size()-1; i++) {
			Alias curAlias = aliasList.get(i);
			Alias nextAlias = aliasList.get(i+1);
			String srcClassName = null;
			String fieldName = null;

			if (curAlias.getAliasType().equals(AliasType.THIS) /*&& nextAlias.getAliasType().equals(AliasType.FIELD)*/) {
				if (nextAlias.getAliasType().equals(AliasType.RETURN_VALUE)) {
					MethodExecution nextMethodExec = nextAlias.getMethodExecution();
					//ArrayやListのときだけラベルを付ける(確実に分かっているものとき)getSignature->contains("List.get(") || "Map.get(") <ホワイトリスト>
					if (nextMethodExec.getSignature().contains("List.get(") ||
							nextMethodExec.getSignature().contains("Map.get(")) {
						srcClassName = nextMethodExec.getThisClassName();
						fieldName = nextMethodExec.getArguments().get(0).getId();
						System.out.println("rTHIS " + srcClassName + ", " +nextMethodExec.getArguments().get(0).getId());
					}
				} else {
					Statement statement = nextAlias.getOccurrencePoint().getStatement();
					if(statement instanceof FieldAccess) {
						String fieldNames[] = formatFieldName(((FieldAccess)statement).getFieldName());
						srcClassName = fieldNames[0];
						fieldName = fieldNames[1];
					}
				}
				System.out.println("THIS " + srcClassName + "(" + curAlias.getObjectId() + ") -> " + "(" + nextAlias.getObjectId() + "), "+ fieldName);
			}
			if(curAlias.getAliasType().equals(AliasType.ARRAY)) {
				Statement statement= nextAlias.getOccurrencePoint().getStatement();
				if(statement instanceof ArrayAccess) {
					srcClassName = ((ArrayAccess)statement).getArrayClassName();
					int index = ((ArrayAccess)statement).getIndex();
					fieldName = formatArrayIndex(index);
					System.out.println("ARRAY " + srcClassName + "(" + curAlias.getObjectId() + ") -> " + "(" +  nextAlias.getObjectId() + "),  " + fieldName);
				}
			}
			if (srcClassName != null && fieldName != null && srcClassName != null && !edgeMap.containsKey(srcClassName + "." + fieldName)) {
				// Add a vertex to the graph in a transactional fashion. The vertex is actually a 'cell' in jgraphx terminology.
				mxgraph.getModel().beginUpdate();
				try {
					List<AliasPair> aliasPairListByAlias = deltaAliasCollector.getAliasPairListByAliasPair(curAlias, nextAlias);
					AliasPair aliasPair = null;
					if (aliasPairListByAlias.size() >= 1) {
						aliasPair = aliasPairListByAlias.get(0);
					}
					String srcObjId = aliasPair.getAliasPair().getKey().getObjectId();
					String dstObjId = aliasPair.getAliasPair().getValue().getObjectId();
					boolean isSrcSideChanged = aliasPair.getIsSrcSideChanged();
					//					String dstClassName = curAlias.getMethodExecution().getThisClassName();
					System.out.println(aliasPair.getAliasPair().getKey().getMethodExecution().isConstructor());
					Object srcCell = objectToVertexMap.get(srcObjId).getCell();
					Object dstCell = objectToVertexMap.get(dstObjId).getCell();
					if (srcCell != null && dstCell != null) { // isCreation()
						System.out.println("makeEdgeObject: " + fieldName + ", " + srcClassName + " (" + srcCell.hashCode() + "), " + " (" + dstCell.hashCode() + ")"/* + ", " + dstClassName*/);
						// BUG:NullPointerException
						Object edge = mxgraph.insertDeltaEdge(mxDefaultParent, fieldName, fieldName, srcCell, dstCell);
						if(isSrcSideChanged) {
							((mxCell)edge).setStyle("exitX=1;exitY=1;exitPerimeter=1;entryX=0;entryY=0;entryPerimeter=1;");
						} else {
							((mxCell)edge).setStyle("exitX=0;exitY=1;exitPerimeter=1;entryX=1;entryY=0;entryPerimeter=1;");
						}
						edgeMap.put(srcClassName + "." + fieldName, new Edge(fieldName, TypeName.Reference, edge));
					}
				} finally {
					mxgraph.getModel().endUpdate();
				}
			}
		}
	}

	/** 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).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);
				}

			}
		}
	}

	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;
	}

	private 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;
	}

	private String formatMethodSignature(String methodSignature) {
		// Step1 : split "("
		String[] methodSignatures = methodSignature.split("\\(");
		methodSignature = methodSignatures[0];
		// Step2 : split " "
		methodSignatures = methodSignature.split(" ");
		StringBuffer sb = new StringBuffer();
		sb.append(methodSignatures[methodSignatures.length-1]);
		sb.append("()");
		return sb.toString();
	}

	private String formatArrayName(String srcClassName) {
		// Step1 : remove "[L"
		StringBuffer sb = new StringBuffer();
		sb.append(srcClassName.substring(2, srcClassName.length()-1));
		sb.append("[]");
		return sb.toString();		
	}

	private String formatArrayIndex(int index) {
		StringBuffer sb = new StringBuffer();
		sb.append("[");
		sb.append(index);
		sb.append("]");
		return sb.toString();
	}

	private 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());
			System.out.println(" " + ((mxICell)e.getCell()).getParent().getId());
		}
	}

	private 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;
		}
	}

	private 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);
			}
		}		
	}
}