package com.aptana.rdt.internal.profiling; import java.util.List; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TreeEditor; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.events.TreeListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ProgressBar; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.part.ViewPart; import com.aptana.rdt.profiling.IProfilingListener; import com.aptana.rdt.profiling.ProfilingPlugin; /** * This view is meant to show you how the flow of the program executed. It lets you drill down the execution paths and see * which methods call which. * * @author Chris Williams * */ public class CallGraphView extends ViewPart implements IProfilingListener { private static final String[] COLUMNS = { "Method", "Time [%]", "Time", "Invocations" }; private TreeViewer fViewer; private ITreeContentProvider fContentProvider; private ITableLabelProvider fLabelProvider; private Tree tree; private boolean useGray = false; private Color gray; @Override public void createPartControl(Composite parent) { tree = new Tree(parent, SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER); tree.setHeaderVisible(true); tree.setLinesVisible(true); GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 1; GridData treeLayoutData = new GridData(GridData.FILL, GridData.FILL, true, true); treeLayoutData.heightHint = tree.getItemHeight() * 16; treeLayoutData.widthHint = 300; tree.setLayoutData(treeLayoutData); tree.setLayout(gridLayout); fViewer= new TreeViewer(tree); final TreeColumn column0 = new TreeColumn(tree, SWT.LEFT); column0.setWidth(300); column0.setText(COLUMNS[0]); final TreeColumn column1 = new TreeColumn(tree, SWT.LEFT); column1.setWidth(250); column1.setText(COLUMNS[1]); final TreeColumn column2 = new TreeColumn(tree, SWT.LEFT); column2.setWidth(100); column2.setText(COLUMNS[2]); final TreeColumn column3 = new TreeColumn(tree, SWT.LEFT); column3.setWidth(100); column3.setText(COLUMNS[3]); fViewer.setColumnProperties(COLUMNS); fViewer.setUseHashlookup(true); setProviders(); gray = ProfilingPlugin.createPianoedColor(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); tree.addTreeListener(new TreeListener() { // Must do this after creating the viewer! public void treeExpanded(TreeEvent e) { TreeItem item = (TreeItem) e.item; TreeItem[] children = item.getItems(); addProgressBars(children); } public void treeCollapsed(TreeEvent e) {} }); createPopupMenu(); ProfilingPlugin.getDefault().addProfilingListener(this); if (ProfilingPlugin.getDefault().lastProfilingResult() != null) { profilingEnded(ProfilingPlugin.getDefault().lastProfilingResult()); } } /** * Creates and registers the context menu */ private void createPopupMenu() { MenuManager menuMgr = new MenuManager("#PopupMenu"); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new OpenMethodCallAction(tree)); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); // Allow other plugins to add here } }); Menu menu = menuMgr.createContextMenu(fViewer.getControl()); fViewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, fViewer); } private void setProviders() { fContentProvider= createContentProvider(); // content provider must be set before the label provider fViewer.setContentProvider(fContentProvider); fLabelProvider= createLabelProvider(); fViewer.setLabelProvider(fLabelProvider); } private ITableLabelProvider createLabelProvider() { return new CallGraphLabelProvider(); } private ITreeContentProvider createContentProvider() { return new CallGraphContentProvider(); } @Override public void setFocus() { fViewer.getTree().setFocus(); } public void profilingEnded(List<ProfileThread> results) { if (fViewer != null) { fViewer.setInput(results); addProgressBars(); } } private void addProgressBars() { addProgressBars(tree.getItems()); } private void addProgressBars(TreeItem[] items) { if (items == null || items.length == 0) return; int count = items.length; for (int i = 0; i < count; i++) { TreeItem item = items[i]; Object data = item.getData(); if (data == null) return; if (useGray) item.setBackground(gray); useGray = !useGray; ProgressBar bar = new ProgressBar(tree, SWT.NONE); int percent = 0; if (data instanceof MethodCall) { percent = Math.round(((MethodCall) data).selfTimePercent()); } else if (data instanceof ProfileThread) { percent = 100; } bar.setMinimum(0); bar.setMaximum(100); bar.setSelection(percent); TreeEditor editor = new TreeEditor(tree); editor.grabHorizontal = editor.grabVertical = true; editor.setEditor(bar, item, 1); addProgressBars(item.getItems()); } } @Override public void dispose() { ProfilingPlugin.getDefault().removeProfilingListener(this); super.dispose(); } }