eu.geclipse.callgraph.views.CallGraphView.java Source code

Java tutorial

Introduction

Here is the source code for eu.geclipse.callgraph.views.CallGraphView.java

Source

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