Java tutorial
/* * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of the License "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * */ /** * */ package com.nokia.carbide.cpp.pi.call; //import java.awt.Color; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.MouseEvent; import java.text.DecimalFormat; import java.util.Vector; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.SubMenuManager; import org.eclipse.jface.dialogs.IPageChangedListener; import org.eclipse.jface.dialogs.PageChangedEvent; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.wizard.Wizard; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; 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.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.ide.IIDEActionConstants; import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveSamples; import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveTable; import com.nokia.carbide.cpp.internal.pi.save.SaveTableWizard; import com.nokia.carbide.cpp.internal.pi.visual.GenericTable; import com.nokia.carbide.cpp.pi.editors.PIPageEditor; import com.nokia.carbide.cpp.pi.util.SourceLookup; public class CallVisualiser extends GenericTable { private static final long serialVersionUID = 1L; // table column IDs in hopes it's quicker than comparing characters protected static final int COLUMN_ID_IS_CALLED = 100; protected static final int COLUMN_ID_IS_CALLER = 101; protected static final int COLUMN_ID_RECURSIVE_CALL = 102; protected static final int COLUMN_ID_CALLER_PERCENT = 103; protected static final int COLUMN_ID_CALLEE_PERCENT = 104; protected static final int COLUMN_ID_IS_CALLED_COUNT = 105; protected static final int COLUMN_ID_IS_CALLER_COUNT = 106; // table column headings protected static final String COLUMN_HEAD_IS_CALLED = Messages.getString("CallVisualiser.isCalled"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_IS_CALLER = Messages.getString("CallVisualiser.isCaller"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_RECURSIVE_CALL = Messages.getString("CallVisualiser.recursiveCaller"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_CALLER_PERCENT = Messages.getString("CallVisualiser.percentOfCalls"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_CALLEE_PERCENT = Messages.getString("CallVisualiser.percentOfCalls"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_IS_CALLED_COUNT = Messages.getString("CallVisualiser.calledSamples"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_IS_CALLER_COUNT = Messages.getString("CallVisualiser.callerSamples"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_IS_CALLED_COUNT2 = Messages.getString("CallVisualiser.calls"); //$NON-NLS-1$ protected static final String COLUMN_HEAD_IS_CALLER_COUNT2 = Messages.getString("CallVisualiser.calls"); //$NON-NLS-1$ // table column widths protected static final int COLUMN_WIDTH_IS_CALLED = 70; protected static final int COLUMN_WIDTH_IS_CALLER = 70; protected static final int COLUMN_WIDTH_RECURSIVE_CALL = 105; protected static final int COLUMN_WIDTH_CALLER_PERCENT = 98; protected static final int COLUMN_WIDTH_CALLEE_PERCENT = 98; protected static final int COLUMN_WIDTH_IS_CALLED_COUNT = 113; protected static final int COLUMN_WIDTH_IS_CALLER_COUNT = 85; protected static final int COLUMN_WIDTH_IS_CALLED_COUNT2 = 65; protected static final int COLUMN_WIDTH_IS_CALLER_COUNT2 = 65; // SashForm to hold the tables and their titles private SashForm sashForm; // Table viewers and their tables private TableViewer callerTableViewer; private Table callerTable; private TableViewer currentFunctionTableViewer; private Table currentFunctionTable; private TableColumn currentFunctionDefaultColumn; private TableViewer calleeTableViewer; private Table calleeTable; // context menus private Menu callerMenu; private Menu currentFunctionMenu; private Menu calleeMenu; private Table currentMenuTable; private SashForm parent; // this display's editor and page private PIPageEditor pageEditor; private int pageIndex; // trace associated with this display private GfcTrace myTrace; /** the editor page this is sitting on */ private Composite curPage; protected boolean isPageActive; protected boolean needsRefresh; //start and end of the timeframe at the last selection event private int curStart; private int curEnd; // lists of functions, function callers, and function callees private GfcFunctionItem[] functionArray; private CallerCalleeItem[] callerList; private CallerCalleeItem[] calleeList; // menu items protected Action copyAction; protected Action copyTableAction; protected Action functionCopyFunctionAction; protected Action saveTableAction; protected Action functionSaveFunctionAction; protected final static int SAMPLES_AT_ONE_TIME = 1000; private Job setTimeframeJob = null; // class to pass sample data to the save wizard public class SaveSampleString implements ISaveSamples { int startIndex = 0; public SaveSampleString() { } public String getData() { return getData(SAMPLES_AT_ONE_TIME); } public String getData(int size) { String returnString = getSampleString(this.startIndex, this.startIndex + size); if (returnString == null) this.startIndex = 0; else this.startIndex += size; return returnString; } public int getIndex() { return this.startIndex; } public void clear() { this.startIndex = 0; } } /* * return the call samples selected in the interval */ protected String getSampleString(int startIndex, int endIndex) { int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0 + 0.0005); int endTime = (int) (PIPageEditor.currentPageEditor().getEndTime() * 1000.0 + 0.0005); // check if we have returned everything if (startIndex > (endTime - startTime)) return null; GfcTrace trace = this.myTrace; Vector samples = trace.samples; String returnString = ""; //$NON-NLS-1$ if (startIndex == 0) returnString = Messages.getString("CallVisualiser.callHeading"); //$NON-NLS-1$ for (int i = startTime + startIndex; i < endTime && i < startTime + endIndex; i++) { GfcSample sample = (GfcSample) samples.get(i); returnString += sample.sampleSynchTime + ",0x" //$NON-NLS-1$ + Long.toHexString(sample.linkRegister) + ",\"" //$NON-NLS-1$ + (sample.getCallerFunctionItt() != null ? sample.getCallerFunctionItt().getFunctionName() : sample.getCallerFunctionSym().getFunctionName()) + "\"," //$NON-NLS-1$ + (sample.getCallerFunctionItt() != null ? sample.getCallerFunctionItt().getFunctionBinary().getBinaryName() : sample.getCallerFunctionSym().getFunctionBinary().getBinaryName()) + ",0x" //$NON-NLS-1$ + Long.toHexString(sample.programCounter) + ",\"" //$NON-NLS-1$ + (sample.getCurrentFunctionItt() != null ? sample.getCurrentFunctionItt().getFunctionName() : sample.getCurrentFunctionSym().getFunctionName()) + "\"," //$NON-NLS-1$ + (sample.getCurrentFunctionItt() != null ? sample.getCurrentFunctionItt().getFunctionBinary().getBinaryName() : sample.getCurrentFunctionSym().getFunctionBinary().getBinaryName()) + "\n"; //$NON-NLS-1$ } return returnString; } protected MenuItem getSaveSamplesItem(Menu menu, boolean enabled) { MenuItem saveSamplesItem = new MenuItem(menu, SWT.PUSH); saveSamplesItem.setText(Messages.getString("CallVisualiser.saveAllSamplesForInterval")); //$NON-NLS-1$ saveSamplesItem.setEnabled(enabled); if (enabled) { saveSamplesItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { action("saveSamples"); //$NON-NLS-1$ } }); } return saveSamplesItem; } public CallVisualiser(PIPageEditor pageEditor, int pageIndex, SashForm parent, GfcTrace trace, Composite curPage) { this.pageEditor = pageEditor; this.pageIndex = pageIndex; this.parent = parent; this.myTrace = trace; this.curPage = curPage; isPageActive = true; needsRefresh = false; // let the trace know about the CallVisualiser so that unit tests can find it trace.setCallVisualiser(this); // create the 3 table viewers: caller functions, selected function, callee functions createTableViewers(parent); createSetTimeframeJob(); createPageListeners(); } public void createTableViewers(SashForm parent) { if (parent == null) return; /* * Create a SashForm with three labeled tables: * * 1. Functions called by * 2. Functions (one checkbox selectable at a time) * 3. Functions called */ // the 3 tables will be in a sashForm if (parent.getOrientation() != SWT.VERTICAL) { // put a SashForm in the SashForm this.sashForm = new SashForm(parent, SWT.VERTICAL); this.sashForm.SASH_WIDTH = 5; // 5 pixel wide sash } else this.sashForm = parent; createCallerTableViewer(sashForm); createCurrentFunctionTableViewer(sashForm); createCalleeTableViewer(sashForm); createDefaultActions(true); } private void createCurrentFunctionTableViewer(SashForm sashForm) { /* * Functions (one checkbox selectable at a time) * * selected checkbox * percent load * function name * function start address * binary containing function * sample count */ Label label; Composite holder; Table table; TableColumn column; // middle functionTable and title holder = new Composite(sashForm, SWT.NONE); GridLayout gridLayout = new GridLayout(1, true); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; holder.setLayout(gridLayout); label = new Label(holder, SWT.CENTER | SWT.BORDER); label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_YELLOW)); label.setFont(PIPageEditor.helvetica_10); label.setText(Messages.getString("CallVisualiser.selectFunction")); //$NON-NLS-1$ label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); this.currentFunctionTableViewer = new TableViewer(holder, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); this.currentFunctionTable = currentFunctionTableViewer.getTable(); // add the label provider and content provider this.currentFunctionTableViewer.setLabelProvider(new SharedLabelProvider(this.currentFunctionTable)); this.currentFunctionTableViewer.setContentProvider(new ArrayContentProvider()); this.currentFunctionTableViewer.setSorter(new SharedSorter()); table = this.currentFunctionTable; table.setRedraw(false); // give the table a heading for use in copying and exported table.setData(Messages.getString("CallVisualiser.selectedFunction")); //$NON-NLS-1$ // create the other table entries when a row in this table is selected table.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent event) { if (!(event.item instanceof TableItem)) return; // set the other tables based on this selection if (!(event.item.getData() instanceof GfcFunctionItem)) return; updateCallerCalleeTables((GfcFunctionItem) event.item.getData()); } public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } }); // data associated with the TableViewer will note which columns contain hex values // Keep this in the order in which columns have been created boolean[] isHex = { false, false, false, true, false, false, false }; this.currentFunctionTable.setData("isHex", isHex); //$NON-NLS-1$ // is called percent column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_IS_CALLED); column.setWidth(COLUMN_WIDTH_IS_CALLED); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLED)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // is caller percent column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_IS_CALLER); column.setWidth(COLUMN_WIDTH_IS_CALLER); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLER)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // function name column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_FUNCTION); column.setWidth(COLUMN_WIDTH_FUNCTION_NAME); column.setData(Integer.valueOf(COLUMN_ID_FUNCTION)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // function start address column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_START_ADDR); column.setWidth(COLUMN_WIDTH_START_ADDRESS); column.setData(Integer.valueOf(COLUMN_ID_START_ADDR)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY); column.setWidth(COLUMN_WIDTH_IN_BINARY); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // path to binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY_PATH); column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY_PATH)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // sample count column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_IS_CALLED_COUNT); column.setWidth(COLUMN_WIDTH_IS_CALLED_COUNT); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLED_COUNT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); // set the default sort column to COLUMN_ID_IS_CALLED_COUNT currentFunctionDefaultColumn = column; // sample count column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_IS_CALLER_COUNT); column.setWidth(COLUMN_WIDTH_IS_CALLER_COUNT); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLER_COUNT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CheckboxColumnSelectionHandler()); table.setLayoutData(new GridData(GridData.FILL_BOTH)); table.setHeaderVisible(true); table.setLinesVisible(true); table.setRedraw(true); // listen for mouse clicks: to select a row, pop up a menu, etc. table.addMouseListener(new CurrentFunctionMouseListener()); table.addFocusListener(new FocusListener() { IAction oldCopyAction = null; public void focusGained(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); // modify what is executed when Copy is called from the Edit menu oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId()); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction); copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); bars.updateActionBars(); // add to the Edit menu IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT); if (editMenuManager instanceof SubMenuManager) { IContributionManager editManager = ((SubMenuManager) editMenuManager).getParent(); ActionContributionItem item; editMenuManager.remove("PICopyFunction"); //$NON-NLS-1$ functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); item = new ActionContributionItem(functionCopyFunctionAction); item.setVisible(true); editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item); editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0); item = new ActionContributionItem(copyTableAction); item.setVisible(true); editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item); } // add to the File menu IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE); if (fileMenuManager instanceof SubMenuManager) { IContributionManager fileManager = ((SubMenuManager) fileMenuManager).getParent(); ActionContributionItem item; fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ saveTableAction.setEnabled(currentFunctionTable.getItemCount() > 0); item = new ActionContributionItem(saveTableAction); item.setVisible(true); fileManager.insertAfter("saveAll", item); //$NON-NLS-1$ fileMenuManager.remove("PISaveFunction"); //$NON-NLS-1$ functionSaveFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); item = new ActionContributionItem(functionSaveFunctionAction); item.setVisible(true); fileManager.insertAfter("PISaveTable", item); //$NON-NLS-1$ } } public void focusLost(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction); bars.updateActionBars(); SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_EDIT); editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ editMenuManager.remove("PICopyFunction"); //$NON-NLS-1$ SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_FILE); fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ fileMenuManager.remove("PISaveFunction"); //$NON-NLS-1$ } }); } private void createCallerTableViewer(SashForm sashForm) { /* * Functions called by * * percent of calls * total percent * caller percent * function name * function start address * binary containing function * sample count */ Label label; Composite holder; Table table; TableColumn column; // top functionTable and title holder = new Composite(sashForm, SWT.NONE); // holder.setLayout(new FillLayout(SWT.VERTICAL)); GridLayout gridLayout = new GridLayout(1, true); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; holder.setLayout(gridLayout); label = new Label(holder, SWT.CENTER | SWT.BORDER); label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_CYAN)); label.setFont(PIPageEditor.helvetica_10); label.setText(Messages.getString("CallVisualiser.callingSelectedFunction")); //$NON-NLS-1$ label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); this.callerTableViewer = new TableViewer(holder, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); this.callerTable = callerTableViewer.getTable(); // add the label provider and content provider this.callerTableViewer.setLabelProvider(new SharedLabelProvider(this.callerTable)); this.callerTableViewer.setContentProvider(new ArrayContentProvider()); this.callerTableViewer.setSorter(new SharedSorter()); table = this.callerTable; table.setRedraw(false); // give the table a heading for possible use in copying and exported table.setData(Messages.getString("CallVisualiser.callerFunctions")); //$NON-NLS-1$ // data associated with the TableViewer will note which columns contain hex values // Keep this in the order in which columns have been created boolean[] isHex = { false, false, false, true, false, false, false }; this.callerTable.setData("isHex", isHex); //$NON-NLS-1$ // percent of calls column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_CALLER_PERCENT); column.setWidth(COLUMN_WIDTH_CALLER_PERCENT); column.setData(Integer.valueOf(COLUMN_ID_CALLER_PERCENT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // sample count column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_IS_CALLER_COUNT2); column.setWidth(COLUMN_WIDTH_IS_CALLER_COUNT2); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLER_COUNT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // function name column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_FUNCTION); column.setWidth(COLUMN_WIDTH_FUNCTION_NAME); column.setData(Integer.valueOf(COLUMN_ID_FUNCTION)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // function start address column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_START_ADDR); column.setWidth(COLUMN_WIDTH_START_ADDRESS); column.setData(Integer.valueOf(COLUMN_ID_START_ADDR)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY); column.setWidth(COLUMN_WIDTH_IN_BINARY); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // path to binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY_PATH); column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY_PATH)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); // is caller percent column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_IS_CALLER); column.setWidth(COLUMN_WIDTH_IS_CALLER); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLER)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledByColumnSelectionHandler()); table.setLayoutData(new GridData(GridData.FILL_BOTH)); // table.setLayout(new FillLayout()); table.setHeaderVisible(true); table.setLinesVisible(true); table.setRedraw(true); // when a row is selected, allow the user to double-click or right click and make that function the selected function table.addSelectionListener(new SelectionAdapter() { public void widgetDefaultSelected(SelectionEvent se) { TableItem item = (TableItem) se.item; Table table = (Table) se.widget; CallerCalleeItem callerCalleeItem = (CallerCalleeItem) item.getData(); // deselect this line table.deselectAll(); // choose this row's function chooseNewFunction(callerCalleeItem); } }); table.addMouseListener(new CallerMouseListener()); table.addFocusListener(new FocusListener() { IAction oldCopyAction = null; public void focusGained(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); // modify what is executed when Copy is called from the Edit menu oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId()); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction); copyAction.setEnabled(callerTable.getSelectionCount() > 0); bars.updateActionBars(); // add to the Edit menu IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT); if (editMenuManager instanceof SubMenuManager) { IContributionManager editManager = ((SubMenuManager) editMenuManager).getParent(); ActionContributionItem item; editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ copyTableAction.setEnabled(callerTable.getItemCount() > 0); item = new ActionContributionItem(copyTableAction); item.setVisible(true); editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item); } // add to the File menu IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE); if (fileMenuManager instanceof SubMenuManager) { IContributionManager fileManager = ((SubMenuManager) fileMenuManager).getParent(); ActionContributionItem item; fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ saveTableAction.setEnabled(callerTable.getItemCount() > 0); item = new ActionContributionItem(saveTableAction); item.setVisible(true); fileManager.insertAfter("saveAll", item); //$NON-NLS-1$ } } public void focusLost(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction); bars.updateActionBars(); SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_EDIT); editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_FILE); fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ } }); } private void createCalleeTableViewer(SashForm sashForm) { /* * Functions called * * percent of calls * total percent * caller percent * function name * function start address * binary containing function * sample count */ Label label; Composite holder; Table table; TableColumn column; // bottom functionTable and title holder = new Composite(sashForm, SWT.NONE); // holder.setLayout(new FillLayout(SWT.VERTICAL)); GridLayout gridLayout = new GridLayout(1, true); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; holder.setLayout(gridLayout); label = new Label(holder, SWT.CENTER | SWT.BORDER); label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_CYAN)); label.setFont(PIPageEditor.helvetica_10); label.setText(Messages.getString("CallVisualiser.calledBySelectedFunction")); //$NON-NLS-1$ label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); this.calleeTableViewer = new TableViewer(holder, SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); this.calleeTable = calleeTableViewer.getTable(); // add the label provider and content provider this.calleeTableViewer.setLabelProvider(new SharedLabelProvider(this.calleeTable)); this.calleeTableViewer.setContentProvider(new ArrayContentProvider()); this.calleeTableViewer.setSorter(new SharedSorter()); table = this.calleeTable; table.setRedraw(false); // give the table a heading for possible use in copying and exported table.setData(Messages.getString("CallVisualiser.calleeFunctions")); //$NON-NLS-1$ // data associated with the TableViewer will note which columns contain hex values // Keep this in the order in which columns have been created boolean[] isHex = { false, false, false, true, false, false, false }; this.calleeTable.setData("isHex", isHex); //$NON-NLS-1$ // percent of calls column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_CALLEE_PERCENT); column.setWidth(COLUMN_WIDTH_CALLEE_PERCENT); column.setData(Integer.valueOf(COLUMN_ID_CALLEE_PERCENT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // sample count column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_IS_CALLED_COUNT2); column.setWidth(COLUMN_WIDTH_IS_CALLED_COUNT2); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLED_COUNT)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // function name column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_FUNCTION); column.setWidth(COLUMN_WIDTH_FUNCTION_NAME); column.setData(Integer.valueOf(COLUMN_ID_FUNCTION)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // function start address column column = new TableColumn(table, SWT.CENTER); column.setText(COLUMN_HEAD_START_ADDR); column.setWidth(COLUMN_WIDTH_START_ADDRESS); // column.setData(Integer.valueOf(COLUMN_ID_START_ADDR3)); column.setData(Integer.valueOf(COLUMN_ID_START_ADDR)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY); column.setWidth(COLUMN_WIDTH_IN_BINARY); // column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY3)); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // path to binary containing function column column = new TableColumn(table, SWT.LEFT); column.setText(COLUMN_HEAD_IN_BINARY_PATH); column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH); // column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY_PATH3)); column.setData(Integer.valueOf(COLUMN_ID_IN_BINARY_PATH)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); // percent of calls column column = new TableColumn(table, SWT.RIGHT); column.setText(COLUMN_HEAD_IS_CALLED); column.setWidth(COLUMN_WIDTH_IS_CALLED); // column.setData(Integer.valueOf(COLUMN_ID_IS_CALLED3)); column.setData(Integer.valueOf(COLUMN_ID_IS_CALLED)); column.setMoveable(true); column.setResizable(true); column.addSelectionListener(new CalledColumnSelectionHandler()); table.setLayoutData(new GridData(GridData.FILL_BOTH)); // table.setLayout(new FillLayout()); table.setHeaderVisible(true); table.setLinesVisible(true); table.setRedraw(true); // when a row is selected, allow the user to double-click or right click and make that function the selected function table.addSelectionListener(new SelectionAdapter() { public void widgetDefaultSelected(SelectionEvent se) { TableItem item = (TableItem) se.item; Table table = (Table) se.widget; CallerCalleeItem callerCallee = (CallerCalleeItem) item.getData(); // deselect this row table.deselectAll(); // choose this row's function chooseNewFunction(callerCallee); } }); table.addMouseListener(new CalleeMouseListener()); table.addFocusListener(new FocusListener() { IAction oldCopyAction = null; public void focusGained(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); // modify what is executed when Copy is called from the Edit menu oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId()); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction); copyAction.setEnabled(calleeTable.getSelectionCount() > 0); bars.updateActionBars(); // add to the Edit menu IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT); if (editMenuManager instanceof SubMenuManager) { IContributionManager editManager = ((SubMenuManager) editMenuManager).getParent(); ActionContributionItem item; editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ copyTableAction.setEnabled(calleeTable.getItemCount() > 0); item = new ActionContributionItem(copyTableAction); item.setVisible(true); editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item); } // add to the File menu IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE); if (fileMenuManager instanceof SubMenuManager) { IContributionManager fileManager = ((SubMenuManager) fileMenuManager).getParent(); ActionContributionItem item; fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ saveTableAction.setEnabled(calleeTable.getItemCount() > 0); item = new ActionContributionItem(saveTableAction); item.setVisible(true); fileManager.insertAfter("saveAll", item); //$NON-NLS-1$ } } public void focusLost(org.eclipse.swt.events.FocusEvent arg0) { IActionBars bars = PIPageEditor.getActionBars(); bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction); bars.updateActionBars(); SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_EDIT); editMenuManager.remove("PICopyTable"); //$NON-NLS-1$ SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager() .find(IIDEActionConstants.M_FILE); fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$ } }); } private void chooseNewFunction(CallerCalleeItem callerCalleeItem) { // find the correct line in the function table and select it int count = currentFunctionTable.getItemCount(); for (int i = 0; i < count; i++) { GfcFunctionItem functionItem = (GfcFunctionItem) (currentFunctionTable.getItem(i).getData()); if (functionItem.name.equals(callerCalleeItem.item.name) && functionItem.dllName.equals(callerCalleeItem.item.dllName)) { currentFunctionTable.select(i); currentFunctionTable.showSelection(); updateCallerCalleeTables(functionItem); return; } } } public void updateCallerCalleeTables(GfcFunctionItem item) { Table table; TableColumn sortByColumn; setCallerListToFunctionsThatCallThisFunction(item); setCalleeListToFunctionsThisFunctionCalls(item); callerTableViewer.setInput(callerList); if ((callerList != null) && (callerList.length > 0)) { SharedSorter sorter = ((SharedSorter) callerTableViewer.getSorter()); int columnID = sorter.getColumnID(); if (columnID == -1) { columnID = COLUMN_ID_CALLER_PERCENT; } else { sorter.setSortAscending(!sorter.getSortAscending()); } sorter.doSort(columnID); sortByColumn = null; table = callerTableViewer.getTable(); for (int i = 0; i < table.getColumnCount(); i++) { if (table.getColumn(i).getData() instanceof Integer) { if (((Integer) table.getColumn(i).getData()) == columnID) { sortByColumn = table.getColumn(i); break; } } } if (sortByColumn != null) { table.setSortColumn(sortByColumn); table.setSortDirection(sorter.getSortAscending() ? SWT.UP : SWT.DOWN); } callerTableViewer.refresh(); } else { callerTableViewer.getTable().setSortColumn(null); } calleeTableViewer.setInput(calleeList); if ((calleeList != null) && (calleeList.length > 0)) { SharedSorter sorter = ((SharedSorter) calleeTableViewer.getSorter()); int columnID = sorter.getColumnID(); if (columnID == -1) { columnID = COLUMN_ID_CALLEE_PERCENT; } else { sorter.setSortAscending(!sorter.getSortAscending()); } sorter.doSort(columnID); sortByColumn = null; table = calleeTableViewer.getTable(); for (int i = 0; i < table.getColumnCount(); i++) { if (table.getColumn(i).getData() instanceof Integer) { if (((Integer) table.getColumn(i).getData()) == columnID) { sortByColumn = table.getColumn(i); break; } } } if (sortByColumn != null) { table.setSortColumn(sortByColumn); table.setSortDirection(sorter.getSortAscending() ? SWT.UP : SWT.DOWN); } calleeTableViewer.refresh(); } else { calleeTableViewer.getTable().setSortColumn(null); } } private class CallerMouseListener implements MouseListener { public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) { } public void mouseDown(org.eclipse.swt.events.MouseEvent me) { } public void mouseUp(org.eclipse.swt.events.MouseEvent me) { copyAction.setEnabled(callerTable.getSelectionCount() > 0); copyTableAction.setEnabled(callerTable.getItemCount() > 0); // only look for button 3 (right click) if (me.button != MouseEvent.BUTTON3) return; // make the caller table the menu table currentMenuTable = callerTable; if (callerMenu != null) { callerMenu.dispose(); } callerMenu = new Menu(callerTable.getShell(), SWT.POP_UP); MenuItem showCallInfoItem = new MenuItem(callerMenu, SWT.PUSH); showCallInfoItem.setText(Messages.getString("CallVisualiser.showCallInfo")); //$NON-NLS-1$ showCallInfoItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent se) { // based on the table's selected item, update the tables TableItem[] selections = callerTable.getSelection(); callerTable.deselectAll(); if (selections.length != 0) chooseNewFunction((CallerCalleeItem) selections[0].getData()); } }); new MenuItem(callerMenu, SWT.SEPARATOR); MenuItem sourceLookupItem = new MenuItem(callerMenu, SWT.PUSH); sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup")); //$NON-NLS-1$ sourceLookupItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent arg0) { } public void widgetSelected(SelectionEvent arg0) { doSourceLookup(callerTable); } }); if (callerTable.getSelectionCount() == 0) { showCallInfoItem.setEnabled(false); sourceLookupItem.setEnabled(false); } // add copy, copy all, and save all new MenuItem(callerMenu, SWT.SEPARATOR); getCopyItem(callerMenu, callerTable.getSelectionCount() > 0); getCopyTableItem(callerMenu, callerTable.getItemCount() > 0); copyAction.setEnabled(callerTable.getSelectionCount() > 0); copyTableAction.setEnabled(callerTable.getItemCount() > 0); new MenuItem(callerMenu, SWT.SEPARATOR); getSaveTableItem(callerMenu, callerTable.getItemCount() > 0); saveTableAction.setEnabled(callerTable.getItemCount() > 0); // save samples int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f); int endTime = (int) (PIPageEditor.currentPageEditor().getEndTime() * 1000.0f); if ((startTime == -1) || (endTime == -1) || (startTime == endTime)) getSaveSamplesItem(callerMenu, false); //$NON-NLS-1$ else getSaveSamplesItem(callerMenu, true); //$NON-NLS-1$ callerMenu.setLocation(callerTable.getParent().toDisplay(me.x, me.y)); callerMenu.setVisible(true); callerTable.setMenu(callerMenu); } } private class CurrentFunctionMouseListener implements MouseListener { public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) { } public void mouseDown(org.eclipse.swt.events.MouseEvent me) { } public void mouseUp(org.eclipse.swt.events.MouseEvent me) { copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0); functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); // only look for button 3 (right click) if (me.button != MouseEvent.BUTTON3) return; // make the current function table the menu table currentMenuTable = currentFunctionTable; if (currentFunctionMenu != null) { currentFunctionMenu.dispose(); } currentFunctionMenu = new Menu(currentFunctionTable.getShell(), SWT.POP_UP); // new MenuItem(callerMenu, SWT.SEPARATOR); MenuItem sourceLookupItem = new MenuItem(currentFunctionMenu, SWT.PUSH); sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup")); //$NON-NLS-1$ sourceLookupItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent arg0) { } public void widgetSelected(SelectionEvent arg0) { doSourceLookup(currentFunctionTable); } }); if (currentFunctionTable.getSelectionCount() == 0) { sourceLookupItem.setEnabled(false); } // add copy, copy all, copy caller/callee info, save all, save caller/callee info new MenuItem(currentFunctionMenu, SWT.SEPARATOR); getCopyItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0); getCopyTableItem(currentFunctionMenu, currentFunctionTable.getItemCount() > 0); getCopyFunctionItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0); copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0); functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); new MenuItem(currentFunctionMenu, SWT.SEPARATOR); getSaveTableItem(currentFunctionMenu, currentFunctionTable.getItemCount() > 0); getSaveFunctionItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0); saveTableAction.setEnabled(currentFunctionTable.getItemCount() > 0); functionSaveFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0); // save samples int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f); int endTime = (int) (PIPageEditor.currentPageEditor().getEndTime() * 1000.0f); if ((startTime == -1) || (endTime == -1) || (startTime == endTime)) getSaveSamplesItem(currentFunctionMenu, false); //$NON-NLS-1$ else getSaveSamplesItem(currentFunctionMenu, true); //$NON-NLS-1$ currentFunctionMenu.setLocation(currentFunctionTable.getParent().toDisplay(me.x, me.y)); currentFunctionMenu.setVisible(true); currentFunctionTable.setMenu(currentFunctionMenu); } } private class CalleeMouseListener implements MouseListener { public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) { } public void mouseDown(org.eclipse.swt.events.MouseEvent me) { } public void mouseUp(org.eclipse.swt.events.MouseEvent me) { copyAction.setEnabled(calleeTable.getSelectionCount() > 0); copyTableAction.setEnabled(calleeTable.getItemCount() > 0); // only look for button 3 (right click) if (me.button != MouseEvent.BUTTON3) return; // make the callee table the menu table currentMenuTable = calleeTable; if (calleeMenu != null) { calleeMenu.dispose(); } calleeMenu = new Menu(calleeTable.getShell(), SWT.POP_UP); MenuItem showCallInfoItem = new MenuItem(calleeMenu, SWT.PUSH); showCallInfoItem.setText(Messages.getString("CallVisualiser.showCallInfo")); //$NON-NLS-1$ showCallInfoItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent se) { // based on the table's selected item, update the tables TableItem[] selections = calleeTable.getSelection(); calleeTable.deselectAll(); if (selections.length != 0) chooseNewFunction((CallerCalleeItem) selections[0].getData()); } }); new MenuItem(calleeMenu, SWT.SEPARATOR); MenuItem sourceLookupItem = new MenuItem(calleeMenu, SWT.PUSH); sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup")); //$NON-NLS-1$ sourceLookupItem.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent arg0) { } public void widgetSelected(SelectionEvent arg0) { doSourceLookup(calleeTable); } }); if (calleeTable.getSelectionCount() == 0) { showCallInfoItem.setEnabled(false); sourceLookupItem.setEnabled(false); } // add copy, copy all, and save all new MenuItem(calleeMenu, SWT.SEPARATOR); getCopyItem(calleeMenu, calleeTable.getSelectionCount() > 0); getCopyTableItem(calleeMenu, calleeTable.getItemCount() > 0); copyAction.setEnabled(calleeTable.getSelectionCount() > 0); copyTableAction.setEnabled(calleeTable.getItemCount() > 0); new MenuItem(calleeMenu, SWT.SEPARATOR); getSaveTableItem(calleeMenu, calleeTable.getItemCount() > 0); saveTableAction.setEnabled(calleeTable.getItemCount() > 0); // save samples int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f); int endTime = (int) (PIPageEditor.currentPageEditor().getEndTime() * 1000.0f); if ((startTime == -1) || (endTime == -1) || (startTime == endTime)) getSaveSamplesItem(calleeMenu, false); //$NON-NLS-1$ else getSaveSamplesItem(calleeMenu, true); //$NON-NLS-1$ calleeMenu.setLocation(calleeTable.getParent().toDisplay(me.x, me.y)); calleeMenu.setVisible(true); calleeTable.setMenu(calleeMenu); } } protected void createDefaultActions(boolean copyFunction) { copyAction = new Action(Messages.getString("CallVisualiser.0")) { //$NON-NLS-1$ public void run() { action("copy"); //$NON-NLS-1$ } }; copyAction.setEnabled(false); copyTableAction = new Action(Messages.getString("CallVisualiser.1")) { //$NON-NLS-1$ public void run() { action("copyTable"); //$NON-NLS-1$ } }; copyTableAction.setEnabled(true); copyTableAction.setId("PICopyTable"); //$NON-NLS-1$ copyTableAction.setText(Messages.getString("CallVisualiser.CopyTable")); //$NON-NLS-1$ saveTableAction = new Action(Messages.getString("CallVisualiser.2")) { //$NON-NLS-1$ public void run() { action("saveTable"); //$NON-NLS-1$ } }; saveTableAction.setEnabled(true); saveTableAction.setId("PISaveTable"); //$NON-NLS-1$ saveTableAction.setText(Messages.getString("CallVisualiser.SaveTable")); //$NON-NLS-1$ functionCopyFunctionAction = new Action(Messages.getString("CallVisualiser.3")) { //$NON-NLS-1$ public void run() { action("copyFunction"); //$NON-NLS-1$ } }; functionCopyFunctionAction.setEnabled(true); functionCopyFunctionAction.setId("PICopyFunction"); //$NON-NLS-1$ functionCopyFunctionAction.setText(Messages.getString("CallVisualiser.CopyDataForFunction")); //$NON-NLS-1$ functionSaveFunctionAction = new Action(Messages.getString("CallVisualiser.4")) { //$NON-NLS-1$ public void run() { action("saveFunction"); //$NON-NLS-1$ } }; functionSaveFunctionAction.setEnabled(true); functionSaveFunctionAction.setId("PISaveFunction"); //$NON-NLS-1$ functionSaveFunctionAction.setText(Messages.getString("CallVisualiser.SaveDataForFunction")); //$NON-NLS-1$ } private class SharedLabelProvider extends LabelProvider implements ITableLabelProvider { Table table; public SharedLabelProvider(Table table) { super(); this.table = table; } public String getColumnText(Object element, int columnIndex) { if (!(element instanceof GfcFunctionItem) && !(element instanceof CallerCalleeItem)) return ""; //$NON-NLS-1$ int columnId = ((Integer) this.table.getColumn(columnIndex).getData()).intValue(); GfcFunctionItem item = null; if (element instanceof GfcFunctionItem) item = (GfcFunctionItem) element; else item = ((CallerCalleeItem) element).item; switch (columnId) { case COLUMN_ID_CALLEE_PERCENT: case COLUMN_ID_CALLER_PERCENT: { double percent; if (element instanceof CallerCalleeItem) percent = ((CallerCalleeItem) element).percent; else percent = 0.0; // Percent load string return (new DecimalFormat(Messages.getString("CallVisualiser.shortDecimalFormat"))).format(percent); //$NON-NLS-1$ } case COLUMN_ID_FUNCTION: { // Function return item.name; } case COLUMN_ID_START_ADDR: { // Function start return Long.toHexString(item.address); } case COLUMN_ID_IN_BINARY: { // Binary String binary = item.dllName; int index = binary.lastIndexOf('\\'); if (index == -1) return binary; else return binary.substring(index + 1); } case COLUMN_ID_IN_BINARY_PATH: { // Path String binary = item.dllName; int index = binary.lastIndexOf('\\'); if (index == -1) return ""; //$NON-NLS-1$ else return binary.substring(0, index); } case COLUMN_ID_IS_CALLED: { // Percent load string return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))) //$NON-NLS-1$ .format(myTrace.getAbsoluteTraditionalPercentageFor(item)); } case COLUMN_ID_IS_CALLER: { // Percent load string return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))) //$NON-NLS-1$ .format(myTrace.getAbsoluteCallerPercentageFor(item)); } case COLUMN_ID_RECURSIVE_CALL: { // Percent load string return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))) //$NON-NLS-1$ .format(myTrace.getRecursiveCallerPrecentageFor(item)); } case COLUMN_ID_IS_CALLED_COUNT: { // Sample count int samples; if (element instanceof CallerCalleeItem) samples = ((CallerCalleeItem) element).samples; else samples = item.isCalledCount(); return String.valueOf(samples); } case COLUMN_ID_IS_CALLER_COUNT: { // Sample count int samples; if (element instanceof CallerCalleeItem) samples = ((CallerCalleeItem) element).samples; else samples = item.isCallerCount(); return String.valueOf(samples); } default: { break; } } // should never get here return ""; //$NON-NLS-1$ } public Image getColumnImage(Object element, int columnIndex) { return null; } } public void selectFunction(String functionName) { } public void setStartAndEnd(int start, int end) { if (this.myTrace == null) return; this.curStart = start; this.curEnd = end; needsRefresh = true; if (isPageActive) { setTimeframeJob.cancel(); setTimeframeJob.schedule(); } } private static class CallerCalleeItem { GfcFunctionItem item; double percent; int samples; } public void setCallerListToFunctionsThatCallThisFunction(GfcFunctionItem function) { if (function == null) { this.callerList = null; return; } GfcFunctionItem[] list = function.getCallerList(); Double[] perc = function.getCallerPercentages(); this.callerList = new CallerCalleeItem[list.length]; for (int i = 0; i < list.length; i++) { this.callerList[i] = new CallerCalleeItem(); this.callerList[i].item = list[i]; this.callerList[i].percent = perc[i]; this.callerList[i].samples = (int) (perc[i] * function.isCalledCount() + 0.5) / 100; } } public void setCalleeListToFunctionsThisFunctionCalls(GfcFunctionItem function) { if (function == null) { this.calleeList = null; return; } GfcFunctionItem[] list = function.getCalleeList(); Double[] perc = function.getCalleePercentages(); this.calleeList = new CallerCalleeItem[list.length]; for (int i = 0; i < list.length; i++) { this.calleeList[i] = new CallerCalleeItem(); this.calleeList[i].item = list[i]; this.calleeList[i].percent = perc[i]; this.calleeList[i].samples = (int) (perc[i] * function.isCallerCount() + 0.5) / 100; } } public void action(String actionString) { if (actionString.equals("copy")) //$NON-NLS-1$ { actionCopyOrSave(true, currentMenuTable, CHECKBOX_NONE, false, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ return; } else if (actionString.equals("copyTable")) //$NON-NLS-1$ { actionCopyOrSave(true, currentMenuTable, CHECKBOX_NONE, true, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ return; } else if (actionString.equals("copyFunction")) //$NON-NLS-1$ { actionCopyOrSaveFunction(true, "\t"); //$NON-NLS-1$ return; } else if (actionString.equals("saveTable")) //$NON-NLS-1$ { actionCopyOrSave(false, currentMenuTable, CHECKBOX_NONE, true, ",", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ return; } else if (actionString.equals("saveFunction")) //$NON-NLS-1$ { actionCopyOrSaveFunction(false, ","); //$NON-NLS-1$ return; } else if (actionString.equals("saveSamples")) //$NON-NLS-1$ { SaveSampleString saveSampleString = new SaveSampleString(); actionSaveSamples(saveSampleString); //$NON-NLS-1$ return; } else if (actionString.equals("saveTableTest")) //$NON-NLS-1$ { // copy save file contents to the clipboard for easy viewing Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); SaveTableString getString = new SaveTableString(currentMenuTable, CHECKBOX_NONE, ",", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ String copyString = getString.getData(); StringSelection contents = new StringSelection(copyString); cb.setContents(contents, contents); return; } else if (actionString.equals("saveFunctionTest")) //$NON-NLS-1$ { // copy save file contents to the clipboard for easy viewing Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); SaveFunctionString getString = new SaveFunctionString(","); //$NON-NLS-1$ String copyString = getString.getData(); StringSelection contents = new StringSelection(copyString); cb.setContents(contents, contents); return; } } /* * TableViewer sorter for the called-by and called function tableviewers */ private class SharedSorter extends ViewerSorter { // sort direction private boolean sortAscending; // last column sorted private int column = -1; /* * decide on which column to sort by, and the sort ordering */ public void doSort(int column) { // ignore the column passed in and use the id set by the column selection handler if (column == this.column) { // sort in other order sortAscending = !sortAscending; } else { switch (column) { case COLUMN_ID_FUNCTION: case COLUMN_ID_START_ADDR: case COLUMN_ID_IN_BINARY: case COLUMN_ID_IN_BINARY_PATH: { // sort in ascending order sortAscending = true; break; } case COLUMN_ID_IS_CALLED: case COLUMN_ID_IS_CALLER: case COLUMN_ID_RECURSIVE_CALL: case COLUMN_ID_CALLER_PERCENT: case COLUMN_ID_CALLEE_PERCENT: case COLUMN_ID_IS_CALLED_COUNT: case COLUMN_ID_IS_CALLER_COUNT: { // sort in descending order sortAscending = false; break; } default: { // ignore the column return; } } this.column = column; } } /* * compare two items from a table column */ public int compare(Viewer viewer, Object e1, Object e2) { int comparison = 0; GfcFunctionItem item1 = null; GfcFunctionItem item2 = null; CallerCalleeItem ccItem1 = null; CallerCalleeItem ccItem2 = null; if (e1 instanceof GfcFunctionItem) { item1 = (GfcFunctionItem) e1; item2 = (GfcFunctionItem) e2; } else { ccItem1 = (CallerCalleeItem) e1; ccItem2 = (CallerCalleeItem) e2; item1 = ccItem1.item; item2 = ccItem2.item; } switch (column) { case COLUMN_ID_CALLER_PERCENT: case COLUMN_ID_CALLEE_PERCENT: { double percent1; double percent2; if (e1 instanceof GfcFunctionItem) { percent1 = 0.0; percent2 = 0.0; } else { percent1 = ccItem1.percent; percent2 = ccItem2.percent; } comparison = percent1 > percent2 ? 1 : -1; break; } case COLUMN_ID_FUNCTION: { comparison = this.getComparator().compare(item1.name, item2.name); break; } case COLUMN_ID_START_ADDR: { comparison = (item1.address > item2.address) ? 1 : -1; break; } case COLUMN_ID_IN_BINARY: { int index; String name1 = item1.dllName; index = name1.lastIndexOf('\\'); if (index != -1) name1 = name1.substring(index); String name2 = item2.dllName; index = name2.lastIndexOf('\\'); if (index != -1) name2 = name2.substring(index); comparison = this.getComparator().compare(name1, name2); break; } case COLUMN_ID_IN_BINARY_PATH: { int index; String name1 = item1.dllName; index = name1.lastIndexOf('\\'); if (index == -1) name1 = ""; //$NON-NLS-1$ else name1 = name1.substring(0, index); String name2 = item2.dllName; index = name2.lastIndexOf('\\'); if (index == -1) name2 = ""; //$NON-NLS-1$ else name2 = name2.substring(0, index); comparison = this.getComparator().compare(name1, name2); break; } case COLUMN_ID_IS_CALLED: { // actual sample count used as a proxy for the percentage comparison = item1.isCalledCount() - item2.isCalledCount(); break; } case COLUMN_ID_IS_CALLER: { // actual sample count used as a proxy for the percentage comparison = item1.isCallerCount() - item2.isCallerCount(); break; } case COLUMN_ID_RECURSIVE_CALL: { comparison = myTrace.getRecursiveCallerPrecentageFor(item1) > myTrace .getRecursiveCallerPrecentageFor(item2) ? 1 : -1; break; } case COLUMN_ID_IS_CALLED_COUNT: { if (e1 instanceof GfcFunctionItem) { comparison = item1.isCalledCount() - item2.isCalledCount(); } else { comparison = ccItem1.samples - ccItem2.samples; } break; } case COLUMN_ID_IS_CALLER_COUNT: { if (e1 instanceof GfcFunctionItem) { comparison = item1.isCallerCount() - item2.isCallerCount(); } else { comparison = ccItem1.samples - ccItem2.samples; } break; } default: { break; } } // for descending order, reverse the sense of the compare if (!sortAscending) comparison = -comparison; return comparison; } public boolean getSortAscending() { return sortAscending; } public void setSortAscending(boolean sortAscending) { this.sortAscending = sortAscending; } public int getColumnID() { return column; } } public void sortAndRefresh(TableViewer tableViewer, TableColumn tableColumn) { Table table = tableViewer.getTable(); int columnID = ((Integer) tableColumn.getData()).intValue(); if (table.getItemCount() == 0) return; // sort by selected columnID ((SharedSorter) tableViewer.getSorter()).doSort(columnID); table.setSortColumn(tableColumn); table.setSortDirection(((SharedSorter) tableViewer.getSorter()).getSortAscending() ? SWT.UP : SWT.DOWN); tableViewer.refresh(); } private class CalledByColumnSelectionHandler extends SelectionAdapter { public void widgetSelected(SelectionEvent e) { if (!(e.widget instanceof TableColumn)) return; sortAndRefresh(callerTableViewer, (TableColumn) e.widget); } } private class CalledColumnSelectionHandler extends SelectionAdapter { public void widgetSelected(SelectionEvent e) { if (!(e.widget instanceof TableColumn)) return; sortAndRefresh(calleeTableViewer, (TableColumn) e.widget); } } private class CheckboxColumnSelectionHandler extends SelectionAdapter { public void widgetSelected(SelectionEvent e) { if (!(e.widget instanceof TableColumn)) return; sortAndRefresh(currentFunctionTableViewer, (TableColumn) e.widget); } } public PIPageEditor getPageEditor() { return this.pageEditor; } public int getPageIndex() { return this.pageIndex; } private MenuItem getCopyFunctionItem(Menu menu, boolean enabled) { MenuItem copyFunctionItem = new MenuItem(menu, SWT.PUSH); copyFunctionItem.setText(Messages.getString("CallVisualiser.CopyDataForFunction")); //$NON-NLS-1$ copyFunctionItem.setEnabled(enabled); if (enabled) { copyFunctionItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { action("copyFunction"); //$NON-NLS-1$ } }); } return copyFunctionItem; } private MenuItem getSaveFunctionItem(Menu menu, boolean enabled) { MenuItem saveFunctionItem = new MenuItem(menu, SWT.PUSH); saveFunctionItem.setText(Messages.getString("CallVisualiser.SaveDataForFunction")); //$NON-NLS-1$ saveFunctionItem.setEnabled(enabled); if (enabled) { saveFunctionItem.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { action("saveFunction"); //$NON-NLS-1$ } }); } return saveFunctionItem; } private void doSourceLookup(Table mytable) { // source look up for selected items if ((mytable.getItemCount() == 0) || (mytable.getSelectionCount() == 0)) return; TableItem selectedItem = mytable.getSelection()[0]; Object selectedData = selectedItem.getData(); String functionName = null; String binaryName = null; if (selectedData instanceof GfcFunctionItem) { GfcFunctionItem functionItem = (GfcFunctionItem) selectedData; functionName = functionItem.name; binaryName = functionItem.dllName; } else if (selectedData instanceof CallerCalleeItem) { CallerCalleeItem callerCalleeItem = (CallerCalleeItem) selectedData; functionName = callerCalleeItem.item.name; binaryName = callerCalleeItem.item.dllName; } if (functionName != null && binaryName != null) { SourceLookup.getInstance().lookupAndopenEditorWithHighlight(functionName, binaryName); } } // class to pass the function caller/callee data to the save wizard private class SaveFunctionString implements ISaveTable { private String separator; public SaveFunctionString(String separator) { this.separator = separator; } public String getData() { return copyFunction(separator); } } private void actionCopyOrSaveFunction(boolean doCopy, String separator) { // one function must be selected if (currentFunctionTable.getSelectionCount() != 1) return; // copy one function's caller and callee data to the clipboard or save to a file if (doCopy) { // change the clipboard contents Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); String copyString = copyFunction(separator); StringSelection contents = new StringSelection(copyString); cb.setContents(contents, contents); } else { SaveFunctionString getString = new SaveFunctionString(separator); WizardDialog dialog; Wizard w = new SaveTableWizard(getString); dialog = new WizardDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), w); dialog.open(); } } private String copyFunction(String separator) { // one function must be selected if (currentFunctionTable.getSelectionCount() != 1) return ""; //$NON-NLS-1$ String copyString = ""; //$NON-NLS-1$ // create the multiple table heading line (e.g., "Selected Function Callers") // space them out based on how many columns are in their table if (currentFunctionTable.getData() instanceof String) { copyString += (String) (currentFunctionTable.getData()); } for (int j = 0; j < currentFunctionTable.getColumnCount(); j++) { copyString += separator; } if (callerTable.getData() instanceof String) { copyString += (String) (callerTable.getData()); } for (int j = 0; j < callerTable.getColumnCount(); j++) { copyString += separator; } if (calleeTable.getData() instanceof String) { copyString += (String) (calleeTable.getData()); } for (int j = 0; j < calleeTable.getColumnCount(); j++) { copyString += separator; } copyString += "\n"; //$NON-NLS-1$ // create the multiple table column headings copyString += copyHeading(currentFunctionTable, CHECKBOX_NONE, separator, separator); //$NON-NLS-1$ copyString += copyHeading(callerTable, CHECKBOX_NONE, separator, separator); //$NON-NLS-1$ copyString += copyHeading(calleeTable, CHECKBOX_NONE, separator, "\n"); //$NON-NLS-1$ // determine the row, column count, and column ordering in each table // NOTE: the first table in the copy will contain the function, and it only its // one selected line will be shown int rowCount0 = 1; int columnCount0 = currentFunctionTable.getColumnCount(); int[] columnOrder0 = currentFunctionTable.getColumnOrder(); boolean[] isHex0 = (boolean[]) currentFunctionTable.getData("isHex"); //$NON-NLS-1$ String emptyRow0 = ""; //$NON-NLS-1$ int rowCount1 = callerTable.getItemCount(); int columnCount1 = callerTable.getColumnCount(); int[] columnOrder1 = callerTable.getColumnOrder(); boolean[] isHex1 = (boolean[]) callerTable.getData("isHex"); //$NON-NLS-1$ String emptyRow1 = ""; //$NON-NLS-1$ int rowCount2 = calleeTable.getItemCount(); int columnCount2 = calleeTable.getColumnCount(); int[] columnOrder2 = calleeTable.getColumnOrder(); boolean[] isHex2 = (boolean[]) calleeTable.getData("isHex"); //$NON-NLS-1$ String emptyRow2 = ""; //$NON-NLS-1$ // determine the number of multiple table rows (max of any table's rows) int rowCount = rowCount0 >= rowCount1 ? rowCount0 : rowCount1; rowCount = rowCount2 > rowCount ? rowCount2 : rowCount; // generate empty row strings, to speed things up if (rowCount0 < rowCount) { for (int j = 0; j < columnCount0 - 1; j++) { emptyRow0 += separator; } } if (rowCount1 < rowCount) { for (int j = 0; j < columnCount1; j++) { emptyRow1 += separator; } } if (rowCount2 < rowCount) { for (int j = 0; j < columnCount2; j++) { emptyRow2 += separator; } } // generate the rows for (int i = 0; i < rowCount; i++) { if (i < 1) { copyString += copyRow(isHex0, currentFunctionTable.getItem(currentFunctionTable.getSelectionIndex()), CHECKBOX_NONE, columnCount0, columnOrder0, separator); } else { copyString += emptyRow0; } if (i < rowCount1) { copyString += separator + copyRow(isHex1, callerTable.getItem(i), CHECKBOX_NONE, columnCount1, columnOrder1, separator); } else { // NOTE: if this is the last table, or the 3rd table has nothing but empty // rows left, we may not need to fill in these fields copyString += emptyRow1; } if (i < rowCount2) { copyString += separator + copyRow(isHex2, calleeTable.getItem(i), CHECKBOX_NONE, columnCount2, columnOrder2, separator); } else { // NOTE: we may not need to fill in the empty fields of the last table copyString += emptyRow2; } copyString += "\n"; //$NON-NLS-1$ } return copyString; } private void createSetTimeframeJob() { //this functionality used to be in the setStartEnd() method //but now the long-running calculations are in a background job //and the short-running refresh of table viewers is done in the UI thread setTimeframeJob = new Job("Updating function hierarchy...") { @Override protected IStatus run(IProgressMonitor monitor) { //run the time consuming calculations in the background if (myTrace == null) { return Status.CANCEL_STATUS; } needsRefresh = false; myTrace.parseEntries(curStart, curEnd); functionArray = myTrace.getEntriesSorted(GfcTrace.SORT_BY_TOTAL_LOAD); return Status.OK_STATUS; } }; setTimeframeJob.addJobChangeListener(new JobChangeAdapter() { public void done(IJobChangeEvent event) { if (event.getResult().isOK()) { Display.getDefault().syncExec(new Runnable() { public void run() { if (!currentFunctionTableViewer.getControl().isDisposed()) { //updating the table viewers has to be done in the UI thread (this operation doesn't take long) currentFunctionTableViewer.setInput(functionArray); updateCallerCalleeTables(null); Table table = currentFunctionTableViewer.getTable(); if (table.getItemCount() == 0) return; if (table.getSortColumn() == null) { table.setSortColumn(currentFunctionDefaultColumn); table.setSortDirection(SWT.UP); } else { // use the user's preferred sort column, if any boolean sortAscending = !((SharedSorter) currentFunctionTableViewer.getSorter()) .getSortAscending(); ((SharedSorter) currentFunctionTableViewer.getSorter()) .setSortAscending(sortAscending); } sortAndRefresh(currentFunctionTableViewer, table.getSortColumn()); } } }); } else { //unsuccessful operation: we still need to refresh needsRefresh = true; } } }); setTimeframeJob.setUser(true); //show a progress dialog to the user currentFunctionTableViewer.getControl().addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { setTimeframeJob.cancel(); } }); } private void createPageListeners() { final IPageChangedListener pageChangeListener = new IPageChangedListener() { /* (non-Javadoc) * @see org.eclipse.jface.dialogs.IPageChangedListener#pageChanged(org.eclipse.jface.dialogs.PageChangedEvent) */ public void pageChanged(PageChangedEvent event) { isPageActive = (event.getSelectedPage() == CallVisualiser.this.curPage);//compare on reference if (isPageActive && needsRefresh) { // if this ProfileVisualiser is the page being activated, // check if the time frame selection needs updating setTimeframeJob.cancel(); setTimeframeJob.schedule(); } } }; final IPartListener partListener = new IPartListener() { public void partActivated(IWorkbenchPart part) { if (part instanceof PIPageEditor) { PIPageEditor editor = (PIPageEditor) part; isPageActive = (editor.getActivePage() == pageIndex); if (isPageActive && needsRefresh) { setTimeframeJob.cancel(); setTimeframeJob.schedule(); } } } public void partBroughtToTop(IWorkbenchPart part) { // nothing to do } public void partClosed(IWorkbenchPart part) { if (part instanceof PIPageEditor) { //remove listeners PIPageEditor editor = (PIPageEditor) part; editor.removePageChangedListener(pageChangeListener); editor.getSite().getPage().removePartListener(this); } } public void partDeactivated(IWorkbenchPart part) { // nothing to do } public void partOpened(IWorkbenchPart part) { // nothing to do } }; PIPageEditor.currentPageEditor().addPageChangedListener(pageChangeListener); PIPageEditor.currentPageEditor().getSite().getPage().addPartListener(partListener); } // added to give JUnit tests access public TableViewer getCallerViewer() { return this.callerTableViewer; } // added to give JUnit tests access public TableViewer getCurrentFunctionViewer() { return this.currentFunctionTableViewer; } // added to give JUnit tests access public TableViewer getCalleeViewer() { return this.calleeTableViewer; } // added to give JUnit tests access public void setCurrentMenuTable(Table currentMenuTable) { this.currentMenuTable = currentMenuTable; } }