Java tutorial
/***************************************************************************** * Copyright (c) 2010 g-Eclipse Consortium * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Christof Klausecker MNM-Team, LMU Munich - initial API and implementation *****************************************************************************/ package eu.geclipse.callgraph.views; import java.util.Iterator; import java.util.Stack; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.core.runtime.CoreException; import org.eclipse.draw2d.Label; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.part.ViewPart; import org.eclipse.zest.core.viewers.AbstractZoomableViewer; import org.eclipse.zest.core.viewers.GraphViewer; import org.eclipse.zest.core.viewers.IZoomableWorkbenchPart; import org.eclipse.zest.core.widgets.Graph; import org.eclipse.zest.core.widgets.GraphConnection; import org.eclipse.zest.core.widgets.GraphNode; import org.eclipse.zest.core.widgets.ZestStyles; import org.eclipse.zest.layouts.LayoutAlgorithm; import org.eclipse.zest.layouts.LayoutStyles; import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm; import org.eclipse.zest.layouts.algorithms.HorizontalShift; import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; import eu.geclipse.eventgraph.tracereader.otf.OTFReader; import eu.geclipse.eventgraph.tracereader.otf.Process; import eu.geclipse.eventgraph.tracereader.otf.util.Node; import eu.geclipse.traceview.IProcess; /** * Uses Zest to draw a Call Graph */ public class CallGraphView extends ViewPart implements IZoomableWorkbenchPart { private Graph graph; private GraphViewer viewer; private long max; private int depth; private int x; private Stack<GraphNode> stack; private ISelectionListener selectionListener; /** * Constructs a new CallGraphView */ public CallGraphView() { this.max = 0; this.x = 100; this.depth = 0; } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(final Composite parent) { this.graph = new Graph(parent, SWT.NONE); this.graph.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { super.widgetSelected(e); } }); this.graph.addPaintListener(new PaintListener() { @SuppressWarnings("synthetic-access") public void paintControl(final PaintEvent e) { CallGraphView.this.graph.layout(); } }); this.selectionListener = new ISelectionListener() { @SuppressWarnings("synthetic-access") public void selectionChanged(final IWorkbenchPart part, final ISelection selection) { if (graph.isDisposed()) { getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(selectionListener); return; } if (selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection) selection; // OTF based call graph if (structuredSelection.getFirstElement() instanceof IProcess) { Iterator iterator = structuredSelection.iterator(); Object[] objects = CallGraphView.this.graph.getConnections().toArray(); for (int i = 0; i < objects.length; i++) { ((GraphConnection) objects[i]).dispose(); } objects = CallGraphView.this.graph.getNodes().toArray(); for (int i = 0; i < objects.length; i++) { ((GraphNode) objects[i]).dispose(); } while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof Process) { Process process = (Process) next; OTFReader otfReader = (OTFReader) process.getTrace(); Node root = otfReader.getRootNode(process.getProcessId()); CallGraphView.this.max = 0; getMax(root); drawNode(root, null); CompositeLayoutAlgorithm treeLayoutAlgorithm = new CompositeLayoutAlgorithm( LayoutStyles.NO_LAYOUT_NODE_RESIZING, new LayoutAlgorithm[] { new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }); CallGraphView.this.graph.setLayoutAlgorithm(treeLayoutAlgorithm, true); } } } else // experimental C/C++ file call graph if (structuredSelection.getFirstElement() instanceof ITranslationUnit) { ITranslationUnit translationUnit = (ITranslationUnit) structuredSelection.getFirstElement(); Object[] objects = CallGraphView.this.graph.getConnections().toArray(); for (int i = 0; i < objects.length; i++) { ((GraphConnection) objects[i]).dispose(); } objects = CallGraphView.this.graph.getNodes().toArray(); for (int i = 0; i < objects.length; i++) { ((GraphNode) objects[i]).dispose(); // TODO find fix to dispose selected nodes } try { IASTTranslationUnit astTranslationUnit = translationUnit.getAST(); // IASTDeclaration[] declarations = astTranslationUnit.getDeclarations(); // declarations[ 0 ].getFileLocation(); // Visitor visitor = new Visitor(); // astTranslationUnit.accept( visitor); IASTNode[] nodes = astTranslationUnit.getChildren(); for (IASTNode node : nodes) { if (node instanceof IASTFunctionDefinition) { IASTFunctionDefinition functionDefinition = (IASTFunctionDefinition) node; if ("main".equals(functionDefinition.getDeclarator().getName().toString())) { //$NON-NLS-1$ CallGraphView.this.depth = 0; CallGraphView.this.x = 0; GraphNode main = new GraphNode(CallGraphView.this.graph, SWT.NONE, "main"); //$NON-NLS-1$ CallGraphView.this.stack = new Stack<GraphNode>(); CallGraphView.this.stack.push(main); node(functionDefinition); } } } } catch (CoreException e) { e.printStackTrace(); } } } } }; getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this.selectionListener); } private void nodeIf(final IASTIfStatement ifStatement) { this.depth += 50; int elsepos = this.depth + 50; // IF GraphNode ifNode = new GraphNode(this.graph, SWT.NONE, "if " + ifStatement.getConditionExpression().getRawSignature()); //$NON-NLS-1$ ifNode.setLocation(this.x - ifNode.getSize().width / 2, this.depth); this.x -= ifNode.getSize().width + 50; this.depth += 50; GraphNode thenNode = new GraphNode(this.graph, SWT.NONE, "then"); //$NON-NLS-1$ thenNode.setLocation(this.x - thenNode.getSize().width / 2, this.depth); new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, this.stack.lastElement(), ifNode); new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, ifNode, thenNode); this.stack.push(thenNode); node(ifStatement.getThenClause()); this.stack.pop(); this.x += ifNode.getSize().width + 50; int backup = this.depth; this.depth = elsepos; if (ifStatement.getElseClause() != null) { this.x += ifNode.getSize().width + 50; GraphNode elseNode = new GraphNode(this.graph, SWT.NONE, "else"); //$NON-NLS-1$ new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, ifNode, elseNode); elseNode.setLocation(this.x - elseNode.getSize().width / 2, this.depth); this.stack.push(elseNode); node(ifStatement.getElseClause()); this.stack.pop(); this.x -= ifNode.getSize().width + 50; } this.depth = backup; } private void nodeFor(final IASTForStatement forStatement) { this.depth += 50; GraphNode graphNode = new GraphNode(this.graph, SWT.NONE, "for " + forStatement.getInitializerStatement().getRawSignature()); //$NON-NLS-1$ graphNode.setLocation(this.x - graphNode.getSize().width / 2, this.depth); this.x -= graphNode.getSize().width + 50; new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, this.stack.lastElement(), graphNode); this.stack.push(graphNode); this.x += graphNode.getSize().width + 50; node(forStatement.getBody()); new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, this.stack.pop(), graphNode); } private void node(final IASTNode node) { IASTNode[] children = node.getChildren(); for (IASTNode child : children) { // Function Call if (child instanceof IASTFunctionCallExpression) { this.depth += 50; IASTFunctionCallExpression functionCallExpression = (IASTFunctionCallExpression) child; for (IASTNode n : functionCallExpression.getFunctionNameExpression().getChildren()) { GraphNode graphNode = new GraphNode(this.graph, SWT.NONE, n.getRawSignature()); graphNode.setLocation(this.x - graphNode.getSize().width / 2, this.depth); new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, this.stack.pop(), graphNode); this.stack.push(graphNode); } } // IF and ELSE else if (child instanceof IASTIfStatement) { IASTIfStatement ifStatement = (IASTIfStatement) child; nodeIf(ifStatement); // WHILE } else if (child instanceof IASTWhileStatement) { this.depth += 50; IASTWhileStatement whileStatement = (IASTWhileStatement) child; this.depth++; GraphNode graphNode = new GraphNode(this.graph, SWT.NONE, "while"); //$NON-NLS-1$ graphNode.setLocation(x - graphNode.getSize().width / 2, this.depth); new GraphConnection(this.graph, ZestStyles.CONNECTIONS_DIRECTED, this.stack.lastElement(), graphNode); this.stack.push(graphNode); node(child); this.stack.pop(); } else // FOR if (child instanceof IASTForStatement) { IASTForStatement forStatement = (IASTForStatement) child; nodeFor(forStatement); } else { node(child); } } } private void getMax(final Node node) { if (this.max < node.getTime()) { this.max = node.getTime(); } for (Node child : node.getChildren()) { getMax(child); } } private void drawNode(final Node node, final GraphNode parent) { GraphNode graphNode = new GraphNode(this.graph, SWT.NONE, node.getFunctionName()); int percentage = ((int) ((node.getTime() * 255) / this.max)); Label label = new Label(); label.setText("time: " + node.getTime()); graphNode.setTooltip(label); Color color = new Color(Display.getDefault(), new RGB(255, 255 - percentage, 255 - percentage)); graphNode.setBackgroundColor(color); if (parent != null) { GraphConnection graphConnection = new GraphConnection(this.graph, SWT.None, parent, graphNode); graphConnection.setText(Integer.toString(node.getCount())); } for (Node child : node.getChildren()) drawNode(child, graphNode); } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#setFocus() */ @Override public void setFocus() { // TODO Auto-generated method stub } /* * (non-Javadoc) * @see org.eclipse.zest.core.viewers.IZoomableWorkbenchPart#getZoomableViewer() */ public AbstractZoomableViewer getZoomableViewer() { return this.viewer; } }